@microsoft/fast-element 1.10.5 → 2.0.0-beta.10

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.
Files changed (122) hide show
  1. package/.eslintrc.json +1 -12
  2. package/CHANGELOG.json +629 -6
  3. package/CHANGELOG.md +152 -5
  4. package/dist/dts/components/attributes.d.ts +14 -1
  5. package/dist/dts/components/{controller.d.ts → element-controller.d.ts} +32 -32
  6. package/dist/dts/components/fast-definitions.d.ts +51 -11
  7. package/dist/dts/components/fast-element.d.ts +18 -23
  8. package/dist/dts/context.d.ts +157 -0
  9. package/dist/{esm/observation/behavior.js → dts/debug.d.ts} +0 -0
  10. package/dist/dts/di/di.d.ts +899 -0
  11. package/dist/dts/index.d.ts +17 -16
  12. package/dist/dts/index.debug.d.ts +2 -0
  13. package/dist/dts/index.rollup.d.ts +2 -0
  14. package/dist/dts/index.rollup.debug.d.ts +3 -0
  15. package/dist/dts/interfaces.d.ts +176 -0
  16. package/dist/dts/metadata.d.ts +25 -0
  17. package/dist/dts/observation/arrays.d.ts +207 -0
  18. package/dist/dts/observation/notifier.d.ts +18 -18
  19. package/dist/dts/observation/observable.d.ts +117 -34
  20. package/dist/dts/observation/update-queue.d.ts +40 -0
  21. package/dist/dts/pending-task.d.ts +20 -0
  22. package/dist/dts/platform.d.ts +23 -66
  23. package/dist/dts/polyfills.d.ts +8 -0
  24. package/dist/dts/state/exports.d.ts +3 -0
  25. package/dist/dts/state/reactive.d.ts +8 -0
  26. package/dist/dts/state/state.d.ts +141 -0
  27. package/dist/dts/state/visitor.d.ts +6 -0
  28. package/dist/dts/state/watch.d.ts +10 -0
  29. package/dist/dts/styles/css-directive.d.ts +44 -6
  30. package/dist/dts/styles/css.d.ts +19 -3
  31. package/dist/dts/styles/element-styles.d.ts +49 -63
  32. package/dist/dts/styles/host.d.ts +68 -0
  33. package/dist/dts/templating/binding-signal.d.ts +21 -0
  34. package/dist/dts/templating/binding-two-way.d.ts +39 -0
  35. package/dist/dts/templating/binding.d.ts +101 -70
  36. package/dist/dts/templating/children.d.ts +18 -15
  37. package/dist/dts/templating/compiler.d.ts +46 -28
  38. package/dist/dts/templating/dom.d.ts +41 -0
  39. package/dist/dts/templating/html-directive.d.ts +239 -45
  40. package/dist/dts/templating/markup.d.ts +48 -0
  41. package/dist/dts/templating/node-observation.d.ts +45 -30
  42. package/dist/dts/templating/ref.d.ts +6 -20
  43. package/dist/dts/templating/render.d.ts +272 -0
  44. package/dist/dts/templating/repeat.d.ts +36 -33
  45. package/dist/dts/templating/slotted.d.ts +13 -14
  46. package/dist/dts/templating/template.d.ts +28 -22
  47. package/dist/dts/templating/view.d.ts +82 -24
  48. package/dist/dts/templating/when.d.ts +3 -3
  49. package/dist/dts/testing/exports.d.ts +3 -0
  50. package/dist/dts/testing/fakes.d.ts +4 -0
  51. package/dist/dts/testing/fixture.d.ts +84 -0
  52. package/dist/dts/testing/timeout.d.ts +7 -0
  53. package/dist/{tsdoc-metadata.json → dts/tsdoc-metadata.json} +1 -1
  54. package/dist/dts/utilities.d.ts +22 -0
  55. package/dist/esm/components/attributes.js +38 -28
  56. package/dist/esm/components/{controller.js → element-controller.js} +150 -140
  57. package/dist/esm/components/fast-definitions.js +48 -46
  58. package/dist/esm/components/fast-element.js +31 -12
  59. package/dist/esm/context.js +163 -0
  60. package/dist/esm/debug.js +61 -0
  61. package/dist/esm/di/di.js +1435 -0
  62. package/dist/esm/index.debug.js +2 -0
  63. package/dist/esm/index.js +20 -14
  64. package/dist/esm/index.rollup.debug.js +3 -0
  65. package/dist/esm/index.rollup.js +2 -0
  66. package/dist/esm/interfaces.js +12 -1
  67. package/dist/esm/metadata.js +60 -0
  68. package/dist/esm/observation/arrays.js +570 -0
  69. package/dist/esm/observation/notifier.js +27 -35
  70. package/dist/esm/observation/observable.js +116 -149
  71. package/dist/esm/observation/update-queue.js +67 -0
  72. package/dist/esm/pending-task.js +16 -0
  73. package/dist/esm/platform.js +60 -42
  74. package/dist/esm/polyfills.js +85 -0
  75. package/dist/esm/state/exports.js +3 -0
  76. package/dist/esm/state/reactive.js +34 -0
  77. package/dist/esm/state/state.js +148 -0
  78. package/dist/esm/state/visitor.js +28 -0
  79. package/dist/esm/state/watch.js +36 -0
  80. package/dist/esm/styles/css-directive.js +29 -13
  81. package/dist/esm/styles/css.js +29 -42
  82. package/dist/esm/styles/element-styles.js +79 -104
  83. package/dist/esm/styles/host.js +1 -0
  84. package/dist/esm/templating/binding-signal.js +83 -0
  85. package/dist/esm/templating/binding-two-way.js +103 -0
  86. package/dist/esm/templating/binding.js +189 -159
  87. package/dist/esm/templating/children.js +33 -23
  88. package/dist/esm/templating/compiler.js +258 -152
  89. package/dist/esm/templating/dom.js +49 -0
  90. package/dist/esm/templating/html-directive.js +193 -36
  91. package/dist/esm/templating/markup.js +75 -0
  92. package/dist/esm/templating/node-observation.js +51 -45
  93. package/dist/esm/templating/ref.js +8 -25
  94. package/dist/esm/templating/render.js +391 -0
  95. package/dist/esm/templating/repeat.js +83 -79
  96. package/dist/esm/templating/slotted.js +23 -20
  97. package/dist/esm/templating/template.js +51 -93
  98. package/dist/esm/templating/view.js +125 -46
  99. package/dist/esm/templating/when.js +6 -4
  100. package/dist/esm/testing/exports.js +3 -0
  101. package/dist/esm/testing/fakes.js +76 -0
  102. package/dist/esm/testing/fixture.js +86 -0
  103. package/dist/esm/testing/timeout.js +24 -0
  104. package/dist/esm/utilities.js +44 -0
  105. package/dist/fast-element.api.json +12153 -5373
  106. package/dist/fast-element.d.ts +1448 -696
  107. package/dist/fast-element.debug.js +4107 -0
  108. package/dist/fast-element.debug.min.js +1 -0
  109. package/dist/fast-element.js +3817 -4029
  110. package/dist/fast-element.min.js +1 -1
  111. package/dist/fast-element.untrimmed.d.ts +2814 -0
  112. package/docs/api-report.md +567 -254
  113. package/docs/fast-element-2-changes.md +15 -0
  114. package/karma.conf.cjs +6 -17
  115. package/package.json +76 -15
  116. package/dist/dts/dom.d.ts +0 -112
  117. package/dist/dts/observation/array-change-records.d.ts +0 -48
  118. package/dist/dts/observation/array-observer.d.ts +0 -9
  119. package/dist/dts/observation/behavior.d.ts +0 -19
  120. package/dist/esm/dom.js +0 -207
  121. package/dist/esm/observation/array-change-records.js +0 -326
  122. package/dist/esm/observation/array-observer.js +0 -177
@@ -1,54 +1,17 @@
1
- /**
2
- * A reference to globalThis, with support
3
- * for browsers that don't yet support the spec.
4
- * @public
5
- */
6
- export const $global = (function () {
7
- if (typeof globalThis !== "undefined") {
8
- // We're running in a modern environment.
9
- return globalThis;
10
- }
11
- if (typeof global !== "undefined") {
12
- // We're running in NodeJS
13
- return global;
14
- }
15
- if (typeof self !== "undefined") {
16
- // We're running in a worker.
17
- return self;
18
- }
19
- if (typeof window !== "undefined") {
20
- // We're running in the browser's main thread.
21
- return window;
22
- }
23
- try {
24
- // Hopefully we never get here...
25
- // Not all environments allow eval and Function. Use only as a last resort:
26
- // eslint-disable-next-line no-new-func
27
- return new Function("return this")();
28
- }
29
- catch (_a) {
30
- // If all fails, give up and create an object.
31
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
32
- return {};
33
- }
34
- })();
35
- // API-only Polyfill for trustedTypes
36
- if ($global.trustedTypes === void 0) {
37
- $global.trustedTypes = { createPolicy: (n, r) => r };
38
- }
1
+ // ensure FAST global - duplicated in polyfills.ts and debug.ts
39
2
  const propConfig = {
40
3
  configurable: false,
41
4
  enumerable: false,
42
5
  writable: false,
43
6
  };
44
- if ($global.FAST === void 0) {
45
- Reflect.defineProperty($global, "FAST", Object.assign({ value: Object.create(null) }, propConfig));
7
+ if (globalThis.FAST === void 0) {
8
+ Reflect.defineProperty(globalThis, "FAST", Object.assign({ value: Object.create(null) }, propConfig));
46
9
  }
47
10
  /**
48
11
  * The FAST global.
49
12
  * @internal
50
13
  */
51
- export const FAST = $global.FAST;
14
+ export const FAST = globalThis.FAST;
52
15
  if (FAST.getById === void 0) {
53
16
  const storage = Object.create(null);
54
17
  Reflect.defineProperty(FAST, "getById", Object.assign({ value(id, initialize) {
@@ -59,11 +22,66 @@ if (FAST.getById === void 0) {
59
22
  return found;
60
23
  } }, propConfig));
61
24
  }
25
+ if (FAST.error === void 0) {
26
+ Object.assign(FAST, {
27
+ warn() { },
28
+ error(code) {
29
+ return new Error(`Error ${code}`);
30
+ },
31
+ addMessages() { },
32
+ });
33
+ }
62
34
  /**
63
35
  * A readonly, empty array.
64
36
  * @remarks
65
37
  * Typically returned by APIs that return arrays when there are
66
38
  * no actual items to return.
67
- * @internal
39
+ * @public
68
40
  */
69
41
  export const emptyArray = Object.freeze([]);
42
+ /**
43
+ * Do not change. Part of shared kernel contract.
44
+ * @internal
45
+ */
46
+ export function createTypeRegistry() {
47
+ const typeToDefinition = new Map();
48
+ return Object.freeze({
49
+ register(definition) {
50
+ if (typeToDefinition.has(definition.type)) {
51
+ return false;
52
+ }
53
+ typeToDefinition.set(definition.type, definition);
54
+ return true;
55
+ },
56
+ getByType(key) {
57
+ return typeToDefinition.get(key);
58
+ },
59
+ getForInstance(object) {
60
+ if (object === null || object === void 0) {
61
+ return void 0;
62
+ }
63
+ return typeToDefinition.get(object.constructor);
64
+ },
65
+ });
66
+ }
67
+ /**
68
+ * Creates a function capable of locating metadata associated with a type.
69
+ * @returns A metadata locator function.
70
+ * @internal
71
+ */
72
+ export function createMetadataLocator() {
73
+ const metadataLookup = new WeakMap();
74
+ return function (target) {
75
+ let metadata = metadataLookup.get(target);
76
+ if (metadata === void 0) {
77
+ let currentTarget = Reflect.getPrototypeOf(target);
78
+ while (metadata === void 0 && currentTarget !== null) {
79
+ metadata = metadataLookup.get(currentTarget);
80
+ currentTarget = Reflect.getPrototypeOf(currentTarget);
81
+ }
82
+ metadata = metadata === void 0 ? [] : metadata.slice(0);
83
+ metadataLookup.set(target, metadata);
84
+ }
85
+ return metadata;
86
+ };
87
+ }
@@ -0,0 +1,85 @@
1
+ (function ensureGlobalThis() {
2
+ if (typeof globalThis !== "undefined") {
3
+ // We're running in a modern environment.
4
+ return;
5
+ }
6
+ if (typeof global !== "undefined") {
7
+ // We're running in NodeJS
8
+ global.globalThis = global;
9
+ }
10
+ else if (typeof self !== "undefined") {
11
+ self.globalThis = self;
12
+ }
13
+ else if (typeof window !== "undefined") {
14
+ // We're running in the browser's main thread.
15
+ window.globalThis = window;
16
+ }
17
+ else {
18
+ // Hopefully we never get here...
19
+ // Not all environments allow eval and Function. Use only as a last resort:
20
+ // eslint-disable-next-line no-new-func
21
+ const result = new Function("return this")();
22
+ result.globalThis = result;
23
+ }
24
+ })();
25
+ // API-only Polyfill for trustedTypes
26
+ if (!globalThis.trustedTypes) {
27
+ globalThis.trustedTypes = {
28
+ createPolicy: (n, r) => r,
29
+ };
30
+ }
31
+ // ensure FAST global - duplicated in platform.ts
32
+ const propConfig = {
33
+ configurable: false,
34
+ enumerable: false,
35
+ writable: false,
36
+ };
37
+ if (globalThis.FAST === void 0) {
38
+ Reflect.defineProperty(globalThis, "FAST", Object.assign({ value: Object.create(null) }, propConfig));
39
+ }
40
+ const FAST = globalThis.FAST;
41
+ if (FAST.getById === void 0) {
42
+ const storage = Object.create(null);
43
+ Reflect.defineProperty(FAST, "getById", Object.assign({ value(id, initialize) {
44
+ let found = storage[id];
45
+ if (found === void 0) {
46
+ found = initialize ? (storage[id] = initialize()) : null;
47
+ }
48
+ return found;
49
+ } }, propConfig));
50
+ }
51
+ // duplicated from DOM
52
+ const supportsAdoptedStyleSheets = Array.isArray(document.adoptedStyleSheets) &&
53
+ "replace" in CSSStyleSheet.prototype;
54
+ function usableStyleTarget(target) {
55
+ return target === document ? document.body : target;
56
+ }
57
+ let id = 0;
58
+ const nextStyleId = () => `fast-${++id}`;
59
+ export class StyleElementStrategy {
60
+ constructor(styles) {
61
+ this.styles = styles;
62
+ this.styleClass = nextStyleId();
63
+ }
64
+ addStylesTo(target) {
65
+ target = usableStyleTarget(target);
66
+ const styles = this.styles;
67
+ const styleClass = this.styleClass;
68
+ for (let i = 0; i < styles.length; i++) {
69
+ const element = document.createElement("style");
70
+ element.innerHTML = styles[i];
71
+ element.className = styleClass;
72
+ target.append(element);
73
+ }
74
+ }
75
+ removeStylesFrom(target) {
76
+ const styles = target.querySelectorAll(`.${this.styleClass}`);
77
+ target = usableStyleTarget(target);
78
+ for (let i = 0, ii = styles.length; i < ii; ++i) {
79
+ target.removeChild(styles[i]);
80
+ }
81
+ }
82
+ }
83
+ if (!supportsAdoptedStyleSheets) {
84
+ FAST.getById(/* KernelServiceId.styleSheetStrategy */ 5, () => StyleElementStrategy);
85
+ }
@@ -0,0 +1,3 @@
1
+ export { reactive } from "./reactive.js";
2
+ export { watch } from "./watch.js";
3
+ export * from "./state.js";
@@ -0,0 +1,34 @@
1
+ import { noop } from "../interfaces.js";
2
+ import { Observable } from "../observation/observable.js";
3
+ import { visitObject } from "./visitor.js";
4
+ const observed = new WeakSet();
5
+ const makeObserverVisitor = {
6
+ visitObject: noop,
7
+ visitArray: noop,
8
+ visitProperty(object, propertyName, value) {
9
+ Reflect.defineProperty(object, propertyName, {
10
+ enumerable: true,
11
+ get() {
12
+ Observable.track(object, propertyName);
13
+ return value;
14
+ },
15
+ set(newValue) {
16
+ if (value !== newValue) {
17
+ value = newValue;
18
+ Observable.notify(object, propertyName);
19
+ }
20
+ },
21
+ });
22
+ },
23
+ };
24
+ /**
25
+ * Converts a plain object to a reactive, observable object.
26
+ * @param object - The object to make reactive.
27
+ * @param deep - Indicates whether or not to deeply convert the oject.
28
+ * @returns The converted object.
29
+ * @beta
30
+ */
31
+ export function reactive(object, deep = false) {
32
+ visitObject(object, deep, makeObserverVisitor, void 0, observed);
33
+ return object;
34
+ }
@@ -0,0 +1,148 @@
1
+ // Inspired by https://www.starbeamjs.com/
2
+ import { isFunction, isString } from "../interfaces.js";
3
+ import { Observable } from "../observation/observable.js";
4
+ import { reactive } from "./reactive.js";
5
+ const defaultStateOptions = {
6
+ deep: false,
7
+ };
8
+ /**
9
+ * Creates a reactive state value.
10
+ * @param value - The initial state value.
11
+ * @param options - Options to customize the state or a friendly name.
12
+ * @returns A State instance.
13
+ * @beta
14
+ */
15
+ export function state(value, options = defaultStateOptions) {
16
+ var _a;
17
+ if (isString(options)) {
18
+ options = { deep: false, name: options };
19
+ }
20
+ const host = reactive({ value }, options.deep);
21
+ const state = (() => host.value);
22
+ Object.defineProperty(state, "current", {
23
+ get: () => host.value,
24
+ set: (value) => (host.value = value),
25
+ });
26
+ Object.defineProperty(state, "name", {
27
+ value: (_a = options.name) !== null && _a !== void 0 ? _a : "SharedState",
28
+ });
29
+ state.set = (value) => (host.value = value);
30
+ state.asReadonly = () => {
31
+ const readonlyState = (() => host.value);
32
+ Object.defineProperty(readonlyState, "current", {
33
+ get: () => host.value,
34
+ });
35
+ Object.defineProperty(readonlyState, "name", {
36
+ value: `${state.name} (Readonly)`,
37
+ });
38
+ return Object.freeze(readonlyState);
39
+ };
40
+ return state;
41
+ }
42
+ /**
43
+ * Creates a reactive state that has its value associated with a specific owner.
44
+ * @param value - The initial value or a factory that provides an initial value for each owner.
45
+ * @param options - Options to customize the state or a friendly name.
46
+ * @returns An OwnedState instance.
47
+ * @beta
48
+ */
49
+ export function ownedState(value, options = defaultStateOptions) {
50
+ var _a;
51
+ if (isString(options)) {
52
+ options = { deep: false, name: options };
53
+ }
54
+ if (!isFunction(value)) {
55
+ const v = value;
56
+ value = () => v;
57
+ }
58
+ const storage = new WeakMap();
59
+ const getHost = (owner) => {
60
+ let host = storage.get(owner);
61
+ if (host === void 0) {
62
+ host = reactive({ value: value() }, options.deep);
63
+ storage.set(owner, host);
64
+ }
65
+ return host;
66
+ };
67
+ const state = ((owner) => getHost(owner).value);
68
+ Object.defineProperty(state, "name", {
69
+ value: (_a = options.name) !== null && _a !== void 0 ? _a : "OwnedState",
70
+ });
71
+ state.set = (owner, value) => (getHost(owner).value = value);
72
+ state.asReadonly = () => {
73
+ const readonlyState = ((owner) => getHost(owner).value);
74
+ Object.defineProperty(readonlyState, "name", {
75
+ value: `${state.name} (Readonly)`,
76
+ });
77
+ return Object.freeze(readonlyState);
78
+ };
79
+ return state;
80
+ }
81
+ /**
82
+ * Creates a ComputedState.
83
+ * @param initialize - The initialization callback.
84
+ * @param name - A friendly name for this computation.
85
+ * @returns A ComputedState
86
+ * @beta
87
+ */
88
+ export function computedState(initialize, name = "ComputedState") {
89
+ let setupCallback = null;
90
+ const builder = {
91
+ on: {
92
+ setup(callback) {
93
+ setupCallback = callback;
94
+ },
95
+ },
96
+ };
97
+ const computer = initialize(builder);
98
+ const host = reactive({ value: null }, false);
99
+ const output = (() => host.value);
100
+ Object.defineProperty(output, "current", {
101
+ get: () => host.value,
102
+ });
103
+ Object.defineProperty(output, "name", {
104
+ value: name,
105
+ });
106
+ // eslint-disable-next-line prefer-const
107
+ let computedNotifier;
108
+ const computedSubscriber = {
109
+ handleChange() {
110
+ host.value = computedNotifier.observe(null);
111
+ },
112
+ };
113
+ computedNotifier = Observable.binding(computer, computedSubscriber);
114
+ computedNotifier.setMode(false);
115
+ let cleanup;
116
+ let setupNotifier;
117
+ if (setupCallback) {
118
+ const setupSubscriber = {
119
+ handleChange() {
120
+ if (cleanup) {
121
+ cleanup();
122
+ }
123
+ cleanup = setupNotifier.observe(null);
124
+ host.value = computer();
125
+ },
126
+ };
127
+ setupNotifier = Observable.binding(setupCallback, setupSubscriber);
128
+ setupNotifier.setMode(false);
129
+ cleanup = setupNotifier.observe(null);
130
+ }
131
+ host.value = computedNotifier.observe(null);
132
+ output.dispose = () => {
133
+ if (cleanup) {
134
+ cleanup();
135
+ }
136
+ if (setupNotifier) {
137
+ setupNotifier.dispose();
138
+ }
139
+ computedNotifier.dispose();
140
+ };
141
+ output.subscribe = (subscriber) => {
142
+ computedNotifier.subscribe(subscriber);
143
+ };
144
+ output.unsubscribe = (subscriber) => {
145
+ computedNotifier.unsubscribe(subscriber);
146
+ };
147
+ return output;
148
+ }
@@ -0,0 +1,28 @@
1
+ function shouldTraverse(value, traversed) {
2
+ return (value !== null &&
3
+ value !== void 0 &&
4
+ typeof value === "object" &&
5
+ !traversed.has(value));
6
+ }
7
+ export function visitObject(object, deep, visitor, data, traversed) {
8
+ if (!shouldTraverse(object, traversed)) {
9
+ return;
10
+ }
11
+ traversed.add(object);
12
+ if (Array.isArray(object)) {
13
+ visitor.visitArray(object, data);
14
+ for (const item of object) {
15
+ visitObject(item, deep, visitor, data, traversed);
16
+ }
17
+ }
18
+ else {
19
+ visitor.visitObject(object, data);
20
+ for (const key in object) {
21
+ const value = object[key];
22
+ visitor.visitProperty(object, key, value, data);
23
+ if (deep) {
24
+ visitObject(value, deep, visitor, data, traversed);
25
+ }
26
+ }
27
+ }
28
+ }
@@ -0,0 +1,36 @@
1
+ import { isFunction, noop } from "../interfaces.js";
2
+ import { ArrayObserver } from "../observation/arrays.js";
3
+ import { Observable } from "../observation/observable.js";
4
+ import { visitObject } from "./visitor.js";
5
+ function watchObject(object, data) {
6
+ const notifier = Observable.getNotifier(object);
7
+ notifier.subscribe(data.subscriber);
8
+ data.notifiers.push(notifier);
9
+ }
10
+ const watchVisitor = {
11
+ visitProperty: noop,
12
+ visitObject: watchObject,
13
+ visitArray: watchObject,
14
+ };
15
+ /**
16
+ * Deeply subscribes to changes in existing observable objects.
17
+ * @param object - The observable object to watch.
18
+ * @param subscriber - The handler to call when changes are made to the object.
19
+ * @returns A disposable that can be used to unsubscribe from change updates.
20
+ * @beta
21
+ */
22
+ export function watch(object, subscriber) {
23
+ const data = {
24
+ notifiers: [],
25
+ subscriber: isFunction(subscriber) ? { handleChange: subscriber } : subscriber,
26
+ };
27
+ ArrayObserver.enable();
28
+ visitObject(object, true, watchVisitor, data, new Set());
29
+ return {
30
+ dispose() {
31
+ for (const n of data.notifiers) {
32
+ n.unsubscribe(data.subscriber);
33
+ }
34
+ },
35
+ };
36
+ }
@@ -1,21 +1,37 @@
1
+ import { createTypeRegistry } from "../platform.js";
2
+ const registry = createTypeRegistry();
1
3
  /**
2
- * Directive for use in {@link css}.
3
- *
4
+ * Instructs the css engine to provide dynamic styles or
5
+ * associate behaviors with styles.
4
6
  * @public
5
7
  */
6
- export class CSSDirective {
8
+ export const CSSDirective = Object.freeze({
7
9
  /**
8
- * Creates a CSS fragment to interpolate into the CSS document.
9
- * @returns - the string to interpolate into CSS
10
+ * Gets the directive definition associated with the instance.
11
+ * @param instance - The directive instance to retrieve the definition for.
10
12
  */
11
- createCSS() {
12
- return "";
13
- }
13
+ getForInstance: registry.getForInstance,
14
14
  /**
15
- * Creates a behavior to bind to the host element.
16
- * @returns - the behavior to bind to the host element, or undefined.
15
+ * Gets the directive definition associated with the specified type.
16
+ * @param type - The directive type to retrieve the definition for.
17
17
  */
18
- createBehavior() {
19
- return undefined;
20
- }
18
+ getByType: registry.getByType,
19
+ /**
20
+ * Defines a CSSDirective.
21
+ * @param type - The type to define as a directive.
22
+ */
23
+ define(type) {
24
+ registry.register({ type });
25
+ return type;
26
+ },
27
+ });
28
+ /**
29
+ * Decorator: Defines a CSSDirective.
30
+ * @public
31
+ */
32
+ export function cssDirective() {
33
+ /* eslint-disable-next-line @typescript-eslint/explicit-function-return-type */
34
+ return function (type) {
35
+ CSSDirective.define(type);
36
+ };
21
37
  }
@@ -1,18 +1,18 @@
1
+ import { isString } from "../interfaces.js";
1
2
  import { CSSDirective } from "./css-directive.js";
2
3
  import { ElementStyles } from "./element-styles.js";
3
4
  function collectStyles(strings, values) {
4
5
  const styles = [];
5
6
  let cssString = "";
6
7
  const behaviors = [];
8
+ const add = (behavior) => {
9
+ behaviors.push(behavior);
10
+ };
7
11
  for (let i = 0, ii = strings.length - 1; i < ii; ++i) {
8
12
  cssString += strings[i];
9
13
  let value = values[i];
10
- if (value instanceof CSSDirective) {
11
- const behavior = value.createBehavior();
12
- value = value.createCSS();
13
- if (behavior) {
14
- behaviors.push(behavior);
15
- }
14
+ if (CSSDirective.getForInstance(value) !== void 0) {
15
+ value = value.createCSS(add);
16
16
  }
17
17
  if (value instanceof ElementStyles || value instanceof CSSStyleSheet) {
18
18
  if (cssString.trim() !== "") {
@@ -42,21 +42,17 @@ function collectStyles(strings, values) {
42
42
  * The css helper supports interpolation of strings and ElementStyle instances.
43
43
  * @public
44
44
  */
45
- export function css(strings, ...values) {
45
+ export const css = ((strings, ...values) => {
46
46
  const { styles, behaviors } = collectStyles(strings, values);
47
- const elementStyles = ElementStyles.create(styles);
48
- if (behaviors.length) {
49
- elementStyles.withBehaviors(...behaviors);
50
- }
51
- return elementStyles;
52
- }
53
- class CSSPartial extends CSSDirective {
47
+ const elementStyles = new ElementStyles(styles);
48
+ return behaviors.length ? elementStyles.withBehaviors(...behaviors) : elementStyles;
49
+ });
50
+ class CSSPartial {
54
51
  constructor(styles, behaviors) {
55
- super();
56
52
  this.behaviors = behaviors;
57
53
  this.css = "";
58
54
  const stylesheets = styles.reduce((accumulated, current) => {
59
- if (typeof current === "string") {
55
+ if (isString(current)) {
60
56
  this.css += current;
61
57
  }
62
58
  else {
@@ -65,39 +61,30 @@ class CSSPartial extends CSSDirective {
65
61
  return accumulated;
66
62
  }, []);
67
63
  if (stylesheets.length) {
68
- this.styles = ElementStyles.create(stylesheets);
64
+ this.styles = new ElementStyles(stylesheets);
69
65
  }
70
66
  }
71
- createBehavior() {
72
- return this;
73
- }
74
- createCSS() {
75
- return this.css;
76
- }
77
- bind(el) {
67
+ createCSS(add) {
68
+ this.behaviors.forEach(add);
78
69
  if (this.styles) {
79
- el.$fastController.addStyles(this.styles);
80
- }
81
- if (this.behaviors.length) {
82
- el.$fastController.addBehaviors(this.behaviors);
70
+ add(this);
83
71
  }
72
+ return this.css;
84
73
  }
85
- unbind(el) {
86
- if (this.styles) {
87
- el.$fastController.removeStyles(this.styles);
88
- }
89
- if (this.behaviors.length) {
90
- el.$fastController.removeBehaviors(this.behaviors);
91
- }
74
+ addedCallback(controller) {
75
+ controller.addStyles(this.styles);
76
+ }
77
+ removedCallback(controller) {
78
+ controller.removeStyles(this.styles);
92
79
  }
93
80
  }
81
+ CSSDirective.define(CSSPartial);
82
+ css.partial = (strings, ...values) => {
83
+ const { styles, behaviors } = collectStyles(strings, values);
84
+ return new CSSPartial(styles, behaviors);
85
+ };
94
86
  /**
95
- * Transforms a template literal string into partial CSS.
96
- * @param strings - The string fragments that are interpolated with the values.
97
- * @param values - The values that are interpolated with the string fragments.
87
+ * @deprecated Use css.partial instead.
98
88
  * @public
99
89
  */
100
- export function cssPartial(strings, ...values) {
101
- const { styles, behaviors } = collectStyles(strings, values);
102
- return new CSSPartial(styles, behaviors);
103
- }
90
+ export const cssPartial = css.partial;