From 3ba17dcdf9edb6e9e163368d2445520dee985f90 Mon Sep 17 00:00:00 2001 From: electrovir Date: Sat, 29 Jul 2023 01:01:51 +0000 Subject: [PATCH] add perInstance state prop helper --- package-lock.json | 4 +- package.json | 2 +- .../declarative-element-init.ts | 3 +- .../properties/per-instance.test.ts | 43 +++++++++++++++++++ .../properties/per-instance.ts | 13 ++++++ src/test/elements/all-book-entries.ts | 2 +- ...props-as-inputs.ts => observable-props.ts} | 21 ++++++--- 7 files changed, 77 insertions(+), 11 deletions(-) create mode 100644 src/declarative-element/properties/per-instance.test.ts create mode 100644 src/declarative-element/properties/per-instance.ts rename src/test/elements/entries/{observable-props-as-inputs.ts => observable-props.ts} (70%) diff --git a/package-lock.json b/package-lock.json index 26f01790..b4cbb37b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "element-vir", - "version": "16.0.3", + "version": "16.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "element-vir", - "version": "16.0.3", + "version": "16.1.0", "license": "(MIT or CC0 1.0)", "dependencies": { "@augment-vir/browser": "^16.0.1", diff --git a/package.json b/package.json index a3eb0e61..e683da0a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "element-vir", - "version": "16.0.3", + "version": "16.1.0", "keywords": [ "custom", "web", diff --git a/src/declarative-element/declarative-element-init.ts b/src/declarative-element/declarative-element-init.ts index 22180223..f9fa1efb 100644 --- a/src/declarative-element/declarative-element-init.ts +++ b/src/declarative-element/declarative-element-init.ts @@ -29,7 +29,8 @@ export type DeclarativeElementInit< styles?: CSSResult | StylesCallback; /** * The definition of and initial values for the element's internal state. Note that this is - * defined statically: the init value will be the same for all instances of this element. + * defined statically: the init value will be the same for all instances of this element because + * it is only defined once. */ stateInitStatic?: StateInit; /** Events that the element can dispatch. (These can be thought of as "outputs".) */ diff --git a/src/declarative-element/properties/per-instance.test.ts b/src/declarative-element/properties/per-instance.test.ts new file mode 100644 index 00000000..f7629ef6 --- /dev/null +++ b/src/declarative-element/properties/per-instance.test.ts @@ -0,0 +1,43 @@ +import {randomString} from '@augment-vir/browser'; +import {assertTypeOf, typedAssertInstanceOf} from '@augment-vir/browser-testing'; +import {assert, fixture as renderFixture} from '@open-wc/testing'; +import {html} from '../../template-transforms/vir-html/vir-html'; +import {defineElementNoInputs} from '../define-element-no-inputs'; +import {perInstance} from './per-instance'; + +describe(perInstance.name, () => { + it('allows host to be assigned to instance type', async () => { + const MyElement = defineElementNoInputs({ + tagName: `some-tag-${randomString()}`, + stateInitStatic: { + myPerInstanceProp: perInstance(() => ({stuff: 'hi'})), + }, + renderCallback({state}) { + assertTypeOf(state.myPerInstanceProp).toEqualTypeOf<{stuff: string}>(); + return state.myPerInstanceProp.stuff; + }, + }); + + const fixture = await renderFixture( + html` +
+ <${MyElement}> + <${MyElement}> +
+ `, + ); + + typedAssertInstanceOf(fixture, HTMLDivElement); + + const elements = Array.from(fixture.querySelectorAll(MyElement.tagName)); + + assert.lengthOf(elements, 2); + + typedAssertInstanceOf(elements[0], MyElement); + typedAssertInstanceOf(elements[1], MyElement); + assert.isFalse( + elements[0].instanceState.myPerInstanceProp === + elements[1].instanceState.myPerInstanceProp, + ); + }); +}); diff --git a/src/declarative-element/properties/per-instance.ts b/src/declarative-element/properties/per-instance.ts new file mode 100644 index 00000000..b06a0b47 --- /dev/null +++ b/src/declarative-element/properties/per-instance.ts @@ -0,0 +1,13 @@ +import {ElementVirStateSetup} from './element-vir-state-setup'; + +/** + * A state prop helper that sets up the given callback for each instance of the element that this + * state is contained within. + */ +export function perInstance(creationCallback: () => T): T { + const stateSetup: ElementVirStateSetup = { + _elementVirStateSetup: creationCallback, + }; + + return stateSetup as T; +} diff --git a/src/test/elements/all-book-entries.ts b/src/test/elements/all-book-entries.ts index 8defbecb..970c3986 100644 --- a/src/test/elements/all-book-entries.ts +++ b/src/test/elements/all-book-entries.ts @@ -1,4 +1,4 @@ -import {observablePropInputTestPage} from './entries/observable-props-as-inputs'; +import {observablePropInputTestPage} from './entries/observable-props'; import {oldTestAppPage} from './entries/old-test-app/vir-old-test-app.element'; export const allBookEntries = [ diff --git a/src/test/elements/entries/observable-props-as-inputs.ts b/src/test/elements/entries/observable-props.ts similarity index 70% rename from src/test/elements/entries/observable-props-as-inputs.ts rename to src/test/elements/entries/observable-props.ts index 9597a56c..34e0f22f 100644 --- a/src/test/elements/entries/observable-props-as-inputs.ts +++ b/src/test/elements/entries/observable-props.ts @@ -10,7 +10,7 @@ import { const myObservableProp = createObservablePropertyWithSetter(5); -const VirObservablePropInputTestParent = defineElementNoInputs({ +const VirObservablePropsTestParent = defineElementNoInputs({ tagName: 'vir-observable-prop-input-test-parent', stateInitStatic: { renderCount: 0, @@ -20,9 +20,9 @@ const VirObservablePropInputTestParent = defineElementNoInputs({ return html`

Parent render count (should not change): ${state.renderCount}

- <${VirObservablePropInputTestChild.assign({ + <${VirObservablePropsTestChild.assign({ observableProp: myObservableProp, - })}> + })}>

`; }, }); -const VirObservablePropInputTestChild = defineElement<{observableProp: typeof myObservableProp}>()({ +const VirObservablePropsTestChild = defineElement<{observableProp: typeof myObservableProp}>()({ tagName: 'vir-observable-prop-input-test-child', stateInitStatic: { renderCount: 0, @@ -46,6 +46,15 @@ const VirObservablePropInputTestChild = defineElement<{observableProp: typeof my return html`

child render count (should increase): ${state.renderCount}

observableProp value: ${inputs.observableProp.value}

+

+ +

`; }, }); @@ -58,7 +67,7 @@ export const observablePropInputTestPage = defineBookPage({ title: 'test', renderCallback() { return html` - <${VirObservablePropInputTestParent}> + <${VirObservablePropsTestParent}> `; }, });