ember-primitives 0.39.0 → 0.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,58 @@
1
+ import Component from "@glimmer/component";
2
+ import type { Newable } from "./type-utils";
3
+ import type Owner from "@ember/owner";
4
+ export declare class Provide<Data extends object> extends Component<{
5
+ Args: {
6
+ /**
7
+ * What data do you want to provide to the DOM subtree?
8
+ *
9
+ * If this is a function or class, it will be instantiated and given an
10
+ * owner + destroyable linkage via `createStore`
11
+ */
12
+ data: Data | (() => Data) | Newable<Data>;
13
+ /**
14
+ * Optionally, you may use string-based keys to reference the data in the Provide.
15
+ *
16
+ * This is not recommended though, because when using a class or other object-like structure,
17
+ * the type in the `<Consume>` component can be derived from that class or object-like structure.
18
+ * With string keys, the `<Consume>` type will be unknown.
19
+ */
20
+ key?: string;
21
+ };
22
+ Blocks: {
23
+ /**
24
+ * The content that this component will _provide_ data to the entire hierarchy.
25
+ */
26
+ default: [];
27
+ };
28
+ }> {
29
+ get data(): Data;
30
+ element: HTMLDivElement;
31
+ constructor(owner: Owner, args: {
32
+ data: Data | (() => Data) | Newable<Data>;
33
+ key?: string;
34
+ });
35
+ }
36
+ type DataForKey<Key> = Key extends string ? unknown : Key extends Newable<infer T> ? T : Key extends () => infer T ? T : Key;
37
+ export declare class Consume<Key extends object | string> extends Component<{
38
+ Args: {
39
+ key: Key;
40
+ };
41
+ Blocks: {
42
+ default: [
43
+ context: {
44
+ data: DataForKey<Key>;
45
+ }
46
+ ];
47
+ };
48
+ }> {
49
+ getData: () => DataForKey<Key>;
50
+ element: HTMLDivElement;
51
+ constructor(owner: Owner, args: {
52
+ key: Key;
53
+ });
54
+ get context(): {
55
+ readonly data: DataForKey<Key>;
56
+ };
57
+ }
58
+ export {};
@@ -0,0 +1,86 @@
1
+ import Component from '@glimmer/component';
2
+ import { tracked, cached } from '@glimmer/tracking';
3
+ import { assert } from '@ember/debug';
4
+ import { createStore } from 'ember-primitives/store';
5
+ import { precompileTemplate } from '@ember/template-compilation';
6
+ import { setComponentTemplate } from '@ember/component';
7
+ import { g, i, n } from 'decorator-transforms/runtime';
8
+
9
+ const LOOKUP = new WeakMap();
10
+ class Provide extends Component {
11
+ get data() {
12
+ assert(`@data is missing in <Provide>. Please pass @data.`, "data" in this.args);
13
+ /**
14
+ * This covers both classes and functions
15
+ */
16
+ if (typeof this.args.data === "function") {
17
+ return createStore(this, this.args.data);
18
+ }
19
+ /**
20
+ * Non-instantiable value
21
+ */
22
+ return this.args.data;
23
+ }
24
+ element;
25
+ constructor(owner, args) {
26
+ super(owner, args);
27
+ const element = document.createElement("div");
28
+ element.style.display = "contents";
29
+ const key = this.args.key ?? this.args.data;
30
+ LOOKUP.set(element, [key, () => this.data]);
31
+ this.element = element;
32
+ }
33
+ static {
34
+ setComponentTemplate(precompileTemplate("\n {{this.element}}\n\n {{#in-element this.element}}\n {{yield}}\n {{/in-element}}\n ", {
35
+ strictMode: true
36
+ }), this);
37
+ }
38
+ }
39
+ function findForKey(startElement, key) {
40
+ let parent = startElement;
41
+ while (parent = parent.parentElement) {
42
+ const maybe = LOOKUP.get(parent);
43
+ if (!maybe) {
44
+ continue;
45
+ }
46
+ if (maybe[0] === key) {
47
+ return maybe[1];
48
+ }
49
+ }
50
+ }
51
+ class Consume extends Component {
52
+ static {
53
+ g(this.prototype, "getData", [tracked]);
54
+ }
55
+ #getData = (i(this, "getData"), void 0); // SAFETY: We do a runtime assert in the getter below.
56
+ element;
57
+ constructor(owner, args) {
58
+ super(owner, args);
59
+ this.element = document.createElement("div");
60
+ this.element.style.display = "contents";
61
+ }
62
+ get context() {
63
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
64
+ const self = this;
65
+ return {
66
+ get data() {
67
+ const getData = findForKey(self.element, self.args.key);
68
+ assert(`Could not find provided context in <Consume>. Please assure that there is a corresponding <Provide> component before using this <Consume> component`, getData);
69
+ // SAFETY: return type handled by getter's signature
70
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
71
+ return getData();
72
+ }
73
+ };
74
+ }
75
+ static {
76
+ n(this.prototype, "context", [cached]);
77
+ }
78
+ static {
79
+ setComponentTemplate(precompileTemplate("\n {{this.element}}\n\n {{#in-element this.element}}\n {{yield this.context}}\n {{/in-element}}\n ", {
80
+ strictMode: true
81
+ }), this);
82
+ }
83
+ }
84
+
85
+ export { Consume, Provide };
86
+ //# sourceMappingURL=dom-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dom-context.js","sources":["../src/dom-context.gts"],"sourcesContent":["import Component from \"@glimmer/component\";\nimport { cached, tracked } from \"@glimmer/tracking\";\nimport { assert } from \"@ember/debug\";\n\nimport { createStore } from \"ember-primitives/store\";\n\nimport type { Newable } from \"./type-utils\";\nimport type Owner from \"@ember/owner\";\n\n/**\n * IMPLEMENTATION NOTE:\n * we don't use https://github.com/webcomponents-cg/community-protocols/blob/main/proposals/context.md\n * because it is not inherently reactive.\n *\n * Its *event* based, which opts you out of fine-grained reactivity.\n * We want minimal effort fine-grained reactivity.\n *\n * This Technique follows the DOM tree, and is synchronous,\n * allowing correct fine-grained signals-based reactivity.\n *\n * We *could* do less work to find Providers,\n * but only if we forgoe DOM-tree scoping.\n * We must traverse the DOM hierarchy to validate that we aren't accessing providers from different subtrees.\n */\nconst LOOKUP = new WeakMap<Element, [unknown, () => unknown]>();\n\nexport class Provide<Data extends object> extends Component<{\n Args: {\n /**\n * What data do you want to provide to the DOM subtree?\n *\n * If this is a function or class, it will be instantiated and given an\n * owner + destroyable linkage via `createStore`\n */\n data: Data | (() => Data) | Newable<Data>;\n\n /**\n * Optionally, you may use string-based keys to reference the data in the Provide.\n *\n * This is not recommended though, because when using a class or other object-like structure,\n * the type in the `<Consume>` component can be derived from that class or object-like structure.\n * With string keys, the `<Consume>` type will be unknown.\n */\n key?: string;\n };\n Blocks: {\n /**\n * The content that this component will _provide_ data to the entire hierarchy.\n */\n default: [];\n };\n}> {\n get data() {\n assert(`@data is missing in <Provide>. Please pass @data.`, \"data\" in this.args);\n\n /**\n * This covers both classes and functions\n */\n if (typeof this.args.data === \"function\") {\n return createStore<Data>(this, this.args.data);\n }\n\n /**\n * Non-instantiable value\n */\n return this.args.data;\n }\n\n element: HTMLDivElement;\n\n constructor(\n owner: Owner,\n args: {\n data: Data | (() => Data) | Newable<Data>;\n key?: string;\n },\n ) {\n super(owner, args);\n\n const element = document.createElement(\"div\");\n\n element.style.display = \"contents\";\n\n const key = this.args.key ?? this.args.data;\n\n LOOKUP.set(element, [key, () => this.data]);\n this.element = element;\n }\n\n <template>\n {{this.element}}\n\n {{#in-element this.element}}\n {{yield}}\n {{/in-element}}\n </template>\n}\n\nfunction findForKey<Data>(startElement: Element, key: string | object): undefined | (() => Data) {\n let parent: Element | null = startElement;\n\n while ((parent = parent.parentElement)) {\n const maybe = LOOKUP.get(parent);\n\n if (!maybe) {\n continue;\n }\n\n if (maybe[0] === key) {\n return maybe[1] as () => Data;\n }\n }\n}\n\ntype DataForKey<Key> = Key extends string\n ? unknown\n : Key extends Newable<infer T>\n ? T\n : Key extends () => infer T\n ? T\n : Key;\n\nexport class Consume<Key extends object | string> extends Component<{\n Args: {\n key: Key;\n };\n Blocks: {\n default: [\n context: {\n data: DataForKey<Key>;\n },\n ];\n };\n}> {\n // SAFETY: We do a runtime assert in the getter below.\n @tracked getData!: () => DataForKey<Key>;\n\n element: HTMLDivElement;\n\n constructor(owner: Owner, args: { key: Key }) {\n super(owner, args);\n\n this.element = document.createElement(\"div\");\n this.element.style.display = \"contents\";\n }\n\n @cached\n get context() {\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n const self = this;\n\n return {\n get data(): DataForKey<Key> {\n const getData = findForKey<Key>(self.element, self.args.key);\n\n assert(\n `Could not find provided context in <Consume>. Please assure that there is a corresponding <Provide> component before using this <Consume> component`,\n getData,\n );\n\n // SAFETY: return type handled by getter's signature\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return getData() as any;\n },\n };\n }\n\n <template>\n {{this.element}}\n\n {{#in-element this.element}}\n {{yield this.context}}\n {{/in-element}}\n </template>\n}\n"],"names":["LOOKUP","WeakMap","Provide","Component","data","assert","args","createStore","element","constructor","owner","document","createElement","style","display","key","set","setComponentTemplate","precompileTemplate","strictMode","findForKey","startElement","parent","parentElement","maybe","get","Consume","tracked","i","void 0","context","self","getData","n","prototype","cached"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ember-primitives",
3
- "version": "0.39.0",
3
+ "version": "0.40.0",
4
4
  "description": "Making apps easier to build",
5
5
  "sideEffects": [
6
6
  "*.css"