Skip to content

Commit

Permalink
add perInstance state prop helper
Browse files Browse the repository at this point in the history
  • Loading branch information
electrovir committed Jul 29, 2023
1 parent 618f946 commit 3ba17dc
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 11 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "element-vir",
"version": "16.0.3",
"version": "16.1.0",
"keywords": [
"custom",
"web",
Expand Down
3 changes: 2 additions & 1 deletion src/declarative-element/declarative-element-init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ export type DeclarativeElementInit<
styles?: CSSResult | StylesCallback<TagName, HostClassKeys, CssVarKeys>;
/**
* 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".) */
Expand Down
43 changes: 43 additions & 0 deletions src/declarative-element/properties/per-instance.test.ts
Original file line number Diff line number Diff line change
@@ -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`
<div>
<${MyElement}></${MyElement}>
<${MyElement}></${MyElement}>
</div>
`,
);

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,
);
});
});
13 changes: 13 additions & 0 deletions src/declarative-element/properties/per-instance.ts
Original file line number Diff line number Diff line change
@@ -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<T>(creationCallback: () => T): T {
const stateSetup: ElementVirStateSetup<T> = {
_elementVirStateSetup: creationCallback,
};

return stateSetup as T;
}
2 changes: 1 addition & 1 deletion src/test/elements/all-book-entries.ts
Original file line number Diff line number Diff line change
@@ -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 = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -20,23 +20,23 @@ const VirObservablePropInputTestParent = defineElementNoInputs({
return html`
<p>Parent render count (should not change): ${state.renderCount}</p>
<p>
<${VirObservablePropInputTestChild.assign({
<${VirObservablePropsTestChild.assign({
observableProp: myObservableProp,
})}></${VirObservablePropInputTestChild}>
})}></${VirObservablePropsTestChild}>
</p>
<p>
<button
${listen('click', () => {
myObservableProp.setValue(randomInteger({min: 1, max: 100}));
})}
>
trigger update
trigger update from parent
</button>
</p>
`;
},
});
const VirObservablePropInputTestChild = defineElement<{observableProp: typeof myObservableProp}>()({
const VirObservablePropsTestChild = defineElement<{observableProp: typeof myObservableProp}>()({
tagName: 'vir-observable-prop-input-test-child',
stateInitStatic: {
renderCount: 0,
Expand All @@ -46,6 +46,15 @@ const VirObservablePropInputTestChild = defineElement<{observableProp: typeof my
return html`
<p>child render count (should increase): ${state.renderCount}</p>
<p>observableProp value: ${inputs.observableProp.value}</p>
<p>
<button
${listen('click', () => {
inputs.observableProp.setValue(randomInteger({min: 101, max: 200}));
})}
>
trigger update from child
</button>
</p>
`;
},
});
Expand All @@ -58,7 +67,7 @@ export const observablePropInputTestPage = defineBookPage({
title: 'test',
renderCallback() {
return html`
<${VirObservablePropInputTestParent}></${VirObservablePropInputTestParent}>
<${VirObservablePropsTestParent}></${VirObservablePropsTestParent}>
`;
},
});
Expand Down

0 comments on commit 3ba17dc

Please sign in to comment.