@webjsdev/core 0.7.65 → 0.9.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.
Files changed (92) hide show
  1. package/README.md +5 -0
  2. package/dist/webjs-core-browser.js +6 -5
  3. package/dist/webjs-core-browser.js.map +3 -3
  4. package/dist/webjs-core-testing.js +22 -21
  5. package/dist/webjs-core-testing.js.map +3 -3
  6. package/dist/webjs-core.js +7 -6
  7. package/dist/webjs-core.js.map +3 -3
  8. package/index-browser.js +18 -9
  9. package/index.d.ts +26 -10
  10. package/index.js +21 -9
  11. package/package.json +15 -2
  12. package/src/action-effects-client.d.ts +5 -0
  13. package/src/action-effects-client.js +84 -0
  14. package/src/action-seed-client.js +5 -5
  15. package/src/asset-url.js +12 -13
  16. package/src/async-directive.d.ts +18 -0
  17. package/src/async-directive.js +88 -0
  18. package/src/attribute-directives.d.ts +6 -0
  19. package/src/attribute-directives.js +49 -0
  20. package/src/attribute-reader.js +213 -25
  21. package/src/binding-prefixes.js +10 -53
  22. package/src/component/lifecycle.js +921 -252
  23. package/src/component/reactive.js +7 -14
  24. package/src/component/server-element.js +23 -1
  25. package/src/component.d.ts +160 -44
  26. package/src/context.d.ts +94 -18
  27. package/src/context.js +341 -217
  28. package/src/converters.d.ts +7 -0
  29. package/src/converters.js +38 -0
  30. package/src/css.d.ts +32 -6
  31. package/src/css.js +178 -14
  32. package/src/directive.d.ts +58 -0
  33. package/src/directive.js +119 -0
  34. package/src/directives.d.ts +40 -1
  35. package/src/directives.js +160 -1
  36. package/src/form-action.d.ts +13 -0
  37. package/src/form-action.js +139 -4
  38. package/src/hot.js +23 -0
  39. package/src/html.d.ts +8 -0
  40. package/src/html.js +55 -2
  41. package/src/is-server.d.ts +2 -0
  42. package/src/is-server.js +18 -0
  43. package/src/jsx-guard.js +130 -0
  44. package/src/metadata.d.ts +22 -3
  45. package/src/nav.d.ts +4 -1
  46. package/src/nav.js +44 -11
  47. package/src/optimistic.js +2 -2
  48. package/src/refresh-header.js +52 -0
  49. package/src/registry.js +10 -1
  50. package/src/render-client/adopt-slots.js +250 -0
  51. package/src/render-client/parts.js +790 -42
  52. package/src/render-client/reconciler.js +84 -23
  53. package/src/render-client/template-compiler.js +152 -43
  54. package/src/render-client.d.ts +6 -1
  55. package/src/render-server/attrs.js +2 -2
  56. package/src/render-server/compile.js +50 -2
  57. package/src/render-server/errors.js +37 -0
  58. package/src/render-server/expand.js +100 -20
  59. package/src/render-server/served-attrs.js +78 -0
  60. package/src/render-server/walk.js +177 -5
  61. package/src/render-server.d.ts +3 -0
  62. package/src/render-server.js +2 -0
  63. package/src/repeat.d.ts +7 -2
  64. package/src/repeat.js +20 -6
  65. package/src/router-client/anchors.js +3 -1
  66. package/src/router-client/boundaries.js +15 -1
  67. package/src/router-client/constants.js +30 -0
  68. package/src/router-client/dom-differ.js +17 -0
  69. package/src/router-client/fetch-apply.js +107 -5
  70. package/src/router-client/frames.js +6 -3
  71. package/src/router-client/head-merge.js +58 -10
  72. package/src/router-client/navigator.js +49 -9
  73. package/src/router-client/owned-styles.js +372 -0
  74. package/src/router-client/prefetch.js +6 -4
  75. package/src/router-client/root-attrs.js +43 -0
  76. package/src/router-client/stream.js +7 -0
  77. package/src/router-client/stylesheets.js +191 -0
  78. package/src/router-client/swap.js +53 -10
  79. package/src/routes.d.ts +75 -18
  80. package/src/sentinels.d.ts +2 -0
  81. package/src/sentinels.js +4 -0
  82. package/src/serialize.d.ts +2 -0
  83. package/src/serialize.js +35 -4
  84. package/src/signal.d.ts +7 -0
  85. package/src/signal.js +26 -6
  86. package/src/slot/polyfills.js +3 -3
  87. package/src/slot.js +4 -8
  88. package/src/static-html.d.ts +22 -0
  89. package/src/static-html.js +144 -0
  90. package/src/task.d.ts +63 -20
  91. package/src/task.js +326 -293
  92. package/src/webjs-config.d.ts +2 -9
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Static expressions, lit's `lit/static-html.js` under a WebJs path:
3
+ * `@webjsdev/core/static-html`.
4
+ *
5
+ * Portions derived from Lit, Copyright Google LLC, BSD-3-Clause.
6
+ *
7
+ * A static value is spliced into the template's STRINGS before the renderer
8
+ * ever sees them, so it can sit where an ordinary hole cannot: a tag name, an
9
+ * attribute name. The classic use is a component whose child tag is chosen at
10
+ * runtime.
11
+ *
12
+ * ```js
13
+ * import { html, literal, unsafeStatic } from '@webjsdev/core/static-html';
14
+ *
15
+ * const tag = literal`my-button`;
16
+ * html`<${tag} label="Save"></${tag}>`;
17
+ *
18
+ * // A string from data must go through unsafeStatic, which trusts it as markup.
19
+ * html`<${unsafeStatic(level)}>Title</${unsafeStatic(level)}>`;
20
+ * ```
21
+ *
22
+ * The merged strings array is cached by its joined text, so every render of
23
+ * the same static shape hands the renderers the SAME array, which is what
24
+ * their template caches key on (identity). A static that changes between
25
+ * renders produces a different shape, and so a fresh template, exactly as in
26
+ * lit.
27
+ *
28
+ * NEVER pass user input to `unsafeStatic`: it is inserted as markup.
29
+ *
30
+ * @module static-html
31
+ */
32
+
33
+ import { html as coreHtml, svg as coreSvg, mathml as coreMathml } from './html.js';
34
+
35
+ /**
36
+ * Brand on every static value. `Symbol.for` so a value made by one loaded copy
37
+ * of this module is recognised by another (the source module and a bundle).
38
+ */
39
+ const STATIC = Symbol.for('webjs.static');
40
+
41
+ /**
42
+ * @typedef {{ _$webjsStatic: string, r: symbol }} StaticValue
43
+ */
44
+
45
+ /** @param {unknown} value @returns {string | undefined} */
46
+ function unwrapStaticValue(value) {
47
+ if (value && typeof value === 'object' && /** @type {any} */ (value).r === STATIC) {
48
+ return /** @type {any} */ (value)._$webjsStatic;
49
+ }
50
+ return undefined;
51
+ }
52
+
53
+ /**
54
+ * Wrap a string so it is inserted as static markup, lit's `unsafeStatic`. The
55
+ * string is trusted: NEVER pass user input.
56
+ *
57
+ * @param {string} value
58
+ * @returns {StaticValue}
59
+ */
60
+ export function unsafeStatic(value) {
61
+ return { _$webjsStatic: value, r: STATIC };
62
+ }
63
+
64
+ /**
65
+ * A static value from a template literal, lit's `literal`. Every interpolated
66
+ * value must itself be a static value (another `literal` or `unsafeStatic`),
67
+ * so a literal can never carry untrusted text.
68
+ *
69
+ * @param {TemplateStringsArray} strings
70
+ * @param {...unknown} values
71
+ * @returns {StaticValue}
72
+ */
73
+ export function literal(strings, ...values) {
74
+ let text = strings[0];
75
+ for (let i = 0; i < values.length; i++) {
76
+ const s = unwrapStaticValue(values[i]);
77
+ if (s === undefined) {
78
+ throw new Error(
79
+ `Value passed to 'literal' function must be a 'literal' result: ${String(values[i])}. ` +
80
+ `Use 'unsafeStatic' to pass non-literal values, but take care to ensure page security.`,
81
+ );
82
+ }
83
+ text += s + strings[i + 1];
84
+ }
85
+ return { _$webjsStatic: text, r: STATIC };
86
+ }
87
+
88
+ /**
89
+ * One strings array per static shape, kept for the life of the process as Lit
90
+ * keeps it: the renderers key their template caches on its identity, so a
91
+ * shape still in use must never get a new array. Only literal statics belong
92
+ * here; `unsafeStatic` over request data makes a new shape per value.
93
+ * @type {Map<string, string[]>}
94
+ */
95
+ const stringsCache = new Map();
96
+
97
+ /**
98
+ * Wrap a template tag so it accepts static values, lit's `withStatic`.
99
+ *
100
+ * @template R
101
+ * @param {(strings: TemplateStringsArray | string[], ...values: unknown[]) => R} coreTag
102
+ * @returns {(strings: TemplateStringsArray | string[], ...values: unknown[]) => R}
103
+ */
104
+ export function withStatic(coreTag) {
105
+ return (strings, ...values) => {
106
+ const l = values.length;
107
+ /** @type {string[]} */
108
+ const staticStrings = [];
109
+ /** @type {unknown[]} */
110
+ const dynamicValues = [];
111
+ let hasStatics = false;
112
+ let i = 0;
113
+ while (i < l) {
114
+ let s = strings[i];
115
+ let staticValue;
116
+ while (i < l && (staticValue = unwrapStaticValue(values[i])) !== undefined) {
117
+ s += staticValue + strings[++i];
118
+ hasStatics = true;
119
+ }
120
+ if (i !== l) dynamicValues.push(values[i]);
121
+ staticStrings.push(s);
122
+ i++;
123
+ }
124
+ if (i === l) staticStrings.push(strings[l]);
125
+ if (!hasStatics) return coreTag(strings, ...values);
126
+ // A NUL separator cannot occur in template source, so two different
127
+ // shapes never share a key.
128
+ const key = staticStrings.join('\u0000');
129
+ let cached = stringsCache.get(key);
130
+ if (cached === undefined) {
131
+ /** @type {any} */ (staticStrings).raw = staticStrings;
132
+ cached = staticStrings;
133
+ stringsCache.set(key, cached);
134
+ }
135
+ return coreTag(cached, ...dynamicValues);
136
+ };
137
+ }
138
+
139
+ /** `html` that accepts static values (`literal` / `unsafeStatic`). */
140
+ export const html = withStatic(coreHtml);
141
+ /** `svg` that accepts static values. */
142
+ export const svg = withStatic(coreSvg);
143
+ /** `mathml` that accepts static values. */
144
+ export const mathml = withStatic(coreMathml);
package/src/task.d.ts CHANGED
@@ -1,4 +1,14 @@
1
- import type { ReactiveController, WebComponent } from './component.js';
1
+ /**
2
+ * @license
3
+ * Portions derived from Lit (`@lit/task`), Copyright Google LLC, BSD-3-Clause.
4
+ */
5
+ import type { ReactiveController } from './component.js';
6
+
7
+ /** The host a Task attaches to: any ReactiveController host (a WebComponent). */
8
+ interface TaskHost {
9
+ addController(controller: ReactiveController): void;
10
+ requestUpdate(): void;
11
+ }
2
12
 
3
13
  export const TaskStatus: {
4
14
  readonly INITIAL: 0;
@@ -7,27 +17,60 @@ export const TaskStatus: {
7
17
  readonly ERROR: 3;
8
18
  };
9
19
 
10
- export type TaskStatusValue = (typeof TaskStatus)[keyof typeof TaskStatus];
20
+ export type TaskStatus = (typeof TaskStatus)[keyof typeof TaskStatus];
21
+
22
+ /** Return it from a task function to put the task back into INITIAL. */
23
+ export const initialState: unique symbol;
24
+ export type InitialState = typeof initialState;
11
25
 
12
- export class Task<T = unknown> implements ReactiveController {
13
- constructor(host: WebComponent, options: {
14
- task: (...args: any[]) => Promise<T>;
15
- args?: () => unknown[];
16
- autoRun?: boolean;
17
- });
18
- get status(): TaskStatusValue;
19
- get value(): T | undefined;
26
+ /** Called as `task(args, { signal })`, where `args` is the array `args()` returned. */
27
+ export type TaskFunction<D extends ReadonlyArray<unknown>, R = unknown> = (
28
+ args: D,
29
+ options: { signal: AbortSignal },
30
+ ) => R | InitialState | Promise<R | InitialState>;
31
+
32
+ export type ArgsFunction<D extends ReadonlyArray<unknown>> = () => D;
33
+
34
+ export interface TaskConfig<T extends ReadonlyArray<unknown>, R> {
35
+ task: TaskFunction<T, R>;
36
+ args?: ArgsFunction<T>;
37
+ /** `true` runs in `hostUpdate`, `'afterUpdate'` in `hostUpdated`, `false` only on `run()`. */
38
+ autoRun?: boolean | 'afterUpdate';
39
+ argsEqual?: (oldArgs: T, newArgs: T) => boolean;
40
+ initialValue?: R;
41
+ onComplete?: (value: R) => unknown;
42
+ onError?: (error: unknown) => unknown;
43
+ }
44
+
45
+ export interface StatusRenderer<R> {
46
+ initial?: () => unknown;
47
+ pending?: () => unknown;
48
+ complete?: (value: R) => unknown;
49
+ error?: (error: unknown) => unknown;
50
+ }
51
+
52
+ export class Task<
53
+ const T extends ReadonlyArray<unknown> = ReadonlyArray<unknown>,
54
+ const R = unknown,
55
+ > implements ReactiveController {
56
+ autoRun: boolean | 'afterUpdate';
57
+ constructor(host: TaskHost, task: TaskFunction<T, R>, args?: ArgsFunction<T>);
58
+ constructor(host: TaskHost, config: TaskConfig<T, R>);
59
+ get taskComplete(): Promise<R>;
60
+ get status(): TaskStatus;
61
+ get value(): R | undefined;
20
62
  get error(): unknown;
21
- run(): Promise<void>;
22
- abort(): void;
23
- render(handlers?: {
24
- initial?: () => unknown;
25
- pending?: () => unknown;
26
- complete?: (value: T) => unknown;
27
- error?: (error: unknown) => unknown;
28
- }): unknown;
63
+ run(args?: T): Promise<void>;
64
+ abort(reason?: unknown): void;
65
+ render<X extends StatusRenderer<R>>(
66
+ renderer: X,
67
+ ): MaybeReturnType<X['initial']> | MaybeReturnType<X['pending']> | MaybeReturnType<X['complete']> | MaybeReturnType<X['error']>;
29
68
  hostUpdate(): void;
30
69
  hostUpdated(): void;
31
- hostConnected(): void;
32
- hostDisconnected(): void;
33
70
  }
71
+
72
+ type MaybeReturnType<F> = F extends (...args: never[]) => infer R ? R : undefined;
73
+
74
+ export function shallowArrayEquals<T extends ReadonlyArray<unknown>>(oldArgs: T, newArgs: T): boolean;
75
+ export function deepArrayEquals<T extends ReadonlyArray<unknown>>(oldArgs: T, newArgs: T): boolean;
76
+ export function deepEquals(a: unknown, b: unknown): boolean;