@fusion.dev/helix-core 0.0.0-dev → 0.0.3
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
package/custom-elements.json
CHANGED
|
@@ -46,6 +46,15 @@
|
|
|
46
46
|
"default": "new Set<string>()",
|
|
47
47
|
"description": "Which state attributes this controller wrote, so only those are removed."
|
|
48
48
|
},
|
|
49
|
+
{
|
|
50
|
+
"kind": "field",
|
|
51
|
+
"name": "recorded",
|
|
52
|
+
"type": {
|
|
53
|
+
"text": "HTMLElement | undefined"
|
|
54
|
+
},
|
|
55
|
+
"privacy": "private",
|
|
56
|
+
"description": "The control the record above is about, so a replacement resets it."
|
|
57
|
+
},
|
|
49
58
|
{
|
|
50
59
|
"kind": "method",
|
|
51
60
|
"name": "forward",
|
|
@@ -149,7 +158,7 @@
|
|
|
149
158
|
"text": "'block' | 'inline' | 'none'"
|
|
150
159
|
},
|
|
151
160
|
"default": "'inline'",
|
|
152
|
-
"description": "Which axis the readings are laid out along.\n\n**An axis and not a boolean, because two of the four charts do not use x.**\
|
|
161
|
+
"description": "Which axis the readings are laid out along.\n\n**An axis and not a boolean, because two of the four charts do not use x.**\nA horizontal bar chart runs its categories *down* the box, so resolving\nevery reading from the pointer's x leaves a move from the first row to the\nlast never changing the answer: measured on four rows, all four reported\nthe third, which is the slot the middle of the box falls in. It looks like\na tooltip that will not follow and is a tooltip reading the wrong axis.\n\n`none` is the ring. Its slices are real elements at every angle, so the\nreading under the pointer is the one the pointer is over, and arithmetic on\neither axis would answer with whichever slice shared a coordinate: at three\no'clock and at nine o'clock, x alone gives the same slice for opposite\nsides. The slices call `set` and this only holds the answer."
|
|
153
162
|
},
|
|
154
163
|
{
|
|
155
164
|
"kind": "method",
|
|
@@ -283,7 +292,7 @@
|
|
|
283
292
|
},
|
|
284
293
|
{
|
|
285
294
|
"kind": "class",
|
|
286
|
-
"description": "Lets a control elsewhere on the page operate this one, declaratively.\n\n```html\n<helix-button commandfor=\"confirm\" command=\"--show\">Delete…</helix-button>\n<helix-dialog id=\"confirm\">…</helix-dialog>\n```\n\n**The platform's own invoker, not a convention of ours.** `commandfor` and\n`command` are attributes the browser understands: it resolves the id, wires\nthe two together, and dispatches a `command` event at the target when the\ntrigger is activated. That is a real event with a real source, so it works\nfor a click, for Enter, for Space, and for anything else the platform decides\ncounts as activation later.\n\
|
|
295
|
+
"description": "Lets a control elsewhere on the page operate this one, declaratively.\n\n```html\n<helix-button commandfor=\"confirm\" command=\"--show\">Delete…</helix-button>\n<helix-dialog id=\"confirm\">…</helix-dialog>\n```\n\n**The platform's own invoker, not a convention of ours.** `commandfor` and\n`command` are attributes the browser understands: it resolves the id, wires\nthe two together, and dispatches a `command` event at the target when the\ntrigger is activated. That is a real event with a real source, so it works\nfor a click, for Enter, for Space, and for anything else the platform decides\ncounts as activation later.\n\nA `data-` recipe of our own would mean a delegated document listener a\nconsumer cannot see, an id lookup and activation semantics we would write\nourselves, and a convention that is ours to document and theirs to learn.\n\n**Only custom commands reach a custom element.** The built-in ones\n(`show-modal`, `close`, `toggle-popover`) are defined against native elements\nand the browser applies them itself; pointed at a custom element they do\nnothing. So the names here start with `--`, which is the platform's marker\nfor \"the target decides what this means\", and the target deciding is exactly\nwhat this is.\n\nUnrecognized commands are left alone rather than swallowed, so a host that\nanswers `--show` does not quietly absorb a `--print` meant for something\nelse.",
|
|
287
296
|
"name": "CommandController",
|
|
288
297
|
"members": [
|
|
289
298
|
{
|
|
@@ -367,7 +376,7 @@
|
|
|
367
376
|
"declarations": [
|
|
368
377
|
{
|
|
369
378
|
"kind": "class",
|
|
370
|
-
"description": "Puts text on the clipboard and holds a confirmation for a moment.\n\nA controller rather than a component, because copying is a behavior and not a\nshape. Color's chip is a swatch that copies, and a copy button is a button\nthat copies, and those two have nothing in common to look at: what they share\nis the write, the confirmation that follows it, the timer that ends it and the\nevent that announces it. Written twice, the second one would get the failure\ncase wrong.\n\n**There are two routes and both are tried**, because the modern one is gated\nin more places than it looks
|
|
379
|
+
"description": "Puts text on the clipboard and holds a confirmation for a moment.\n\nA controller rather than a component, because copying is a behavior and not a\nshape. Color's chip is a swatch that copies, and a copy button is a button\nthat copies, and those two have nothing in common to look at: what they share\nis the write, the confirmation that follows it, the timer that ends it and the\nevent that announces it. Written twice, the second one would get the failure\ncase wrong.\n\n**There are two routes and both are tried**, because the modern one is gated\nin more places than it looks and a control that does nothing is\nindistinguishable from a broken one. See `write` above.\n\n**Where neither route is allowed, the failure is silence.** The confirmation\ndoes not appear, which is the honest report: a message about a clipboard is\nworse than a chip that did not flash, and there is nothing a reader could do\nabout a permission policy anyway.\n\n**The event is announced after the write, not before it.** It is not\ncancelable for the same reason: by the time anything could be said, the text\nis already on the clipboard, and an event that cannot prevent what it\ndescribes should not pretend otherwise.\n\nThe timer is cleared when the host leaves the document, or a component removed\nmid-confirmation asks a detached element to re-render.",
|
|
371
380
|
"name": "CopyController",
|
|
372
381
|
"members": [
|
|
373
382
|
{
|
|
@@ -445,7 +454,7 @@
|
|
|
445
454
|
"declarations": [
|
|
446
455
|
{
|
|
447
456
|
"kind": "class",
|
|
448
|
-
"description": "Pushes a group's `disabled` onto its members, on every update, unasked.\n\n**The cascade itself is `inheritDisabled`, and this is what makes it\nautomatic.**
|
|
457
|
+
"description": "Pushes a group's `disabled` onto its members, on every update, unasked.\n\n**The cascade itself is `inheritDisabled`, and this is what makes it\nautomatic.** Called by hand it runs only when whichever method holds the call\nruns, so a group whose items changed by some other path leaves them holding\nthe last answer, and a group that forgets the call gets no cascade at all\nwith nothing to say so: the property exists, the attribute reflects, and the\nmembers simply ignore it. That is invisible in review and shows up only when\nsomeone disables a set.\n\nIt adds no API. A group already has `disabled`, from `HelixFormElement` or\nfrom the consumer; nothing here introduces a property or a method for anyone\nto call. By this repo's own rule that makes it a controller and not a mixin:\nit reacts to a lifecycle and nothing else.\n\nSo a group states its members once, at construction, and never thinks about\nit again:\n\n new DisabledCascadeController(this, { items: () => this.items })\n\n**Runs after every render, and on every `slotchange`.** The second half is\nnot an extra: a member arriving in the light DOM changes no property, so Lit\nschedules nothing, and a render-only cascade leaves a member slotted into an\nalready-disabled group enabled. Measured before it was added, on a radio\ngroup holding two disabled members with a third inserted: `110`, and the\nthird was live in a set nobody could use.\n\nThe listener is on the render root rather than on the host, because\n`slotchange` bubbles but is not composed: it reaches the shadow root that\nowns the slot and stops there. On the host it would never fire at all.\n\nAfter render rather than before, because the items are read from the DOM and\na newly slotted member is not there until the render that assigns it.\n\nIdempotent, so running on every update costs a comparison per member and\nnothing else: `inheritDisabled` writes only where the answer changed and\nremembers what each member said for itself, which is what lets a group be\nre-enabled without freeing a member that was disabled on its own.",
|
|
449
458
|
"name": "DisabledCascadeController",
|
|
450
459
|
"members": [
|
|
451
460
|
{
|
|
@@ -522,7 +531,7 @@
|
|
|
522
531
|
"declarations": [
|
|
523
532
|
{
|
|
524
533
|
"kind": "class",
|
|
525
|
-
"description": "Closes an overlay on Escape or on a pointer press outside it.\n\nBoth, because they are different intentions with the same meaning: Escape is\nthe keyboard's way out and clicking away is the pointer's, and an overlay\nthat
|
|
534
|
+
"description": "Closes an overlay on Escape or on a pointer press outside it.\n\nBoth, because they are different intentions with the same meaning: Escape is\nthe keyboard's way out and clicking away is the pointer's, and an overlay\nthat honors only one is one half its readers cannot dismiss.\n\nThe outside press is watched on `pointerdown` rather than `click`, so a press\nthat starts outside and drags across the overlay still counts as leaving\nrather than as interacting.\n\nA press inside a frame is the third case, and it needs its own signal. The\nframe swallows the event, so the document that owns the overlay never sees a\n`pointerdown` at all.\n\nWhere the frame is same-origin there is a document to listen to, and this\nlistens to it: the same handler, on every reachable frame document, so a\npress in there arrives as a press whose path holds nothing of the overlay,\nwhich is what it is.\n\n**The focus signal alone was not enough, and a browser difference is why.**\nA press in a frame moves focus into it in Chromium, so the window blurs and a\nframe is what took focus. WebKit does neither: focus stays on the menu item\nthe reader pressed to open the overlay, the window never blurs, and every\nobservable thing about that tap says nothing happened. Measured on the\nsandbox, whose preview is a frame filling half the tool, the settings menu\ncould not be dismissed by pressing the component it configures.\n\nBoth signals are kept, because they answer different frames. The listener\nonly reaches same-origin ones; the blur only fires where the browser moves\nfocus. A cross-origin frame in Chromium has the second and not the first.",
|
|
526
535
|
"name": "DismissController",
|
|
527
536
|
"members": [
|
|
528
537
|
{
|
|
@@ -583,6 +592,28 @@
|
|
|
583
592
|
"privacy": "private",
|
|
584
593
|
"readonly": true
|
|
585
594
|
},
|
|
595
|
+
{
|
|
596
|
+
"kind": "method",
|
|
597
|
+
"name": "frameDocuments",
|
|
598
|
+
"privacy": "private",
|
|
599
|
+
"static": true,
|
|
600
|
+
"return": {
|
|
601
|
+
"type": {
|
|
602
|
+
"text": "Document[]"
|
|
603
|
+
}
|
|
604
|
+
},
|
|
605
|
+
"description": "Every frame document on the page this one is allowed to read.\n\nThrough the shadow roots as well, because a component that renders a frame\nrenders it inside itself: the sandbox's preview is one, and\n`document.querySelectorAll` cannot see it.\n\nA cross-origin frame throws on `contentDocument` rather than returning\nnull in some browsers, so the read is guarded and the frame is simply\nskipped. Nothing is lost by skipping it that was not already lost: there is\nno listener to add to a document this one may not touch."
|
|
606
|
+
},
|
|
607
|
+
{
|
|
608
|
+
"kind": "field",
|
|
609
|
+
"name": "frames",
|
|
610
|
+
"type": {
|
|
611
|
+
"text": "Document[]"
|
|
612
|
+
},
|
|
613
|
+
"privacy": "private",
|
|
614
|
+
"default": "[]",
|
|
615
|
+
"description": "The frame documents being listened to, held so the same ones are released.\n\nGathered when the overlay opens rather than watched for: an overlay is open\nfor as long as a reader is deciding something, and a frame that arrives\ninside that window is a page rebuilding itself under a menu, which is not a\ncase worth a `MutationObserver` on every open surface. Held rather than\nre-collected on the way out, because a frame removed while the overlay was\nopen would otherwise be missed and one navigated elsewhere would be a\ndifferent document."
|
|
616
|
+
},
|
|
586
617
|
{
|
|
587
618
|
"kind": "method",
|
|
588
619
|
"name": "activate",
|
|
@@ -633,7 +664,7 @@
|
|
|
633
664
|
"declarations": [
|
|
634
665
|
{
|
|
635
666
|
"kind": "class",
|
|
636
|
-
"description": "One page of a nested set showing at a time, with a way back.\n\nA drill-down replaces the panel rather than opening a second one beside it.\nThat is the right shape wherever there is no room for two: on a phone there\nis no second column, and on a touch screen there is no hover to open one\nwith. What a reader gets instead is one panel, a title saying where they are,\nand a way back.\n\n**
|
|
667
|
+
"description": "One page of a nested set showing at a time, with a way back.\n\nA drill-down replaces the panel rather than opening a second one beside it.\nThat is the right shape wherever there is no room for two: on a phone there\nis no second column, and on a touch screen there is no hover to open one\nwith. What a reader gets instead is one panel, a title saying where they are,\nand a way back.\n\n**None of this is about menus.** A settings panel, a filter stack or a\nnavigation tree gets the same behavior without being a menu that is\npretending.\n\n**The tree is the state.** A row's page is its own children, assigned to a\nslot, so the controller holds one reference, the row currently drilled into,\nand derives everything else from the DOM. The alternative, an id per page and\na map beside it, is a second copy of the structure that a consumer can put\nout of step with the first.\n\n**A stack, not a pointer.** `back()` returns to the page above rather than to\nthe root, because a reader three levels down pressed one control and expects\none level. The stack is rebuilt from the DOM by walking up from the current\nrow, so it cannot disagree with the tree: a page removed while it was showing\ntakes its ancestors with it, and `atRoot` becomes true rather than the\ncontroller holding a reference to something detached.\n\nNothing here decides what a row *is*, what it renders, or what happens when\none is chosen. It answers where the reader is and what is on this page.",
|
|
637
668
|
"name": "DrilldownController",
|
|
638
669
|
"members": [
|
|
639
670
|
{
|
|
@@ -827,7 +858,7 @@
|
|
|
827
858
|
"declarations": [
|
|
828
859
|
{
|
|
829
860
|
"kind": "class",
|
|
830
|
-
"description": "Places one element against another, and keeps it there.\n\nPositioning is `@floating-ui/dom` rather than arithmetic written here. Two\nthings in particular are why. A `position: fixed` element inside an ancestor\ncarrying `transform`, `filter`, `will-change`, or `contain` is positioned\nagainst that ancestor and not the viewport, so viewport coordinates land it\nsomewhere else entirely. And an overlay has to clear its nearest *clipping*\nancestor, not just the window, or it is placed correctly inside a scrolling\npanel and clipped out of sight by it. Both are ordinary here, and both are a\nlong tail of browser behavior rather than a formula.\n\n`autoUpdate` keeps the position through scrolling on any ancestor, resizes of\neither element, and layout shifts.\n\nThe side the element actually landed on is written back as `data-placement`,\nso a styled tier can animate from it rather than from the side that was\nasked for.\n\n**The custom properties are declared here because this is what writes them.**\nEach carries a measurement taken against the viewport that no stylesheet can\ntake for itself, and `core` ships no CSS, so there is no reader inside this\npackage and none of them is private. `
|
|
861
|
+
"description": "Places one element against another, and keeps it there.\n\nPositioning is `@floating-ui/dom` rather than arithmetic written here. Two\nthings in particular are why. A `position: fixed` element inside an ancestor\ncarrying `transform`, `filter`, `will-change`, or `contain` is positioned\nagainst that ancestor and not the viewport, so viewport coordinates land it\nsomewhere else entirely. And an overlay has to clear its nearest *clipping*\nancestor, not just the window, or it is placed correctly inside a scrolling\npanel and clipped out of sight by it. Both are ordinary here, and both are a\nlong tail of browser behavior rather than a formula.\n\n`autoUpdate` keeps the position through scrolling on any ancestor, resizes of\neither element, and layout shifts.\n\nThe side the element actually landed on is written back as `data-placement`,\nso a styled tier can animate from it rather than from the side that was\nasked for.\n\n**The custom properties are declared here because this is what writes them.**\nEach carries a measurement taken against the viewport that no stylesheet can\ntake for itself, and `core` ships no CSS, so there is no reader inside this\npackage and none of them is private. the `hooks` rule pairs a documented\nhook with a rule that reads one, in both directions.",
|
|
831
862
|
"name": "FloatingController",
|
|
832
863
|
"cssProperties": [
|
|
833
864
|
{
|
|
@@ -874,7 +905,7 @@
|
|
|
874
905
|
},
|
|
875
906
|
"privacy": "private",
|
|
876
907
|
"default": "0",
|
|
877
|
-
"description": "Which run of placements the results coming back belong to.\n\n`computePosition` is async, so a measurement started before `stop()` still\nresolves after it and
|
|
908
|
+
"description": "Which run of placements the results coming back belong to.\n\n`computePosition` is async, so a measurement started before `stop()` still\nresolves after it and would write its result onto a surface that had just\nbeen taken down: the inline `position` and `translate` back on, and with\nthem `data-placed`, which is the attribute five families gate visibility\non. Opening and closing inside one task is all it takes, since the write\nlands a microtask later.\n\nA counter rather than an `AbortController`, because there is nothing to\nabort: the work is already done by the time the answer arrives and the only\nquestion is whether anybody still wants it."
|
|
878
909
|
},
|
|
879
910
|
{
|
|
880
911
|
"kind": "field",
|
|
@@ -1037,7 +1068,7 @@
|
|
|
1037
1068
|
"declarations": [
|
|
1038
1069
|
{
|
|
1039
1070
|
"kind": "class",
|
|
1040
|
-
"description": "Measures the marked child and writes the geometry onto a traveling mark.\n\
|
|
1071
|
+
"description": "Measures the marked child and writes the geometry onto a traveling mark.\n\nServes `Navigation`, `Tabs`, `Toggle.Group` and `Outline`. The two things\nhand-written copies of this get wrong:\n\n**The inline axis is signed.** In a right-to-left document the distance is\nmeasured from the surface's right edge and applied as a negative translation,\nbecause the mark travels from the inline start and the inline start is on the\nright. Measuring from the physical left and applying an unsigned offset from\nthe inline-start edge sends the mark the wrong way in RTL.\n\n**The border has to come off both axes.** `getBoundingClientRect` gives the\nborder box and the containing block is the padding box, so a surface with a\nborder of its own puts the mark one border-width out. `clientLeft` and\n`clientTop` are the border widths, already resolved, which is why they are\nused here rather than parsing `borderLeftWidth`.\n\n**Nothing is written until there is something to measure.** A zero-width box\nis a component whose children have not upgraded yet, and writing zeroes would\npark the mark at the origin and leave it there. The `data-placed` attribute is\nwhat a stylesheet waits for, so a mark fades in where it belongs rather than\nsliding from the corner on first paint.\n\nThe four custom properties are the contract. What a component does with them\nis its own business, which is how one controller serves a bar under a tab, a\npill filling it, and a rule down the side of a contents page.\n\n**Declared here because this is what writes them.** `core` ships no CSS, so\nevery reader is outside this package and none of these is private.\nthe `hooks` rule pairs a documented hook with a rule that reads one, in both\ndirections.",
|
|
1041
1072
|
"name": "IndicatorController",
|
|
1042
1073
|
"cssProperties": [
|
|
1043
1074
|
{
|
|
@@ -1139,7 +1170,7 @@
|
|
|
1139
1170
|
"text": "{ on: HTMLElement; settle: (event?: TransitionEvent) => void } | undefined"
|
|
1140
1171
|
},
|
|
1141
1172
|
"privacy": "private",
|
|
1142
|
-
"description": "The listener currently waiting, so the next move can take it off first.\n\n**Without this, a move inside a second orphans a listener.**
|
|
1173
|
+
"description": "The listener currently waiting, so the next move can take it off first.\n\n**Without this, a move inside a second orphans a listener.** Clearing the\ntimer is not enough on its own: the `transitionend` that would remove the\nlistener never arrives under reduced motion, where there is no transition\nto end, so a reader changing tabs quickly, or any reader at all with motion\nreduced, leaves one dead listener per selection on an element that lives as\nlong as the page."
|
|
1143
1174
|
},
|
|
1144
1175
|
{
|
|
1145
1176
|
"kind": "method",
|
|
@@ -1182,7 +1213,7 @@
|
|
|
1182
1213
|
"declarations": [
|
|
1183
1214
|
{
|
|
1184
1215
|
"kind": "class",
|
|
1185
|
-
"description": "Moves through a set of items with the arrow keys, and chooses as it goes.\n\n**Moving and choosing are one act here, not two.** That is the radio group\npattern and it is the difference from a listbox: moving focus without\nchoosing leaves a keyboard reader sitting on an item they have not selected,\nwith nothing on screen saying which of the two is true. A pointer user\nchooses by arriving, so a keyboard user does too.\n\n**Both axes, always.** A vertical set still answers left and right, and a\nhorizontal one still answers up and down. Binding only the axis the items\nhappen to be laid out on means a reader who guesses wrong gets nothing, and\n`orientation` is presentation: the same set of choices reads the same way\nwhichever direction it runs.\n\nDisabled items are skipped rather than stopped at, so a set with a gap in it\nstill moves in one press.\n\
|
|
1216
|
+
"description": "Moves through a set of items with the arrow keys, and chooses as it goes.\n\n**Moving and choosing are one act here, not two.** That is the radio group\npattern and it is the difference from a listbox: moving focus without\nchoosing leaves a keyboard reader sitting on an item they have not selected,\nwith nothing on screen saying which of the two is true. A pointer user\nchooses by arriving, so a keyboard user does too.\n\n**Both axes, always.** A vertical set still answers left and right, and a\nhorizontal one still answers up and down. Binding only the axis the items\nhappen to be laid out on means a reader who guesses wrong gets nothing, and\n`orientation` is presentation: the same set of choices reads the same way\nwhichever direction it runs.\n\nDisabled items are skipped rather than stopped at, so a set with a gap in it\nstill moves in one press.\n\nA set that starts from focus rather than from the selection, or that moves\nwithout choosing, says so through `origin` and `selects`. Neither is a reason\nto keep a hand-written copy, and neither exempts a set from both axes.",
|
|
1186
1217
|
"name": "KeyboardNavigationController",
|
|
1187
1218
|
"members": [
|
|
1188
1219
|
{
|
|
@@ -1290,7 +1321,7 @@
|
|
|
1290
1321
|
"declarations": [
|
|
1291
1322
|
{
|
|
1292
1323
|
"kind": "class",
|
|
1293
|
-
"description": "A surface that floats against something, in the top layer, until dismissed.\n\
|
|
1324
|
+
"description": "A surface that floats against something, in the top layer, until dismissed.\n\nBundles the three things that always travel together: the popover API, a\n`FloatingController` and a `DismissController`.\n\n**The top layer is the whole point.** A floating panel has to escape every\nclipping ancestor between it and the page, and `position: fixed` does not do\nthat: it is clipped by `overflow` on any ancestor and re-anchored entirely by\nan ancestor carrying `transform`, `filter` or `contain`. The popover API\nlifts the element out of the tree's paint order for real, and it is the only\nthing that does.\n\n`manual` rather than `auto`, because the host owns dismissal. `auto`\npopovers light-dismiss themselves and close each other, which is close to\nwhat is wanted and not the same: a select that closed itself before its own\nchange event landed, or a submenu that closed its parent, are both things the\nplatform would do here and neither is right.\n\n**The order matters on the way up.** `showPopover` first, then position:\nmeasuring an element that is still `display: none` gives zeroes, so a surface\npositioned before it is shown lands at the origin and slides into place on\nthe next frame. On the way down it is the reverse, and stopping the observer\nbefore hiding avoids a final measurement of an element on its way out.\n\nWhat this does not own is *when*. Opening is the host's, because a menu opens\non click, a tooltip on hover and a select on either, and none of that is\nabout surfaces.",
|
|
1294
1325
|
"name": "PopoverController",
|
|
1295
1326
|
"members": [
|
|
1296
1327
|
{
|
|
@@ -1422,7 +1453,7 @@
|
|
|
1422
1453
|
"declarations": [
|
|
1423
1454
|
{
|
|
1424
1455
|
"kind": "class",
|
|
1425
|
-
"description": "Resolves the element a chart reads from, and follows it.\n\
|
|
1456
|
+
"description": "Resolves the element a chart reads from, and follows it.\n\nEvery chart that takes a `for` wants exactly this, and wants it to behave\nidentically, so it is a controller rather than a paragraph in each of them.\n\nA controller and not a pure function, by the test the rules set: it reacts to\nthe host's lifecycle. It has to start watching when the host connects, stop\nwhen it leaves, and re-resolve when `for` changes.\n\n**What it refuses is as much the point as what it accepts.** A `<table>` or\nanything built from grid roles, including this library's own `helix-table`,\nwhose roles live in `ElementInternals` and therefore write no attribute at\nall. Anything else resolves to null, so a `for` pointed at a paragraph draws\nnothing rather than something arbitrary.\n\nThe element is watched for `childList` and `characterData` alike, because\nrenaming a series edits a text node in place rather than replacing a cell,\nand nothing in a page has reason to know a chart is reading it.",
|
|
1426
1457
|
"name": "SourceController",
|
|
1427
1458
|
"members": [
|
|
1428
1459
|
{
|
|
@@ -1509,7 +1540,7 @@
|
|
|
1509
1540
|
"declarations": [
|
|
1510
1541
|
{
|
|
1511
1542
|
"kind": "class",
|
|
1512
|
-
"description": "Reads a design token as the sRGB triple a shader or a 2D canvas can take, and\ntells the host when the palette underneath it moves.\n\n**Two hops, and both are load-bearing.** A custom property's own value is the\nunevaluated function text, so `getComputedStyle` on a probe is the only way\nto see what it resolves to. And what it resolves to is not `rgb()`: the\npalette derives from an `oklch()` seed, and Chrome answers `lab(100 0 0)` for\nwhite. Parsing that with a regular expression for numbers reads the three\nchannels as 100, 0 and 0, which divided by 255 is a dark red.\n\
|
|
1543
|
+
"description": "Reads a design token as the sRGB triple a shader or a 2D canvas can take, and\ntells the host when the palette underneath it moves.\n\n**Two hops, and both are load-bearing.** A custom property's own value is the\nunevaluated function text, so `getComputedStyle` on a probe is the only way\nto see what it resolves to. And what it resolves to is not `rgb()`: the\npalette derives from an `oklch()` seed, and Chrome answers `lab(100 0 0)` for\nwhite. Parsing that with a regular expression for numbers reads the three\nchannels as 100, 0 and 0, which divided by 255 is a dark red.\n\nA screenshot cannot catch that: a warm cast on a saturated gradient is also\nwhat chroma subsampling produces, so the picture agrees with the bug.\n\nThe conversion is therefore the browser's own: fill a pixel and read it back.\nThat holds for `lab()`, `oklch()`, `color-mix()` and whatever a token is\nwritten in next, which is the property worth having in a design system whose\npalette is derived rather than listed.\n\n**A controller and not a mixin**, by this repository's own line: it adds no\nproperty or method a consumer sets. It reacts to lifecycle, holding a probe\nthat has to be created after the host connects and removed when it leaves,\nand it watches for the color mode changing so the host can repaint.\n\n**Client only, and that is the contract rather than a limitation.** There is\nno computed style on a server and no canvas to convert with, so `read`\nanswers the fallback there. Every caller is drawing into a canvas, which does\nnot exist on a server either.",
|
|
1513
1544
|
"name": "TokenColorController",
|
|
1514
1545
|
"members": [
|
|
1515
1546
|
{
|
|
@@ -1620,7 +1651,7 @@
|
|
|
1620
1651
|
"declarations": [
|
|
1621
1652
|
{
|
|
1622
1653
|
"kind": "class",
|
|
1623
|
-
"description": "Works out which slice of a long set is worth rendering.\n\n**A controller and not an element, which is the whole reason it is here.**\nTable, Listbox, Combobox and Tree each need windowing *inside* themselves,\nand an element would make each of them nest one in its own shadow root: a\nlistbox whose options are inside a `<helix-virtual-list>` is a listbox whose\noptions are no longer its children, so its own keyboard, its own selection\nand its own ARIA all have a stranger in the middle of them.\n\n**A windowed set still reports its true length, and each row its true\nposition.** This is the part virtualization usually gets wrong and the reason\nthe arithmetic lives somewhere shared. A reader on row 4,000 of 10,000 must\nhear \"4,000 of 10,000\", so `aria-setsize` is the count and `aria-posinset` is\nthe real index, never the position within the rendered slice. The window is a\nrendering decision and the set is a fact, and a component that lets the first\noverwrite the second has told a screen reader the list is twelve long.\n\n**The spacers are what make the scrollbar honest.** Rendering twelve rows in\na box that should scroll for ten thousand gives a thumb the size of the\ntrack, so the room the absent rows would have taken is left as padding before\nand after. A reader dragging that thumb is dragging against the real length.\n\n**What it does not do, and the reason is narrower than it first looks.** True\nvirtualization means never creating the rows that are not on screen, and that\nneeds the set as *data*. Two channels are shut: a consumer's items arrive as\nlight-DOM children, which exist by the time this could decide not to create\nthem, and an `items` property cannot survive React hydration, which skips\nevery property it would have to apply imperatively (see `bindReactHandler`,\nand the note in the rules that objects and functions have that bug and are\nnot fixed).\n\n**A third is open
|
|
1654
|
+
"description": "Works out which slice of a long set is worth rendering.\n\n**A controller and not an element, which is the whole reason it is here.**\nTable, Listbox, Combobox and Tree each need windowing *inside* themselves,\nand an element would make each of them nest one in its own shadow root: a\nlistbox whose options are inside a `<helix-virtual-list>` is a listbox whose\noptions are no longer its children, so its own keyboard, its own selection\nand its own ARIA all have a stranger in the middle of them.\n\n**A windowed set still reports its true length, and each row its true\nposition.** This is the part virtualization usually gets wrong and the reason\nthe arithmetic lives somewhere shared. A reader on row 4,000 of 10,000 must\nhear \"4,000 of 10,000\", so `aria-setsize` is the count and `aria-posinset` is\nthe real index, never the position within the rendered slice. The window is a\nrendering decision and the set is a fact, and a component that lets the first\noverwrite the second has told a screen reader the list is twelve long.\n\n**The spacers are what make the scrollbar honest.** Rendering twelve rows in\na box that should scroll for ten thousand gives a thumb the size of the\ntrack, so the room the absent rows would have taken is left as padding before\nand after. A reader dragging that thumb is dragging against the real length.\n\n**What it does not do, and the reason is narrower than it first looks.** True\nvirtualization means never creating the rows that are not on screen, and that\nneeds the set as *data*. Two channels are shut: a consumer's items arrive as\nlight-DOM children, which exist by the time this could decide not to create\nthem, and an `items` property cannot survive React hydration, which skips\nevery property it would have to apply imperatively (see `bindReactHandler`,\nand the note in the rules that objects and functions have that bug and are\nnot fixed).\n\n**A third channel is open.** Data as *text*\nin the markup, a `<script type=\"application/json\">` child or an attribute, is\nneither a property nor a node per row: React's hydration bug cannot touch text\nit renders as a child, a server emits it, and the node count is one. The\ncharts already read data out of the document this way, `for=\"<id>\"` at a real\n`<table>`, so the pattern is in the library rather than being invented for\nthis.\n\nSo the thing actually blocked is the *row template*. Turning an item into\nmarkup wants either a render function, which is a function property and dies\non the same bug, or a `<template>` with named holes, which survives because it\nis markup and which no component here asks anyone to write. That is a decision\nabout what this library is willing to look like, not a platform limit, and it\nis open at #71.\n\nSo what this buys is the expensive half rather than all of it: the rows\noutside the window are not laid out and not painted, which is where the time\ngoes in a long list, and the node count stays. That is worth having and it is\nnot worth calling something it is not. An element that windows children it\nwas handed is not a virtual list, whatever it is named.\n\n**One estimate, not per-row measurement.** Measuring every row to place it is\nhow a virtual list ends up reading the layout it is trying to avoid, and it\nis what makes them jump: a row taller than its estimate shifts everything\nafter it at the moment it renders. A fixed estimate is a straight line\nbetween scroll offset and index, which never disagrees with itself. Rows of\ngenuinely different heights are a different component and a harder one.",
|
|
1624
1655
|
"name": "VirtualizeController",
|
|
1625
1656
|
"members": [
|
|
1626
1657
|
{
|
|
@@ -1931,7 +1962,7 @@
|
|
|
1931
1962
|
},
|
|
1932
1963
|
{
|
|
1933
1964
|
"kind": "class",
|
|
1934
|
-
"description": "A stop asking the tour to move.\n\nComposed and bubbling, because a stop is slotted into the root and the root\nhas to hear it across that boundary.\n\n**A class rather than
|
|
1965
|
+
"description": "A stop asking the tour to move.\n\nComposed and bubbling, because a stop is slotted into the root and the root\nhas to hear it across that boundary.\n\n**A class rather than a hand-rolled `CustomEvent`.** A dispatch is matched as\n`new HelixSomethingEvent(`, so a raw `CustomEvent` is not held to being\ndeclared and nothing carries it into the manifest: consumers can hear it and\ncannot find it.",
|
|
1935
1966
|
"name": "HelixTourAskEvent",
|
|
1936
1967
|
"members": [
|
|
1937
1968
|
{
|
|
@@ -1953,7 +1984,7 @@
|
|
|
1953
1984
|
},
|
|
1954
1985
|
{
|
|
1955
1986
|
"kind": "class",
|
|
1956
|
-
"description": "The eyedropper opening, and closing again.\n\nTwo events rather than one carrying a flag, because what a consumer does with\nthem is not symmetrical: the surface holding the picker has to get out of the\nway for the sample and come back afterwards, and those are two moments with\ndifferent work in each.\n\n**A class rather than
|
|
1987
|
+
"description": "The eyedropper opening, and closing again.\n\nTwo events rather than one carrying a flag, because what a consumer does with\nthem is not symmetrical: the surface holding the picker has to get out of the\nway for the sample and come back afterwards, and those are two moments with\ndifferent work in each.\n\n**A class rather than a bare `Event`.** The check that holds an event to being\ndeclared reads `new Event(` as well as `new HelixSomethingEvent(`, so a\nhand-rolled one is public API a consumer can hear and cannot find.\n\nNo detail, because there is nothing to say beyond that it happened.",
|
|
1957
1988
|
"name": "HelixSampleStartEvent",
|
|
1958
1989
|
"members": [
|
|
1959
1990
|
{
|
|
@@ -2019,7 +2050,7 @@
|
|
|
2019
2050
|
},
|
|
2020
2051
|
{
|
|
2021
2052
|
"kind": "class",
|
|
2022
|
-
"description": "A set is about to make a different child current, and can be refused.\n\n**
|
|
2053
|
+
"description": "A set is about to make a different child current, and can be refused.\n\n**Not a generic `helix-change`.** `Tabs` moving to another tab, `Tree` marking\nanother row and `Steps` advancing are not a value changing, they are a set\nchoosing, and the platform's word for a committed value would say the wrong\nthing. `active` names which child is current, so `activate` is the verb, and\nunlike `change` the platform has no claim on it.\n\n**This fires before the state moves.** Inside a handler `currentTarget.active`\nstill holds the previous value, and `detail.value` is a proposal another\nlistener may refuse, so a consumer who only wants to know which child is\ncurrent listens for `helix-activate` instead. `helix-select` is not that\nnotification either: it fires when an item is *chosen*, not when `active` is\nassigned.\n\nThe shape is the one `MixinControllerOpen` already has, a cancelable request\nand a plain notification after the state has moved.",
|
|
2023
2054
|
"name": "HelixBeforeActivateEvent",
|
|
2024
2055
|
"members": [
|
|
2025
2056
|
{
|
|
@@ -2041,7 +2072,7 @@
|
|
|
2041
2072
|
},
|
|
2042
2073
|
{
|
|
2043
2074
|
"kind": "class",
|
|
2044
|
-
"description": "A set has made a different child current.\n\nThe notification half of `helix-before-activate`, dispatched after the state\nhas moved, so `currentTarget.active` is the new value and the detail is a fact\nrather than a proposal.\n\n**Not cancelable**, for the reason every notification here is not: the\ndecision was taken by the event before it, and a second refusable event for\none transition is two answers to one question.\n\n**Prefixed, and it has to be.** `activate` unprefixed is not in any\n`*EventMap` in the DOM library, checked rather than assumed, but the prefix is\nwhat stops an event dispatched inside a shadow root and retargeted to the host\nbeing mistaken for something the host's own contents sent.
|
|
2075
|
+
"description": "A set has made a different child current.\n\nThe notification half of `helix-before-activate`, dispatched after the state\nhas moved, so `currentTarget.active` is the new value and the detail is a fact\nrather than a proposal.\n\n**Not cancelable**, for the reason every notification here is not: the\ndecision was taken by the event before it, and a second refusable event for\none transition is two answers to one question.\n\n**Prefixed, and it has to be.** `activate` unprefixed is not in any\n`*EventMap` in the DOM library, checked rather than assumed, but the prefix is\nwhat stops an event dispatched inside a shadow root and retargeted to the host\nbeing mistaken for something the host's own contents sent.",
|
|
2045
2076
|
"name": "HelixActivateEvent",
|
|
2046
2077
|
"members": [
|
|
2047
2078
|
{
|
|
@@ -2107,7 +2138,7 @@
|
|
|
2107
2138
|
},
|
|
2108
2139
|
{
|
|
2109
2140
|
"kind": "class",
|
|
2110
|
-
"description": "The divider between a sandbox's panes is about to move, and can be refused.\n\nIts own verb rather than a `helix-before-resize` carrying which divider moved:\na sandbox has two, and they were told apart by a field on a detail every other\nrequest in this file also carries.
|
|
2141
|
+
"description": "The divider between a sandbox's panes is about to move, and can be refused.\n\nIts own verb rather than a `helix-before-resize` carrying which divider moved:\na sandbox has two, and they were told apart by a field on a detail every other\nrequest in this file also carries.",
|
|
2111
2142
|
"name": "HelixBeforeSplitEvent",
|
|
2112
2143
|
"members": [
|
|
2113
2144
|
{
|
|
@@ -2195,7 +2226,7 @@
|
|
|
2195
2226
|
},
|
|
2196
2227
|
{
|
|
2197
2228
|
"kind": "class",
|
|
2198
|
-
"description": "A value is about to change, and the change can be refused.\n\n**The request half of every value control.** It announces the value being\n*proposed*, before anything moves, so a listener calling `preventDefault()`\nrefuses it and the control stays where it was. That is how a consumer takes\none decision without declaring a mode, which is what 294 settled: the element\nalways owns and applies its state, and refusing is the way to take it over.\n\n**The notification is native and separate.** Once this has gone out and the\nvalue has moved, the control announces it again under the platform's own\nname, `input` while a reader is editing and `change` when they are done, so\n`onChange` in React and `onchange=` in HTML both reach it and\n`currentTarget.value` is correct by the time a handler reads it. This event\ncarries the detail because at the moment it fires the value is not on the\nelement yet.\n\n
|
|
2229
|
+
"description": "A value is about to change, and the change can be refused.\n\n**The request half of every value control.** It announces the value being\n*proposed*, before anything moves, so a listener calling `preventDefault()`\nrefuses it and the control stays where it was. That is how a consumer takes\none decision without declaring a mode, which is what 294 settled: the element\nalways owns and applies its state, and refusing is the way to take it over.\n\n**The notification is native and separate.** Once this has gone out and the\nvalue has moved, the control announces it again under the platform's own\nname, `input` while a reader is editing and `change` when they are done, so\n`onChange` in React and `onchange=` in HTML both reach it and\n`currentTarget.value` is correct by the time a handler reads it. This event\ncarries the detail because at the moment it fires the value is not on the\nelement yet.\n\n**`announcesInput` picks which native notification fires, not which name this\ncarries.** Granularity is the platform's own distinction, `input` against\n`change`; the request is always this one event.",
|
|
2199
2230
|
"name": "HelixBeforeChangeEvent",
|
|
2200
2231
|
"members": [
|
|
2201
2232
|
{
|
|
@@ -2217,7 +2248,7 @@
|
|
|
2217
2248
|
},
|
|
2218
2249
|
{
|
|
2219
2250
|
"kind": "class",
|
|
2220
|
-
"description": "A checked state is about to change, and the change can be refused.\n\n**Its own event rather than a `helix-before-change` carrying a boolean
|
|
2251
|
+
"description": "A checked state is about to change, and the change can be refused.\n\n**Its own event rather than a `helix-before-change` carrying a boolean.**\nThrough the value event the state arrives as `String(checked)`, so a consumer\nreceives the string `\"false\"`, which is truthy, and a test asserting the value\npasses on that bug. A control whose state is a boolean wants an event with a\ntyped boolean in it.\n\nThe notification is native, as it is for a value: the control relays `change`\nfrom the inner input and announces `input` beside it, so `onChange` reads\n`currentTarget.checked` and gets a boolean from the platform.\n\nIt also ends a collision: Checkbox Group listened for its boxes' change and\ndispatched its own under the same name from the same host, so it needed\n`stopImmediatePropagation` to keep a consumer from receiving one box's boolean\nalongside the whole set. Two names, two facts.",
|
|
2221
2252
|
"name": "HelixBeforeToggleEvent",
|
|
2222
2253
|
"members": [
|
|
2223
2254
|
{
|
|
@@ -2327,7 +2358,7 @@
|
|
|
2327
2358
|
},
|
|
2328
2359
|
{
|
|
2329
2360
|
"kind": "class",
|
|
2330
|
-
"description": "Fired when a header crosses the threshold between resting at the top of the\npage and floating over it.\n\n**
|
|
2361
|
+
"description": "Fired when a header crosses the threshold between resting at the top of the\npage and floating over it.\n\n**The threshold lives in a custom state, and is announced rather than\nreflected.** A `data-scrolled` on the host is an attribute nobody rendered: a\nserver sends the element without it and the element adds it on upgrade, so a\nframework hydrating the page finds markup that no longer matches what it sent.\nA custom state is deliberately not in the DOM and therefore not something a\nhydration pass can disagree with.\n\nThat closes the observability an attribute would accidentally provide. A\n`MutationObserver` can watch an attribute and there is no equivalent for\n`ElementInternals.states`, so a component holding a boolean nothing can read\nis a component with a private opinion its consumers demonstrably need: the\nbar's own backdrop is drawn by the page around it, and the page has to know\nwhen to light it.\n\nNot cancelable. It reports where the page is rather than asking permission to\nbe there, and refusing it would leave the state and the announcement\ndisagreeing.\n\nThe hysteresis stays inside the header, which is the point of announcing at\nall: a consumer listening to `scroll` itself would be a second opinion on\nwhen the page counts as scrolled, and the two would part company at the eight\npixels of travel this waits for.",
|
|
2331
2362
|
"name": "HelixScrolledEvent",
|
|
2332
2363
|
"members": [
|
|
2333
2364
|
{
|
|
@@ -2459,7 +2490,7 @@
|
|
|
2459
2490
|
},
|
|
2460
2491
|
{
|
|
2461
2492
|
"kind": "class",
|
|
2462
|
-
"description": "Fired when the reader asks for a different order.\n\nCancelable, and refusing it leaves the order alone, which is what makes a\nserver-side sort expressible: the consumer refuses the local reorder, fetches,\nand hands back a new set.
|
|
2493
|
+
"description": "Fired when the reader asks for a different order.\n\nCancelable, and refusing it leaves the order alone, which is what makes a\nserver-side sort expressible: the consumer refuses the local reorder, fetches,\nand hands back a new set. This is the element reporting that a heading was\nclicked, before it acts on it.\n\nNot `helix-change`: nothing about the data changed, only the order it is read\nin, and a consumer listening for changes to a value should not hear a sort.\nThat is the same distinction `helix-filter` is drawn on.",
|
|
2463
2494
|
"name": "HelixSortEvent",
|
|
2464
2495
|
"members": [
|
|
2465
2496
|
{
|
|
@@ -2839,7 +2870,7 @@
|
|
|
2839
2870
|
},
|
|
2840
2871
|
"static": true,
|
|
2841
2872
|
"default": "'helix-headless-'",
|
|
2842
|
-
"description": "The prefix this tier registers its elements under.\n\n**A component that renders another renders its own tier's version of it**,\nso `helix-headless-pagination-size` composes `helix-headless-select` and\n`helix-pagination-size` composes `helix-select`. One template says\n`${this.tag('select')}` and each tier answers with its own name.\n\
|
|
2873
|
+
"description": "The prefix this tier registers its elements under.\n\n**A component that renders another renders its own tier's version of it**,\nso `helix-headless-pagination-size` composes `helix-headless-select` and\n`helix-pagination-size` composes `helix-select`. One template says\n`${this.tag('select')}` and each tier answers with its own name.\n\n**The public tag may not be the composed one, in either tier.** Using it\ncosts three things: the name means two different things depending on what a\nconsumer imported, the headless tier composes an element it does not ship,\nand the composition cannot be tested there at all, because there is no\n`helix-select` on that tier to test it against.\n\n**A prefix rather than an override per composition**, which was the first\nplan and does not compile. An override re-renders the fragment from the\nsubclass, and the fragment reads members the base keeps private:\n`PaginationSize` alone would have had to widen `options`, `current` and\n`handleChange` to `protected` so a subclass could say the same thing again.\nSixteen families of that is a lot of encapsulation spent on saying one\nword differently."
|
|
2843
2874
|
},
|
|
2844
2875
|
{
|
|
2845
2876
|
"kind": "method",
|
|
@@ -2893,7 +2924,7 @@
|
|
|
2893
2924
|
}
|
|
2894
2925
|
}
|
|
2895
2926
|
],
|
|
2896
|
-
"description": "Records a boolean fact about this element as a custom state.\n\n**The host belongs to whoever rendered it, and a component's own\nbookkeeping may not be kept there.** An attribute written on the first\nupdate is markup a consumer's server never sent, so a React consumer\nhydrates a DOM that has gained attributes since and reports a mismatch it\nwill not patch up. A custom state is not in the DOM at all: it carries the\nfact to a stylesheet through `:state()` and leaves the markup alone, so the\nserver's output and the client's agree by construction.\n\n`SETTLED` carries the long version of that argument
|
|
2927
|
+
"description": "Records a boolean fact about this element as a custom state.\n\n**The host belongs to whoever rendered it, and a component's own\nbookkeeping may not be kept there.** An attribute written on the first\nupdate is markup a consumer's server never sent, so a React consumer\nhydrates a DOM that has gained attributes since and reports a mismatch it\nwill not patch up. A custom state is not in the DOM at all: it carries the\nfact to a stylesheet through `:state()` and leaves the markup alone, so the\nserver's output and the client's agree by construction.\n\n`SETTLED` carries the long version of that argument; `checked`, `open`,\n`invalid` and `has-label` are recorded the same way, each of them a state a\n`default-*` attribute resolves before React reaches the node.\n\n**Deferring the definitions is not a fix and could not be.** Importing them\nfrom an effect so the upgrades fall the other side of hydration works only\nwhile hydration is one pass: anything that splits it, a streamed segment or\na suspended boundary, puts an upgrade back inside the window. Timing cannot\nbe the guarantee when the fact is kept somewhere React reconciles.\n\nFeature-tested rather than assumed, the way `hostAria` tests element\nreferences. An engine without `CustomStateSet` records nothing and keeps\nwhatever the resting rule draws, which is the safe direction to fail.\n\n**Lit's server shim is no longer one of them**, and this said it was.\n`@lit-labs/ssr-dom-shim@1.6.0` sets `this.states = new Set()` in its\n`ElementInternals` constructor, so the guard passes on the server and a\ncustom state is recorded where nothing reads it, which is harmless. The\nengines the test is for are browsers: Safari below 17.4 and Firefox below\n126. There the write is a `TypeError`, so a component that bypasses this\nfails to render rather than rendering without whatever the state draws."
|
|
2897
2928
|
},
|
|
2898
2929
|
{
|
|
2899
2930
|
"kind": "field",
|
|
@@ -2902,7 +2933,7 @@
|
|
|
2902
2933
|
"text": "Promise<void>"
|
|
2903
2934
|
},
|
|
2904
2935
|
"readonly": true,
|
|
2905
|
-
"description": "Resolves a frame after the first update, when transitions are switched on.\n\n**Named `whenSettled` because `settled` was taken four times over.** Image\nand Splitter each have a private `settle`, and both color controls carry a\n`settled` of their own, all of them older than this and none of them about\ntransitions. A base class takes the name every subclass then cannot use, so\nit takes the one nobody wanted.\n\n**The state it reports cannot be watched, which is why this exists.** A\n`MutationObserver` could see `[data-settled]` arrive and there is no\nequivalent for `ElementInternals.states`: a custom state is deliberately not\nin the DOM, which is the whole reason it replaced the attribute. Anything\nthat used to wait on the attribute waits on this instead, and gets a better\nsignal for it, an awaited promise being what the callers wanted rather than\na mutation they had to interpret.\n\nSeparate from `updateComplete`, which resolves in the microtask checkpoint\nthe suppression is still active in. That is the distinction `readyToMove`\nin `@fusion.dev/helix-testing`
|
|
2936
|
+
"description": "Resolves a frame after the first update, when transitions are switched on.\n\n**Named `whenSettled` because `settled` was taken four times over.** Image\nand Splitter each have a private `settle`, and both color controls carry a\n`settled` of their own, all of them older than this and none of them about\ntransitions. A base class takes the name every subclass then cannot use, so\nit takes the one nobody wanted.\n\n**The state it reports cannot be watched, which is why this exists.** A\n`MutationObserver` could see `[data-settled]` arrive and there is no\nequivalent for `ElementInternals.states`: a custom state is deliberately not\nin the DOM, which is the whole reason it replaced the attribute. Anything\nthat used to wait on the attribute waits on this instead, and gets a better\nsignal for it, an awaited promise being what the callers wanted rather than\na mutation they had to interpret.\n\nSeparate from `updateComplete`, which resolves in the microtask checkpoint\nthe suppression is still active in. That is the distinction `readyToMove`\nin `@fusion.dev/helix-testing` is written around.\n\nIt never resolves where `requestAnimationFrame` never fires, which is a\nserver, a hidden tab, and happy-dom. Callers that must not hang race it\nagainst a timeout; `readyToMove` does exactly that.",
|
|
2906
2937
|
"default": "new Promise<void>((resolve) => { this.resolveSettled = resolve })"
|
|
2907
2938
|
},
|
|
2908
2939
|
{
|
|
@@ -3022,7 +3053,7 @@
|
|
|
3022
3053
|
"text": "boolean"
|
|
3023
3054
|
},
|
|
3024
3055
|
"default": "false",
|
|
3025
|
-
"description": "Whether the control is non-interactive.\n\nReflected, because the styled tier selects on it, and mirrored to\n`aria-disabled` rather than removing the element from the accessibility\ntree, so a screen reader can still announce that the control exists.\n\nThe mirror is
|
|
3056
|
+
"description": "Whether the control is non-interactive.\n\nReflected, because the styled tier selects on it, and mirrored to\n`aria-disabled` rather than removing the element from the accessibility\ntree, so a screen reader can still announce that the control exists.\n\nThe mirror itself is in `willUpdate` below, here rather than in each\ncontrol, because here is where `disabled` is.",
|
|
3026
3057
|
"attribute": "disabled",
|
|
3027
3058
|
"reflects": true
|
|
3028
3059
|
},
|
|
@@ -3034,7 +3065,7 @@
|
|
|
3034
3065
|
},
|
|
3035
3066
|
"privacy": "protected",
|
|
3036
3067
|
"default": "false",
|
|
3037
|
-
"description": "Whether an ancestor `<fieldset disabled>` has switched this control off.\n\nThe platform tells a form-associated element through `formDisabledCallback`\nand nothing
|
|
3068
|
+
"description": "Whether an ancestor `<fieldset disabled>` has switched this control off.\n\nThe platform tells a form-associated element through `formDisabledCallback`\nand nothing else does, so without this a control inside a disabled fieldset\nstays fully typeable and announces itself as enabled.\n\nThe submission half is already the platform's: measured, the fieldset's\ncontrols are absent from the form's entry list and the host matches\n`:disabled`, so the value never goes anywhere. What is missing without this\nis everything a reader can see or touch.\n\nState rather than the `disabled` property. Writing that would reflect an\nattribute the consumer's server markup does not have, which React reports\non hydration and does not patch up, and it would also silently overwrite\nwhat the consumer set."
|
|
3038
3069
|
},
|
|
3039
3070
|
{
|
|
3040
3071
|
"kind": "method",
|
|
@@ -3061,7 +3092,7 @@
|
|
|
3061
3092
|
"text": "string"
|
|
3062
3093
|
},
|
|
3063
3094
|
"default": "''",
|
|
3064
|
-
"description": "Name submitted with the form.\n\n**Reflected, and it is the exception to \"reflect only what CSS selects\non\".** The platform builds a form's entry list from the `name` *content\nattribute*, not from the property, so a control named through the property\nsubmitted under no name at all and was silently dropped. Measured: two\ninputs in one form, one named by attribute and one by property, and the\nform carried a single entry.\n\nSafe for a React consumer, which is what the rule is protecting: React\nrenders a custom element's props as attributes on the server, so the name\nis already in the markup being hydrated and reflecting it writes what is\nthere. It is only a change to the markup when a consumer assigns it\nimperatively later, and nothing is hydrating by then.\n\nHere rather than on each control
|
|
3095
|
+
"description": "Name submitted with the form.\n\n**Reflected, and it is the exception to \"reflect only what CSS selects\non\".** The platform builds a form's entry list from the `name` *content\nattribute*, not from the property, so a control named through the property\nsubmitted under no name at all and was silently dropped. Measured: two\ninputs in one form, one named by attribute and one by property, and the\nform carried a single entry.\n\nSafe for a React consumer, which is what the rule is protecting: React\nrenders a custom element's props as attributes on the server, so the name\nis already in the markup being hydrated and reflecting it writes what is\nthere. It is only a change to the markup when a consumer assigns it\nimperatively later, and nothing is hydrating by then.\n\nHere rather than on each control.",
|
|
3065
3096
|
"attribute": "name",
|
|
3066
3097
|
"reflects": true
|
|
3067
3098
|
},
|
|
@@ -3107,7 +3138,7 @@
|
|
|
3107
3138
|
},
|
|
3108
3139
|
"static": true,
|
|
3109
3140
|
"default": "'helix-headless-'",
|
|
3110
|
-
"description": "The prefix this tier registers its elements under.\n\n**A component that renders another renders its own tier's version of it**,\nso `helix-headless-pagination-size` composes `helix-headless-select` and\n`helix-pagination-size` composes `helix-select`. One template says\n`${this.tag('select')}` and each tier answers with its own name.\n\
|
|
3141
|
+
"description": "The prefix this tier registers its elements under.\n\n**A component that renders another renders its own tier's version of it**,\nso `helix-headless-pagination-size` composes `helix-headless-select` and\n`helix-pagination-size` composes `helix-select`. One template says\n`${this.tag('select')}` and each tier answers with its own name.\n\n**The public tag may not be the composed one, in either tier.** Using it\ncosts three things: the name means two different things depending on what a\nconsumer imported, the headless tier composes an element it does not ship,\nand the composition cannot be tested there at all, because there is no\n`helix-select` on that tier to test it against.\n\n**A prefix rather than an override per composition**, which was the first\nplan and does not compile. An override re-renders the fragment from the\nsubclass, and the fragment reads members the base keeps private:\n`PaginationSize` alone would have had to widen `options`, `current` and\n`handleChange` to `protected` so a subclass could say the same thing again.\nSixteen families of that is a lot of encapsulation spent on saying one\nword differently.",
|
|
3111
3142
|
"inheritedFrom": {
|
|
3112
3143
|
"name": "HelixElement",
|
|
3113
3144
|
"module": "src/helix-element/helix-element.ts"
|
|
@@ -3173,7 +3204,7 @@
|
|
|
3173
3204
|
}
|
|
3174
3205
|
}
|
|
3175
3206
|
],
|
|
3176
|
-
"description": "Records a boolean fact about this element as a custom state.\n\n**The host belongs to whoever rendered it, and a component's own\nbookkeeping may not be kept there.** An attribute written on the first\nupdate is markup a consumer's server never sent, so a React consumer\nhydrates a DOM that has gained attributes since and reports a mismatch it\nwill not patch up. A custom state is not in the DOM at all: it carries the\nfact to a stylesheet through `:state()` and leaves the markup alone, so the\nserver's output and the client's agree by construction.\n\n`SETTLED` carries the long version of that argument
|
|
3207
|
+
"description": "Records a boolean fact about this element as a custom state.\n\n**The host belongs to whoever rendered it, and a component's own\nbookkeeping may not be kept there.** An attribute written on the first\nupdate is markup a consumer's server never sent, so a React consumer\nhydrates a DOM that has gained attributes since and reports a mismatch it\nwill not patch up. A custom state is not in the DOM at all: it carries the\nfact to a stylesheet through `:state()` and leaves the markup alone, so the\nserver's output and the client's agree by construction.\n\n`SETTLED` carries the long version of that argument; `checked`, `open`,\n`invalid` and `has-label` are recorded the same way, each of them a state a\n`default-*` attribute resolves before React reaches the node.\n\n**Deferring the definitions is not a fix and could not be.** Importing them\nfrom an effect so the upgrades fall the other side of hydration works only\nwhile hydration is one pass: anything that splits it, a streamed segment or\na suspended boundary, puts an upgrade back inside the window. Timing cannot\nbe the guarantee when the fact is kept somewhere React reconciles.\n\nFeature-tested rather than assumed, the way `hostAria` tests element\nreferences. An engine without `CustomStateSet` records nothing and keeps\nwhatever the resting rule draws, which is the safe direction to fail.\n\n**Lit's server shim is no longer one of them**, and this said it was.\n`@lit-labs/ssr-dom-shim@1.6.0` sets `this.states = new Set()` in its\n`ElementInternals` constructor, so the guard passes on the server and a\ncustom state is recorded where nothing reads it, which is harmless. The\nengines the test is for are browsers: Safari below 17.4 and Firefox below\n126. There the write is a `TypeError`, so a component that bypasses this\nfails to render rather than rendering without whatever the state draws.",
|
|
3177
3208
|
"inheritedFrom": {
|
|
3178
3209
|
"name": "HelixElement",
|
|
3179
3210
|
"module": "src/helix-element/helix-element.ts"
|
|
@@ -3186,7 +3217,7 @@
|
|
|
3186
3217
|
"text": "Promise<void>"
|
|
3187
3218
|
},
|
|
3188
3219
|
"readonly": true,
|
|
3189
|
-
"description": "Resolves a frame after the first update, when transitions are switched on.\n\n**Named `whenSettled` because `settled` was taken four times over.** Image\nand Splitter each have a private `settle`, and both color controls carry a\n`settled` of their own, all of them older than this and none of them about\ntransitions. A base class takes the name every subclass then cannot use, so\nit takes the one nobody wanted.\n\n**The state it reports cannot be watched, which is why this exists.** A\n`MutationObserver` could see `[data-settled]` arrive and there is no\nequivalent for `ElementInternals.states`: a custom state is deliberately not\nin the DOM, which is the whole reason it replaced the attribute. Anything\nthat used to wait on the attribute waits on this instead, and gets a better\nsignal for it, an awaited promise being what the callers wanted rather than\na mutation they had to interpret.\n\nSeparate from `updateComplete`, which resolves in the microtask checkpoint\nthe suppression is still active in. That is the distinction `readyToMove`\nin `@fusion.dev/helix-testing`
|
|
3220
|
+
"description": "Resolves a frame after the first update, when transitions are switched on.\n\n**Named `whenSettled` because `settled` was taken four times over.** Image\nand Splitter each have a private `settle`, and both color controls carry a\n`settled` of their own, all of them older than this and none of them about\ntransitions. A base class takes the name every subclass then cannot use, so\nit takes the one nobody wanted.\n\n**The state it reports cannot be watched, which is why this exists.** A\n`MutationObserver` could see `[data-settled]` arrive and there is no\nequivalent for `ElementInternals.states`: a custom state is deliberately not\nin the DOM, which is the whole reason it replaced the attribute. Anything\nthat used to wait on the attribute waits on this instead, and gets a better\nsignal for it, an awaited promise being what the callers wanted rather than\na mutation they had to interpret.\n\nSeparate from `updateComplete`, which resolves in the microtask checkpoint\nthe suppression is still active in. That is the distinction `readyToMove`\nin `@fusion.dev/helix-testing` is written around.\n\nIt never resolves where `requestAnimationFrame` never fires, which is a\nserver, a hidden tab, and happy-dom. Callers that must not hang race it\nagainst a timeout; `readyToMove` does exactly that.",
|
|
3190
3221
|
"default": "new Promise<void>((resolve) => { this.resolveSettled = resolve })",
|
|
3191
3222
|
"inheritedFrom": {
|
|
3192
3223
|
"name": "HelixElement",
|
|
@@ -3280,7 +3311,7 @@
|
|
|
3280
3311
|
"text": "boolean"
|
|
3281
3312
|
},
|
|
3282
3313
|
"default": "false",
|
|
3283
|
-
"description": "Whether the control is non-interactive.\n\nReflected, because the styled tier selects on it, and mirrored to\n`aria-disabled` rather than removing the element from the accessibility\ntree, so a screen reader can still announce that the control exists.\n\nThe mirror is
|
|
3314
|
+
"description": "Whether the control is non-interactive.\n\nReflected, because the styled tier selects on it, and mirrored to\n`aria-disabled` rather than removing the element from the accessibility\ntree, so a screen reader can still announce that the control exists.\n\nThe mirror itself is in `willUpdate` below, here rather than in each\ncontrol, because here is where `disabled` is.",
|
|
3284
3315
|
"fieldName": "disabled"
|
|
3285
3316
|
},
|
|
3286
3317
|
{
|
|
@@ -3289,7 +3320,7 @@
|
|
|
3289
3320
|
"text": "string"
|
|
3290
3321
|
},
|
|
3291
3322
|
"default": "''",
|
|
3292
|
-
"description": "Name submitted with the form.\n\n**Reflected, and it is the exception to \"reflect only what CSS selects\non\".** The platform builds a form's entry list from the `name` *content\nattribute*, not from the property, so a control named through the property\nsubmitted under no name at all and was silently dropped. Measured: two\ninputs in one form, one named by attribute and one by property, and the\nform carried a single entry.\n\nSafe for a React consumer, which is what the rule is protecting: React\nrenders a custom element's props as attributes on the server, so the name\nis already in the markup being hydrated and reflecting it writes what is\nthere. It is only a change to the markup when a consumer assigns it\nimperatively later, and nothing is hydrating by then.\n\nHere rather than on each control
|
|
3323
|
+
"description": "Name submitted with the form.\n\n**Reflected, and it is the exception to \"reflect only what CSS selects\non\".** The platform builds a form's entry list from the `name` *content\nattribute*, not from the property, so a control named through the property\nsubmitted under no name at all and was silently dropped. Measured: two\ninputs in one form, one named by attribute and one by property, and the\nform carried a single entry.\n\nSafe for a React consumer, which is what the rule is protecting: React\nrenders a custom element's props as attributes on the server, so the name\nis already in the markup being hydrated and reflecting it writes what is\nthere. It is only a change to the markup when a consumer assigns it\nimperatively later, and nothing is hydrating by then.\n\nHere rather than on each control.",
|
|
3293
3324
|
"fieldName": "name"
|
|
3294
3325
|
}
|
|
3295
3326
|
],
|
|
@@ -4648,7 +4679,7 @@
|
|
|
4648
4679
|
"text": "number"
|
|
4649
4680
|
},
|
|
4650
4681
|
"default": "24",
|
|
4651
|
-
"description": "How many
|
|
4682
|
+
"description": "How many colors the series palette has, and so where it starts over.\n\nHere rather than in each chart, because a number two files have to agree on\nis a number that will stop agreeing: when the palette went from eight to\ntwenty-four, one of five copies was missed and drew every ninth series in the\nfirst color while the legend beside it named the ninth."
|
|
4652
4683
|
},
|
|
4653
4684
|
{
|
|
4654
4685
|
"kind": "function",
|
|
@@ -4670,7 +4701,7 @@
|
|
|
4670
4701
|
},
|
|
4671
4702
|
{
|
|
4672
4703
|
"kind": "class",
|
|
4673
|
-
"description": "The public surface `MixinChartSource` adds.\n\nDeclared separately because TypeScript cannot emit declarations for an\nanonymous class that has private or protected members (TS4094), and every\nclass extending `HelixElement` inherits protected `willUpdate` and `updated`.\nReturning the class directly was tried and refused for exactly that.\n\n**Every member here is documented twice, and that is the convention rather\nthan an oversight.** TypeScript reads this interface; the analyzer reads the\ninner class. Documented only here, `helix-convention-lint` failed the build\nwith six `Public member has no description` on three charts that had just\nbeen given a shared, fully documented property.\n\n**The protected members are declared here too, and have to be.** Cast to an\ninterface holding only `for` and `label`, `series` and `named` vanished from\nthe emitted `.d.ts` and every chart failed with `Property 'series' does not\nexist`. A mixin's interface is not its public API, it is everything a\nsubclass can see.\n\n**The series palette, and the one property every chart's mark reads.** A\nchart knows which series a bar belongs to and CSS cannot count it, so the\nheadless tier writes `--chart-series: var(--chart-series-3)` onto the\nrectangle and each styled sheet is one rule rather than twenty-four.\n\nDeclared here because this is where `seriesIndex` and `PALETTE` live, and\nbecause a hook repeated on four families is a hook four families have to keep\nagreeing about
|
|
4704
|
+
"description": "The public surface `MixinChartSource` adds.\n\nDeclared separately because TypeScript cannot emit declarations for an\nanonymous class that has private or protected members (TS4094), and every\nclass extending `HelixElement` inherits protected `willUpdate` and `updated`.\nReturning the class directly was tried and refused for exactly that.\n\n**Every member here is documented twice, and that is the convention rather\nthan an oversight.** TypeScript reads this interface; the analyzer reads the\ninner class. Documented only here, `helix-convention-lint` failed the build\nwith six `Public member has no description` on three charts that had just\nbeen given a shared, fully documented property.\n\n**The protected members are declared here too, and have to be.** Cast to an\ninterface holding only `for` and `label`, `series` and `named` vanished from\nthe emitted `.d.ts` and every chart failed with `Property 'series' does not\nexist`. A mixin's interface is not its public API, it is everything a\nsubclass can see.\n\n**The series palette, and the one property every chart's mark reads.** A\nchart knows which series a bar belongs to and CSS cannot count it, so the\nheadless tier writes `--chart-series: var(--chart-series-3)` onto the\nrectangle and each styled sheet is one rule rather than twenty-four.\n\nDeclared here because this is where `seriesIndex` and `PALETTE` live, and\nbecause a hook repeated on four families is a hook four families have to keep\nagreeing about.\n\nThe numbered twenty-four are the seam between the tiers: `chart/series.css`\npoints each at a semantic token, which is a decision and so belongs to the\nstyled tier, and a consumer on `headless` sets the same names to whatever\nthey like. The headless examples set them to a ramp of grays.",
|
|
4674
4705
|
"name": "MixinChartSourceInterface",
|
|
4675
4706
|
"cssProperties": [
|
|
4676
4707
|
{
|
|
@@ -4840,7 +4871,7 @@
|
|
|
4840
4871
|
},
|
|
4841
4872
|
{
|
|
4842
4873
|
"kind": "mixin",
|
|
4843
|
-
"description": "The half of a chart that is about finding its numbers rather than drawing.\n\
|
|
4874
|
+
"description": "The half of a chart that is about finding its numbers rather than drawing.\n\n**A mixin rather than a controller**, by the rule the tier notes give: it\nintroduces `for` and `label`, which a consumer writes. `SourceController` is\nthe other half and stays a controller, because resolving an id and watching\nfor changes is behavior nobody calls.\n\n**`Legend` deliberately does not take this.** It reads a table and has no\ndrawing to title, so `label` would be API it never uses, and a mixin applied\nfor four fifths of a fit is how a shared thing starts drifting.",
|
|
4844
4875
|
"name": "MixinChartSource",
|
|
4845
4876
|
"members": [
|
|
4846
4877
|
{
|
|
@@ -4902,7 +4933,7 @@
|
|
|
4902
4933
|
"type": {
|
|
4903
4934
|
"text": "Row[]"
|
|
4904
4935
|
},
|
|
4905
|
-
"description": "Every row of the table, with each cell's text as well as its number.\n\nThis is where a tooltip's content comes from, and it is deliberately not\n`series`. A chart draws numbers; a reader resting a pointer on one wants\nwhat the table says, which is `$128k` and not `128000`, and often wants\nthe column beside it that nothing plotted at all.\n\n**Not `rows
|
|
4936
|
+
"description": "Every row of the table, with each cell's text as well as its number.\n\nThis is where a tooltip's content comes from, and it is deliberately not\n`series`. A chart draws numbers; a reader resting a pointer on one wants\nwhat the table says, which is `$128k` and not `128000`, and often wants\nthe column beside it that nothing plotted at all.\n\n**Not `rows`.** It is the source table's rows, and `rows` on a chart is a\nname a chart wants for itself: `helix-heatmap` takes `rows=\"7\"` to mean a\ncalendar week, and declaring that against a base class whose `rows` is a\n`Row[]` getter is a type error at best. Name the member for what it holds\nrather than for the shortest word available.",
|
|
4906
4937
|
"readonly": true
|
|
4907
4938
|
},
|
|
4908
4939
|
{
|
|
@@ -5089,9 +5120,19 @@
|
|
|
5089
5120
|
},
|
|
5090
5121
|
{
|
|
5091
5122
|
"kind": "mixin",
|
|
5092
|
-
"description": "Grafts the two states a collection has that are not its content.\n\n**Empty and loading are different answers and a reader can tell them apart.**\n\"No results\" under a spinner is a lie for as long as the request is in\nflight, and a blank box is not an answer at all: a reader cannot know whether\na list is empty, still arriving, or broken
|
|
5123
|
+
"description": "Grafts the two states a collection has that are not its content.\n\n**Empty and loading are different answers and a reader can tell them apart.**\n\"No results\" under a spinner is a lie for as long as the request is in\nflight, and a blank box is not an answer at all: a reader cannot know whether\na list is empty, still arriving, or broken.\n\n**`aria-busy` on the collection, not on the message.** A reader with a screen\nreader is told the region is changing and then told once, politely, what it\nsettled on: a live region that fires on every intermediate state is a reader\nbeing read a progress bar.\n\n**The status replaces the rows rather than sitting above them.** A list that\nshows \"Loading\" over the last request's results is a list that lies about\nwhich question it is answering, and this is the point in a component's life\nwhen a consumer is most likely to be looking at stale content.\n\n**`empty` and `loading` are documented on each of the five families that\napply this, rather than here.** See `MixinField` for why a class-level tag on\na mixin reaches no manifest.",
|
|
5093
5124
|
"name": "MixinCollection",
|
|
5094
5125
|
"members": [
|
|
5126
|
+
{
|
|
5127
|
+
"kind": "field",
|
|
5128
|
+
"name": "emptyText",
|
|
5129
|
+
"type": {
|
|
5130
|
+
"text": "string"
|
|
5131
|
+
},
|
|
5132
|
+
"default": "'Nothing to show'",
|
|
5133
|
+
"description": "What is said where there are none, and none are coming.",
|
|
5134
|
+
"attribute": "empty-text"
|
|
5135
|
+
},
|
|
5095
5136
|
{
|
|
5096
5137
|
"kind": "field",
|
|
5097
5138
|
"name": "loading",
|
|
@@ -5113,16 +5154,6 @@
|
|
|
5113
5154
|
"description": "What is said while they are on their way.",
|
|
5114
5155
|
"attribute": "loading-text"
|
|
5115
5156
|
},
|
|
5116
|
-
{
|
|
5117
|
-
"kind": "field",
|
|
5118
|
-
"name": "emptyText",
|
|
5119
|
-
"type": {
|
|
5120
|
-
"text": "string"
|
|
5121
|
-
},
|
|
5122
|
-
"default": "'Nothing to show'",
|
|
5123
|
-
"description": "What is said where there are none, and none are coming.",
|
|
5124
|
-
"attribute": "empty-text"
|
|
5125
|
-
},
|
|
5126
5157
|
{
|
|
5127
5158
|
"kind": "field",
|
|
5128
5159
|
"name": "slotCounted",
|
|
@@ -5141,7 +5172,7 @@
|
|
|
5141
5172
|
},
|
|
5142
5173
|
"privacy": "private",
|
|
5143
5174
|
"default": "0",
|
|
5144
|
-
"description": "How many there were, the last time anyone looked.\n\n**
|
|
5175
|
+
"description": "How many there were, the last time anyone looked.\n\n**Never name this `rows`.** TypeScript's `private` is a compile-time\nclaim and the runtime field is whatever it is named, so a subclass\ndeclaring `@property() rows` for the data a consumer hands it would share\none field with this counter: the slot count would overwrite the\nconsumer's array on every `updated`, and `hasRows` would read the array's\nlength as a slot count. Nothing would throw. `helix-data-table` takes\nexactly that property."
|
|
5145
5176
|
},
|
|
5146
5177
|
{
|
|
5147
5178
|
"kind": "method",
|
|
@@ -5160,7 +5191,7 @@
|
|
|
5160
5191
|
}
|
|
5161
5192
|
}
|
|
5162
5193
|
],
|
|
5163
|
-
"description": "Counts what a rows slot was given.\n\nEmptiness is a fact about light DOM children and the server has none to\ncount. `slotchange` never fires there, so `counted` is false exactly when\nthe answer is unknown, and an unknown answer is not \"empty\": a list that\nshipped \"Nothing to show\" over markup about to have rows in it is the one\nthing an empty state must never do.
|
|
5194
|
+
"description": "Counts what a rows slot was given.\n\nEmptiness is a fact about light DOM children and the server has none to\ncount. `slotchange` never fires there, so `counted` is false exactly when\nthe answer is unknown, and an unknown answer is not \"empty\": a list that\nshipped \"Nothing to show\" over markup about to have rows in it is the one\nthing an empty state must never do."
|
|
5164
5195
|
},
|
|
5165
5196
|
{
|
|
5166
5197
|
"kind": "field",
|
|
@@ -5192,6 +5223,15 @@
|
|
|
5192
5223
|
}
|
|
5193
5224
|
],
|
|
5194
5225
|
"attributes": [
|
|
5226
|
+
{
|
|
5227
|
+
"name": "empty-text",
|
|
5228
|
+
"type": {
|
|
5229
|
+
"text": "string"
|
|
5230
|
+
},
|
|
5231
|
+
"default": "'Nothing to show'",
|
|
5232
|
+
"description": "What is said where there are none, and none are coming.",
|
|
5233
|
+
"fieldName": "emptyText"
|
|
5234
|
+
},
|
|
5195
5235
|
{
|
|
5196
5236
|
"name": "loading",
|
|
5197
5237
|
"type": {
|
|
@@ -5209,15 +5249,6 @@
|
|
|
5209
5249
|
"default": "'Loading'",
|
|
5210
5250
|
"description": "What is said while they are on their way.",
|
|
5211
5251
|
"fieldName": "loadingText"
|
|
5212
|
-
},
|
|
5213
|
-
{
|
|
5214
|
-
"name": "empty-text",
|
|
5215
|
-
"type": {
|
|
5216
|
-
"text": "string"
|
|
5217
|
-
},
|
|
5218
|
-
"default": "'Nothing to show'",
|
|
5219
|
-
"description": "What is said where there are none, and none are coming.",
|
|
5220
|
-
"fieldName": "emptyText"
|
|
5221
5252
|
}
|
|
5222
5253
|
],
|
|
5223
5254
|
"parameters": [
|
|
@@ -5264,7 +5295,7 @@
|
|
|
5264
5295
|
"type": {
|
|
5265
5296
|
"text": "string"
|
|
5266
5297
|
},
|
|
5267
|
-
"description": "Which item is current, by its `value`.\n\nReading gives the real one
|
|
5298
|
+
"description": "Which item is current, by its `value`.\n\nReading gives the real one. Writing always applies, and is a seed and a\ncorrection rather than a claim of ownership: a consumer who wants the\ndecision refuses the `helix-before-activate`."
|
|
5268
5299
|
},
|
|
5269
5300
|
{
|
|
5270
5301
|
"kind": "field",
|
|
@@ -5309,14 +5340,14 @@
|
|
|
5309
5340
|
}
|
|
5310
5341
|
}
|
|
5311
5342
|
],
|
|
5312
|
-
"description": "Which item is current, given what there is to choose from.\n\nThe first enabled one when `
|
|
5343
|
+
"description": "Which item is current, given what there is to choose from.\n\nThe first enabled one when `active` names nothing, which is a set before\nits consumer has chosen and a set whose current item has just been removed."
|
|
5313
5344
|
}
|
|
5314
5345
|
],
|
|
5315
5346
|
"helix": {}
|
|
5316
5347
|
},
|
|
5317
5348
|
{
|
|
5318
5349
|
"kind": "mixin",
|
|
5319
|
-
"description": "Grafts \"which one of these is the current one\" onto a container.\n\nFor a set where one member is current and the set is not a form control:\ntabs, a tree, a nav bar, a carousel. Where it *is* a form control the value\nis submitted and belongs to `MixinControllerValue`, which is why these are\ntwo mixins and not one with a flag.\n\n**Announcing before applying is the part worth sharing.**
|
|
5350
|
+
"description": "Grafts \"which one of these is the current one\" onto a container.\n\nFor a set where one member is current and the set is not a form control:\ntabs, a tree, a nav bar, a carousel. Where it *is* a form control the value\nis submitted and belongs to `MixinControllerValue`, which is why these are\ntwo mixins and not one with a flag.\n\n**Announcing before applying is the part worth sharing.** Writing the current\nvalue straight from the item's event leaves a consumer no way to refuse a\nchange, and whether a selection can be refused must not depend on which\ncomponent a reader is looking at.\n\n**The fallback is the other half.** `items.find(match) ?? items[0]` is not\nthe obvious line it looks like: it is what makes a set whose `active` names\nnothing still show something, which is every set before its consumer has set\none and every set whose current item has just been removed. `resolveActive`\nalso skips disabled items in that fallback, or a set opening on a disabled\nfirst item shows it as current.",
|
|
5320
5351
|
"name": "MixinControllerActive",
|
|
5321
5352
|
"members": [
|
|
5322
5353
|
{
|
|
@@ -5325,7 +5356,7 @@
|
|
|
5325
5356
|
"type": {
|
|
5326
5357
|
"text": "string"
|
|
5327
5358
|
},
|
|
5328
|
-
"description": "Which item is current, by its `value`.\n\
|
|
5359
|
+
"description": "Which item is current, by its `value`.\n\nNot `option.active`, which is the option the keyboard is on: that is a\ndifferent question from which one is chosen.\n\nWriting always applies, so `<helix-tabs active=\"one\">` starts on that\ntab, and `default-active` is how markup says where to start without\nnaming the current one.",
|
|
5329
5360
|
"attribute": "active"
|
|
5330
5361
|
},
|
|
5331
5362
|
{
|
|
@@ -5346,7 +5377,7 @@
|
|
|
5346
5377
|
},
|
|
5347
5378
|
"privacy": "private",
|
|
5348
5379
|
"default": "undefined",
|
|
5349
|
-
"description": "The state, whoever set it, and `undefined` until somebody has.\n\nOne field and not two. Writing always applies, the way a native control\ndoes when a script assigns to it.
|
|
5380
|
+
"description": "The state, whoever set it, and `undefined` until somebody has.\n\nOne field and not two. Writing always applies, the way a native control\ndoes when a script assigns to it."
|
|
5350
5381
|
},
|
|
5351
5382
|
{
|
|
5352
5383
|
"kind": "method",
|
|
@@ -5364,7 +5395,7 @@
|
|
|
5364
5395
|
}
|
|
5365
5396
|
}
|
|
5366
5397
|
],
|
|
5367
|
-
"description": "Requests a new current item, and reports whether the request stood.\n\nAnnounces before it acts, so `preventDefault()` on the `helix-before-activate` is\na refusal and nothing moves. Unlike a native control, nothing has moved\nby the time this runs, so refusing is simply not writing: there is\nnothing to put back. Nobody refusing means the set updates itself,\nwhether or not a consumer declared `active`, a declared property being a\nseed and a correction.
|
|
5398
|
+
"description": "Requests a new current item, and reports whether the request stood.\n\nAnnounces before it acts, so `preventDefault()` on the `helix-before-activate` is\na refusal and nothing moves. Unlike a native control, nothing has moved\nby the time this runs, so refusing is simply not writing: there is\nnothing to put back. Nobody refusing means the set updates itself,\nwhether or not a consumer declared `active`, a declared property being a\nseed and a correction."
|
|
5368
5399
|
},
|
|
5369
5400
|
{
|
|
5370
5401
|
"kind": "method",
|
|
@@ -5383,7 +5414,7 @@
|
|
|
5383
5414
|
}
|
|
5384
5415
|
}
|
|
5385
5416
|
],
|
|
5386
|
-
"description": "Says the current child moved, once it has.\n\n
|
|
5417
|
+
"description": "Says the current child moved, once it has.\n\n`helix-activate` rather than a native word: nothing on the platform means\n\"a set chose a different member\", and borrowing `change` would be a lie\nabout what moved.\n\nA consumer who only wants to know which child is current cannot use\n`helix-before-activate` for it, that one firing *before* `apply`, so\n`currentTarget.active` is the previous value inside the handler and\n`detail.value` is a proposal another listener may refuse. `helix-select`\nis no substitute either: it fires when an item is *chosen* and not when\n`active` is assigned.\n\n**After `apply`, which is the whole reason it is a second event**, so the\nstate is on the element by the time a handler reads it. Not cancelable:\nthe decision was taken by the event before this one, and two refusable\nevents for one transition are two answers to one question."
|
|
5387
5418
|
},
|
|
5388
5419
|
{
|
|
5389
5420
|
"kind": "method",
|
|
@@ -5402,7 +5433,7 @@
|
|
|
5402
5433
|
}
|
|
5403
5434
|
}
|
|
5404
5435
|
],
|
|
5405
|
-
"description": "Which item is current, given what there is to choose from.\n\nThe first enabled one when `
|
|
5436
|
+
"description": "Which item is current, given what there is to choose from.\n\nThe first enabled one when `active` names nothing, which is a set before\nits consumer has chosen and a set whose current item has just been\nremoved. Disabled items are skipped in the fallback but not in the match:\na consumer who names a disabled item meant it, and quietly moving to\nanother would be the component overruling them."
|
|
5406
5437
|
}
|
|
5407
5438
|
],
|
|
5408
5439
|
"events": [
|
|
@@ -5418,7 +5449,7 @@
|
|
|
5418
5449
|
"type": {
|
|
5419
5450
|
"text": "string"
|
|
5420
5451
|
},
|
|
5421
|
-
"description": "Which item is current, by its `value`.\n\
|
|
5452
|
+
"description": "Which item is current, by its `value`.\n\nNot `option.active`, which is the option the keyboard is on: that is a\ndifferent question from which one is chosen.\n\nWriting always applies, so `<helix-tabs active=\"one\">` starts on that\ntab, and `default-active` is how markup says where to start without\nnaming the current one.",
|
|
5422
5453
|
"fieldName": "active"
|
|
5423
5454
|
},
|
|
5424
5455
|
{
|
|
@@ -5475,7 +5506,7 @@
|
|
|
5475
5506
|
"type": {
|
|
5476
5507
|
"text": "boolean"
|
|
5477
5508
|
},
|
|
5478
|
-
"description": "Whether the control is checked.\n\nReading gives the real state,
|
|
5509
|
+
"description": "Whether the control is checked.\n\nReading gives the real state. Writing always applies, and is a seed and a\ncorrection rather than a claim of ownership: a consumer who wants the\ndecision refuses the `helix-before-toggle`."
|
|
5479
5510
|
},
|
|
5480
5511
|
{
|
|
5481
5512
|
"kind": "field",
|
|
@@ -5521,14 +5552,14 @@
|
|
|
5521
5552
|
"text": "void"
|
|
5522
5553
|
}
|
|
5523
5554
|
},
|
|
5524
|
-
"description": "Drops the
|
|
5555
|
+
"description": "Drops the recorded state, so the control reads `defaultChecked` again.\n\nA form reset has to return a control to what its markup declared, and\nassigning `checked` cannot do it: any assignment records a state, and the\nrecorded state is private to the mixin. This is the only way to clear it."
|
|
5525
5556
|
}
|
|
5526
5557
|
],
|
|
5527
5558
|
"helix": {}
|
|
5528
5559
|
},
|
|
5529
5560
|
{
|
|
5530
5561
|
"kind": "mixin",
|
|
5531
|
-
"description": "Grafts
|
|
5562
|
+
"description": "Grafts checked state onto a base class.\n\n`checked` is a seed and a correction rather than a claim: the element applies\nits own changes from wherever markup started it, `defaultChecked` is what a\nreset returns to, and a consumer takes the decision by refusing the\n`helix-before-toggle`.\n\nRecords `:state(checked)` whenever the element is checked. Styled tiers\nselect on that rather than on `[checked]`, which is absent until somebody\nwrites it.",
|
|
5532
5563
|
"name": "MixinControllerChecked",
|
|
5533
5564
|
"members": [
|
|
5534
5565
|
{
|
|
@@ -5537,7 +5568,7 @@
|
|
|
5537
5568
|
"type": {
|
|
5538
5569
|
"text": "boolean"
|
|
5539
5570
|
},
|
|
5540
|
-
"description": "Whether the control is checked.\n\nOne property rather than two.
|
|
5571
|
+
"description": "Whether the control is checked.\n\nOne property rather than two. Writing always applies;\n`<helix-checkbox checked>` is the same statement in markup.\n\nNot reflected: the attribute is the consumer's input and stays as they\nwrote it, and `:state(checked)` carries the resolved state for\nstylesheets.",
|
|
5541
5572
|
"attribute": "checked"
|
|
5542
5573
|
},
|
|
5543
5574
|
{
|
|
@@ -5558,7 +5589,7 @@
|
|
|
5558
5589
|
},
|
|
5559
5590
|
"privacy": "private",
|
|
5560
5591
|
"default": "undefined",
|
|
5561
|
-
"description": "The state, whoever set it, and `undefined` until somebody has.\n\nOne field and not two. Writing always applies, the way a native control\ndoes when a script assigns to it.
|
|
5592
|
+
"description": "The state, whoever set it, and `undefined` until somebody has.\n\nOne field and not two. Writing always applies, the way a native control\ndoes when a script assigns to it."
|
|
5562
5593
|
},
|
|
5563
5594
|
{
|
|
5564
5595
|
"kind": "method",
|
|
@@ -5576,7 +5607,7 @@
|
|
|
5576
5607
|
}
|
|
5577
5608
|
}
|
|
5578
5609
|
],
|
|
5579
|
-
"description": "Requests a checked change, and reports whether it was applied.\n\nAnnounces before it acts, so `preventDefault()` on the\n`helix-before-toggle` is a refusal and nothing moves. Nobody refusing
|
|
5610
|
+
"description": "Requests a checked change, and reports whether it was applied.\n\nAnnounces before it acts, so `preventDefault()` on the\n`helix-before-toggle` is a refusal and nothing moves. Nobody refusing\nmeans the element updates itself, whether or not a consumer declared the\nproperty: a declared property is a seed and a correction, the way\n`<input value>` is, and a consumer who wants the change for themselves\nrefuses it and assigns their own."
|
|
5580
5611
|
},
|
|
5581
5612
|
{
|
|
5582
5613
|
"kind": "method",
|
|
@@ -5604,7 +5635,7 @@
|
|
|
5604
5635
|
}
|
|
5605
5636
|
}
|
|
5606
5637
|
],
|
|
5607
|
-
"description": "Restores the control when the browser brings a form back.\n\
|
|
5638
|
+
"description": "Restores the control when the browser brings a form back.\n\nThe mixin owns `checked`, so the mixin owns putting it back: written on\none consumer and not the other, a reader who navigates away and comes\nback to a restored form finds that control flipped off.\n\nThrough the public accessor rather than the private field, so a restore\ntakes the same path a script assignment does."
|
|
5608
5639
|
},
|
|
5609
5640
|
{
|
|
5610
5641
|
"kind": "method",
|
|
@@ -5614,7 +5645,7 @@
|
|
|
5614
5645
|
"text": "void"
|
|
5615
5646
|
}
|
|
5616
5647
|
},
|
|
5617
|
-
"description": "Drops the
|
|
5648
|
+
"description": "Drops the recorded state, so the control reads `defaultChecked` again.\n\nA form reset has to return a control to what its markup declared, and no\nassignment to `checked` can do that: any assignment records a state. The\nrecorded state lives here, so this is where it is dropped."
|
|
5618
5649
|
}
|
|
5619
5650
|
],
|
|
5620
5651
|
"events": [
|
|
@@ -5631,7 +5662,7 @@
|
|
|
5631
5662
|
"type": {
|
|
5632
5663
|
"text": "boolean"
|
|
5633
5664
|
},
|
|
5634
|
-
"description": "Whether the control is checked.\n\nOne property rather than two.
|
|
5665
|
+
"description": "Whether the control is checked.\n\nOne property rather than two. Writing always applies;\n`<helix-checkbox checked>` is the same statement in markup.\n\nNot reflected: the attribute is the consumer's input and stays as they\nwrote it, and `:state(checked)` carries the resolved state for\nstylesheets.",
|
|
5635
5666
|
"fieldName": "checked"
|
|
5636
5667
|
},
|
|
5637
5668
|
{
|
|
@@ -5696,7 +5727,7 @@
|
|
|
5696
5727
|
"type": {
|
|
5697
5728
|
"text": "boolean"
|
|
5698
5729
|
},
|
|
5699
|
-
"description": "Whether the element is open.\n\nReading gives the real state,
|
|
5730
|
+
"description": "Whether the element is open.\n\nReading gives the real state. Writing always applies, and is a seed and a\ncorrection rather than a claim of ownership: a consumer who wants the\ndecision refuses the `helix-before-open` or `helix-before-close`."
|
|
5700
5731
|
},
|
|
5701
5732
|
{
|
|
5702
5733
|
"kind": "method",
|
|
@@ -5731,7 +5762,7 @@
|
|
|
5731
5762
|
},
|
|
5732
5763
|
{
|
|
5733
5764
|
"kind": "mixin",
|
|
5734
|
-
"description": "Grafts open state onto a base class, and says so twice.\n\n`helix-before-open` and `helix-before-close` announce the change while it is\nstill a request, so `preventDefault()` refuses it and nothing moves. Native\n`toggle` announces it afterwards, once the state has actually gone, carrying\n`newState` and `oldState` the way the platform does on `<details>` and on a\npopover. The first is how a consumer takes the decision; the second is what\nthey bind when they only want to know
|
|
5765
|
+
"description": "Grafts open state onto a base class, and says so twice.\n\n`helix-before-open` and `helix-before-close` announce the change while it is\nstill a request, so `preventDefault()` refuses it and nothing moves. Native\n`toggle` announces it afterwards, once the state has actually gone, carrying\n`newState` and `oldState` the way the platform does on `<details>` and on a\npopover. The first is how a consumer takes the decision; the second is what\nthey bind when they only want to know.\n\n`open` is a seed and a correction rather than a claim: the element applies\nits own changes from wherever markup started it, and `defaultOpen` is what a\nreset returns to.\n\nRecords `:state(open)` whenever the element is open. Styled tiers select on\nthat rather than on `[open]`, which is absent until somebody writes it.",
|
|
5735
5766
|
"name": "MixinControllerOpen",
|
|
5736
5767
|
"members": [
|
|
5737
5768
|
{
|
|
@@ -5740,7 +5771,7 @@
|
|
|
5740
5771
|
"type": {
|
|
5741
5772
|
"text": "boolean"
|
|
5742
5773
|
},
|
|
5743
|
-
"description": "Whether the element is open.\n\nOne property, not two
|
|
5774
|
+
"description": "Whether the element is open.\n\nOne property, not two, so `dialog.open` answers the question anyone\nasking it meant. Writing always applies; `<helix-dialog open>` is the\nsame statement in markup.\n\n**Not reflected, and that is required rather than tidy.** Reflection\nwrites the resolved state back as an attribute, so an element that opened\nitself would put `open` on its own host: cloned, serialized for\nhydration, or diffed by a framework, it comes back holding whatever the\nlast reader did rather than what the author wrote. `:state(open)` carries\nthe resolved state for stylesheets, which is what the mirror is for.",
|
|
5744
5775
|
"attribute": "open"
|
|
5745
5776
|
},
|
|
5746
5777
|
{
|
|
@@ -5761,7 +5792,7 @@
|
|
|
5761
5792
|
},
|
|
5762
5793
|
"privacy": "private",
|
|
5763
5794
|
"default": "undefined",
|
|
5764
|
-
"description": "The state, whoever set it, and `undefined` until somebody has.\n\nPrefixed, and it has to be. These mixins compose onto one prototype\nchain, `Select` takes this one and `MixinControllerValue` together, and\nTypeScript's `private` is a compile-time fiction: two mixins with a field\ncalled `state` share one property on the instance, and the second one\nsilently overwrites the first. Measured, as a select whose `value` came\nback holding its `open` boolean.\n\nOne field and not two. Writing always applies,
|
|
5795
|
+
"description": "The state, whoever set it, and `undefined` until somebody has.\n\nPrefixed, and it has to be. These mixins compose onto one prototype\nchain, `Select` takes this one and `MixinControllerValue` together, and\nTypeScript's `private` is a compile-time fiction: two mixins with a field\ncalled `state` share one property on the instance, and the second one\nsilently overwrites the first. Measured, as a select whose `value` came\nback holding its `open` boolean.\n\nOne field and not two. Writing always applies, the way a native control\ndoes when a script assigns to it."
|
|
5765
5796
|
},
|
|
5766
5797
|
{
|
|
5767
5798
|
"kind": "method",
|
|
@@ -5779,7 +5810,7 @@
|
|
|
5779
5810
|
}
|
|
5780
5811
|
}
|
|
5781
5812
|
],
|
|
5782
|
-
"description": "Requests an open-state change, and reports whether it was applied.\n\nAnnounces before it acts, so `preventDefault()` on the `helix-before-open` or\n`helix-before-close` is a refusal and nothing moves. Nobody refusing means the\nelement opens or closes itself, whether or not a consumer declared\n`open`: a declared property is a seed and a correction, and a consumer\nwho wants the decision for themselves refuses it and assigns their own
|
|
5813
|
+
"description": "Requests an open-state change, and reports whether it was applied.\n\nAnnounces before it acts, so `preventDefault()` on the `helix-before-open` or\n`helix-before-close` is a refusal and nothing moves. Nobody refusing means the\nelement opens or closes itself, whether or not a consumer declared\n`open`: a declared property is a seed and a correction, and a consumer\nwho wants the decision for themselves refuses it and assigns their own."
|
|
5783
5814
|
},
|
|
5784
5815
|
{
|
|
5785
5816
|
"kind": "method",
|
|
@@ -5798,7 +5829,7 @@
|
|
|
5798
5829
|
}
|
|
5799
5830
|
}
|
|
5800
5831
|
],
|
|
5801
|
-
"description": "Says the state moved, under the platform's own name and in its shape.\n\n
|
|
5832
|
+
"description": "Says the state moved, under the platform's own name and in its shape.\n\n**A native `toggle` from inside a shadow root reaches nobody**, because\nit neither bubbles nor composes, so the ten families showing a\n`popover=\"manual\"` panel and the two rendering a real `<dialog>` announce\nnothing to a consumer. The disclosures have no native element to fire\nanything at all: `AccordionItem` and `TreeItem` are `aria-expanded` and\n`hidden` written by hand, which is `<details>`'s job done manually.\n\n**From here rather than from `PopoverController`.** The controller covers\neleven families and the mixin covers sixteen, so announcing from both\nwould announce twice on the ten they share. What `toggle` reports is the\n*state*, and the state is this mixin's; the controller is a way of\nputting a panel on the screen.\n\n**`newState` and `oldState`, because that is the platform's shape**, so a\nconsumer arriving from `<details>` reads the same two words. Not\ncancelable: the before events are the request, and a second cancelable\nevent for one transition is two answers to one question."
|
|
5802
5833
|
},
|
|
5803
5834
|
{
|
|
5804
5835
|
"kind": "method",
|
|
@@ -5817,7 +5848,7 @@
|
|
|
5817
5848
|
"type": {
|
|
5818
5849
|
"text": "boolean"
|
|
5819
5850
|
},
|
|
5820
|
-
"description": "Whether the element is open.\n\nOne property, not two
|
|
5851
|
+
"description": "Whether the element is open.\n\nOne property, not two, so `dialog.open` answers the question anyone\nasking it meant. Writing always applies; `<helix-dialog open>` is the\nsame statement in markup.\n\n**Not reflected, and that is required rather than tidy.** Reflection\nwrites the resolved state back as an attribute, so an element that opened\nitself would put `open` on its own host: cloned, serialized for\nhydration, or diffed by a framework, it comes back holding whatever the\nlast reader did rather than what the author wrote. `:state(open)` carries\nthe resolved state for stylesheets, which is what the mirror is for.",
|
|
5821
5852
|
"fieldName": "open"
|
|
5822
5853
|
},
|
|
5823
5854
|
{
|
|
@@ -5882,7 +5913,7 @@
|
|
|
5882
5913
|
"type": {
|
|
5883
5914
|
"text": "string"
|
|
5884
5915
|
},
|
|
5885
|
-
"description": "What the control holds now, and what its form submits.\n\nReading gives the real value,
|
|
5916
|
+
"description": "What the control holds now, and what its form submits.\n\nReading gives the real value. Writing always applies, and is a seed and a\ncorrection rather than a claim of ownership: a consumer who wants the\ndecision refuses the `helix-before-change`."
|
|
5886
5917
|
},
|
|
5887
5918
|
{
|
|
5888
5919
|
"kind": "field",
|
|
@@ -5892,7 +5923,7 @@
|
|
|
5892
5923
|
},
|
|
5893
5924
|
"privacy": "protected",
|
|
5894
5925
|
"readonly": true,
|
|
5895
|
-
"description": "Whether every edit is announced, rather than every settled value.\n\nA control the reader types or drags in moves continuously, and the platform\ncalls that `input`: `<input type=\"text\">` fires one per keystroke and fires\n`change` once, on commit. Five controls here are that shape, and the rest\nchange in discrete steps where a step *is* the change.\n\nIt selects the event rather than the timing. `requestValue` is called\nwhenever the value moves either way; this decides whether the control sends\n`input` alone or `input` and `change` together
|
|
5926
|
+
"description": "Whether every edit is announced, rather than every settled value.\n\nA control the reader types or drags in moves continuously, and the platform\ncalls that `input`: `<input type=\"text\">` fires one per keystroke and fires\n`change` once, on commit. Five controls here are that shape, and the rest\nchange in discrete steps where a step *is* the change.\n\nIt selects the event rather than the timing. `requestValue` is called\nwhenever the value moves either way; this decides whether the control sends\n`input` alone or `input` and `change` together."
|
|
5896
5927
|
},
|
|
5897
5928
|
{
|
|
5898
5929
|
"kind": "method",
|
|
@@ -5945,7 +5976,7 @@
|
|
|
5945
5976
|
},
|
|
5946
5977
|
{
|
|
5947
5978
|
"kind": "mixin",
|
|
5948
|
-
"description": "Grafts `value`, `defaultValue`, and the two callbacks that answer a form.\n\
|
|
5979
|
+
"description": "Grafts `value`, `defaultValue`, and the two callbacks that answer a form.\n\n**Derived on read, never seeded in a lifecycle hook.** `value` falls back to\n`defaultValue`, so the server and the client agree without either running a\nhook. Seeding in `connectedCallback` is the trap: SSR never calls it, so a\ncontrol with a `default-value` would serve empty and fill itself at\nhydration, a flash for a reader and a mismatch for React.\n\n**What it does not own is reporting.** `setFormValue` stays with the\ncomponent, because what an empty value means is the component's business: a\ntext field submits its emptiness, since `\"\"` is an answer and the field was\non the form, while a group with nothing chosen submits nothing at all.\n\n`Checkbox` deliberately does not take this. Its `value` is what it submits\n*when it is on* rather than what it holds, so it is configuration rather than\nstate, and the state it does have is `checked`, which is\n`MixinControllerChecked`'s.",
|
|
5949
5980
|
"name": "MixinControllerValue",
|
|
5950
5981
|
"members": [
|
|
5951
5982
|
{
|
|
@@ -5964,7 +5995,7 @@
|
|
|
5964
5995
|
"type": {
|
|
5965
5996
|
"text": "string"
|
|
5966
5997
|
},
|
|
5967
|
-
"description": "What the control holds now, and what its form submits.\n\nOne property, not two
|
|
5998
|
+
"description": "What the control holds now, and what its form submits.\n\nOne property, not two, so `input.value` answers the question anyone\nasking it meant. Writing always applies; `<helix-input value=\"x\">` is the\nsame statement in markup, and `default-value` is how markup seeds a value\na reset should return to.",
|
|
5968
5999
|
"attribute": "value"
|
|
5969
6000
|
},
|
|
5970
6001
|
{
|
|
@@ -5986,7 +6017,7 @@
|
|
|
5986
6017
|
"privacy": "protected",
|
|
5987
6018
|
"readonly": true,
|
|
5988
6019
|
"default": "false",
|
|
5989
|
-
"description": "Whether a reader edits this continuously, which decides the native name.\n\
|
|
6020
|
+
"description": "Whether a reader edits this continuously, which decides the native name.\n\nThe request event is `helix-before-change` whatever the answer; this\ndecides which native event announces the result, `input` while a reader\nis editing against `change` when they are done, which is the distinction\nthe platform already draws.\n\nDiscrete by default: only a control the reader edits continuously says\notherwise."
|
|
5990
6021
|
},
|
|
5991
6022
|
{
|
|
5992
6023
|
"kind": "method",
|
|
@@ -6015,7 +6046,7 @@
|
|
|
6015
6046
|
}
|
|
6016
6047
|
}
|
|
6017
6048
|
],
|
|
6018
|
-
"description": "Requests a new value, and reports whether the request stood.\n\nAnnounces before it acts, so `preventDefault()` on the `helix-before-change` is\na refusal and nothing moves. Nobody refusing means the control updates\nitself, whether or not a consumer declared `value`: a declared property\nis a seed and a correction, the way `<input value>` is, and a consumer\nwho wants the change for themselves refuses it and assigns their own
|
|
6049
|
+
"description": "Requests a new value, and reports whether the request stood.\n\nAnnounces before it acts, so `preventDefault()` on the `helix-before-change` is\na refusal and nothing moves. Nobody refusing means the control updates\nitself, whether or not a consumer declared `value`: a declared property\nis a seed and a correction, the way `<input value>` is, and a consumer\nwho wants the change for themselves refuses it and assigns their own."
|
|
6019
6050
|
},
|
|
6020
6051
|
{
|
|
6021
6052
|
"kind": "method",
|
|
@@ -6075,7 +6106,7 @@
|
|
|
6075
6106
|
"type": {
|
|
6076
6107
|
"text": "string"
|
|
6077
6108
|
},
|
|
6078
|
-
"description": "What the control holds now, and what its form submits.\n\nOne property, not two
|
|
6109
|
+
"description": "What the control holds now, and what its form submits.\n\nOne property, not two, so `input.value` answers the question anyone\nasking it meant. Writing always applies; `<helix-input value=\"x\">` is the\nsame statement in markup, and `default-value` is how markup seeds a value\na reset should return to.",
|
|
6079
6110
|
"fieldName": "value"
|
|
6080
6111
|
}
|
|
6081
6112
|
],
|
|
@@ -6159,7 +6190,7 @@
|
|
|
6159
6190
|
},
|
|
6160
6191
|
{
|
|
6161
6192
|
"kind": "mixin",
|
|
6162
|
-
"description": "Grafts `dismissible`, its label, and the event that says so.\n\
|
|
6193
|
+
"description": "Grafts `dismissible`, its label, and the event that says so.\n\n**The label reads the default slot, never `this.textContent`**, which is\nevery light-DOM descendant including the ones assigned elsewhere. On\n`Announcement` and `Tag` the two are the same thing, because they have one\nslot. On `Toast.Item` the second sweeps in the actions: a message reading\n\"Could not reach the server\" with a `Retry` button announces itself as \"Could\nnot reach the server Retry\", and the consumer removing it from their list\ngets that string to match on.\n\n**`dismissEvent()` is separate from `dismiss()` for the one that needs it.**\n`Announcement` and `Tag` dispatch and are done: they own no state, so a\nrefusal is the whole of the consumer's answer. `Toast.Item` holds an `open`\nand applies the change itself, so its event goes through `requestChange` with\nan `apply` beside it. Giving it the event rather than the method lets it keep\nthe contract and skip the default.",
|
|
6163
6194
|
"name": "MixinDismissible",
|
|
6164
6195
|
"members": [
|
|
6165
6196
|
{
|
|
@@ -6278,7 +6309,7 @@
|
|
|
6278
6309
|
"text": "string | undefined"
|
|
6279
6310
|
},
|
|
6280
6311
|
"readonly": true,
|
|
6281
|
-
"description": "
|
|
6312
|
+
"description": "Id of the description node, for `aria-describedby` on the control.\n\n`undefined` when there is nothing to point at, so the attribute is absent\nrather than pointing at an id that renders nothing."
|
|
6282
6313
|
},
|
|
6283
6314
|
{
|
|
6284
6315
|
"kind": "field",
|
|
@@ -6399,7 +6430,7 @@
|
|
|
6399
6430
|
}
|
|
6400
6431
|
}
|
|
6401
6432
|
],
|
|
6402
|
-
"description": "Reports \"required and empty\" against a rendered part, or clears it.\n\n`empty` is the control's own answer to whether it holds nothing, `message`\nis what to say about it, and `anchor` names the part the browser should\npoint its bubble at.
|
|
6433
|
+
"description": "Reports \"required and empty\" against a rendered part, or clears it.\n\n`empty` is the control's own answer to whether it holds nothing, `message`\nis what to say about it, and `anchor` names the part the browser should\npoint its bubble at."
|
|
6403
6434
|
},
|
|
6404
6435
|
{
|
|
6405
6436
|
"kind": "field",
|
|
@@ -6415,28 +6446,28 @@
|
|
|
6415
6446
|
},
|
|
6416
6447
|
{
|
|
6417
6448
|
"kind": "mixin",
|
|
6418
|
-
"description": "Grafts a label, help text, and a validation message onto a control.\n\n**Over `HelixElement` rather than `HelixFormElement`, because not every\ncontrol that wants a label is form-associated.** A checkbox group is the\ncase: each box in it submits itself already, so the group deliberately\nreports no value of its own, and every form-related member of\n`ElementInternals` throws `NotSupportedError` on an element that is not\nform-associated. Measured, and the ARIA members are fine on the same\nelement, which is why the naming and describing work there and only the\nvalidity has to ask first.\n\nEvery form control wants the same three things around it and wants them in a\ndifferent arrangement: a label above an input, beside a checkbox, and over a\ngroup. So this owns the properties, the parts, and the wiring, and each\ncontrol places the nodes where its own geometry needs them. Same part names\neither way, so one stylesheet in the styled tier dresses all of them.\n\n**Not a wrapping `Field` component, and that is not a style preference.** A\nwrapper cannot name what it wraps. Its label would live in its own shadow\nroot and the control in another, and measured in Chrome 148: an\n`aria-labelledby` IDREF cannot see across, and\n`control.ariaLabelledByElements = [labelInTheWrapper]` reads back as zero\nelements, the reference dropped. The same assignment with a label in the\ncontrol's own tree is kept. That pattern works in React libraries because\nthey have no shadow boundary; bringing it here brings the ergonomics and none\nof the conditions that made it work.\n\n**A control whose label is its content renders its own.** A checkbox is named\nby the words beside it, inside the `<label>` that forwards the press, so it\nuses its default slot and nesting `renderLabel`'s `<label>` in there would be\ninvalid markup. `label` is that slot's fallback either way.\n\nWorth knowing, because it costs a label and gives no warning: **a\nwhitespace-only text node is assigned to the default slot and defeats its\nfallback.** Measured in Chrome 148, and a newline between the tags is enough,\nso `<helix-checkbox label=\"Accept\">` closed on the next line renders no label\nat all. A named slot does not have this problem, because `slot=\"label\"` is an\nattribute and a text node has none. It is the platform's behavior rather\nthan ours, and the same is already true of every slot fallback here.\n\n**The ids are fixed rather than generated.** IDREFs resolve within the tree\nthat holds them, so two controls on a page each carrying `helix-hint` in\ntheir own shadow root do not collide. That also removes the usual hydration\nhazard, since there is no generated value for a server and a client to\ndisagree about.\n\n**A group has to say it differently.** A control's `<input>` and its hint\nare both in the shadow root, so a plain `aria-describedby` resolves. A\ngroup's host is in the light DOM and its hint is not, so the IDREF cannot\nreach and `element.ariaDescribedByElements` drops the reference. Only\n`internals.ariaDescribedByElements` keeps it, which is what `describeHost`\nuses. Measured the same way, and the failure is silent either way: the\ndescription simply never reaches the accessibility tree.\n\n
|
|
6449
|
+
"description": "Grafts a label, help text, and a validation message onto a control.\n\n**Over `HelixElement` rather than `HelixFormElement`, because not every\ncontrol that wants a label is form-associated.** A checkbox group is the\ncase: each box in it submits itself already, so the group deliberately\nreports no value of its own, and every form-related member of\n`ElementInternals` throws `NotSupportedError` on an element that is not\nform-associated. Measured, and the ARIA members are fine on the same\nelement, which is why the naming and describing work there and only the\nvalidity has to ask first.\n\nEvery form control wants the same three things around it and wants them in a\ndifferent arrangement: a label above an input, beside a checkbox, and over a\ngroup. So this owns the properties, the parts, and the wiring, and each\ncontrol places the nodes where its own geometry needs them. Same part names\neither way, so one stylesheet in the styled tier dresses all of them.\n\n**Not a wrapping `Field` component, and that is not a style preference.** A\nwrapper cannot name what it wraps. Its label would live in its own shadow\nroot and the control in another, and measured in Chrome 148: an\n`aria-labelledby` IDREF cannot see across, and\n`control.ariaLabelledByElements = [labelInTheWrapper]` reads back as zero\nelements, the reference dropped. The same assignment with a label in the\ncontrol's own tree is kept. That pattern works in React libraries because\nthey have no shadow boundary; bringing it here brings the ergonomics and none\nof the conditions that made it work.\n\n**A control whose label is its content renders its own.** A checkbox is named\nby the words beside it, inside the `<label>` that forwards the press, so it\nuses its default slot and nesting `renderLabel`'s `<label>` in there would be\ninvalid markup. `label` is that slot's fallback either way.\n\nWorth knowing, because it costs a label and gives no warning: **a\nwhitespace-only text node is assigned to the default slot and defeats its\nfallback.** Measured in Chrome 148, and a newline between the tags is enough,\nso `<helix-checkbox label=\"Accept\">` closed on the next line renders no label\nat all. A named slot does not have this problem, because `slot=\"label\"` is an\nattribute and a text node has none. It is the platform's behavior rather\nthan ours, and the same is already true of every slot fallback here.\n\n**The ids are fixed rather than generated.** IDREFs resolve within the tree\nthat holds them, so two controls on a page each carrying `helix-hint` in\ntheir own shadow root do not collide. That also removes the usual hydration\nhazard, since there is no generated value for a server and a client to\ndisagree about.\n\n**A group has to say it differently.** A control's `<input>` and its hint\nare both in the shadow root, so a plain `aria-describedby` resolves. A\ngroup's host is in the light DOM and its hint is not, so the IDREF cannot\nreach and `element.ariaDescribedByElements` drops the reference. Only\n`internals.ariaDescribedByElements` keeps it, which is what `describeHost`\nuses. Measured the same way, and the failure is silent either way: the\ndescription simply never reaches the accessibility tree.\n\n**The label, the hint and the feedback are documented on each component that\napplies this, rather than here.** Declaring them once on this mixin is the\nobvious fix and does not work: the analyzer reads `@csspart` off a custom\nelement class, so a class-level tag here reaches the manifest as nothing at\nall, on this JSDoc and on the inner class alike. Measured both ways, and the\ninner-class version is the dangerous one, since it satisfies the rule while\nevery API page stays exactly as wrong as before. Members are different and\ndo inherit, which is what the note about the inner class in the area rules\nis about.",
|
|
6419
6450
|
"name": "MixinField",
|
|
6420
6451
|
"members": [
|
|
6421
6452
|
{
|
|
6422
6453
|
"kind": "field",
|
|
6423
|
-
"name": "
|
|
6454
|
+
"name": "feedback",
|
|
6424
6455
|
"type": {
|
|
6425
6456
|
"text": "string"
|
|
6426
6457
|
},
|
|
6427
6458
|
"default": "''",
|
|
6428
|
-
"description": "
|
|
6429
|
-
"attribute": "
|
|
6459
|
+
"description": "What is wrong, in the reader's words rather than the browser's.",
|
|
6460
|
+
"attribute": "feedback"
|
|
6430
6461
|
},
|
|
6431
6462
|
{
|
|
6432
6463
|
"kind": "field",
|
|
6433
|
-
"name": "
|
|
6464
|
+
"name": "hint",
|
|
6434
6465
|
"type": {
|
|
6435
6466
|
"text": "string"
|
|
6436
6467
|
},
|
|
6437
6468
|
"default": "''",
|
|
6438
|
-
"description": "
|
|
6439
|
-
"attribute": "
|
|
6469
|
+
"description": "Help under the control, shown while there is nothing wrong.",
|
|
6470
|
+
"attribute": "hint"
|
|
6440
6471
|
},
|
|
6441
6472
|
{
|
|
6442
6473
|
"kind": "field",
|
|
@@ -6467,7 +6498,7 @@
|
|
|
6467
6498
|
},
|
|
6468
6499
|
"privacy": "private",
|
|
6469
6500
|
"default": "false",
|
|
6470
|
-
"description": "Whether the reader has had a go at the field yet.\n\
|
|
6501
|
+
"description": "Whether the reader has had a go at the field yet.\n\n**Not `:user-invalid`**, which is the platform's own answer to \"is this\nfield wrong *yet*\" and cannot work here, for a structural reason rather\nthan a browser bug: it tracks interaction with the element it is on, and\nnobody interacts with this element. The reader types into an `<input>`\ninside its shadow root, so the host's interaction flag is never set and\nthe selector never matches. Measured after submitting an invalid required\nfield and again after editing one and leaving it: false both times, while\n`:invalid` matched both times.\n\nSo the moments are listened for instead, and both of them demonstrably\nreach the host: `invalid` when a form is submitted with this control\nfailing, and `change` when the reader has edited and committed. Focus\nalone is deliberately not one of them. Tabbing past an empty required\nfield should not be answered with an error.\n\n**A composite control has to construct its own `change`, and this mixin\ndeliberately does not do it for them.** A native `change` is\n`composed: false`, so a control built from several inner inputs never\nrelays one to its host: `Input` gets this free from its one control,\nwhile a `PinInput` of four boxes has no inner `change` that means the\ncode is entered, so a half-entered code is never `touched` and can never\nsay what is wrong with it.\n\n**The obvious shared fix is for `touched` to take a `focusout`, and it is\nthe wrong one**, because it is the paragraph above undone: a `focusout`\nfires on the reader who tabbed past and typed nothing, which is exactly\nthe case this refuses to call an error. What a composite needs is not a\nfocus moment, it is the native meaning of `change`, \"edited, then left\",\nand the editing half is the part a mixin up here cannot see.\n\n**Nor is there one shape to extract yet.** The two composites solve it\ndifferently and both are right: `PinInput` is focus-driven, taking a\nbaseline when focus arrives from outside the row and announcing on the\nway out if it moved, and `DateInput` is value-driven, stopping its inner\n`change` and announcing once the date itself moves. Only one of them has\na leaving moment at all, so generalizing from the pair is generalizing\nfrom one. The trigger for lifting it is a third control that needs the\nfocus-driven shape, at which point what moves up is the\nbaseline-and-commit pair rather than `touched`."
|
|
6471
6502
|
},
|
|
6472
6503
|
{
|
|
6473
6504
|
"kind": "field",
|
|
@@ -6499,7 +6530,7 @@
|
|
|
6499
6530
|
"text": "TemplateResult | typeof nothing"
|
|
6500
6531
|
}
|
|
6501
6532
|
},
|
|
6502
|
-
"description": "A label above the control, pointing at it.\n\nA real `<label for>`, so pressing the words focuses the field and the\nbrowser does the forwarding. It resolves because `for` looks within the\nsame tree, and the control it names is in this shadow root.\n\n**Nothing at all when there is no label**, which is the same rule the\nhint and the feedback follow: none of the three is always used, and an\nelement rendered empty is not free. It still generates a box, so it still\ntakes a row of the grid and a gap on either side of it, which is a field\nthat has moved down the page for a label nobody wrote. `nothing` leaves\ncomment markers rather than a node, so the gap has nothing to sit between.\n\n**`aria-label` names without showing**, and it is forwarded rather than\nleft where the consumer put it. A custom element has no way to delegate a\nlabel to the control inside it, so an `aria-label` on the host reaches\nnothing: measured, the inner input came back with no label and no name of\nits own while the attribute sat on the wrapper. What happens instead is\nthat the label is rendered and clipped, so the name arrives through the\nsame `<label for>` a visible one does.\n\
|
|
6533
|
+
"description": "A label above the control, pointing at it.\n\nA real `<label for>`, so pressing the words focuses the field and the\nbrowser does the forwarding. It resolves because `for` looks within the\nsame tree, and the control it names is in this shadow root.\n\n**Nothing at all when there is no label**, which is the same rule the\nhint and the feedback follow: none of the three is always used, and an\nelement rendered empty is not free. It still generates a box, so it still\ntakes a row of the grid and a gap on either side of it, which is a field\nthat has moved down the page for a label nobody wrote. `nothing` leaves\ncomment markers rather than a node, so the gap has nothing to sit between.\n\n**`aria-label` names without showing**, and it is forwarded rather than\nleft where the consumer put it. A custom element has no way to delegate a\nlabel to the control inside it, so an `aria-label` on the host reaches\nnothing: measured, the inner input came back with no label and no name of\nits own while the attribute sat on the wrapper. What happens instead is\nthat the label is rendered and clipped, so the name arrives through the\nsame `<label for>` a visible one does.\n\nThe rule is that `label` means a label, `aria-label` means a name, and\nneither means an unnamed field a screen reader announces as \"edit text\"."
|
|
6503
6534
|
},
|
|
6504
6535
|
{
|
|
6505
6536
|
"kind": "method",
|
|
@@ -6584,27 +6615,27 @@
|
|
|
6584
6615
|
}
|
|
6585
6616
|
}
|
|
6586
6617
|
],
|
|
6587
|
-
"description": "Reports \"required and empty\" and refreshes the message, or clears both.\n\
|
|
6618
|
+
"description": "Reports \"required and empty\" and refreshes the message, or clears both.\n\nTwo things differ between the controls that call this, so those are the\narguments: whether the control is empty, which only it can say, and the\nsentence to say about it, which is different for a box, a switch and a\nset. The anchor is looked up here because every one of them anchors on a\nrendered part and the browser needs somewhere to point the bubble.\n\nThe message is not derived from the control's kind, deliberately. \"Tick\nthis box\" and \"Choose one\" are not the same instruction and a lookup\ntable would be one more thing to keep in step with the components."
|
|
6588
6619
|
}
|
|
6589
6620
|
],
|
|
6590
6621
|
"attributes": [
|
|
6591
6622
|
{
|
|
6592
|
-
"name": "
|
|
6623
|
+
"name": "feedback",
|
|
6593
6624
|
"type": {
|
|
6594
6625
|
"text": "string"
|
|
6595
6626
|
},
|
|
6596
6627
|
"default": "''",
|
|
6597
|
-
"description": "
|
|
6598
|
-
"fieldName": "
|
|
6628
|
+
"description": "What is wrong, in the reader's words rather than the browser's.",
|
|
6629
|
+
"fieldName": "feedback"
|
|
6599
6630
|
},
|
|
6600
6631
|
{
|
|
6601
|
-
"name": "
|
|
6632
|
+
"name": "hint",
|
|
6602
6633
|
"type": {
|
|
6603
6634
|
"text": "string"
|
|
6604
6635
|
},
|
|
6605
6636
|
"default": "''",
|
|
6606
|
-
"description": "
|
|
6607
|
-
"fieldName": "
|
|
6637
|
+
"description": "Help under the control, shown while there is nothing wrong.",
|
|
6638
|
+
"fieldName": "hint"
|
|
6608
6639
|
},
|
|
6609
6640
|
{
|
|
6610
6641
|
"name": "label",
|
|
@@ -6720,7 +6751,7 @@
|
|
|
6720
6751
|
}
|
|
6721
6752
|
}
|
|
6722
6753
|
],
|
|
6723
|
-
"description": "Takes the pointer for a drag, and carries on if the platform refuses.\n\n**Capture is an enhancement, and the drag has to survive losing it.** What it\nbuys is events continuing to arrive once the pointer leaves the target, which\nmatters because a thin divider is easy to outrun. What it costs, called bare,\nis the rest of the handler: `setPointerCapture` throws `NotFoundError` when\nthe id names no active pointer, and every one of these calls sits above the\nlines that set the dragging flag and call `preventDefault`. So a refusal did\nnot degrade the drag, it canceled it.\n\nThat is reachable outside a test: a pointer released between the event being\nqueued and the handler running is gone by the time this is called, and a\nsynthetic `pointerdown` has no active pointer at all
|
|
6754
|
+
"description": "Takes the pointer for a drag, and carries on if the platform refuses.\n\n**Capture is an enhancement, and the drag has to survive losing it.** What it\nbuys is events continuing to arrive once the pointer leaves the target, which\nmatters because a thin divider is easy to outrun. What it costs, called bare,\nis the rest of the handler: `setPointerCapture` throws `NotFoundError` when\nthe id names no active pointer, and every one of these calls sits above the\nlines that set the dragging flag and call `preventDefault`. So a refusal did\nnot degrade the drag, it canceled it.\n\nThat is reachable outside a test: a pointer released between the event being\nqueued and the handler running is gone by the time this is called, and a\nsynthetic `pointerdown` has no active pointer at all.\n\nReturns whether it took, for the callers that then ask `hasPointerCapture`\nbefore believing a move belongs to them."
|
|
6724
6755
|
}
|
|
6725
6756
|
],
|
|
6726
6757
|
"exports": [
|
|
@@ -6760,7 +6791,7 @@
|
|
|
6760
6791
|
}
|
|
6761
6792
|
}
|
|
6762
6793
|
],
|
|
6763
|
-
"description": "The nearest ancestor that is an instance of a class, crossing shadow roots.\n\n**Identity rather than tag name
|
|
6794
|
+
"description": "The nearest ancestor that is an instance of a class, crossing shadow roots.\n\n**Identity rather than tag name.** Matching `helix-accordion-item` ties the\nheadless tier to the styled one by string, and only `@fusion.dev/helix`\nregisters a `helix-*` tag.\n\nThe consequence is silent rather than loud. Subclassing a headless element under\na different tag is exactly what the headless tier exists to allow, and it is\nwhat `helix/styled` itself does. Under a third tag a lookup by tag returns\n`null`, so an accordion's `mode` is ignored and every section behaves as\n`multiple` with no error anywhere.\n\n**`closest()` alone is not enough**, which is why this walks rather than\ndelegating. `closest()` stops at a shadow boundary: a component slotted into\nanother component's shadow root has a `parentNode` chain that ends at a\n`ShadowRoot`, and `closest` will not step across it. Following `host` is what\nmakes a nested arrangement resolve, and nesting through a slot is the\nordinary case for anything composable."
|
|
6764
6795
|
}
|
|
6765
6796
|
],
|
|
6766
6797
|
"exports": [
|
|
@@ -6794,7 +6825,7 @@
|
|
|
6794
6825
|
}
|
|
6795
6826
|
}
|
|
6796
6827
|
],
|
|
6797
|
-
"description": "Builds a stylesheet from CSS authored in a `.css` file.\n\nComponent styles live in real `.css` files rather than `css` tagged\ntemplates, so they get CSS tooling: syntax highlighting, formatters, the\ntoken linter, and a diff that reads as CSS. `
|
|
6828
|
+
"description": "Builds a stylesheet from CSS authored in a `.css` file.\n\nComponent styles live in real `.css` files rather than `css` tagged\ntemplates, so they get CSS tooling: syntax highlighting, formatters, the\ntoken linter, and a diff that reads as CSS. `turbo run styles` compiles each\none into a sibling `.css.ts` that calls this.\n\nThe `unsafe` in `unsafeCSS` warns about interpolating untrusted input into a\nstylesheet. That is not what happens here: the argument is a build-time\nconstant read from a file in this repo, never a runtime value. Wrapping it\nkeeps the warning where it belongs, on `unsafeCSS` itself, and gives one seam\nto change if constructable stylesheets become the better primitive."
|
|
6798
6829
|
}
|
|
6799
6830
|
],
|
|
6800
6831
|
"exports": [
|
|
@@ -6907,7 +6938,7 @@
|
|
|
6907
6938
|
}
|
|
6908
6939
|
}
|
|
6909
6940
|
],
|
|
6910
|
-
"description": "Draws an icon that was imported by name, rather than looked up by string.\n\n**`<helix-icon name=\"play\">` indexes the whole icon set at runtime.** Its\nrender is `icons[this.name]`, and no bundler can shake a dynamic index, so\nevery consumer of any component that renders one ships all of the generated\npath data: measured at 50,814 bytes raw and 15,010 gzipped for 102 icons, and\ngrowing about 147 gzipped bytes per icon added. A named import ships one path\nand is checked when the package compiles rather than
|
|
6941
|
+
"description": "Draws an icon that was imported by name, rather than looked up by string.\n\n**`<helix-icon name=\"play\">` indexes the whole icon set at runtime.** Its\nrender is `icons[this.name]`, and no bundler can shake a dynamic index, so\nevery consumer of any component that renders one ships all of the generated\npath data: measured at 50,814 bytes raw and 15,010 gzipped for 102 icons, and\ngrowing about 147 gzipped bytes per icon added. A named import ships one path\nand is checked when the package compiles rather than by a name lookup later.\n\nThat element still earns its place as *public* API, where a consumer writes a\nname in markup and a lookup is the only thing that can work. What it should\nnot be is how this library draws its own marks.\n\n**There is no `part` option, and there cannot be.** A part name behind an\ninterpolation is a part the manifest cannot see, so the component's own\nstylesheet matches nothing and the part stops being\nAPI. `Trend` needs one and therefore writes its `<svg>` out with a literal\n`part=\"icon\"`, which is the honest cost: a helper can carry everything except\nthe thing static analysis has to read.\n\n`data-glyph` rather than a class, because the sizing lives in\n`helix/styled/src/icon/glyph.css` and a component's own `--icon-size`\ndeclarations have to keep working untouched: the variable was read by\n`helix-icon`, and now it is read by the rule that sheet carries. Without it\nevery one of those declarations would go quietly dead and every mark in six\nfamilies would change size."
|
|
6911
6942
|
}
|
|
6912
6943
|
],
|
|
6913
6944
|
"exports": [
|
|
@@ -7062,7 +7093,7 @@
|
|
|
7062
7093
|
}
|
|
7063
7094
|
}
|
|
7064
7095
|
],
|
|
7065
|
-
"description": "Whether `node` sits inside `root`, following shadow boundaries upward.\n\n`Node.contains` walks `parentNode` and a shadow root's `parentNode` is null,\nso it answers false for anything inside a component. Paired with\n`deepActiveElement`, which returns exactly such a node, that pairing is a trap\nof its own: the two look like they belong together and one of them crosses.\n\n`
|
|
7096
|
+
"description": "Whether `node` sits inside `root`, following shadow boundaries upward.\n\n`Node.contains` walks `parentNode` and a shadow root's `parentNode` is null,\nso it answers false for anything inside a component. Paired with\n`deepActiveElement`, which returns exactly such a node, that pairing is a trap\nof its own: the two look like they belong together and one of them crosses.\n\n`contains(deepActiveElement())` is the shape to avoid: focus on a\n`helix-button` reports as the `<button>` in its shadow root, which is in no\nlight-DOM container anywhere, so a trap written that way reads every reader\nas already outside it.\n\n`host` is reached without naming `ShadowRoot`, which the server has no global\nfor. This runs from a keydown handler and would never execute there, but a\nbare reference is the kind that surfaces as a crash in Lit's result collector\nthe first time something calls it early."
|
|
7066
7097
|
}
|
|
7067
7098
|
],
|
|
7068
7099
|
"exports": [
|
|
@@ -7151,7 +7182,7 @@
|
|
|
7151
7182
|
}
|
|
7152
7183
|
}
|
|
7153
7184
|
],
|
|
7154
|
-
"description": "Writes a host's semantics onto its `ElementInternals`.\n\nOnto internals rather than onto the host, which is the whole point: an\nattribute written at upgrade is markup a React consumer's server output never\nhad, and hydration reports the difference. Internals carry the same meaning\nto the accessibility tree and leave the element as the consumer wrote it.\n\n**Empty means absent, and that is the trap this exists for.** Assigning `''`\nto `ariaLabel` is not the same as not naming the element: it is a name of no\ncharacters, which a screen reader announces as an unnamed control while every\ncheck for \"is it labeled\" passes.
|
|
7185
|
+
"description": "Writes a host's semantics onto its `ElementInternals`.\n\nOnto internals rather than onto the host, which is the whole point: an\nattribute written at upgrade is markup a React consumer's server output never\nhad, and hydration reports the difference. Internals carry the same meaning\nto the accessibility tree and leave the element as the consumer wrote it.\n\n**Empty means absent, and that is the trap this exists for.** Assigning `''`\nto `ariaLabel` is not the same as not naming the element: it is a name of no\ncharacters, which a screen reader announces as an unnamed control while every\ncheck for \"is it labeled\" passes. Clearing is `null`, and this is the one\nplace that has to remember it.\n\n**Element references are feature-tested rather than assumed.** They are the\nonly way a host in the light DOM can point at a node in its own shadow root,\nan IDREF cannot cross that boundary, and the plain `element.aria*Elements`\nreflection drops the reference where `ElementInternals` keeps it. Older\nengines have neither, and assigning to a property they do not implement is a\nsilent no-op rather than an error, so the guard is what makes the absence\nvisible to anything reading this.\n\nOmitted keys are left alone, so a component that sets its role once in\n`willUpdate` and its references later in `updated` does not have to repeat\nitself or risk clearing what the other call wrote."
|
|
7155
7186
|
}
|
|
7156
7187
|
],
|
|
7157
7188
|
"exports": [
|
|
@@ -7283,7 +7314,7 @@
|
|
|
7283
7314
|
"text": "ComplexAttributeConverter<boolean>"
|
|
7284
7315
|
},
|
|
7285
7316
|
"default": "{ fromAttribute: (value: string | null): boolean => value !== null && value !== 'false', /* Written out so it survives being reflected later. `''` rather than `'true'`, which is what a boolean attribute looks like everywhere else. */ toAttribute: (value: boolean): string | null => (value ? '' : 'false'), }",
|
|
7286
|
-
"description": "For a boolean property that is on unless a consumer says otherwise.\n\n**Lit's boolean converter cannot express false, and that is the whole\nproblem.** It answers `value !== null`, so an attribute is true by being\nthere: `modal` is true, `modal=\"\"` is true, and `modal=\"false\"` is true as\nwell, because it is present. A property defaulting to `true` therefore has no\nattribute that turns it off at all, and a consumer who writes the obvious\nthing gets the opposite of what they asked for, silently.\n\
|
|
7317
|
+
"description": "For a boolean property that is on unless a consumer says otherwise.\n\n**Lit's boolean converter cannot express false, and that is the whole\nproblem.** It answers `value !== null`, so an attribute is true by being\nthere: `modal` is true, `modal=\"\"` is true, and `modal=\"false\"` is true as\nwell, because it is present. A property defaulting to `true` therefore has no\nattribute that turns it off at all, and a consumer who writes the obvious\nthing gets the opposite of what they asked for, silently.\n\nSo: absent is the default, present is on, and the one string that means off\nis the one a consumer would write. `\"false\"` only, and not `\"0\"` or `\"no\"`,\nbecause a converter that accepts a vocabulary invites a consumer to guess at\nit, and the one they guess wrong is the one that silently means on.\n\n**The other answer is to invert the property, and it is worse.** `Drawer`\nwould take `modeless`, absent meaning modal, which satisfies the rule that a\nreflected property takes no default. It also renames the thing every consumer\nalready writes, to a word nobody reaches for, so that markup can express a\nstate that is rare. The name stays and the attribute learns to say no."
|
|
7287
7318
|
}
|
|
7288
7319
|
],
|
|
7289
7320
|
"exports": [
|
|
@@ -7316,7 +7347,8 @@
|
|
|
7316
7347
|
"text": "Element"
|
|
7317
7348
|
}
|
|
7318
7349
|
}
|
|
7319
|
-
]
|
|
7350
|
+
],
|
|
7351
|
+
"description": "Reads a table as series, one per data column.\n\n**The table is the chart's accessible representation, not a fallback for\none.** Every chart here takes its numbers from real markup rather than from a\nproperty, so the page is readable with no script at all, sortable by anything\nthat sorts tables, and correct in a screen reader without a parallel\ndescription that has to be kept in step by hand. A `values` array would be\neasier to pass and would make the accessible version the thing nobody\nmaintains.\n\nThe shape is the ordinary one: a header row naming the series, a first column\nof row headers, and numbers in the rest. A single-column table has one series\nand takes its name from the caption, since a header row of one is usually\nabsent.\n\n`data-value` wins over the cell's text, because `$1.2k` is what a reader\nshould see and is not a number. `Number()` rather than `parseFloat`, because\nthe second reads `12abc` as 12: a value that is nearly a number is a mistake\nworth dropping rather than rounding off, and a dropped point is visible where\na silently truncated one is not."
|
|
7320
7352
|
},
|
|
7321
7353
|
{
|
|
7322
7354
|
"kind": "function",
|
|
@@ -7449,7 +7481,7 @@
|
|
|
7449
7481
|
}
|
|
7450
7482
|
}
|
|
7451
7483
|
],
|
|
7452
|
-
"description": "Which item a value names, or the first that could stand in for it.\n\n`items.find(match) ?? items[0]` was written by hand in four components and it\nis not the obvious line it looks like. It is what makes a set whose `value`\nnames nothing still show something, which is every set before its consumer\nhas chosen and every set whose current item has just been removed.\n\nThe fallback skips disabled items and the match does not. A consumer who\nnames a disabled item meant it, and quietly moving to another would be the\ncomponent overruling them; but falling back *onto* a disabled item is the\ncomponent choosing, and it should not choose something out of play.
|
|
7484
|
+
"description": "Which item a value names, or the first that could stand in for it.\n\n`items.find(match) ?? items[0]` was written by hand in four components and it\nis not the obvious line it looks like. It is what makes a set whose `value`\nnames nothing still show something, which is every set before its consumer\nhas chosen and every set whose current item has just been removed.\n\nThe fallback skips disabled items and the match does not. A consumer who\nnames a disabled item meant it, and quietly moving to another would be the\ncomponent overruling them; but falling back *onto* a disabled item is the\ncomponent choosing, and it should not choose something out of play. Taking\n`items[0]` either way opens a set on a disabled first item and shows it as\ncurrent.\n\nA plain function rather than only a method on `MixinControllerActive`,\nbecause the components that need it are split across two mixins: a set whose\nvalue is submitted takes `MixinControllerValue` and cannot also take the\nactive one without two properties called `value`."
|
|
7453
7485
|
}
|
|
7454
7486
|
],
|
|
7455
7487
|
"exports": [
|
|
@@ -7692,7 +7724,7 @@
|
|
|
7692
7724
|
}
|
|
7693
7725
|
}
|
|
7694
7726
|
],
|
|
7695
|
-
"description": "Whether a consumer put anything in a slot.\n\n**There is no selector for this**, which is why it is script. `slot:empty`\nlooks like the answer and is not: a slot's children are its *fallback*, and\nassigned nodes are not children, so `:empty` is true whenever the fallback is\nabsent whether or not the consumer slotted anything. `:host(:has(...))` is\ninvalid CSS, and the server has no children to inspect.\n\nThe answer matters because an empty wrapper is not free. A region that\ngenerates a box is a flex item or a grid item whether or not it holds\nanything, so it takes the container's gap: an announcement with no actions\
|
|
7727
|
+
"description": "Whether a consumer put anything in a slot.\n\n**There is no selector for this**, which is why it is script. `slot:empty`\nlooks like the answer and is not: a slot's children are its *fallback*, and\nassigned nodes are not children, so `:empty` is true whenever the fallback is\nabsent whether or not the consumer slotted anything. `:host(:has(...))` is\ninvalid CSS, and the server has no children to inspect.\n\nThe answer matters because an empty wrapper is not free. A region that\ngenerates a box is a flex item or a grid item whether or not it holds\nanything, so it takes the container's gap: an announcement with no actions\npays the row gap twice. `display: none` is the only fix, because only a box\nthat is not generated has no gap beside it.\n\nText or an element, because neither alone is the test. An element on its own\ncounts a whitespace-only span as content; text on its own counts an icon as\nnothing.\n\n`flatten` is deliberate here, unlike the tooltip's emptiness test: this asks\n\"will anything render\", where that one asks \"did the consumer provide\nanything\", and a slot showing its fallback does render."
|
|
7696
7728
|
}
|
|
7697
7729
|
],
|
|
7698
7730
|
"exports": [
|
|
@@ -7732,7 +7764,7 @@
|
|
|
7732
7764
|
}
|
|
7733
7765
|
}
|
|
7734
7766
|
],
|
|
7735
|
-
"description": "Tells a slotted trigger that it opens something, and whether it is open.\n\n**
|
|
7767
|
+
"description": "Tells a slotted trigger that it opens something, and whether it is open.\n\n**Writing `aria-expanded` onto the consumer's element is a hydration\nmismatch, so it is not written.** The gap that answer was reaching for is\nreal: a consumer who has to mirror `open` back onto their own trigger is a\nconsumer who will forget, and the failure is silent to everyone who can see\nthe screen. It is still the wrong answer, because a component decorating a\nconsumer's markup after upgrading is one whose output a React consumer's\nhydration disagrees with.\n\n**Measured 28 Aug 2026 against React 19.2.8.** Four\nfamilies were server-rendered as React emits them and hydrated with the\nelement definitions loaded either side of `hydrateRoot`:\n\n```\ncase writes to trigger hydration mismatch\nmegamenu aria-expanded yes, both load orders\nspeed dial aria-expanded yes, both load orders\npopover nothing no\nmenu nothing no\n```\n\nReact reports \"some attributes of the server rendered HTML didn't match the\nclient properties. This won't be patched up\", and the cost is not the console\nline: it answers a mismatch by discarding the server's HTML for that subtree\nand rebuilding it, which is what the carousel's own note records blinding an\n`<helix-aura>` two sections away.\n\n**A property crosses the gap that an attribute cannot.** React diffs the\nattributes it rendered and never looks at a property, so the state reaches\nthe trigger, lands as `aria-expanded` inside *that element's* shadow root,\nand the consumer's markup is exactly what they served. Both positions get\nwhat they were protecting: nothing is written onto the consumer's element,\nand the reader is still told what the control does.\n\n**Set before upgrade is safe**, which is what lets this run without waiting\nfor a definition: `ReactiveElement` captures an instance property assigned\nbefore it upgrades and re-applies it, so a trigger whose module has not\nloaded yet still ends up with the value.\n\n**A plain element is warned about rather than written to.** A\n`<button slot=\"trigger\">` has no shadow root to keep the state out of the\nmarkup and no property to take it, and a consumer cannot mirror it themselves\nbecause the open state belongs to the component. Saying so once is the same\nanswer `Tooltip` gives about the link it will not write for them."
|
|
7736
7768
|
}
|
|
7737
7769
|
],
|
|
7738
7770
|
"exports": [
|
|
@@ -7797,7 +7829,7 @@
|
|
|
7797
7829
|
"text": "Record<HelixStatusTone, ToneMark>"
|
|
7798
7830
|
},
|
|
7799
7831
|
"default": "{ danger: { icon: xCircleFill, label: 'Error' }, info: { icon: infoFill, label: 'Information' }, success: { icon: checkCircleFill, label: 'Success' }, warning: { icon: warningFill, label: 'Warning' }, }",
|
|
7800
|
-
"description": "The one status vocabulary.\n\
|
|
7832
|
+
"description": "The one status vocabulary.\n\nA reader meets these marks in a passage and in a message and has to read them\nas the same four things, so there is one place they come from.\n\n**Filled at every tone**, or a set meant to be read as one vocabulary has a\nmember drawn a different way. Filled because a tone mark is a status\nindicator and not an action: it wants to read at a glance and at a small\nsize, where an outline at this weight loses its interior.\n\n**The label is not the tone name.** `danger` is announced as \"Error\",\nbecause that is the word a reader understands and `danger` is the word the API\nuses. Both matter and they are not the same string."
|
|
7801
7833
|
},
|
|
7802
7834
|
{
|
|
7803
7835
|
"kind": "function",
|