@livenetworks/ashlar 2.1.13 → 2.2.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 (101) hide show
  1. package/components/COMPONENTS.md +80 -80
  2. package/components/ln-api-connector/ln-api-connector.schema.json +105 -105
  3. package/components/ln-chart/ln-chart-dev.scss +0 -4
  4. package/components/ln-core/README.md +21 -21
  5. package/components/ln-core/ln-core.schema.json +120 -120
  6. package/components/ln-core/query.js +113 -113
  7. package/components/ln-data-coordinator/README.md +2 -0
  8. package/components/ln-data-coordinator/ln-data-coordinator.js +1 -1
  9. package/components/ln-data-coordinator/ln-data-coordinator.schema.json +196 -196
  10. package/components/ln-data-coordinator/src/ln-data-coordinator.js +457 -432
  11. package/components/ln-data-store/ln-data-store.schema.json +92 -92
  12. package/components/ln-date/ln-date.js +1 -1
  13. package/components/ln-date/src/ln-date.js +1 -1
  14. package/components/ln-debug/ln-debug.js +1 -1
  15. package/components/ln-debug/ln-debug.schema.json +28 -28
  16. package/components/ln-debug/src/generated-attributes.js +304 -302
  17. package/components/ln-dropdown/ln-dropdown.schema.json +90 -90
  18. package/components/ln-external-links/README.md +19 -19
  19. package/components/ln-external-links/ln-external-links.js +1 -1
  20. package/components/ln-external-links/ln-external-links.schema.json +9 -0
  21. package/components/ln-external-links/ln-external-links.scss +12 -0
  22. package/components/ln-external-links/src/ln-external-links.js +3 -2
  23. package/components/ln-filter/README.md +2 -1
  24. package/components/ln-filter/ln-filter.js +1 -1
  25. package/components/ln-filter/ln-filter.schema.json +157 -169
  26. package/components/ln-filter/src/ln-filter.js +1 -3
  27. package/components/ln-form/ln-form.schema.json +57 -57
  28. package/components/ln-key/ln-key.js +1 -1
  29. package/components/ln-key/ln-key.schema.json +8 -0
  30. package/components/ln-key/src/ln-key.js +8 -5
  31. package/components/ln-obfuscator/ln-obfuscator.js +1 -1
  32. package/components/ln-obfuscator/ln-obfuscator.schema.json +6 -0
  33. package/components/ln-obfuscator/src/ln-obfuscator.js +2 -2
  34. package/components/ln-options/ln-options.schema.json +47 -47
  35. package/components/ln-popover/ln-popover.schema.json +82 -82
  36. package/components/ln-progress/ln-progress.schema.json +0 -13
  37. package/components/ln-search/ln-search.schema.json +111 -111
  38. package/components/ln-sort/README.md +1 -0
  39. package/components/ln-sort/ln-sort.js +1 -1
  40. package/components/ln-sort/ln-sort.schema.json +100 -112
  41. package/components/ln-sort/src/sort-model.js +1 -6
  42. package/components/ln-sortable/ln-sortable.schema.json +38 -38
  43. package/components/ln-sortable/ln-sortable.scss +25 -25
  44. package/components/ln-table/README.md +8 -1
  45. package/components/ln-table/ln-table.js +1 -1
  46. package/components/ln-table/ln-table.schema.json +195 -195
  47. package/components/ln-table/src/ln-table.js +43 -7
  48. package/components/ln-table-coordinator/ln-table-coordinator.js +1 -1
  49. package/components/ln-table-coordinator/ln-table-coordinator.schema.json +18 -0
  50. package/components/ln-table-coordinator/src/ln-table-coordinator.js +104 -2
  51. package/components/ln-toast/README.md +1 -1
  52. package/components/ln-toast/ln-toast.js +1 -1
  53. package/components/ln-toast/ln-toast.schema.json +6 -0
  54. package/components/ln-toast/src/ln-toast.js +1 -1
  55. package/components/ln-validate/README.md +6 -6
  56. package/components/ln-validate/ln-validate-dev.scss +0 -5
  57. package/components/ln-validate/ln-validate.js +1 -1
  58. package/components/ln-validate/ln-validate.schema.json +0 -6
  59. package/components/ln-validate/src/ln-validate.js +48 -29
  60. package/ln-ashlar.html-data.json +1824 -1814
  61. package/package.json +95 -95
  62. package/theme/README.md +7 -6
  63. package/theme/base/_global.scss +2 -2
  64. package/theme/base/_reset.scss +11 -0
  65. package/theme/components/_app-shell.scss +0 -8
  66. package/theme/components/_form.scss +6 -6
  67. package/theme/components/_ln-table.scss +6 -3
  68. package/theme/components/_scrollbar.scss +5 -4
  69. package/theme/components/_sortable.scss +19 -19
  70. package/theme/components/_stat-card.scss +1 -0
  71. package/theme/components/_table.scss +10 -33
  72. package/theme/config/_density.scss +236 -104
  73. package/theme/config/_palette.scss +71 -49
  74. package/theme/config/_theme.scss +27 -31
  75. package/theme/config/_tokens.scss +28 -26
  76. package/theme/config/mixins/_app-shell.scss +17 -21
  77. package/theme/config/mixins/_btn.scss +4 -2
  78. package/theme/config/mixins/_card.scss +87 -67
  79. package/theme/config/mixins/_colors.scss +2 -1
  80. package/theme/config/mixins/_display.scss +12 -0
  81. package/theme/config/mixins/_footer.scss +3 -1
  82. package/theme/config/mixins/_form.scss +48 -16
  83. package/theme/config/mixins/_layout.scss +9 -0
  84. package/theme/config/mixins/_ln-table.scss +22 -15
  85. package/theme/config/mixins/_modal.scss +3 -0
  86. package/theme/config/mixins/_nav.scss +27 -4
  87. package/theme/config/mixins/_sidebar.scss +2 -1
  88. package/theme/config/mixins/_stat-card.scss +33 -2
  89. package/theme/config/mixins/_status-badge.scss +1 -0
  90. package/theme/config/mixins/_table.scss +81 -39
  91. package/theme/config/mixins/_tabs.scss +31 -0
  92. package/theme/config/mixins/_toast.scss +0 -1
  93. package/theme/designs/relaxed/_card.scss +12 -0
  94. package/theme/designs/relaxed/_layout.scss +24 -0
  95. package/theme/ln-ashlar-core.scss +1 -0
  96. package/theme/ln-ashlar-dev.scss +0 -1
  97. package/theme/ln-ashlar-relaxed.scss +67 -0
  98. package/theme/tailwind/components.css +561 -24
  99. package/theme/utilities/_utilities.scss +1 -11
  100. package/web-types.json +2351 -2337
  101. package/components/ln-progress/ln-progress-dev.scss +0 -8
@@ -211,86 +211,86 @@ function _domObserver() {
211
211
 
212
212
  ---
213
213
 
214
- ## Reactive Rendering Pattern
215
-
216
- When a component has **multiple internal state properties** or frequent updates that drive DOM updates, use `createBatcher` + `fill()` from ln-core. This eliminates manual querySelector chains and coalesces multiple synchronous state changes into a single DOM update.
217
-
218
- ### The core primitives
219
-
220
- | Helper | Role |
221
- |--------|------|
222
- | `createBatcher(renderFn, afterRender)` | Coalesces sync state changes into one `renderFn` call via `queueMicrotask` |
223
- | `fill(root, data)` | Writes state to DOM via `data-ln-field`, `data-ln-attr`, `data-ln-show`, `data-ln-class` |
224
-
225
- ### Pattern
226
-
227
- ```javascript
228
- import { createBatcher, fill, dispatch } from '../ln-core';
229
-
230
- function _component(dom) {
231
- this.dom = dom;
232
- const self = this;
233
-
234
- this.state = { key: null, value: null };
235
-
236
- this.queueRender = createBatcher(
237
- function () {
238
- if (!self._destroyed) {
239
- self._render();
240
- }
241
- }, // runs after current sync block
242
- function () {
243
- if (!self._destroyed) {
244
- self._afterRender();
245
- }
246
- } // runs after render — dispatch events here
247
- );
248
- }
249
-
250
- _component.prototype._render = function () {
251
- fill(this.dom, this.state);
252
- // additional DOM logic derived from state
253
- };
254
-
255
- _component.prototype._afterRender = function () {
256
- dispatch(this.dom, 'ln-component:changed', { key: this.state.key });
257
- };
258
-
259
- _component.prototype.update = function (key, value) {
260
- this.state.key = key;
261
- this.state.value = value;
262
- this.queueRender(); // Multiple sync updates trigger exactly ONE render pass
263
- };
264
- ```
265
-
266
- When multiple properties change in the same sync block:
267
-
268
- ```javascript
269
- this.state.key = 'status';
270
- this.state.value = 'active';
271
- this.queueRender();
272
- // → microtask fires → _render() once → _afterRender() once
273
- ```
274
-
275
- ### `fill()` — limitations
276
-
277
- `fill()` sets `textContent` for `data-ln-field` — it does **not** set `.value` on `<input>`, `<textarea>`, or `<select>`. For form elements, set `.value` manually after `fill()`.
278
-
279
- ### When to use
280
-
281
- Use `createBatcher` when a component has **frequent or multiple state updates** (e.g. search input, filter checkboxes, sorting), and multiple updates can occur in the same synchronous cycle.
282
-
283
- **Don't use it for:**
284
- - Single boolean state — `this.isOpen = true; dom.classList.toggle(...)` is simpler
285
- - Event-driven rendering — components that receive data via `set-data` events (ln-table)
286
- - One-shot renders — clone template + fill once, no ongoing state
287
-
288
- ### Used in
289
-
290
- Used in `ln-search`, `ln-filter`, `ln-list`, and `ln-data-coordinator` for microtask render coalescing.
291
-
292
- ---
293
-
214
+ ## Reactive Rendering Pattern
215
+
216
+ When a component has **multiple internal state properties** or frequent updates that drive DOM updates, use `createBatcher` + `fill()` from ln-core. This eliminates manual querySelector chains and coalesces multiple synchronous state changes into a single DOM update.
217
+
218
+ ### The core primitives
219
+
220
+ | Helper | Role |
221
+ |--------|------|
222
+ | `createBatcher(renderFn, afterRender)` | Coalesces sync state changes into one `renderFn` call via `queueMicrotask` |
223
+ | `fill(root, data)` | Writes state to DOM via `data-ln-field`, `data-ln-attr`, `data-ln-show`, `data-ln-class` |
224
+
225
+ ### Pattern
226
+
227
+ ```javascript
228
+ import { createBatcher, fill, dispatch } from '../ln-core';
229
+
230
+ function _component(dom) {
231
+ this.dom = dom;
232
+ const self = this;
233
+
234
+ this.state = { key: null, value: null };
235
+
236
+ this.queueRender = createBatcher(
237
+ function () {
238
+ if (!self._destroyed) {
239
+ self._render();
240
+ }
241
+ }, // runs after current sync block
242
+ function () {
243
+ if (!self._destroyed) {
244
+ self._afterRender();
245
+ }
246
+ } // runs after render — dispatch events here
247
+ );
248
+ }
249
+
250
+ _component.prototype._render = function () {
251
+ fill(this.dom, this.state);
252
+ // additional DOM logic derived from state
253
+ };
254
+
255
+ _component.prototype._afterRender = function () {
256
+ dispatch(this.dom, 'ln-component:changed', { key: this.state.key });
257
+ };
258
+
259
+ _component.prototype.update = function (key, value) {
260
+ this.state.key = key;
261
+ this.state.value = value;
262
+ this.queueRender(); // Multiple sync updates trigger exactly ONE render pass
263
+ };
264
+ ```
265
+
266
+ When multiple properties change in the same sync block:
267
+
268
+ ```javascript
269
+ this.state.key = 'status';
270
+ this.state.value = 'active';
271
+ this.queueRender();
272
+ // → microtask fires → _render() once → _afterRender() once
273
+ ```
274
+
275
+ ### `fill()` — limitations
276
+
277
+ `fill()` sets `textContent` for `data-ln-field` — it does **not** set `.value` on `<input>`, `<textarea>`, or `<select>`. For form elements, set `.value` manually after `fill()`.
278
+
279
+ ### When to use
280
+
281
+ Use `createBatcher` when a component has **frequent or multiple state updates** (e.g. search input, filter checkboxes, sorting), and multiple updates can occur in the same synchronous cycle.
282
+
283
+ **Don't use it for:**
284
+ - Single boolean state — `this.isOpen = true; dom.classList.toggle(...)` is simpler
285
+ - Event-driven rendering — components that receive data via `set-data` events (ln-table)
286
+ - One-shot renders — clone template + fill once, no ongoing state
287
+
288
+ ### Used in
289
+
290
+ Used in `ln-search`, `ln-filter`, `ln-list`, and `ln-data-coordinator` for microtask render coalescing.
291
+
292
+ ---
293
+
294
294
  ## CustomEvent Communication
295
295
 
296
296
  Components do NOT know about each other. Communication ONLY via CustomEvent.
@@ -1,105 +1,105 @@
1
- {
2
- "$comment": "This file is partly generated. The $comment, component, generator, and each attribute's direction, sources, type, values, fallback, and description keys are owned by the generator and synchronized from JS source code. All other keys are preserved and safe to hand-author. Regenerate with `npm run sync:ln-schemas`.",
3
- "component": "ln-api-connector",
4
- "generator": "scripts/sync-ln-schemas.mjs",
5
- "attributes": {
6
- "data-ln-api-base-url": {
7
- "direction": null,
8
- "sources": [
9
- "src/ln-api-connector.js"
10
- ],
11
- "type": "string",
12
- "fallback": "",
13
- "description": "Base URL endpoint for API requests"
14
- },
15
- "data-ln-api-connector": {
16
- "direction": null,
17
- "sources": [
18
- "src/ln-api-connector.js"
19
- ],
20
- "type": "marker",
21
- "description": "Mounts API connector bridging REST backend and ln-ashlar data coordinators"
22
- },
23
- "data-ln-api-connector-query-debounce": {
24
- "direction": "author",
25
- "sources": [
26
- "src/ln-api-connector.js"
27
- ],
28
- "type": "integer",
29
- "fallback": 200,
30
- "min": 0,
31
- "description": "Debounce delay in milliseconds before dispatching query requests"
32
- },
33
- "data-ln-api-endpoint": {
34
- "direction": "author",
35
- "sources": [
36
- "src/ln-api-connector.js"
37
- ],
38
- "type": "string",
39
- "fallback": "",
40
- "description": "Alias for data-ln-api-path"
41
- },
42
- "data-ln-api-headers": {
43
- "direction": null,
44
- "sources": [
45
- "src/ln-api-connector.js"
46
- ],
47
- "type": "json",
48
- "description": "Custom HTTP headers in JSON format or semicolon-separated pairs"
49
- },
50
- "data-ln-api-param-limit": {
51
- "direction": "author",
52
- "sources": [
53
- "src/ln-api-connector.js"
54
- ],
55
- "type": "string",
56
- "fallback": "limit",
57
- "description": "Query parameter name for pagination page size"
58
- },
59
- "data-ln-api-param-offset": {
60
- "direction": "author",
61
- "sources": [
62
- "src/ln-api-connector.js"
63
- ],
64
- "type": "string",
65
- "fallback": "offset",
66
- "description": "Query parameter name for pagination offset"
67
- },
68
- "data-ln-api-param-search": {
69
- "direction": "author",
70
- "sources": [
71
- "src/ln-api-connector.js"
72
- ],
73
- "type": "string",
74
- "fallback": "search",
75
- "description": "Query parameter name for text search filter"
76
- },
77
- "data-ln-api-param-sort-dir": {
78
- "direction": "author",
79
- "sources": [
80
- "src/ln-api-connector.js"
81
- ],
82
- "type": "string",
83
- "fallback": "sort_dir",
84
- "description": "Query parameter name for sort direction"
85
- },
86
- "data-ln-api-param-sort-field": {
87
- "direction": "author",
88
- "sources": [
89
- "src/ln-api-connector.js"
90
- ],
91
- "type": "string",
92
- "fallback": "sort_by",
93
- "description": "Query parameter name for sort field"
94
- },
95
- "data-ln-api-path": {
96
- "direction": "author",
97
- "sources": [
98
- "src/ln-api-connector.js"
99
- ],
100
- "type": "string",
101
- "fallback": "",
102
- "description": "Resource path appended to base URL"
103
- }
104
- }
105
- }
1
+ {
2
+ "$comment": "This file is partly generated. The $comment, component, generator, and each attribute's direction, sources, type, values, fallback, and description keys are owned by the generator and synchronized from JS source code. All other keys are preserved and safe to hand-author. Regenerate with `npm run sync:ln-schemas`.",
3
+ "component": "ln-api-connector",
4
+ "generator": "scripts/sync-ln-schemas.mjs",
5
+ "attributes": {
6
+ "data-ln-api-base-url": {
7
+ "direction": null,
8
+ "sources": [
9
+ "src/ln-api-connector.js"
10
+ ],
11
+ "type": "string",
12
+ "fallback": "",
13
+ "description": "Base URL endpoint for API requests"
14
+ },
15
+ "data-ln-api-connector": {
16
+ "direction": null,
17
+ "sources": [
18
+ "src/ln-api-connector.js"
19
+ ],
20
+ "type": "marker",
21
+ "description": "Mounts API connector bridging REST backend and ln-ashlar data coordinators"
22
+ },
23
+ "data-ln-api-connector-query-debounce": {
24
+ "direction": "author",
25
+ "sources": [
26
+ "src/ln-api-connector.js"
27
+ ],
28
+ "type": "integer",
29
+ "fallback": 200,
30
+ "min": 0,
31
+ "description": "Debounce delay in milliseconds before dispatching query requests"
32
+ },
33
+ "data-ln-api-endpoint": {
34
+ "direction": "author",
35
+ "sources": [
36
+ "src/ln-api-connector.js"
37
+ ],
38
+ "type": "string",
39
+ "fallback": "",
40
+ "description": "Alias for data-ln-api-path"
41
+ },
42
+ "data-ln-api-headers": {
43
+ "direction": null,
44
+ "sources": [
45
+ "src/ln-api-connector.js"
46
+ ],
47
+ "type": "json",
48
+ "description": "Custom HTTP headers in JSON format or semicolon-separated pairs"
49
+ },
50
+ "data-ln-api-param-limit": {
51
+ "direction": "author",
52
+ "sources": [
53
+ "src/ln-api-connector.js"
54
+ ],
55
+ "type": "string",
56
+ "fallback": "limit",
57
+ "description": "Query parameter name for pagination page size"
58
+ },
59
+ "data-ln-api-param-offset": {
60
+ "direction": "author",
61
+ "sources": [
62
+ "src/ln-api-connector.js"
63
+ ],
64
+ "type": "string",
65
+ "fallback": "offset",
66
+ "description": "Query parameter name for pagination offset"
67
+ },
68
+ "data-ln-api-param-search": {
69
+ "direction": "author",
70
+ "sources": [
71
+ "src/ln-api-connector.js"
72
+ ],
73
+ "type": "string",
74
+ "fallback": "search",
75
+ "description": "Query parameter name for text search filter"
76
+ },
77
+ "data-ln-api-param-sort-dir": {
78
+ "direction": "author",
79
+ "sources": [
80
+ "src/ln-api-connector.js"
81
+ ],
82
+ "type": "string",
83
+ "fallback": "sort_dir",
84
+ "description": "Query parameter name for sort direction"
85
+ },
86
+ "data-ln-api-param-sort-field": {
87
+ "direction": "author",
88
+ "sources": [
89
+ "src/ln-api-connector.js"
90
+ ],
91
+ "type": "string",
92
+ "fallback": "sort_by",
93
+ "description": "Query parameter name for sort field"
94
+ },
95
+ "data-ln-api-path": {
96
+ "direction": "author",
97
+ "sources": [
98
+ "src/ln-api-connector.js"
99
+ ],
100
+ "type": "string",
101
+ "fallback": "",
102
+ "description": "Resource path appended to base URL"
103
+ }
104
+ }
105
+ }
@@ -1,10 +1,6 @@
1
1
  @use '../../theme/config/mixins' as *;
2
2
 
3
3
  [data-ln-debug] {
4
- [data-ln-chart]:not(.chart) {
5
- @include dev-dom-error("[data-ln-chart] is missing the required .chart visual class.");
6
- }
7
-
8
4
  [data-ln-chart]:not([data-ln-chart-x]),
9
5
  [data-ln-chart]:not([data-ln-chart-y]) {
10
6
  @include dev-dom-error("[data-ln-chart] requires data-ln-chart-x and data-ln-chart-y.");
@@ -559,24 +559,24 @@ const batchRender = createBatcher(
559
559
 
560
560
  ---
561
561
 
562
- ## Reactive Rendering Pattern
563
-
564
- The `createBatcher` primitive and DOM rendering helpers (`fill`, `renderList`) are designed to be used together as the canonical ln-ashlar microtask render loop:
565
-
566
- 1. **State mutation.** Component updates internal data properties (e.g. `this.state.key = 'val'`).
567
- 2. **Microtask queue.** The component triggers the `schedule()` function returned by `createBatcher`. Any number of synchronous assignments in the same sync block schedule a single microtask.
568
- 3. **One render.** When the microtask fires, the batcher calls `renderFn` exactly once. `renderFn` typically calls `fill(this.dom, this.state)` (or `renderList` for keyed collections) to project state into the DOM, then the optional `afterRender` callback fires (commonly used to dispatch a `ln-{component}:rendered` or changed event).
569
-
570
- Two state assignments on the same tick produce one DOM update:
571
-
572
- The pattern is: **state mutation → microtask queue → one render**.
573
- Never wire sync state updates directly to immediate DOM writes when multiple attributes or filter parameters can change simultaneously — batching prevents layout thrashing.
574
-
575
- For further details, see
576
- [Reactive Rendering Pattern in components/COMPONENTS.md](../../components/COMPONENTS.md#reactive-rendering-pattern).
577
-
578
- ---
579
-
562
+ ## Reactive Rendering Pattern
563
+
564
+ The `createBatcher` primitive and DOM rendering helpers (`fill`, `renderList`) are designed to be used together as the canonical ln-ashlar microtask render loop:
565
+
566
+ 1. **State mutation.** Component updates internal data properties (e.g. `this.state.key = 'val'`).
567
+ 2. **Microtask queue.** The component triggers the `schedule()` function returned by `createBatcher`. Any number of synchronous assignments in the same sync block schedule a single microtask.
568
+ 3. **One render.** When the microtask fires, the batcher calls `renderFn` exactly once. `renderFn` typically calls `fill(this.dom, this.state)` (or `renderList` for keyed collections) to project state into the DOM, then the optional `afterRender` callback fires (commonly used to dispatch a `ln-{component}:rendered` or changed event).
569
+
570
+ Two state assignments on the same tick produce one DOM update:
571
+
572
+ The pattern is: **state mutation → microtask queue → one render**.
573
+ Never wire sync state updates directly to immediate DOM writes when multiple attributes or filter parameters can change simultaneously — batching prevents layout thrashing.
574
+
575
+ For further details, see
576
+ [Reactive Rendering Pattern in components/COMPONENTS.md](../../components/COMPONENTS.md#reactive-rendering-pattern).
577
+
578
+ ---
579
+
580
580
  ## window-cache.js
581
581
 
582
582
  ### createWindowCache(config)
@@ -951,9 +951,9 @@ import { dispatch, dispatchCancelable, guardBody, findElements, createBatcher, f
951
951
  const self = this;
952
952
 
953
953
  // Reactive state + batched rendering
954
- this.state = { items: [] };
955
- this.batchRender = createBatcher(function () {
956
- if (!self._destroyed) self._render();
954
+ this.state = { items: [] };
955
+ this.batchRender = createBatcher(function () {
956
+ if (!self._destroyed) self._render();
957
957
  });
958
958
 
959
959
  return this;