@fusion.dev/helix-core 0.0.0-dev → 0.0.2
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.
- package/custom-elements.json +156 -124
- package/dist/controllers/aria-forward-controller/aria-forward-controller.d.ts +2 -0
- package/dist/controllers/aria-forward-controller/aria-forward-controller.js +44 -17
- package/dist/controllers/chart-pointer-controller/chart-pointer-controller.d.ts +5 -6
- package/dist/controllers/chart-pointer-controller/chart-pointer-controller.js +5 -6
- package/dist/controllers/command-controller/command-controller.d.ts +5 -7
- package/dist/controllers/command-controller/command-controller.js +5 -7
- package/dist/controllers/copy-controller/copy-controller.d.ts +2 -4
- package/dist/controllers/copy-controller/copy-controller.js +7 -9
- package/dist/controllers/disabled-cascade-controller/disabled-cascade-controller.d.ts +10 -17
- package/dist/controllers/disabled-cascade-controller/disabled-cascade-controller.js +11 -18
- package/dist/controllers/dismiss-controller/dismiss-controller.d.ts +44 -6
- package/dist/controllers/dismiss-controller/dismiss-controller.js +77 -10
- package/dist/controllers/drilldown-controller/drilldown-controller.d.ts +3 -6
- package/dist/controllers/drilldown-controller/drilldown-controller.js +3 -6
- package/dist/controllers/floating-controller/floating-controller.d.ts +7 -8
- package/dist/controllers/floating-controller/floating-controller.js +69 -38
- package/dist/controllers/focus-trap-controller/focus-trap-controller.js +7 -10
- package/dist/controllers/indicator-controller/indicator-controller.d.ts +17 -29
- package/dist/controllers/indicator-controller/indicator-controller.js +11 -21
- package/dist/controllers/keyboard-navigation-controller/keyboard-navigation-controller.d.ts +3 -13
- package/dist/controllers/keyboard-navigation-controller/keyboard-navigation-controller.js +11 -24
- package/dist/controllers/popover-controller/popover-controller.d.ts +2 -7
- package/dist/controllers/popover-controller/popover-controller.js +3 -9
- package/dist/controllers/source-controller/source-controller.d.ts +2 -5
- package/dist/controllers/source-controller/source-controller.js +2 -5
- package/dist/controllers/token-color-controller/token-color-controller.d.ts +2 -4
- package/dist/controllers/token-color-controller/token-color-controller.js +2 -4
- package/dist/controllers/virtualize-controller/virtualize-controller.d.ts +1 -1
- package/dist/controllers/virtualize-controller/virtualize-controller.js +15 -15
- package/dist/events/element-events.js +0 -5
- package/dist/events/events.d.ts +55 -93
- package/dist/events/events.js +68 -105
- package/dist/helix-element/helix-element.d.ts +26 -27
- package/dist/helix-element/helix-element.js +83 -100
- package/dist/helix-form-element/helix-form-element.d.ts +11 -17
- package/dist/helix-form-element/helix-form-element.js +15 -21
- package/dist/mixins/mixin-chart-source/mixin-chart-source.d.ts +6 -14
- package/dist/mixins/mixin-chart-source/mixin-chart-source.js +12 -25
- package/dist/mixins/mixin-collection/mixin-collection.d.ts +1 -7
- package/dist/mixins/mixin-collection/mixin-collection.js +16 -23
- package/dist/mixins/mixin-controller-active/mixin-controller-active.d.ts +15 -16
- package/dist/mixins/mixin-controller-active/mixin-controller-active.js +28 -42
- package/dist/mixins/mixin-controller-checked/mixin-controller-checked.d.ts +15 -17
- package/dist/mixins/mixin-controller-checked/mixin-controller-checked.js +33 -45
- package/dist/mixins/mixin-controller-open/mixin-controller-open.d.ts +4 -4
- package/dist/mixins/mixin-controller-open/mixin-controller-open.js +29 -45
- package/dist/mixins/mixin-controller-value/mixin-controller-value.d.ts +10 -18
- package/dist/mixins/mixin-controller-value/mixin-controller-value.js +14 -31
- package/dist/mixins/mixin-dismissible/mixin-dismissible.d.ts +10 -15
- package/dist/mixins/mixin-dismissible/mixin-dismissible.js +10 -15
- package/dist/mixins/mixin-field/mixin-field.d.ts +10 -12
- package/dist/mixins/mixin-field/mixin-field.js +48 -64
- package/dist/utils/capture-pointer/capture-pointer.d.ts +1 -4
- package/dist/utils/capture-pointer/capture-pointer.js +1 -4
- package/dist/utils/closest-instance/closest-instance.d.ts +6 -10
- package/dist/utils/closest-instance/closest-instance.js +6 -10
- package/dist/utils/create-sheet/create-sheet.d.ts +1 -1
- package/dist/utils/create-sheet/create-sheet.js +1 -1
- package/dist/utils/custom-element/custom-element.d.ts +0 -21
- package/dist/utils/custom-element/custom-element.js +1 -1
- package/dist/utils/draw-icon/draw-icon.d.ts +3 -3
- package/dist/utils/draw-icon/draw-icon.js +3 -3
- package/dist/utils/elapsed-time/elapsed-time.js +1 -3
- package/dist/utils/focusable-elements/focusable-elements.d.ts +3 -4
- package/dist/utils/focusable-elements/focusable-elements.js +9 -11
- package/dist/utils/format-numbers/format-numbers.js +1 -4
- package/dist/utils/host-aria/host-aria.d.ts +2 -2
- package/dist/utils/host-aria/host-aria.js +2 -2
- package/dist/utils/line-path/line-path.js +1 -1
- package/dist/utils/on-unless-false/on-unless-false.d.ts +0 -5
- package/dist/utils/on-unless-false/on-unless-false.js +0 -5
- package/dist/utils/read-series/read-series.d.ts +26 -0
- package/dist/utils/read-series/read-series.js +26 -29
- package/dist/utils/relative-time/relative-time.js +5 -6
- package/dist/utils/request-change/request-change.d.ts +9 -20
- package/dist/utils/resolve-active-item/resolve-active-item.d.ts +3 -3
- package/dist/utils/resolve-active-item/resolve-active-item.js +3 -3
- package/dist/utils/restore-value/restore-value.js +1 -6
- package/dist/utils/scroll-item-into-view/scroll-item-into-view.js +4 -5
- package/dist/utils/slot-filled/slot-filled.d.ts +2 -4
- package/dist/utils/slot-filled/slot-filled.js +2 -4
- package/dist/utils/tell-disclosure/tell-disclosure.d.ts +15 -18
- package/dist/utils/tell-disclosure/tell-disclosure.js +15 -18
- package/dist/utils/tone-marks/tone-marks.d.ts +10 -16
- package/dist/utils/tone-marks/tone-marks.js +6 -10
- package/dist/utils/value-as/value-as.d.ts +0 -28
- package/dist/utils/value-as/value-as.js +5 -10
- package/package.json +6 -6
|
@@ -19,9 +19,8 @@ const BOX_SIZING = css `
|
|
|
19
19
|
*
|
|
20
20
|
* The UA stylesheet's `[hidden] { display: none }` is user-agent origin, so any
|
|
21
21
|
* author declaration beats it, and a component whose `:host` sets a `display`
|
|
22
|
-
* is doing exactly that.
|
|
23
|
-
* `<helix-
|
|
24
|
-
* audit found three of them and the real count was fifty-seven, because every
|
|
22
|
+
* is doing exactly that. Fifty-seven components stayed visible while hidden,
|
|
23
|
+
* `<helix-grid>`, `<helix-empty>` and `<helix-flex>` among them, because every
|
|
25
24
|
* component that lays itself out has the same fault and nothing connects them.
|
|
26
25
|
*
|
|
27
26
|
* Here rather than in each sheet, for the reason `box-sizing` is here: it is a
|
|
@@ -29,14 +28,13 @@ const BOX_SIZING = css `
|
|
|
29
28
|
* forget the fifty-eighth.
|
|
30
29
|
*
|
|
31
30
|
* **The selector is (0,3,0) on purpose, and the obvious (0,2,0) is not enough.**
|
|
32
|
-
* A bare `:host([hidden])` beats a bare `:host`,
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* `
|
|
37
|
-
* `
|
|
38
|
-
*
|
|
39
|
-
* wins from first position, so the rule can stay prepended.
|
|
31
|
+
* A bare `:host([hidden])` beats a bare `:host`, but it only ties with the
|
|
32
|
+
* `:host([attr])` rules a component uses to set its own `display`, and those win
|
|
33
|
+
* on source order because they are injected after this. Measured, elements
|
|
34
|
+
* styled that way still rendered while hidden: `flex[inline]` at `inline-flex`,
|
|
35
|
+
* `divider[orientation="vertical"]` at `inline-block`, `text[as]` at `block`.
|
|
36
|
+
* The `:not()` lifts it a step and it wins from first position, so the rule can
|
|
37
|
+
* stay prepended.
|
|
40
38
|
*
|
|
41
39
|
* **And the `:not()` is load-bearing beyond specificity.** `hidden="until-found"`
|
|
42
40
|
* is how the platform lets find-in-page reveal collapsed content: the browser
|
|
@@ -60,30 +58,25 @@ const HIDDEN = css `
|
|
|
60
58
|
* so.** `overflow` is what creates a scrollport: without it `scrollTop` is
|
|
61
59
|
* permanently zero and every scroll API on the element is inert. So a component
|
|
62
60
|
* that reads `scrollTop` and cannot declare `overflow` is one whose behavior
|
|
63
|
-
* lives in somebody else's stylesheet
|
|
61
|
+
* lives in somebody else's stylesheet.
|
|
64
62
|
*
|
|
65
63
|
* Measured before deciding: `helix-headless-scroll-area`, the component whose
|
|
66
64
|
* entire purpose is scrolling, computes `overflow-y: visible` on its viewport
|
|
67
|
-
* with `scrollHeight` equal to `clientHeight`. Standing alone it is a div
|
|
68
|
-
* virtual list
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
* exact same category: the rules argue `hidden` is base-tier state because the
|
|
75
|
-
* platform acts on it, and the way the headless tier makes the platform act is a
|
|
76
|
-
* CSS rule shipped from here. "The headless tier has no CSS" has never meant
|
|
77
|
-
* `core` has none; it means `helix/headless` must not depend on
|
|
65
|
+
* with `scrollHeight` equal to `clientHeight`. Standing alone it is a div, and
|
|
66
|
+
* the virtual list is worse because it *acts* on the reading.
|
|
67
|
+
*
|
|
68
|
+
* **It goes here rather than in a stylesheet**, beside `BOX_SIZING`, `HIDDEN`
|
|
69
|
+
* and `SETTLED`, which are the token-free structural rules `core` ships into
|
|
70
|
+
* every shadow root. "The headless tier has no CSS" has never meant `core` has
|
|
71
|
+
* none; it means `helix/headless` must not depend on
|
|
78
72
|
* `@fusion.dev/helix-styles`, and a rule with no token in it does not.
|
|
79
73
|
*
|
|
80
74
|
* **And a rule rather than an inline style, which was the first idea and is
|
|
81
75
|
* wrong.** An inline `style` on a rendered part outranks every author rule
|
|
82
76
|
* short of `!important`, so a consumer wanting `overflow: hidden` on that part
|
|
83
|
-
* would have to fight it
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
* from a consumer simply wins, which is the right way round.
|
|
77
|
+
* would have to fight it and would need `!important` of their own. A shadow rule
|
|
78
|
+
* loses to a document rule, so `::part(viewport) { overflow: … }` from a
|
|
79
|
+
* consumer simply wins, which is the right way round.
|
|
87
80
|
*
|
|
88
81
|
* Both axes, and nothing else. Which *kind* of scrolling, how much room,
|
|
89
82
|
* `overscroll-behavior`, `scroll-snap`, a gutter, a scrollbar treatment: those
|
|
@@ -91,14 +84,13 @@ const HIDDEN = css `
|
|
|
91
84
|
* styled sheet is prepended-after so it overrides at equal specificity anyway.
|
|
92
85
|
*
|
|
93
86
|
* **A component marks a box whose scroll state it reads, and no other**, which
|
|
94
|
-
* is narrower than "every box that ends up scrolling"
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
* apply exactly where it is needed.
|
|
87
|
+
* is narrower than "every box that ends up scrolling". `Megamenu`'s panel
|
|
88
|
+
* scrolls, and only because the styled tier gives it a `max-block-size`: that is
|
|
89
|
+
* a decision, the `overflow` that serves it belongs with it, and the headless
|
|
90
|
+
* tier never asks the panel where it is scrolled to. Marking it anyway moved a
|
|
91
|
+
* heading four pixels, because `overflow` establishes a block formatting context
|
|
92
|
+
* and margins that had been collapsing stopped. A mechanism with a layout
|
|
93
|
+
* consequence is one to apply exactly where it is needed.
|
|
102
94
|
*
|
|
103
95
|
* Three qualify: `ScrollArea`, `VirtualList` and `Carousel`, each of which
|
|
104
96
|
* reads `scrollTop` or `scrollLeft` and acts on the answer.
|
|
@@ -149,20 +141,13 @@ const SCROLLER = css `
|
|
|
149
141
|
* resolved with transitions off, so enabling them changes nothing and there is
|
|
150
142
|
* nothing left to animate.
|
|
151
143
|
*
|
|
152
|
-
* **`:state()` and
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
* `/helix/sandbox` three, every one of them a `data-settled=""` no server sent.
|
|
160
|
-
*
|
|
161
|
-
* It was worked around three times, in `use-sandbox-editor.ts`, in the sandbox
|
|
162
|
-
* barrel and again on the reference pages, each deferring a registration so the
|
|
163
|
-
* frame fell the other side of hydration. Every one of those is a fix for the
|
|
164
|
-
* timing rather than for the cause: the cause is that a component's private
|
|
165
|
-
* bookkeeping was being kept somewhere React reconciles.
|
|
144
|
+
* **`:state()` and never an attribute.** The host is the element React owns, and
|
|
145
|
+
* a definition that lands during module evaluation has a frame to spend before
|
|
146
|
+
* React arrives, so an element writing `[data-settled]` onto its own host leaves
|
|
147
|
+
* React hydrating a DOM that gained an attribute since the server wrote it.
|
|
148
|
+
* Deferring a registration so the frame falls the other side of hydration is a
|
|
149
|
+
* fix for the timing rather than for the cause, which is that a component's
|
|
150
|
+
* private bookkeeping was being kept somewhere React reconciles.
|
|
166
151
|
*
|
|
167
152
|
* A custom state is not in the DOM. It carries the fact to this stylesheet and
|
|
168
153
|
* nothing to the markup, so a server's output and a hydrated client's agree by
|
|
@@ -189,25 +174,25 @@ const REACT_PROPS = '__reactProps$';
|
|
|
189
174
|
* would be a scan per keystroke. Re-scanned whenever the cached key comes back
|
|
190
175
|
* empty, so a second React root with a suffix of its own still resolves.
|
|
191
176
|
*
|
|
192
|
-
* **A miss must not erase it
|
|
193
|
-
*
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
*
|
|
177
|
+
* **A miss must not erase it.** A re-scan that writes its own result back
|
|
178
|
+
* unconditionally sets the key to `undefined` on every dispatch from a node
|
|
179
|
+
* React does not own, and the next React-owned node pays for a full scan again.
|
|
180
|
+
* Most elements in this library are rendered by Lit inside a shadow root and are
|
|
181
|
+
* exactly that kind of node, so the cache is cleared constantly by the
|
|
182
|
+
* components least able to benefit from it. Measured, 20,000 dispatches: 5.3ms
|
|
183
|
+
* with a warm cache against 20.3ms alternating one owned node with one that is
|
|
184
|
+
* not, roughly twice the per-dispatch cost for the half that should have been
|
|
185
|
+
* free.
|
|
201
186
|
*
|
|
202
|
-
* So a miss
|
|
203
|
-
*
|
|
187
|
+
* So a miss leaves the cache alone and only a *different* key replaces it, which
|
|
188
|
+
* keeps the second-React-root case the note above is about.
|
|
204
189
|
*
|
|
205
190
|
* **What is left is a scan per dispatch on a page with no React at all**, since
|
|
206
191
|
* there is no key to find and no honest way to conclude one will never appear:
|
|
207
192
|
* a root can mount at any time, and memoizing "this node is not React's" would
|
|
208
193
|
* silently disable the binding for any element that dispatches before React
|
|
209
194
|
* commits, which is the exact failure this whole mechanism exists to repair.
|
|
210
|
-
* It is around half a microsecond and it is filed rather than hidden.
|
|
195
|
+
* It is around half a microsecond and it is filed rather than hidden.
|
|
211
196
|
*/
|
|
212
197
|
let reactPropsKey;
|
|
213
198
|
/** The props React is holding for a node, if React is holding any. */
|
|
@@ -244,9 +229,9 @@ const REMOVED = new Set(['onActiveChange', 'onCheckedChange', 'onOpenChange', 'o
|
|
|
244
229
|
* do reject a wrong *value* on a normal attribute. Measured with `tsc`.
|
|
245
230
|
*
|
|
246
231
|
* That leaves runtime as the only place a typo can be caught, and React's props
|
|
247
|
-
* bag as the only place to look, which the binding above already reads. Once
|
|
248
|
-
*
|
|
249
|
-
*
|
|
232
|
+
* bag as the only place to look, which the binding above already reads. Once per
|
|
233
|
+
* element, because a warning that repeats on every keystroke is one a consumer
|
|
234
|
+
* silences.
|
|
250
235
|
*
|
|
251
236
|
* `on:helix-open` gets its own message because it is not a mistake so much as
|
|
252
237
|
* the wrong dialect. It is what the Solid types offer, correctly, and React
|
|
@@ -284,7 +269,7 @@ const auditReactProps = (host, props) => {
|
|
|
284
269
|
bubbling, but React binds an `on` prop by reading it as the element itself
|
|
285
270
|
dispatches: one merely passing through never calls this host's own
|
|
286
271
|
`dispatchEvent`, so the prop is recorded and never wired.
|
|
287
|
-
|
|
272
|
+
|
|
288
273
|
Silent when nothing registered the tag, which is a component from outside
|
|
289
274
|
this library or a package built before the map existed. */
|
|
290
275
|
const mine = host instanceof Element ? eventsForTag(host.localName) : undefined;
|
|
@@ -353,7 +338,7 @@ const REACT_WIRES = new Set(['scroll', 'scrollend']);
|
|
|
353
338
|
* React binds a hyphenated prop directly on the element, so our own events are
|
|
354
339
|
* reached by name and are safe to bind again: same type, same callback, same
|
|
355
340
|
* capture flag is a no-op by specification. A native name is different. React
|
|
356
|
-
*
|
|
341
|
+
* recognizes `onChange` and `onLoad` as its own registration names and attaches
|
|
357
342
|
* nothing to the element for either; it relies on a delegated listener at the
|
|
358
343
|
* root, which sees an event only if it **bubbles**, and on a non-delegated list
|
|
359
344
|
* it sets up for `<video>`, `<audio>` and `<img>` and never for a custom
|
|
@@ -364,8 +349,7 @@ const REACT_WIRES = new Set(['scroll', 'scrollend']);
|
|
|
364
349
|
* it and the consumer's handler runs twice. A non-bubbling relay arrives
|
|
365
350
|
* nowhere, and is the bug this exists to close: `<helix-avatar>` relays `load`
|
|
366
351
|
* and `error`, `<helix-video>` relays `ended`, `play` and `pause`, all of them
|
|
367
|
-
* declared public API
|
|
368
|
-
* fallback is a shipped feature that did nothing.
|
|
352
|
+
* declared public API and all of them otherwise silent in React.
|
|
369
353
|
*
|
|
370
354
|
* The name is React's own casing, `onError` rather than `onerror`, because that
|
|
371
355
|
* is what a consumer writes and therefore what is in the props bag. Every
|
|
@@ -422,9 +406,8 @@ const bindReactHandler = (host, event) => {
|
|
|
422
406
|
* the element; the second is what keeps this to the properties that are actually
|
|
423
407
|
* broken, rather than re-applying a string that is already correct. Three
|
|
424
408
|
* qualify today, `rows` on the data table and `cell` and `compare` on a table
|
|
425
|
-
* column
|
|
426
|
-
*
|
|
427
|
-
* this never touches.
|
|
409
|
+
* column; the remaining `attribute: false` properties are booleans and strings a
|
|
410
|
+
* parent writes at runtime, which no consumer passes and this never touches.
|
|
428
411
|
*
|
|
429
412
|
* **`null` is the one place this does not reproduce a client mount, and it is
|
|
430
413
|
* deliberate.** `typeof null` is `'object'`, and React assigns a null prop on a
|
|
@@ -488,13 +471,11 @@ export class HelixElement extends LitElement {
|
|
|
488
471
|
* `helix-pagination-size` composes `helix-select`. One template says
|
|
489
472
|
* `${this.tag('select')}` and each tier answers with its own name.
|
|
490
473
|
*
|
|
491
|
-
*
|
|
492
|
-
*
|
|
493
|
-
*
|
|
494
|
-
*
|
|
495
|
-
*
|
|
496
|
-
* tier to test it against. Thirty-nine specs had to be moved back to
|
|
497
|
-
* `helix/styled` for exactly that reason.
|
|
474
|
+
* **The public tag may not be the composed one, in either tier.** Using it
|
|
475
|
+
* costs three things: the name means two different things depending on what a
|
|
476
|
+
* consumer imported, the headless tier composes an element it does not ship,
|
|
477
|
+
* and the composition cannot be tested there at all, because there is no
|
|
478
|
+
* `helix-select` on that tier to test it against.
|
|
498
479
|
*
|
|
499
480
|
* **A prefix rather than an override per composition**, which was the first
|
|
500
481
|
* plan and does not compile. An override re-renders the fragment from the
|
|
@@ -527,25 +508,27 @@ export class HelixElement extends LitElement {
|
|
|
527
508
|
* fact to a stylesheet through `:state()` and leaves the markup alone, so the
|
|
528
509
|
* server's output and the client's agree by construction.
|
|
529
510
|
*
|
|
530
|
-
* `SETTLED` carries the long version of that argument
|
|
531
|
-
*
|
|
532
|
-
*
|
|
533
|
-
* showcase: a `default-checked` switch, a `default-checked` checkbox and a
|
|
534
|
-
* `default-open` accordion item, each writing its own resolved state onto
|
|
535
|
-
* itself before React reached the node.
|
|
511
|
+
* `SETTLED` carries the long version of that argument; `checked`, `open`,
|
|
512
|
+
* `invalid` and `has-label` are recorded the same way, each of them a state a
|
|
513
|
+
* `default-*` attribute resolves before React reaches the node.
|
|
536
514
|
*
|
|
537
|
-
* **
|
|
538
|
-
*
|
|
539
|
-
*
|
|
540
|
-
*
|
|
541
|
-
*
|
|
542
|
-
* fact is kept somewhere React reconciles.
|
|
515
|
+
* **Deferring the definitions is not a fix and could not be.** Importing them
|
|
516
|
+
* from an effect so the upgrades fall the other side of hydration works only
|
|
517
|
+
* while hydration is one pass: anything that splits it, a streamed segment or
|
|
518
|
+
* a suspended boundary, puts an upgrade back inside the window. Timing cannot
|
|
519
|
+
* be the guarantee when the fact is kept somewhere React reconciles.
|
|
543
520
|
*
|
|
544
521
|
* Feature-tested rather than assumed, the way `hostAria` tests element
|
|
545
522
|
* references. An engine without `CustomStateSet` records nothing and keeps
|
|
546
|
-
* whatever the resting rule draws, which is the safe direction to fail
|
|
547
|
-
*
|
|
548
|
-
*
|
|
523
|
+
* whatever the resting rule draws, which is the safe direction to fail.
|
|
524
|
+
*
|
|
525
|
+
* **Lit's server shim is no longer one of them**, and this said it was.
|
|
526
|
+
* `@lit-labs/ssr-dom-shim@1.6.0` sets `this.states = new Set()` in its
|
|
527
|
+
* `ElementInternals` constructor, so the guard passes on the server and a
|
|
528
|
+
* custom state is recorded where nothing reads it, which is harmless. The
|
|
529
|
+
* engines the test is for are browsers: Safari below 17.4 and Firefox below
|
|
530
|
+
* 126. There the write is a `TypeError`, so a component that bypasses this
|
|
531
|
+
* fails to render rather than rendering without whatever the state draws.
|
|
549
532
|
*/
|
|
550
533
|
toggleState(name, on) {
|
|
551
534
|
if ('states' in this.internals) {
|
|
@@ -643,9 +626,9 @@ export class HelixElement extends LitElement {
|
|
|
643
626
|
* suppressing transitions.
|
|
644
627
|
*
|
|
645
628
|
* A frame later, not now: see `SETTLED` for why `firstUpdated` itself is too
|
|
646
|
-
* early. SSR never calls this, which is correct, because the
|
|
647
|
-
*
|
|
648
|
-
*
|
|
629
|
+
* early. SSR never calls this, which is correct, because the state describes
|
|
630
|
+
* something that happened in a browser and the server has no frame to wait
|
|
631
|
+
* for.
|
|
649
632
|
*/
|
|
650
633
|
firstUpdated(changed) {
|
|
651
634
|
super.firstUpdated(changed);
|
|
@@ -663,10 +646,10 @@ export class HelixElement extends LitElement {
|
|
|
663
646
|
this.toggleState('settled', true);
|
|
664
647
|
this.resolveSettled();
|
|
665
648
|
/* **Audited here as well as at dispatch, and this is the half that catches
|
|
666
|
-
the real mistake.**
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
649
|
+
the real mistake.** From inside `dispatchEvent` alone, an element holding
|
|
650
|
+
a handler prop and sending nothing is never looked at, and a prop on the
|
|
651
|
+
wrong element is exactly the case where that element has no reason to
|
|
652
|
+
dispatch.
|
|
670
653
|
|
|
671
654
|
A frame late, alongside the settled state, because React has to have
|
|
672
655
|
committed its props for there to be anything to read. Once per element
|
|
@@ -30,25 +30,21 @@ export declare class HelixFormElement extends HelixElement {
|
|
|
30
30
|
* `aria-disabled` rather than removing the element from the accessibility
|
|
31
31
|
* tree, so a screen reader can still announce that the control exists.
|
|
32
32
|
*
|
|
33
|
-
* The mirror is
|
|
34
|
-
*
|
|
35
|
-
* itself did nothing. Here is where it belongs, because here is where
|
|
36
|
-
* `disabled` is.
|
|
33
|
+
* The mirror itself is in `willUpdate` below, here rather than in each
|
|
34
|
+
* control, because here is where `disabled` is.
|
|
37
35
|
*/
|
|
38
36
|
disabled: boolean;
|
|
39
37
|
/**
|
|
40
38
|
* Whether an ancestor `<fieldset disabled>` has switched this control off.
|
|
41
39
|
*
|
|
42
40
|
* The platform tells a form-associated element through `formDisabledCallback`
|
|
43
|
-
* and nothing
|
|
44
|
-
*
|
|
45
|
-
* `helix-input` in one accepted text, reported `disabled` as false, and
|
|
46
|
-
* carried no `aria-disabled`.
|
|
41
|
+
* and nothing else does, so without this a control inside a disabled fieldset
|
|
42
|
+
* stays fully typeable and announces itself as enabled.
|
|
47
43
|
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
44
|
+
* The submission half is already the platform's: measured, the fieldset's
|
|
45
|
+
* controls are absent from the form's entry list and the host matches
|
|
46
|
+
* `:disabled`, so the value never goes anywhere. What is missing without this
|
|
47
|
+
* is everything a reader can see or touch.
|
|
52
48
|
*
|
|
53
49
|
* State rather than the `disabled` property. Writing that would reflect an
|
|
54
50
|
* attribute the consumer's server markup does not have, which React reports
|
|
@@ -63,10 +59,9 @@ export declare class HelixFormElement extends HelixElement {
|
|
|
63
59
|
* half of it the consumer wrote.
|
|
64
60
|
*
|
|
65
61
|
* @internal Read by the component itself and by nothing outside it: every
|
|
66
|
-
* call in the library is `this.isDisabled`. Public, it
|
|
62
|
+
* call in the library is `this.isDisabled`. Public, it prints a row on
|
|
67
63
|
* twenty-four families in both tiers, forty-eight in all, on every form
|
|
68
|
-
* control's reference page
|
|
69
|
-
* tables.
|
|
64
|
+
* control's reference page.
|
|
70
65
|
*
|
|
71
66
|
* **A consumer loses nothing, which was measured rather than assumed.**
|
|
72
67
|
* `element.matches(':disabled')` answers the same question, is the platform's
|
|
@@ -133,8 +128,7 @@ export declare class HelixFormElement extends HelixElement {
|
|
|
133
128
|
* there. It is only a change to the markup when a consumer assigns it
|
|
134
129
|
* imperatively later, and nothing is hydrating by then.
|
|
135
130
|
*
|
|
136
|
-
* Here rather than on each control
|
|
137
|
-
* reflected none of them.
|
|
131
|
+
* Here rather than on each control.
|
|
138
132
|
*/
|
|
139
133
|
name: string;
|
|
140
134
|
/**
|
|
@@ -36,25 +36,21 @@ export class HelixFormElement extends HelixElement {
|
|
|
36
36
|
* `aria-disabled` rather than removing the element from the accessibility
|
|
37
37
|
* tree, so a screen reader can still announce that the control exists.
|
|
38
38
|
*
|
|
39
|
-
* The mirror is
|
|
40
|
-
*
|
|
41
|
-
* itself did nothing. Here is where it belongs, because here is where
|
|
42
|
-
* `disabled` is.
|
|
39
|
+
* The mirror itself is in `willUpdate` below, here rather than in each
|
|
40
|
+
* control, because here is where `disabled` is.
|
|
43
41
|
*/
|
|
44
42
|
this.disabled = false;
|
|
45
43
|
/**
|
|
46
44
|
* Whether an ancestor `<fieldset disabled>` has switched this control off.
|
|
47
45
|
*
|
|
48
46
|
* The platform tells a form-associated element through `formDisabledCallback`
|
|
49
|
-
* and nothing
|
|
50
|
-
*
|
|
51
|
-
* `helix-input` in one accepted text, reported `disabled` as false, and
|
|
52
|
-
* carried no `aria-disabled`.
|
|
47
|
+
* and nothing else does, so without this a control inside a disabled fieldset
|
|
48
|
+
* stays fully typeable and announces itself as enabled.
|
|
53
49
|
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
50
|
+
* The submission half is already the platform's: measured, the fieldset's
|
|
51
|
+
* controls are absent from the form's entry list and the host matches
|
|
52
|
+
* `:disabled`, so the value never goes anywhere. What is missing without this
|
|
53
|
+
* is everything a reader can see or touch.
|
|
58
54
|
*
|
|
59
55
|
* State rather than the `disabled` property. Writing that would reflect an
|
|
60
56
|
* attribute the consumer's server markup does not have, which React reports
|
|
@@ -78,8 +74,7 @@ export class HelixFormElement extends HelixElement {
|
|
|
78
74
|
* there. It is only a change to the markup when a consumer assigns it
|
|
79
75
|
* imperatively later, and nothing is hydrating by then.
|
|
80
76
|
*
|
|
81
|
-
* Here rather than on each control
|
|
82
|
-
* reflected none of them.
|
|
77
|
+
* Here rather than on each control.
|
|
83
78
|
*/
|
|
84
79
|
this.name = '';
|
|
85
80
|
}
|
|
@@ -92,10 +87,9 @@ export class HelixFormElement extends HelixElement {
|
|
|
92
87
|
* half of it the consumer wrote.
|
|
93
88
|
*
|
|
94
89
|
* @internal Read by the component itself and by nothing outside it: every
|
|
95
|
-
* call in the library is `this.isDisabled`. Public, it
|
|
90
|
+
* call in the library is `this.isDisabled`. Public, it prints a row on
|
|
96
91
|
* twenty-four families in both tiers, forty-eight in all, on every form
|
|
97
|
-
* control's reference page
|
|
98
|
-
* tables.
|
|
92
|
+
* control's reference page.
|
|
99
93
|
*
|
|
100
94
|
* **A consumer loses nothing, which was measured rather than assumed.**
|
|
101
95
|
* `element.matches(':disabled')` answers the same question, is the platform's
|
|
@@ -181,10 +175,10 @@ __decorate([
|
|
|
181
175
|
property({
|
|
182
176
|
/* Empty means absent, which plain reflection cannot say. `name = ''` is the
|
|
183
177
|
default and Lit reflects it as `name=""`, so every button, switch and
|
|
184
|
-
calendar in the library
|
|
185
|
-
never wrote
|
|
186
|
-
|
|
187
|
-
|
|
178
|
+
calendar in the library would ship an empty name attribute the consumer
|
|
179
|
+
never wrote. Returning `null` removes the attribute instead. Same trap
|
|
180
|
+
`hostAria` exists for: a name of no characters is not the absence of
|
|
181
|
+
one. */
|
|
188
182
|
converter: {
|
|
189
183
|
fromAttribute: (value) => value ?? '',
|
|
190
184
|
toAttribute: (value) => (value === '' ? null : value),
|
|
@@ -3,13 +3,12 @@ import type { HelixElement } from '../../helix-element/helix-element.js';
|
|
|
3
3
|
import { type Row, type Series } from '../../utils/read-series/read-series.js';
|
|
4
4
|
type Constructor<T> = new (...args: any[]) => T;
|
|
5
5
|
/**
|
|
6
|
-
* How many
|
|
6
|
+
* How many colors the series palette has, and so where it starts over.
|
|
7
7
|
*
|
|
8
|
-
* Here rather than in each chart,
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* number two files have to agree on is a number that will stop agreeing.
|
|
8
|
+
* Here rather than in each chart, because a number two files have to agree on
|
|
9
|
+
* is a number that will stop agreeing: when the palette went from eight to
|
|
10
|
+
* twenty-four, one of five copies was missed and drew every ninth series in the
|
|
11
|
+
* first color while the legend beside it named the ninth.
|
|
13
12
|
*/
|
|
14
13
|
export declare const PALETTE = 24;
|
|
15
14
|
/** The palette slot for the nth series, counting from one and wrapping. */
|
|
@@ -41,8 +40,7 @@ export declare const seriesIndex: (depth: number) => number;
|
|
|
41
40
|
*
|
|
42
41
|
* Declared here because this is where `seriesIndex` and `PALETTE` live, and
|
|
43
42
|
* because a hook repeated on four families is a hook four families have to keep
|
|
44
|
-
* agreeing about
|
|
45
|
-
* records somebody making.
|
|
43
|
+
* agreeing about.
|
|
46
44
|
*
|
|
47
45
|
* The numbered twenty-four are the seam between the tiers: `chart/series.css`
|
|
48
46
|
* points each at a semantic token, which is a decision and so belongs to the
|
|
@@ -118,12 +116,6 @@ export declare class MixinChartSourceInterface {
|
|
|
118
116
|
/**
|
|
119
117
|
* The half of a chart that is about finding its numbers rather than drawing.
|
|
120
118
|
*
|
|
121
|
-
* Four families had written this out separately, and the row that asked for it
|
|
122
|
-
* set the bar: two copies is a coincidence and three is a pattern. There were
|
|
123
|
-
* five copies of `for`, four of `label` and three of the caption fallback by the
|
|
124
|
-
* time the line and donut charts landed, which is why this arrives now and not
|
|
125
|
-
* when the second chart did.
|
|
126
|
-
*
|
|
127
119
|
* **A mixin rather than a controller**, by the rule the tier notes give: it
|
|
128
120
|
* introduces `for` and `label`, which a consumer writes. `SourceController` is
|
|
129
121
|
* the other half and stays a controller, because resolving an id and watching
|
|
@@ -9,13 +9,12 @@ import { ChartPointerController } from '../../controllers/chart-pointer-controll
|
|
|
9
9
|
import { SourceController } from '../../controllers/source-controller/source-controller.js';
|
|
10
10
|
import { readRows, readSeries } from '../../utils/read-series/read-series.js';
|
|
11
11
|
/**
|
|
12
|
-
* How many
|
|
12
|
+
* How many colors the series palette has, and so where it starts over.
|
|
13
13
|
*
|
|
14
|
-
* Here rather than in each chart,
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* number two files have to agree on is a number that will stop agreeing.
|
|
14
|
+
* Here rather than in each chart, because a number two files have to agree on
|
|
15
|
+
* is a number that will stop agreeing: when the palette went from eight to
|
|
16
|
+
* twenty-four, one of five copies was missed and drew every ninth series in the
|
|
17
|
+
* first color while the legend beside it named the ninth.
|
|
19
18
|
*/
|
|
20
19
|
export const PALETTE = 24;
|
|
21
20
|
/** The palette slot for the nth series, counting from one and wrapping. */
|
|
@@ -23,12 +22,6 @@ export const seriesIndex = (depth) => (depth % PALETTE) + 1;
|
|
|
23
22
|
/**
|
|
24
23
|
* The half of a chart that is about finding its numbers rather than drawing.
|
|
25
24
|
*
|
|
26
|
-
* Four families had written this out separately, and the row that asked for it
|
|
27
|
-
* set the bar: two copies is a coincidence and three is a pattern. There were
|
|
28
|
-
* five copies of `for`, four of `label` and three of the caption fallback by the
|
|
29
|
-
* time the line and donut charts landed, which is why this arrives now and not
|
|
30
|
-
* when the second chart did.
|
|
31
|
-
*
|
|
32
25
|
* **A mixin rather than a controller**, by the rule the tier notes give: it
|
|
33
26
|
* introduces `for` and `label`, which a consumer writes. `SourceController` is
|
|
34
27
|
* the other half and stays a controller, because resolving an id and watching
|
|
@@ -76,11 +69,8 @@ export const MixinChartSource = (Base) => {
|
|
|
76
69
|
* Re-resolves when the chart is pointed at a different table.
|
|
77
70
|
*
|
|
78
71
|
* `SourceController` watches whatever it resolved on connect, and nothing
|
|
79
|
-
* tells it the id changed.
|
|
80
|
-
*
|
|
81
|
-
* precisely because each file looked complete on its own: pointing a bar
|
|
82
|
-
* chart at a second table worked and pointing a line chart at one left it
|
|
83
|
-
* drawing the first. Extracting the four found it.
|
|
72
|
+
* tells it the id changed. Without this, pointing a chart at a second table
|
|
73
|
+
* leaves it drawing the first, silently.
|
|
84
74
|
*/
|
|
85
75
|
willUpdate(changed) {
|
|
86
76
|
super.willUpdate(changed);
|
|
@@ -112,14 +102,11 @@ export const MixinChartSource = (Base) => {
|
|
|
112
102
|
* what the table says, which is `$128k` and not `128000`, and often wants
|
|
113
103
|
* the column beside it that nothing plotted at all.
|
|
114
104
|
*
|
|
115
|
-
* **Not `rows
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
* where a slot counter called `rows` would have shared one field with a
|
|
121
|
-
* consumer's data property. Name the member for what it holds rather than
|
|
122
|
-
* for the shortest word available.
|
|
105
|
+
* **Not `rows`.** It is the source table's rows, and `rows` on a chart is a
|
|
106
|
+
* name a chart wants for itself: `helix-heatmap` takes `rows="7"` to mean a
|
|
107
|
+
* calendar week, and declaring that against a base class whose `rows` is a
|
|
108
|
+
* `Row[]` getter is a type error at best. Name the member for what it holds
|
|
109
|
+
* rather than for the shortest word available.
|
|
123
110
|
*/
|
|
124
111
|
get sourceRows() {
|
|
125
112
|
const element = this.source.element;
|
|
@@ -32,9 +32,7 @@ export declare class CollectionElement {
|
|
|
32
32
|
* **Empty and loading are different answers and a reader can tell them apart.**
|
|
33
33
|
* "No results" under a spinner is a lie for as long as the request is in
|
|
34
34
|
* flight, and a blank box is not an answer at all: a reader cannot know whether
|
|
35
|
-
* a list is empty, still arriving, or broken.
|
|
36
|
-
* and none of them said either thing, so every consumer wrote their own and
|
|
37
|
-
* wrote it differently.
|
|
35
|
+
* a list is empty, still arriving, or broken.
|
|
38
36
|
*
|
|
39
37
|
* **`aria-busy` on the collection, not on the message.** A reader with a screen
|
|
40
38
|
* reader is told the region is changing and then told once, politely, what it
|
|
@@ -46,10 +44,6 @@ export declare class CollectionElement {
|
|
|
46
44
|
* which question it is answering, and this is the point in a component's life
|
|
47
45
|
* when a consumer is most likely to be looking at stale content.
|
|
48
46
|
*
|
|
49
|
-
* Listbox had `empty-text` and nothing else, and Combobox forwarded it. Both
|
|
50
|
-
* keep the name, so nothing a consumer wrote has moved.
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
47
|
* **`empty` and `loading` are documented on each of the five families that
|
|
54
48
|
* apply this, rather than here.** See `MixinField` for why a class-level tag on
|
|
55
49
|
* a mixin reaches no manifest.
|