@fusion.dev/helix-core 0.25.1 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/custom-elements.json +833 -114
- package/dist/controllers/chart-pointer-controller/chart-pointer-controller.d.ts +23 -1
- package/dist/controllers/chart-pointer-controller/chart-pointer-controller.js +23 -26
- package/dist/controllers/dismiss-controller/dismiss-controller.d.ts +27 -0
- package/dist/controllers/dismiss-controller/dismiss-controller.js +17 -2
- package/dist/controllers/floating-controller/floating-controller.d.ts +13 -0
- package/dist/controllers/floating-controller/floating-controller.js +3 -1
- package/dist/controllers/indicator-controller/indicator-controller.d.ts +16 -0
- package/dist/controllers/indicator-controller/indicator-controller.js +7 -0
- package/dist/controllers/popover-controller/popover-controller.d.ts +22 -0
- package/dist/controllers/popover-controller/popover-controller.js +12 -0
- package/dist/controllers/source-controller/source-controller.d.ts +45 -3
- package/dist/controllers/source-controller/source-controller.js +33 -21
- package/dist/helix-element/helix-element.d.ts +19 -0
- package/dist/helix-element/helix-element.js +5 -94
- package/dist/helix-element/react-bridge.d.ts +104 -0
- package/dist/helix-element/react-bridge.js +94 -0
- package/dist/helix-form-element/helix-form-element.d.ts +19 -0
- package/dist/helix-form-element/helix-form-element.js +6 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/mixins/mixin-chart-source/mixin-chart-source.d.ts +1 -1
- package/dist/mixins/mixin-chart-source/mixin-chart-source.js +2 -5
- package/dist/mixins/mixin-controller-value/mixin-controller-value.js +2 -2
- package/dist/mixins/mixin-field/mixin-field.js +2 -2
- package/dist/mixins/mixin-picker-editing/mixin-picker-editing.d.ts +48 -0
- package/dist/mixins/mixin-picker-editing/mixin-picker-editing.js +43 -0
- package/dist/mixins/mixin-picker-field/mixin-picker-field.d.ts +118 -0
- package/dist/mixins/mixin-picker-field/mixin-picker-field.js +79 -0
- package/dist/utils/draw-icon/draw-icon.d.ts +1 -1
- package/dist/utils/draw-tooltip/draw-tooltip.js +1 -0
- package/package.json +4 -4
- package/dist/mixins/mixin-collection/index.d.ts +0 -1
- package/dist/mixins/mixin-collection/index.js +0 -1
- package/dist/utils/close-markdown/close-markdown.d.ts +0 -39
- package/dist/utils/close-markdown/close-markdown.js +0 -51
package/custom-elements.json
CHANGED
|
@@ -118,29 +118,29 @@
|
|
|
118
118
|
"members": [
|
|
119
119
|
{
|
|
120
120
|
"kind": "field",
|
|
121
|
-
"name": "
|
|
122
|
-
"privacy": "private",
|
|
121
|
+
"name": "host",
|
|
123
122
|
"type": {
|
|
124
123
|
"text": "ChartPointerHost"
|
|
125
124
|
},
|
|
125
|
+
"privacy": "private",
|
|
126
126
|
"default": "host"
|
|
127
127
|
},
|
|
128
128
|
{
|
|
129
129
|
"kind": "field",
|
|
130
|
-
"name": "
|
|
131
|
-
"privacy": "private",
|
|
130
|
+
"name": "moved",
|
|
132
131
|
"type": {
|
|
133
132
|
"text": "boolean"
|
|
134
133
|
},
|
|
134
|
+
"privacy": "private",
|
|
135
135
|
"default": "false"
|
|
136
136
|
},
|
|
137
137
|
{
|
|
138
138
|
"kind": "field",
|
|
139
|
-
"name": "
|
|
140
|
-
"privacy": "private",
|
|
139
|
+
"name": "plot",
|
|
141
140
|
"type": {
|
|
142
141
|
"text": "HTMLElement | undefined"
|
|
143
|
-
}
|
|
142
|
+
},
|
|
143
|
+
"privacy": "private"
|
|
144
144
|
},
|
|
145
145
|
{
|
|
146
146
|
"kind": "field",
|
|
@@ -190,14 +190,14 @@
|
|
|
190
190
|
},
|
|
191
191
|
{
|
|
192
192
|
"kind": "method",
|
|
193
|
-
"name": "
|
|
193
|
+
"name": "box",
|
|
194
194
|
"privacy": "private",
|
|
195
195
|
"return": {
|
|
196
196
|
"type": {
|
|
197
197
|
"text": "DOMRect | undefined"
|
|
198
198
|
}
|
|
199
199
|
},
|
|
200
|
-
"description": "The box the readings are laid out in, which is the plot and not the host.\n\nThe host also holds the row of labels, so measuring against it would map\nthe pointer over a box taller than the drawing. That mattered the moment a\nchart started measuring down the box rather than across it, which is what\n`axis` is for: on a horizontal bar chart the labels are beside the plot\nrather than under it, and the host is wider than the drawing by exactly\ntheir column."
|
|
200
|
+
"description": "The box the readings are laid out in, which is the plot and not the host.\n\nThe host also holds the row of labels, so measuring against it would map\nthe pointer over a box taller than the drawing. That mattered the moment a\nchart started measuring down the box rather than across it, which is what\n`axis` is for: on a horizontal bar chart the labels are beside the plot\nrather than under it, and the host is wider than the drawing by exactly\ntheir column.\n\n**Held only while it is still in the tree.** Every chart renders a\ndifferent template for its empty state, so the plot a pointer crossed\nbefore the table filled is a node Lit has since replaced: held forever, it\nmeasures a detached box and the tooltip never appears. Looked up again\nwhenever the held one has left, which is once per data arrival rather than\nonce per move."
|
|
201
201
|
},
|
|
202
202
|
{
|
|
203
203
|
"kind": "method",
|
|
@@ -219,13 +219,13 @@
|
|
|
219
219
|
},
|
|
220
220
|
{
|
|
221
221
|
"kind": "field",
|
|
222
|
-
"name": "
|
|
222
|
+
"name": "move",
|
|
223
223
|
"privacy": "private",
|
|
224
224
|
"readonly": true
|
|
225
225
|
},
|
|
226
226
|
{
|
|
227
227
|
"kind": "field",
|
|
228
|
-
"name": "
|
|
228
|
+
"name": "leave",
|
|
229
229
|
"privacy": "private",
|
|
230
230
|
"readonly": true
|
|
231
231
|
}
|
|
@@ -602,7 +602,17 @@
|
|
|
602
602
|
"text": "Document[]"
|
|
603
603
|
}
|
|
604
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."
|
|
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.\n\n**And walked only where the page holds a frame at all.** The walk is every\nelement on the page, through every shadow root, and it ran on every\n`activate`, which is every tooltip hover and every menu opening. Measured\nin Chromium on 14 Sep 2026, on a page of 10,006 elements across 500 shadow\nroots, which is the shape of a docs page: 1.36ms per walk, against a\nlength read on `getElementsByTagName('iframe')` too small for\n`performance.now` to resolve over 20,000 runs. That collection is live and\nthe engine keeps its count, so asking it is a read rather than a search.\n\n**What the count cannot see is a frame inside a shadow root**, and that is\na trade made knowingly rather than an oversight. A page whose only frame\nsits in a shadow root reads as having none and skips the walk, so a\nsame-origin frame rendered by a component is not listened to there. The\none frame this library renders inside a shadow root is the sandbox's\npreview, which is sandboxed without `allow-same-origin` and so is a\ndocument this one may not read whether or not it is found: the blur\nsignal is what covers it, and the walk never could. A page with a frame in\nthe light DOM still walks, shadow roots included.\n\nHeld for the rest of the run as well, so overlays that activate together,\na dialog opening a select from its own `updated`, walk once between them.\nA microtask and no longer: what a frame gathered here is good for is the\nlifetime of one open, and the task after this one is a page that may have\ngained a frame."
|
|
606
|
+
},
|
|
607
|
+
{
|
|
608
|
+
"kind": "field",
|
|
609
|
+
"name": "found",
|
|
610
|
+
"type": {
|
|
611
|
+
"text": "Document[] | undefined"
|
|
612
|
+
},
|
|
613
|
+
"privacy": "private",
|
|
614
|
+
"static": true,
|
|
615
|
+
"description": "What the last walk found, for the rest of the run it was made in."
|
|
606
616
|
},
|
|
607
617
|
{
|
|
608
618
|
"kind": "field",
|
|
@@ -916,6 +926,15 @@
|
|
|
916
926
|
"default": "'bottom-start'",
|
|
917
927
|
"description": "The placement in use after the last measurement."
|
|
918
928
|
},
|
|
929
|
+
{
|
|
930
|
+
"kind": "field",
|
|
931
|
+
"name": "padding",
|
|
932
|
+
"type": {
|
|
933
|
+
"text": "number | undefined"
|
|
934
|
+
},
|
|
935
|
+
"privacy": "private",
|
|
936
|
+
"description": "How far the arrow keeps from the floating element's ends, measured once.\n\n`autoUpdate` runs `update` on every scroll frame of every ancestor, and\n`corner` is a `getComputedStyle` and four parses, which was a style read\nper frame for a number that does not change while the surface is up. So it\nis read as placing starts, when the surface has just been shown and has a\ncomputed style to read, and forgotten as placing stops, so a surface\nrestyled between opens is measured again. `update` measures for itself\nwhere nothing started it, which is a `reposition` on a surface placed by\nits own stylesheet."
|
|
937
|
+
},
|
|
919
938
|
{
|
|
920
939
|
"kind": "method",
|
|
921
940
|
"name": "start",
|
|
@@ -1126,6 +1145,17 @@
|
|
|
1126
1145
|
}
|
|
1127
1146
|
}
|
|
1128
1147
|
},
|
|
1148
|
+
{
|
|
1149
|
+
"kind": "method",
|
|
1150
|
+
"name": "watch",
|
|
1151
|
+
"privacy": "private",
|
|
1152
|
+
"return": {
|
|
1153
|
+
"type": {
|
|
1154
|
+
"text": "void"
|
|
1155
|
+
}
|
|
1156
|
+
},
|
|
1157
|
+
"description": "Watches whatever `observe` names now, which `place` asks for on every placement."
|
|
1158
|
+
},
|
|
1129
1159
|
{
|
|
1130
1160
|
"kind": "method",
|
|
1131
1161
|
"name": "hostDisconnected",
|
|
@@ -1373,6 +1403,16 @@
|
|
|
1373
1403
|
"description": "Whether the surface is showing.",
|
|
1374
1404
|
"readonly": true
|
|
1375
1405
|
},
|
|
1406
|
+
{
|
|
1407
|
+
"kind": "method",
|
|
1408
|
+
"name": "hostUpdated",
|
|
1409
|
+
"return": {
|
|
1410
|
+
"type": {
|
|
1411
|
+
"text": "void"
|
|
1412
|
+
}
|
|
1413
|
+
},
|
|
1414
|
+
"description": "Puts the surface where the host's `open` says, however it got there."
|
|
1415
|
+
},
|
|
1376
1416
|
{
|
|
1377
1417
|
"kind": "field",
|
|
1378
1418
|
"name": "places",
|
|
@@ -1458,31 +1498,57 @@
|
|
|
1458
1498
|
"members": [
|
|
1459
1499
|
{
|
|
1460
1500
|
"kind": "field",
|
|
1461
|
-
"name": "
|
|
1462
|
-
"privacy": "private",
|
|
1501
|
+
"name": "host",
|
|
1463
1502
|
"type": {
|
|
1464
1503
|
"text": "SourceHost"
|
|
1465
1504
|
},
|
|
1505
|
+
"privacy": "private",
|
|
1466
1506
|
"default": "host"
|
|
1467
1507
|
},
|
|
1468
1508
|
{
|
|
1469
1509
|
"kind": "field",
|
|
1470
|
-
"name": "
|
|
1471
|
-
"privacy": "private",
|
|
1510
|
+
"name": "observer",
|
|
1472
1511
|
"type": {
|
|
1473
1512
|
"text": "MutationObserver | undefined"
|
|
1474
|
-
}
|
|
1513
|
+
},
|
|
1514
|
+
"privacy": "private"
|
|
1475
1515
|
},
|
|
1476
1516
|
{
|
|
1477
1517
|
"kind": "field",
|
|
1478
|
-
"name": "
|
|
1479
|
-
"privacy": "private",
|
|
1518
|
+
"name": "deferred",
|
|
1480
1519
|
"type": {
|
|
1481
1520
|
"text": "boolean"
|
|
1482
1521
|
},
|
|
1522
|
+
"privacy": "private",
|
|
1483
1523
|
"default": "false",
|
|
1484
1524
|
"description": "Whether a hydrating render was told there was nothing, and needs the render after."
|
|
1485
1525
|
},
|
|
1526
|
+
{
|
|
1527
|
+
"kind": "field",
|
|
1528
|
+
"name": "version",
|
|
1529
|
+
"type": {
|
|
1530
|
+
"text": "number"
|
|
1531
|
+
},
|
|
1532
|
+
"privacy": "private",
|
|
1533
|
+
"default": "0",
|
|
1534
|
+
"description": "Which edit of the table the parses below belong to.\n\nMoved by the watcher and by `watch()`, which are the two things that can\nchange what a chart reads without the chart doing anything: an edit to the\ntable, and `for` naming another one."
|
|
1535
|
+
},
|
|
1536
|
+
{
|
|
1537
|
+
"kind": "field",
|
|
1538
|
+
"name": "heldRows",
|
|
1539
|
+
"type": {
|
|
1540
|
+
"text": "Parsed<Row[]> | undefined"
|
|
1541
|
+
},
|
|
1542
|
+
"privacy": "private"
|
|
1543
|
+
},
|
|
1544
|
+
{
|
|
1545
|
+
"kind": "field",
|
|
1546
|
+
"name": "heldSeries",
|
|
1547
|
+
"type": {
|
|
1548
|
+
"text": "Parsed<Series[]> | undefined"
|
|
1549
|
+
},
|
|
1550
|
+
"privacy": "private"
|
|
1551
|
+
},
|
|
1486
1552
|
{
|
|
1487
1553
|
"kind": "field",
|
|
1488
1554
|
"name": "element",
|
|
@@ -1494,7 +1560,7 @@
|
|
|
1494
1560
|
},
|
|
1495
1561
|
{
|
|
1496
1562
|
"kind": "method",
|
|
1497
|
-
"name": "
|
|
1563
|
+
"name": "resolve",
|
|
1498
1564
|
"privacy": "private",
|
|
1499
1565
|
"return": {
|
|
1500
1566
|
"type": {
|
|
@@ -1509,9 +1575,43 @@
|
|
|
1509
1575
|
"type": {
|
|
1510
1576
|
"text": "Series[]"
|
|
1511
1577
|
},
|
|
1512
|
-
"description": "The series it holds, or none.",
|
|
1578
|
+
"description": "The series it holds, or none.\n\n**Parsed once per edit, not once per read.** A chart's render asks for\nthese several times over, and the pointer asks for the row count on every\nmove, so parsing the whole table on each read was a table walk per\npointermove. The parse is held against the table it came from and the\nedit it saw, and let go when either moves: `element` is compared by\nidentity, so a table replaced under the same id parses again, and the\nwatcher moves the version on every mutation it delivers.\n\nWhich is a microtask after the edit, the observer being what it is. A\nread in the same run as the edit answers the parse before it, and every\nrender that follows, which is what the watcher exists to ask for, answers\nthe one after. The same array comes back until then, so a consumer may\ncompare by identity.",
|
|
1579
|
+
"readonly": true
|
|
1580
|
+
},
|
|
1581
|
+
{
|
|
1582
|
+
"kind": "field",
|
|
1583
|
+
"name": "rows",
|
|
1584
|
+
"type": {
|
|
1585
|
+
"text": "Row[]"
|
|
1586
|
+
},
|
|
1587
|
+
"description": "Every row it holds, text and number alike, or none. Held the way `series` is.",
|
|
1513
1588
|
"readonly": true
|
|
1514
1589
|
},
|
|
1590
|
+
{
|
|
1591
|
+
"kind": "method",
|
|
1592
|
+
"name": "parsed",
|
|
1593
|
+
"privacy": "private",
|
|
1594
|
+
"return": {
|
|
1595
|
+
"type": {
|
|
1596
|
+
"text": "Parsed<T>"
|
|
1597
|
+
}
|
|
1598
|
+
},
|
|
1599
|
+
"parameters": [
|
|
1600
|
+
{
|
|
1601
|
+
"name": "held",
|
|
1602
|
+
"type": {
|
|
1603
|
+
"text": "Parsed<T> | undefined"
|
|
1604
|
+
}
|
|
1605
|
+
},
|
|
1606
|
+
{
|
|
1607
|
+
"name": "read",
|
|
1608
|
+
"type": {
|
|
1609
|
+
"text": "(table: Element | null) => T"
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
],
|
|
1613
|
+
"description": "A held parse where it still describes the table, or a fresh one."
|
|
1614
|
+
},
|
|
1515
1615
|
{
|
|
1516
1616
|
"kind": "method",
|
|
1517
1617
|
"name": "hostConnected",
|
|
@@ -3368,6 +3468,25 @@
|
|
|
3368
3468
|
],
|
|
3369
3469
|
"description": "One composed tag, as a static value a template can interpolate.\n\n`unsafeStatic` is safe by construction: the name is a literal in our own\nsource and the prefix is one of two strings this class defines. Called per\nrender and not cached, which costs nothing, because `static-html` keys its\ntemplate cache on the joined string rather than on the object."
|
|
3370
3470
|
},
|
|
3471
|
+
{
|
|
3472
|
+
"kind": "method",
|
|
3473
|
+
"name": "partNamed",
|
|
3474
|
+
"privacy": "protected",
|
|
3475
|
+
"return": {
|
|
3476
|
+
"type": {
|
|
3477
|
+
"text": "T | null"
|
|
3478
|
+
}
|
|
3479
|
+
},
|
|
3480
|
+
"parameters": [
|
|
3481
|
+
{
|
|
3482
|
+
"name": "name",
|
|
3483
|
+
"type": {
|
|
3484
|
+
"text": "string"
|
|
3485
|
+
}
|
|
3486
|
+
}
|
|
3487
|
+
],
|
|
3488
|
+
"description": "One of this element's own parts, by name, or null where it is not rendered.\n\nNot `part`, which every element already has: `Element.part` is the\n`DOMTokenList` of the names the element itself carries, and a method under\nthat name is a type error on every subclass.\n\n**One guard for every lookup.** Lit's server shim has no `querySelector`\non the render root, so a lookup reached during a server render, from a\ngetter a template reads or from `willUpdate`, throws there and nowhere\nelse. Four spellings of the same guard had grown across the library, and\na fifth site with none. Null on the server, which is what the rest of the\ncode already treats a part that has not rendered as.\n\n`helix component`'s `selectors` reads these calls the way it reads a\n`querySelector('[part=\"x\"]')`, so a name nothing renders is a finding\nrather than a null an optional chain swallows."
|
|
3489
|
+
},
|
|
3371
3490
|
{
|
|
3372
3491
|
"kind": "field",
|
|
3373
3492
|
"name": "internals",
|
|
@@ -3631,6 +3750,155 @@
|
|
|
3631
3750
|
}
|
|
3632
3751
|
]
|
|
3633
3752
|
},
|
|
3753
|
+
{
|
|
3754
|
+
"kind": "javascript-module",
|
|
3755
|
+
"path": "src/helix-element/react-bridge.ts",
|
|
3756
|
+
"declarations": [
|
|
3757
|
+
{
|
|
3758
|
+
"kind": "function",
|
|
3759
|
+
"name": "reactPropsOf",
|
|
3760
|
+
"return": {
|
|
3761
|
+
"type": {
|
|
3762
|
+
"text": "Record<string, unknown> | undefined"
|
|
3763
|
+
}
|
|
3764
|
+
},
|
|
3765
|
+
"parameters": [
|
|
3766
|
+
{
|
|
3767
|
+
"name": "node",
|
|
3768
|
+
"type": {
|
|
3769
|
+
"text": "EventTarget"
|
|
3770
|
+
}
|
|
3771
|
+
}
|
|
3772
|
+
],
|
|
3773
|
+
"description": "The props React is holding for a node, if React is holding any."
|
|
3774
|
+
},
|
|
3775
|
+
{
|
|
3776
|
+
"kind": "function",
|
|
3777
|
+
"name": "auditReactProps",
|
|
3778
|
+
"return": {
|
|
3779
|
+
"type": {
|
|
3780
|
+
"text": "void"
|
|
3781
|
+
}
|
|
3782
|
+
},
|
|
3783
|
+
"parameters": [
|
|
3784
|
+
{
|
|
3785
|
+
"name": "host",
|
|
3786
|
+
"type": {
|
|
3787
|
+
"text": "EventTarget"
|
|
3788
|
+
}
|
|
3789
|
+
},
|
|
3790
|
+
{
|
|
3791
|
+
"name": "props",
|
|
3792
|
+
"type": {
|
|
3793
|
+
"text": "Record<string, unknown>"
|
|
3794
|
+
}
|
|
3795
|
+
}
|
|
3796
|
+
],
|
|
3797
|
+
"description": "Says so when a handler prop is attached to nothing.\n\n**TypeScript will not catch any of this, and that is not our tooling's\nfault.** A JSX attribute whose name is not a valid identifier is exempt from\nchecking on an intrinsic element, and every one of ours carries a hyphen. So\n`onhelix-opne` type-checks, `on:helix-open` type-checks, and a made-up\n`totally-invented` prop type-checks, all against fully generated types that\ndo reject a wrong *value* on a normal attribute. Measured with `tsc`.\n\nThat leaves runtime as the only place a typo can be caught, and React's props\nbag as the only place to look, which the binding above already reads. Once per\nelement, because a warning that repeats on every keystroke is one a consumer\nsilences.\n\n`on:helix-open` gets its own message because it is not a mistake so much as\nthe wrong dialect. It is what the Solid types offer, correctly, and React\nbinds it as an event named `:helix-open`."
|
|
3798
|
+
},
|
|
3799
|
+
{
|
|
3800
|
+
"kind": "function",
|
|
3801
|
+
"name": "reactPropFor",
|
|
3802
|
+
"return": {
|
|
3803
|
+
"type": {
|
|
3804
|
+
"text": "string | undefined"
|
|
3805
|
+
}
|
|
3806
|
+
},
|
|
3807
|
+
"parameters": [
|
|
3808
|
+
{
|
|
3809
|
+
"name": "event",
|
|
3810
|
+
"type": {
|
|
3811
|
+
"text": "Event"
|
|
3812
|
+
}
|
|
3813
|
+
}
|
|
3814
|
+
],
|
|
3815
|
+
"description": "The prop React would be holding for this event, if it is holding one.\n\n**A relayed native event needs a different answer from one of ours, and\ngetting it wrong doubles every call.** Measured against React 19.2.8:\n\n```\nonhelix-before-change <- helix-before-change REACHED (React binds it with addEventListener)\nonChange <- change REACHED (React's delegated root listener)\nonLoad <- load not reached\nonError <- error not reached\nonEnded <- ended not reached\n```\n\nReact binds a hyphenated prop directly on the element, so our own events are\nreached by name and are safe to bind again: same type, same callback, same\ncapture flag is a no-op by specification. A native name is different. React\nrecognizes `onChange` and `onLoad` as its own registration names and attaches\nnothing to the element for either; it relies on a delegated listener at the\nroot, which sees an event only if it **bubbles**, and on a non-delegated list\nit sets up for `<video>`, `<audio>` and `<img>` and never for a custom\nelement.\n\nSo a bubbling relay already arrives and must not be bound again: React's\nlistener is at the root rather than on the element, so nothing deduplicates\nit and the consumer's handler runs twice. A non-bubbling relay arrives\nnowhere, and is the bug this exists to close: `<helix-avatar>` relays `load`\nand `error`, `<helix-video>` relays `ended`, `play` and `pause`, all of them\ndeclared public API and all of them otherwise silent in React.\n\nThe name is React's own casing, `onError` rather than `onerror`, because that\nis what a consumer writes and therefore what is in the props bag. Every\nnative we relay is a single word, so capitalising the first letter is the\nwhole of the rule; a two-word name like `loadeddata` would be `onLoadedData`\nand needs the list extending rather than the rule generalising."
|
|
3816
|
+
},
|
|
3817
|
+
{
|
|
3818
|
+
"kind": "function",
|
|
3819
|
+
"name": "bindReactHandler",
|
|
3820
|
+
"return": {
|
|
3821
|
+
"type": {
|
|
3822
|
+
"text": "void"
|
|
3823
|
+
}
|
|
3824
|
+
},
|
|
3825
|
+
"parameters": [
|
|
3826
|
+
{
|
|
3827
|
+
"name": "host",
|
|
3828
|
+
"type": {
|
|
3829
|
+
"text": "EventTarget"
|
|
3830
|
+
}
|
|
3831
|
+
},
|
|
3832
|
+
{
|
|
3833
|
+
"name": "event",
|
|
3834
|
+
"type": {
|
|
3835
|
+
"text": "Event"
|
|
3836
|
+
}
|
|
3837
|
+
}
|
|
3838
|
+
]
|
|
3839
|
+
},
|
|
3840
|
+
{
|
|
3841
|
+
"kind": "function",
|
|
3842
|
+
"name": "applyReactProperties",
|
|
3843
|
+
"return": {
|
|
3844
|
+
"type": {
|
|
3845
|
+
"text": "boolean"
|
|
3846
|
+
}
|
|
3847
|
+
},
|
|
3848
|
+
"parameters": [
|
|
3849
|
+
{
|
|
3850
|
+
"name": "host",
|
|
3851
|
+
"type": {
|
|
3852
|
+
"text": "LitElement"
|
|
3853
|
+
}
|
|
3854
|
+
}
|
|
3855
|
+
],
|
|
3856
|
+
"description": "Assigns the object and function properties React is holding and never applied.\n\n**The same hydration bug as the handlers above, and it needed its own fix.**\nReact skips every prop it would have to apply imperatively while hydrating,\nnot only listeners. Strings, numbers and booleans arrive anyway, because the\nserver wrote them as attributes and Lit converts them back. An object or a\nfunction arrives by no route at all, and both halves of React agree to drop\nit: the server renderer reaches its custom element branch, finds\n`typeof value === 'object'` and `continue`s, so nothing is written into the\nHTML; and the client's hydrate path only diffs and warns for a custom element,\nnever reaching `setPropOnCustomElement`. Two skips that match, so there is no\nmismatch to report and no warning anywhere.\n\n**The binding trick above does not transfer, which is why this is separate.**\nA listener only has to exist by the time somebody interacts, so binding it at\ndispatch is late enough that hydration has certainly finished and early enough\nto catch the event being sent. A property has to be right before the first\npaint. `connectedCallback` is the obvious early moment and is the wrong one,\nmeasured: an element upgrades when its definition loads, which falls either\nside of hydration depending on how the consumer imported it, and on the side\nthis is for it is too early to see anything.\n\n**Only what the class declared, and only what could not have arrived as an\nattribute.** The first is what stops an arbitrary JSX prop being written onto\nthe element; the second is what keeps this to the properties that are actually\nbroken, rather than re-applying a string that is already correct. Three\nqualify today, `rows` on the data table and `cell` and `compare` on a table\ncolumn; the remaining `attribute: false` properties are booleans and strings a\nparent writes at runtime, which no consumer passes and this never touches.\n\n**`null` is the one place this does not reproduce a client mount, and it is\ndeliberate.** `typeof null` is `'object'`, and React assigns a null prop on a\nclient mount while dropping it on the server, so it is genuinely inside the\ngap this closes. Assigning it would faithfully reproduce a crash: the server\nleft the class default standing, and replacing that default with `null` is the\none case where closing the gap makes the page worse than leaving it open.\n\nIdempotent, so the handover needs no bookkeeping. Lit compares by identity, so\nReact's next commit assigning the same value schedules no update, and one\nassigning a different value is a change whoever writes it."
|
|
3857
|
+
}
|
|
3858
|
+
],
|
|
3859
|
+
"exports": [
|
|
3860
|
+
{
|
|
3861
|
+
"kind": "js",
|
|
3862
|
+
"name": "reactPropsOf",
|
|
3863
|
+
"declaration": {
|
|
3864
|
+
"name": "reactPropsOf",
|
|
3865
|
+
"module": "src/helix-element/react-bridge.ts"
|
|
3866
|
+
}
|
|
3867
|
+
},
|
|
3868
|
+
{
|
|
3869
|
+
"kind": "js",
|
|
3870
|
+
"name": "auditReactProps",
|
|
3871
|
+
"declaration": {
|
|
3872
|
+
"name": "auditReactProps",
|
|
3873
|
+
"module": "src/helix-element/react-bridge.ts"
|
|
3874
|
+
}
|
|
3875
|
+
},
|
|
3876
|
+
{
|
|
3877
|
+
"kind": "js",
|
|
3878
|
+
"name": "reactPropFor",
|
|
3879
|
+
"declaration": {
|
|
3880
|
+
"name": "reactPropFor",
|
|
3881
|
+
"module": "src/helix-element/react-bridge.ts"
|
|
3882
|
+
}
|
|
3883
|
+
},
|
|
3884
|
+
{
|
|
3885
|
+
"kind": "js",
|
|
3886
|
+
"name": "bindReactHandler",
|
|
3887
|
+
"declaration": {
|
|
3888
|
+
"name": "bindReactHandler",
|
|
3889
|
+
"module": "src/helix-element/react-bridge.ts"
|
|
3890
|
+
}
|
|
3891
|
+
},
|
|
3892
|
+
{
|
|
3893
|
+
"kind": "js",
|
|
3894
|
+
"name": "applyReactProperties",
|
|
3895
|
+
"declaration": {
|
|
3896
|
+
"name": "applyReactProperties",
|
|
3897
|
+
"module": "src/helix-element/react-bridge.ts"
|
|
3898
|
+
}
|
|
3899
|
+
}
|
|
3900
|
+
]
|
|
3901
|
+
},
|
|
3634
3902
|
{
|
|
3635
3903
|
"kind": "javascript-module",
|
|
3636
3904
|
"path": "src/helix-form-element/helix-form-element.ts",
|
|
@@ -3690,6 +3958,28 @@
|
|
|
3690
3958
|
],
|
|
3691
3959
|
"description": "The platform's notice that an ancestor fieldset changed.\n\n**The argument is the effective state, and taking it whole is what latched\nevery control in the library.** The platform calls this for the element's\nown `disabled` as well as for a fieldset, and our own arrives here at the\nworst possible moment: reflecting `disabled` to the attribute happens\ninside Lit's `update()`, the UA fires this synchronously from that write,\nand a reactive write during an update is a change-in-update Lit does not\nre-render for. So `formDisabled` ran exactly one update behind forever.\n\nMeasured on Slider, logging what `render` saw:\n\n```\nset true disabled true formDisabled false isDisabled true\nset false disabled false formDisabled true isDisabled true <- stale\n(no third render)\n```\n\nThe host came out right every time, `disabled` false, `:disabled` not\nmatching, and the inner control kept the attribute, so a control disabled\nonce could never be re-enabled. It only shows when something re-enables,\nwhich is the same shape of bug `inheritDisabled` was written for.\n\nOur own half is already in `this.disabled` and `isDisabled` is an or, so\nthis records only what the fieldset adds. That also removes the write\nentirely on the own-disabled path rather than moving it.\n\nThe one case this cannot see is a control that is disabled itself *and*\ninside a disabled fieldset, whose own `disabled` is then removed: the\neffective state does not change, so the platform does not call again, and\nthe fieldset's hold is not recorded. There is no callback to learn it from\nand reading `:disabled` here would answer about the attribute we are in the\nmiddle of removing."
|
|
3692
3960
|
},
|
|
3961
|
+
{
|
|
3962
|
+
"kind": "method",
|
|
3963
|
+
"name": "announceInput",
|
|
3964
|
+
"privacy": "protected",
|
|
3965
|
+
"return": {
|
|
3966
|
+
"type": {
|
|
3967
|
+
"text": "void"
|
|
3968
|
+
}
|
|
3969
|
+
},
|
|
3970
|
+
"description": "Announces `input` from the host, the way the control it stands for would.\n\nComposed, as the native one is: `input` crosses shadow boundaries by\nspecification, so a consumer listening above a composition hears it."
|
|
3971
|
+
},
|
|
3972
|
+
{
|
|
3973
|
+
"kind": "method",
|
|
3974
|
+
"name": "announceChange",
|
|
3975
|
+
"privacy": "protected",
|
|
3976
|
+
"return": {
|
|
3977
|
+
"type": {
|
|
3978
|
+
"text": "void"
|
|
3979
|
+
}
|
|
3980
|
+
},
|
|
3981
|
+
"description": "Announces `change` from the host, the way the control it stands for would.\n\n**Not composed, and that is the shape of the native event rather than a\nchoice made here.** `change` stops at a shadow boundary, so a composed\ncontrol hears its inner control's and relays it under the same name from\nits own host, which is what `onChange` binds. Every control here that\ncommits a value announces it through this, whether the commit came from an\ninner control's own `change`, a step, a scrub or a completed code, so the\nevent is one shape in one place."
|
|
3982
|
+
},
|
|
3693
3983
|
{
|
|
3694
3984
|
"kind": "field",
|
|
3695
3985
|
"name": "name",
|
|
@@ -3773,16 +4063,39 @@
|
|
|
3773
4063
|
}
|
|
3774
4064
|
},
|
|
3775
4065
|
{
|
|
3776
|
-
"kind": "
|
|
3777
|
-
"name": "
|
|
3778
|
-
"type": {
|
|
3779
|
-
"text": "ElementInternals"
|
|
3780
|
-
},
|
|
4066
|
+
"kind": "method",
|
|
4067
|
+
"name": "partNamed",
|
|
3781
4068
|
"privacy": "protected",
|
|
3782
|
-
"
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
4069
|
+
"return": {
|
|
4070
|
+
"type": {
|
|
4071
|
+
"text": "T | null"
|
|
4072
|
+
}
|
|
4073
|
+
},
|
|
4074
|
+
"parameters": [
|
|
4075
|
+
{
|
|
4076
|
+
"name": "name",
|
|
4077
|
+
"type": {
|
|
4078
|
+
"text": "string"
|
|
4079
|
+
}
|
|
4080
|
+
}
|
|
4081
|
+
],
|
|
4082
|
+
"description": "One of this element's own parts, by name, or null where it is not rendered.\n\nNot `part`, which every element already has: `Element.part` is the\n`DOMTokenList` of the names the element itself carries, and a method under\nthat name is a type error on every subclass.\n\n**One guard for every lookup.** Lit's server shim has no `querySelector`\non the render root, so a lookup reached during a server render, from a\ngetter a template reads or from `willUpdate`, throws there and nowhere\nelse. Four spellings of the same guard had grown across the library, and\na fifth site with none. Null on the server, which is what the rest of the\ncode already treats a part that has not rendered as.\n\n`helix component`'s `selectors` reads these calls the way it reads a\n`querySelector('[part=\"x\"]')`, so a name nothing renders is a finding\nrather than a null an optional chain swallows.",
|
|
4083
|
+
"inheritedFrom": {
|
|
4084
|
+
"name": "HelixElement",
|
|
4085
|
+
"module": "src/helix-element/helix-element.ts"
|
|
4086
|
+
}
|
|
4087
|
+
},
|
|
4088
|
+
{
|
|
4089
|
+
"kind": "field",
|
|
4090
|
+
"name": "internals",
|
|
4091
|
+
"type": {
|
|
4092
|
+
"text": "ElementInternals"
|
|
4093
|
+
},
|
|
4094
|
+
"privacy": "protected",
|
|
4095
|
+
"readonly": true,
|
|
4096
|
+
"description": "The element's semantics, set without touching the DOM.\n\n`ElementInternals` sets the implicit role, which an author's own `role`\nattribute still overrides, and it writes no attribute. Setting `role` on the\nhost directly would: that is an attribute the element gives itself after it\nupgrades, which a React consumer's server markup never had, and hydration\nreports it as a mismatch.\n\nAvailable during server rendering. Lit's shim implements `attachInternals`,\nso nothing here needs a guard.",
|
|
4097
|
+
"inheritedFrom": {
|
|
4098
|
+
"name": "HelixElement",
|
|
3786
4099
|
"module": "src/helix-element/helix-element.ts"
|
|
3787
4100
|
}
|
|
3788
4101
|
},
|
|
@@ -4037,6 +4350,7 @@
|
|
|
4037
4350
|
}
|
|
4038
4351
|
}
|
|
4039
4352
|
],
|
|
4353
|
+
"events": [],
|
|
4040
4354
|
"attributes": [
|
|
4041
4355
|
{
|
|
4042
4356
|
"name": "disabled",
|
|
@@ -4067,8 +4381,7 @@
|
|
|
4067
4381
|
"status": "experimental",
|
|
4068
4382
|
"documentation": "https://helix.fusion.dev/core/form-element",
|
|
4069
4383
|
"tier": "core"
|
|
4070
|
-
}
|
|
4071
|
-
"events": []
|
|
4384
|
+
}
|
|
4072
4385
|
}
|
|
4073
4386
|
],
|
|
4074
4387
|
"exports": [
|
|
@@ -4991,6 +5304,38 @@
|
|
|
4991
5304
|
"module": "./mixins/mixin-field/mixin-field.js"
|
|
4992
5305
|
}
|
|
4993
5306
|
},
|
|
5307
|
+
{
|
|
5308
|
+
"kind": "js",
|
|
5309
|
+
"name": "MixinPickerEditing",
|
|
5310
|
+
"declaration": {
|
|
5311
|
+
"name": "MixinPickerEditing",
|
|
5312
|
+
"module": "./mixins/mixin-picker-editing/mixin-picker-editing.js"
|
|
5313
|
+
}
|
|
5314
|
+
},
|
|
5315
|
+
{
|
|
5316
|
+
"kind": "js",
|
|
5317
|
+
"name": "MixinPickerEditingInterface",
|
|
5318
|
+
"declaration": {
|
|
5319
|
+
"name": "MixinPickerEditingInterface",
|
|
5320
|
+
"module": "./mixins/mixin-picker-editing/mixin-picker-editing.js"
|
|
5321
|
+
}
|
|
5322
|
+
},
|
|
5323
|
+
{
|
|
5324
|
+
"kind": "js",
|
|
5325
|
+
"name": "MixinPickerField",
|
|
5326
|
+
"declaration": {
|
|
5327
|
+
"name": "MixinPickerField",
|
|
5328
|
+
"module": "./mixins/mixin-picker-field/mixin-picker-field.js"
|
|
5329
|
+
}
|
|
5330
|
+
},
|
|
5331
|
+
{
|
|
5332
|
+
"kind": "js",
|
|
5333
|
+
"name": "MixinPickerFieldInterface",
|
|
5334
|
+
"declaration": {
|
|
5335
|
+
"name": "MixinPickerFieldInterface",
|
|
5336
|
+
"module": "./mixins/mixin-picker-field/mixin-picker-field.js"
|
|
5337
|
+
}
|
|
5338
|
+
},
|
|
4994
5339
|
{
|
|
4995
5340
|
"kind": "js",
|
|
4996
5341
|
"name": "MixinTokens",
|
|
@@ -5023,14 +5368,6 @@
|
|
|
5023
5368
|
"module": "./utils/capture-pointer/capture-pointer.js"
|
|
5024
5369
|
}
|
|
5025
5370
|
},
|
|
5026
|
-
{
|
|
5027
|
-
"kind": "js",
|
|
5028
|
-
"name": "closeMarkdown",
|
|
5029
|
-
"declaration": {
|
|
5030
|
-
"name": "closeMarkdown",
|
|
5031
|
-
"module": "./utils/close-markdown/close-markdown.js"
|
|
5032
|
-
}
|
|
5033
|
-
},
|
|
5034
5371
|
{
|
|
5035
5372
|
"kind": "js",
|
|
5036
5373
|
"name": "closestInstance",
|
|
@@ -5720,7 +6057,7 @@
|
|
|
5720
6057
|
"type": {
|
|
5721
6058
|
"text": "Series[]"
|
|
5722
6059
|
},
|
|
5723
|
-
"description": "The columns of the table, one series each, or none if there is no table.",
|
|
6060
|
+
"description": "The columns of the table, one series each, or none if there is no table.\n\nHeld by the controller between edits, so a render reading this five\ntimes parses the table once. See `SourceController.series`.",
|
|
5724
6061
|
"readonly": true
|
|
5725
6062
|
},
|
|
5726
6063
|
{
|
|
@@ -5816,29 +6153,6 @@
|
|
|
5816
6153
|
}
|
|
5817
6154
|
]
|
|
5818
6155
|
},
|
|
5819
|
-
{
|
|
5820
|
-
"kind": "javascript-module",
|
|
5821
|
-
"path": "src/mixins/mixin-collection/index.ts",
|
|
5822
|
-
"declarations": [],
|
|
5823
|
-
"exports": [
|
|
5824
|
-
{
|
|
5825
|
-
"kind": "js",
|
|
5826
|
-
"name": "CollectionElement",
|
|
5827
|
-
"declaration": {
|
|
5828
|
-
"name": "CollectionElement",
|
|
5829
|
-
"module": "./mixin-collection.js"
|
|
5830
|
-
}
|
|
5831
|
-
},
|
|
5832
|
-
{
|
|
5833
|
-
"kind": "js",
|
|
5834
|
-
"name": "MixinCollection",
|
|
5835
|
-
"declaration": {
|
|
5836
|
-
"name": "MixinCollection",
|
|
5837
|
-
"module": "./mixin-collection.js"
|
|
5838
|
-
}
|
|
5839
|
-
}
|
|
5840
|
-
]
|
|
5841
|
-
},
|
|
5842
6156
|
{
|
|
5843
6157
|
"kind": "javascript-module",
|
|
5844
6158
|
"path": "src/mixins/mixin-collection/mixin-collection.ts",
|
|
@@ -6847,7 +7161,7 @@
|
|
|
6847
7161
|
{
|
|
6848
7162
|
"kind": "method",
|
|
6849
7163
|
"name": "announceNatively",
|
|
6850
|
-
"privacy": "
|
|
7164
|
+
"privacy": "protected",
|
|
6851
7165
|
"return": {
|
|
6852
7166
|
"type": {
|
|
6853
7167
|
"text": "void"
|
|
@@ -6902,20 +7216,6 @@
|
|
|
6902
7216
|
"description": "Restores the value when the browser brings a form back.\n\nFalling back to `defaultValue` rather than to empty, because a restore\nwith no state is a form the browser has nothing recorded for, which is\nthe same situation as a fresh one."
|
|
6903
7217
|
}
|
|
6904
7218
|
],
|
|
6905
|
-
"events": [
|
|
6906
|
-
{
|
|
6907
|
-
"name": "input",
|
|
6908
|
-
"type": {
|
|
6909
|
-
"text": "Event"
|
|
6910
|
-
}
|
|
6911
|
-
},
|
|
6912
|
-
{
|
|
6913
|
-
"name": "change",
|
|
6914
|
-
"type": {
|
|
6915
|
-
"text": "Event"
|
|
6916
|
-
}
|
|
6917
|
-
}
|
|
6918
|
-
],
|
|
6919
7219
|
"attributes": [
|
|
6920
7220
|
{
|
|
6921
7221
|
"name": "default-value",
|
|
@@ -7510,6 +7810,459 @@
|
|
|
7510
7810
|
}
|
|
7511
7811
|
]
|
|
7512
7812
|
},
|
|
7813
|
+
{
|
|
7814
|
+
"kind": "javascript-module",
|
|
7815
|
+
"path": "src/mixins/mixin-picker-editing/mixin-picker-editing.ts",
|
|
7816
|
+
"declarations": [
|
|
7817
|
+
{
|
|
7818
|
+
"kind": "class",
|
|
7819
|
+
"description": "The public surface `MixinPickerEditing` adds.\n\nDeclared separately because TypeScript cannot emit declarations for an\nanonymous class that has private members (TS4094). Casting the mixin's return\nto this interface keeps the internals private and the build working.",
|
|
7820
|
+
"name": "MixinPickerEditingInterface",
|
|
7821
|
+
"members": [
|
|
7822
|
+
{
|
|
7823
|
+
"kind": "field",
|
|
7824
|
+
"name": "editing",
|
|
7825
|
+
"type": {
|
|
7826
|
+
"text": "boolean"
|
|
7827
|
+
},
|
|
7828
|
+
"privacy": "protected",
|
|
7829
|
+
"description": "Whether the caret is in the field, which is when it holds the value."
|
|
7830
|
+
},
|
|
7831
|
+
{
|
|
7832
|
+
"kind": "field",
|
|
7833
|
+
"name": "handleBlur",
|
|
7834
|
+
"type": {
|
|
7835
|
+
"text": "() => void"
|
|
7836
|
+
},
|
|
7837
|
+
"privacy": "protected",
|
|
7838
|
+
"readonly": true,
|
|
7839
|
+
"description": "The caret has left, so the field renders again."
|
|
7840
|
+
},
|
|
7841
|
+
{
|
|
7842
|
+
"kind": "field",
|
|
7843
|
+
"name": "handleFocus",
|
|
7844
|
+
"type": {
|
|
7845
|
+
"text": "(event: FocusEvent) => void"
|
|
7846
|
+
},
|
|
7847
|
+
"privacy": "protected",
|
|
7848
|
+
"readonly": true,
|
|
7849
|
+
"description": "Focusing the field opens the picker, and only from outside the element."
|
|
7850
|
+
},
|
|
7851
|
+
{
|
|
7852
|
+
"kind": "field",
|
|
7853
|
+
"name": "readOnly",
|
|
7854
|
+
"type": {
|
|
7855
|
+
"text": "boolean"
|
|
7856
|
+
},
|
|
7857
|
+
"description": "Whether the control refuses changes while still submitting its value."
|
|
7858
|
+
},
|
|
7859
|
+
{
|
|
7860
|
+
"kind": "method",
|
|
7861
|
+
"name": "requestValue",
|
|
7862
|
+
"return": {
|
|
7863
|
+
"type": {
|
|
7864
|
+
"text": "boolean"
|
|
7865
|
+
}
|
|
7866
|
+
},
|
|
7867
|
+
"parameters": [
|
|
7868
|
+
{
|
|
7869
|
+
"name": "next",
|
|
7870
|
+
"type": {
|
|
7871
|
+
"text": "string"
|
|
7872
|
+
}
|
|
7873
|
+
}
|
|
7874
|
+
],
|
|
7875
|
+
"description": "Refuses every change while read-only. See `readOnly`."
|
|
7876
|
+
}
|
|
7877
|
+
],
|
|
7878
|
+
"helix": {}
|
|
7879
|
+
},
|
|
7880
|
+
{
|
|
7881
|
+
"kind": "mixin",
|
|
7882
|
+
"description": "Grafts the typing half of a picker field: it opens on arrival, holds the\nvalue while the caret is in it, and refuses while read-only.\n\n**Over `MixinPickerField` and not part of it, because Color Input takes the\none and not the other.** Date Input and Time Input show a rendering while\nnobody is in the field, `4 August 2026` and `2:30 PM`, and the value itself\nwhile somebody is, because `Intl` formats and does not parse and a document\nbeing edited must not be a rendering of something else. That split needs to\nknow when the caret is in the field, which is `editing`; and a reader who\nreaches such a field is choosing, so arriving opens the picker. A color has\nneither: `#ff0000` is what is typed and what is shown, and a reader who has\nthe hex pastes it and never opens anything. `readOnly` is the third thing\nColor Input does not have, and a mixin cannot give it one without changing\nits API.",
|
|
7883
|
+
"name": "MixinPickerEditing",
|
|
7884
|
+
"members": [
|
|
7885
|
+
{
|
|
7886
|
+
"kind": "field",
|
|
7887
|
+
"name": "readOnly",
|
|
7888
|
+
"type": {
|
|
7889
|
+
"text": "boolean"
|
|
7890
|
+
},
|
|
7891
|
+
"default": "false",
|
|
7892
|
+
"description": "Whether the control refuses changes while still submitting its value.\n\n**Enforced by refusing every request in one place**, which is the seam this\ncomponent already has: `requestValue` is what every path here comes through,\nand gating it once is what stops the next call site from being written\nwithout the check.\n\nNot `disabled`, which is the confusion worth naming: a disabled control\nsubmits nothing and leaves the tab order, and a read-only one submits its\nvalue and stays reachable, which is what a form showing a value somebody\nelse set needs.",
|
|
7893
|
+
"attribute": "readonly",
|
|
7894
|
+
"reflects": true
|
|
7895
|
+
},
|
|
7896
|
+
{
|
|
7897
|
+
"kind": "field",
|
|
7898
|
+
"name": "editing",
|
|
7899
|
+
"type": {
|
|
7900
|
+
"text": "boolean"
|
|
7901
|
+
},
|
|
7902
|
+
"privacy": "protected",
|
|
7903
|
+
"default": "false",
|
|
7904
|
+
"description": "Whether the caret is in the field, which is when it holds the value."
|
|
7905
|
+
},
|
|
7906
|
+
{
|
|
7907
|
+
"kind": "method",
|
|
7908
|
+
"name": "requestValue",
|
|
7909
|
+
"return": {
|
|
7910
|
+
"type": {
|
|
7911
|
+
"text": "boolean"
|
|
7912
|
+
}
|
|
7913
|
+
},
|
|
7914
|
+
"parameters": [
|
|
7915
|
+
{
|
|
7916
|
+
"name": "next",
|
|
7917
|
+
"type": {
|
|
7918
|
+
"text": "string"
|
|
7919
|
+
}
|
|
7920
|
+
}
|
|
7921
|
+
],
|
|
7922
|
+
"description": "Refuses every change while read-only. See `readOnly`."
|
|
7923
|
+
},
|
|
7924
|
+
{
|
|
7925
|
+
"kind": "field",
|
|
7926
|
+
"name": "handleBlur",
|
|
7927
|
+
"privacy": "protected",
|
|
7928
|
+
"readonly": true,
|
|
7929
|
+
"description": "The caret has left, so the field renders again."
|
|
7930
|
+
},
|
|
7931
|
+
{
|
|
7932
|
+
"kind": "field",
|
|
7933
|
+
"name": "handleFocus",
|
|
7934
|
+
"privacy": "protected",
|
|
7935
|
+
"readonly": true,
|
|
7936
|
+
"description": "Focusing the field opens the picker.\n\nA reader who reaches this control is choosing, and making them find the\ntrigger afterwards is a second action for something they have already\nasked for. Typing still works with it up, because the picker follows the\nfield rather than the other way round.\n\n**Only where focus arrived from outside this element**, which is the whole\nof the difficulty: picking shuts the panel and puts the caret back in the\nfield, so an unguarded version reopens the picker the reader just\nanswered. `relatedTarget` is where focus came from, so a hand-off from the\npicker or the trigger is left alone and only a genuine arrival opens\nanything. `returning` covers the hand-off `relatedTarget` cannot see, and\n`MixinPickerField` says why.\n\nOn the input rather than on the field, too. Focus does not bubble, so a\nlistener there covers the text and not the trigger, which is what keeps\npressing the trigger from opening the panel on focus and then shutting it\nagain on the click."
|
|
7937
|
+
}
|
|
7938
|
+
],
|
|
7939
|
+
"attributes": [
|
|
7940
|
+
{
|
|
7941
|
+
"name": "readonly",
|
|
7942
|
+
"type": {
|
|
7943
|
+
"text": "boolean"
|
|
7944
|
+
},
|
|
7945
|
+
"default": "false",
|
|
7946
|
+
"description": "Whether the control refuses changes while still submitting its value.\n\n**Enforced by refusing every request in one place**, which is the seam this\ncomponent already has: `requestValue` is what every path here comes through,\nand gating it once is what stops the next call site from being written\nwithout the check.\n\nNot `disabled`, which is the confusion worth naming: a disabled control\nsubmits nothing and leaves the tab order, and a read-only one submits its\nvalue and stays reachable, which is what a form showing a value somebody\nelse set needs.",
|
|
7947
|
+
"fieldName": "readOnly"
|
|
7948
|
+
}
|
|
7949
|
+
],
|
|
7950
|
+
"parameters": [
|
|
7951
|
+
{
|
|
7952
|
+
"name": "Base",
|
|
7953
|
+
"type": {
|
|
7954
|
+
"text": "T"
|
|
7955
|
+
}
|
|
7956
|
+
}
|
|
7957
|
+
]
|
|
7958
|
+
}
|
|
7959
|
+
],
|
|
7960
|
+
"exports": [
|
|
7961
|
+
{
|
|
7962
|
+
"kind": "js",
|
|
7963
|
+
"name": "MixinPickerEditingInterface",
|
|
7964
|
+
"declaration": {
|
|
7965
|
+
"name": "MixinPickerEditingInterface",
|
|
7966
|
+
"module": "src/mixins/mixin-picker-editing/mixin-picker-editing.ts"
|
|
7967
|
+
}
|
|
7968
|
+
},
|
|
7969
|
+
{
|
|
7970
|
+
"kind": "js",
|
|
7971
|
+
"name": "MixinPickerEditing",
|
|
7972
|
+
"declaration": {
|
|
7973
|
+
"name": "MixinPickerEditing",
|
|
7974
|
+
"module": "src/mixins/mixin-picker-editing/mixin-picker-editing.ts"
|
|
7975
|
+
}
|
|
7976
|
+
}
|
|
7977
|
+
]
|
|
7978
|
+
},
|
|
7979
|
+
{
|
|
7980
|
+
"kind": "javascript-module",
|
|
7981
|
+
"path": "src/mixins/mixin-picker-field/mixin-picker-field.ts",
|
|
7982
|
+
"declarations": [
|
|
7983
|
+
{
|
|
7984
|
+
"kind": "class",
|
|
7985
|
+
"description": "The public surface `MixinPickerField` adds.\n\nDeclared separately because TypeScript cannot emit declarations for an\nanonymous class that has private members (TS4094). Casting the mixin's return\nto this interface keeps the internals private and the build working.",
|
|
7986
|
+
"name": "MixinPickerFieldInterface",
|
|
7987
|
+
"members": [
|
|
7988
|
+
{
|
|
7989
|
+
"kind": "field",
|
|
7990
|
+
"name": "anchor",
|
|
7991
|
+
"type": {
|
|
7992
|
+
"text": "HTMLElement | null"
|
|
7993
|
+
},
|
|
7994
|
+
"privacy": "protected",
|
|
7995
|
+
"description": "What the label points at and focus lands on.\n\nThe text control, unless a family says otherwise: Color Input in `swatch`\nhas no text control, and its trigger is the only thing in the field a label\ncan name.",
|
|
7996
|
+
"readonly": true
|
|
7997
|
+
},
|
|
7998
|
+
{
|
|
7999
|
+
"kind": "field",
|
|
8000
|
+
"name": "control",
|
|
8001
|
+
"type": {
|
|
8002
|
+
"text": "HTMLInputElement | null"
|
|
8003
|
+
},
|
|
8004
|
+
"privacy": "protected",
|
|
8005
|
+
"description": "The text input, or `null` where there is no DOM to hold one.",
|
|
8006
|
+
"readonly": true
|
|
8007
|
+
},
|
|
8008
|
+
{
|
|
8009
|
+
"kind": "field",
|
|
8010
|
+
"name": "display",
|
|
8011
|
+
"type": {
|
|
8012
|
+
"text": "string"
|
|
8013
|
+
},
|
|
8014
|
+
"privacy": "protected",
|
|
8015
|
+
"description": "What the field shows, which is the value unless a family renders it.\n\nDate Input and Time Input show a written date or time while nobody is in\nthe field and the value itself while somebody is; Color Input shows the\nvalue either way. What `restore` puts back is whichever the family says.",
|
|
8016
|
+
"readonly": true
|
|
8017
|
+
},
|
|
8018
|
+
{
|
|
8019
|
+
"kind": "method",
|
|
8020
|
+
"name": "focus",
|
|
8021
|
+
"return": {
|
|
8022
|
+
"type": {
|
|
8023
|
+
"text": "void"
|
|
8024
|
+
}
|
|
8025
|
+
},
|
|
8026
|
+
"parameters": [
|
|
8027
|
+
{
|
|
8028
|
+
"name": "options",
|
|
8029
|
+
"optional": true,
|
|
8030
|
+
"type": {
|
|
8031
|
+
"text": "FocusOptions"
|
|
8032
|
+
}
|
|
8033
|
+
}
|
|
8034
|
+
],
|
|
8035
|
+
"description": "Puts the caret in the field, the way a label pointing at one would."
|
|
8036
|
+
},
|
|
8037
|
+
{
|
|
8038
|
+
"kind": "field",
|
|
8039
|
+
"name": "handleKeydown",
|
|
8040
|
+
"type": {
|
|
8041
|
+
"text": "(event: KeyboardEvent) => void"
|
|
8042
|
+
},
|
|
8043
|
+
"privacy": "protected",
|
|
8044
|
+
"readonly": true,
|
|
8045
|
+
"description": "Escape shuts the panel without moving the value."
|
|
8046
|
+
},
|
|
8047
|
+
{
|
|
8048
|
+
"kind": "field",
|
|
8049
|
+
"name": "panel",
|
|
8050
|
+
"type": {
|
|
8051
|
+
"text": "PopoverController"
|
|
8052
|
+
},
|
|
8053
|
+
"privacy": "protected",
|
|
8054
|
+
"readonly": true,
|
|
8055
|
+
"description": "The overlay, placed against the field rather than the trigger."
|
|
8056
|
+
},
|
|
8057
|
+
{
|
|
8058
|
+
"kind": "method",
|
|
8059
|
+
"name": "restore",
|
|
8060
|
+
"privacy": "protected",
|
|
8061
|
+
"return": {
|
|
8062
|
+
"type": {
|
|
8063
|
+
"text": "void"
|
|
8064
|
+
}
|
|
8065
|
+
},
|
|
8066
|
+
"description": "Puts the field back where the answer differs from what was typed."
|
|
8067
|
+
},
|
|
8068
|
+
{
|
|
8069
|
+
"kind": "method",
|
|
8070
|
+
"name": "returnFocus",
|
|
8071
|
+
"privacy": "protected",
|
|
8072
|
+
"return": {
|
|
8073
|
+
"type": {
|
|
8074
|
+
"text": "void"
|
|
8075
|
+
}
|
|
8076
|
+
},
|
|
8077
|
+
"description": "Puts the caret back in the field without the field reopening the panel."
|
|
8078
|
+
},
|
|
8079
|
+
{
|
|
8080
|
+
"kind": "field",
|
|
8081
|
+
"name": "returning",
|
|
8082
|
+
"type": {
|
|
8083
|
+
"text": "boolean"
|
|
8084
|
+
},
|
|
8085
|
+
"privacy": "protected",
|
|
8086
|
+
"description": "Whether this element is moving the focus itself, right now."
|
|
8087
|
+
},
|
|
8088
|
+
{
|
|
8089
|
+
"kind": "method",
|
|
8090
|
+
"name": "sync",
|
|
8091
|
+
"privacy": "protected",
|
|
8092
|
+
"return": {
|
|
8093
|
+
"type": {
|
|
8094
|
+
"text": "void"
|
|
8095
|
+
}
|
|
8096
|
+
},
|
|
8097
|
+
"description": "Reports the value and the validity the host stands behind."
|
|
8098
|
+
},
|
|
8099
|
+
{
|
|
8100
|
+
"kind": "method",
|
|
8101
|
+
"name": "validate",
|
|
8102
|
+
"privacy": "protected",
|
|
8103
|
+
"return": {
|
|
8104
|
+
"type": {
|
|
8105
|
+
"text": "string"
|
|
8106
|
+
}
|
|
8107
|
+
},
|
|
8108
|
+
"description": "What is wrong with the value, in the reader's words, or nothing.\n\nThe one check the platform cannot make: the control is `type=\"text\"` and\nhas no idea what a date, a time or a color is, so the family says what one\nlooks like and `sync` reports it as `badInput`. Empty means the platform's\nown verdict stands."
|
|
8109
|
+
}
|
|
8110
|
+
],
|
|
8111
|
+
"helix": {}
|
|
8112
|
+
},
|
|
8113
|
+
{
|
|
8114
|
+
"kind": "mixin",
|
|
8115
|
+
"description": "Grafts a floating picker onto a text field, and the protocol between them.\n\n**Three families are this shape and were three copies of it.** Date Input,\nTime Input and Color Input each render a text control, a trigger and a\n`popover=\"manual\"` surface holding a picker that already exists on its own,\nand each owed the same wiring: the panel that floats the surface against the\nfield, the Escape that shuts it and hands the caret back, the restore that\nputs the control back where a refusal left the value, and the sync that\nreports the value and a verdict the platform cannot reach. Measured on the\ndiff that made the lift, 14 Sep 2026, comments counted: 223 lines left Date\nInput and 32 came back, 185 left Time Input and 32 came back, 87 left\nColor Input and 11 came back.\n\n**What it does not own is the picker, the typing or the value's shape.**\nWhich element floats in the surface, what a keystroke means, what the field\nshows when idle and what is wrong with a value are each the family's, which\nis why `display` and `validate` are seams here and the template stays where\nit was. A family renders `field`, `control`, `trigger` and `surface`; this\nreads them.\n\n**The parts this reads are the host's, so the name is a parameter.** A\nliteral `[part=\"control\"]` here would be a lookup nothing in this file\nrenders, which is the fault `helix component`'s `selectors` exists to catch\nand would rightly report. `MixinField.reportRequired` takes its anchor the\nsame way, and for the same reason: a mixin reads a part out of whatever host\napplies it.\n\n**Opening on focus, `readOnly` and the idle rendering are not here.** They\nare `MixinPickerEditing`'s, because Color Input has none of the three: a hex\nis pasted and read at a glance, so its field neither renders nor opens on\narrival, and giving it `readOnly` would be a property its API does not have.\n\n**Three things the two typed families share stay with them.** `renderTrigger`\ndiffers only by its icon and would still be the wrong thing to lift: a part a\nmixin renders belongs to every host that applies it, which is how\n`helix component`'s `parts` reads a chain, so `trigger-icon` would be\ncredited to Color Input, whose trigger is a swatch and documents no such\npart. `renderTag` names its part after the family, `date` or `time`, and\nwrites the label on the remove control differently in each. `valueAsDate`\nand `valueAsNumber` are public, convert a different way, and carry a\ndifferent note onto each family's page, which a mixin could only carry as\none.\n\n**Four more families look like this and are not.** Select has no text to\nhand the caret to: its panel hangs off the trigger and dismissal refocuses\nthat. Combobox has the text and a different agreement with it: a press\nanywhere in the field is inside, the gap is four, Escape closes without the\n`returning` flag because nothing there opens on arrival, and the control is\nreconciled against a completion rather than restored to a value. Input and\nTextarea open nothing, and their `readOnly` is the native attribute rather\nthan a gate on `requestValue`, so a programmatic change still lands. What\nthose two share with this is `focus()` and the platform's verdict copied in\n`sync`, which is not a protocol.",
|
|
8116
|
+
"name": "MixinPickerField",
|
|
8117
|
+
"members": [
|
|
8118
|
+
{
|
|
8119
|
+
"kind": "field",
|
|
8120
|
+
"name": "panel",
|
|
8121
|
+
"privacy": "protected",
|
|
8122
|
+
"readonly": true,
|
|
8123
|
+
"default": "new PopoverController(this, { anchor: () => this.partNamed('field'), /* The surface *and* the trigger. * * A control is not always one element: the button that opens this panel is * part of it, and a press on it is not a press outside. Scoped to the * surface alone, `pointerdown` on the trigger closes the panel and the * trigger's own `toggleOpen` reopens it on the `click` that follows, so the * panel can never be closed by the button that opened it. * `DismissController` documents this failure and takes a list for it. */ boundary: (): readonly (Element | null | undefined)[] => [ this.partNamed('surface'), this.partNamed('trigger'), ], /* Wider than the four every other panel here takes. Those sit against a control the same width as themselves and read as an extension of it; this one is a picker of its own size hanging off a field, so the gap is what says the two are separate things rather than one control that grew. */ offset: () => 8, onDismiss: () => this.requestOpen(false), open: () => this.open, placement: 'bottom-start', surface: () => this.partNamed('surface'), })",
|
|
8124
|
+
"description": "The overlay, placed against the field rather than the trigger.\n\nAgainst the field because that is the box a reader sees as the control: a\ncalendar hung off a small button at one end of a wide field reads as\nbelonging to the button. `Select` anchors to its trigger for the opposite\nreason, its trigger being the whole control."
|
|
8125
|
+
},
|
|
8126
|
+
{
|
|
8127
|
+
"kind": "field",
|
|
8128
|
+
"name": "anchor",
|
|
8129
|
+
"type": {
|
|
8130
|
+
"text": "HTMLElement | null"
|
|
8131
|
+
},
|
|
8132
|
+
"privacy": "protected",
|
|
8133
|
+
"description": "What the label points at and focus lands on.",
|
|
8134
|
+
"readonly": true
|
|
8135
|
+
},
|
|
8136
|
+
{
|
|
8137
|
+
"kind": "field",
|
|
8138
|
+
"name": "control",
|
|
8139
|
+
"type": {
|
|
8140
|
+
"text": "HTMLInputElement | null"
|
|
8141
|
+
},
|
|
8142
|
+
"privacy": "protected",
|
|
8143
|
+
"description": "The text input, or `null` where there is no DOM to hold one.",
|
|
8144
|
+
"readonly": true
|
|
8145
|
+
},
|
|
8146
|
+
{
|
|
8147
|
+
"kind": "field",
|
|
8148
|
+
"name": "display",
|
|
8149
|
+
"type": {
|
|
8150
|
+
"text": "string"
|
|
8151
|
+
},
|
|
8152
|
+
"privacy": "protected",
|
|
8153
|
+
"description": "What the field shows, which is the value unless a family renders it.",
|
|
8154
|
+
"readonly": true
|
|
8155
|
+
},
|
|
8156
|
+
{
|
|
8157
|
+
"kind": "method",
|
|
8158
|
+
"name": "validate",
|
|
8159
|
+
"privacy": "protected",
|
|
8160
|
+
"return": {
|
|
8161
|
+
"type": {
|
|
8162
|
+
"text": "string"
|
|
8163
|
+
}
|
|
8164
|
+
},
|
|
8165
|
+
"description": "What is wrong with the value, in the reader's words, or nothing."
|
|
8166
|
+
},
|
|
8167
|
+
{
|
|
8168
|
+
"kind": "method",
|
|
8169
|
+
"name": "restore",
|
|
8170
|
+
"privacy": "protected",
|
|
8171
|
+
"return": {
|
|
8172
|
+
"type": {
|
|
8173
|
+
"text": "void"
|
|
8174
|
+
}
|
|
8175
|
+
},
|
|
8176
|
+
"description": "Puts the field back where the answer differs from what was typed.\n\n`requestValue` is the mixin's, and it announces and decides; this is the\nother half, which `Input` needs for the same reason: the native control has\nalready changed, so wherever the answer does not follow it, it has to be\nrestored. A refusal and a consumer who owns `value` and has not given a new\none are the same thing from here."
|
|
8177
|
+
},
|
|
8178
|
+
{
|
|
8179
|
+
"kind": "method",
|
|
8180
|
+
"name": "sync",
|
|
8181
|
+
"privacy": "protected",
|
|
8182
|
+
"return": {
|
|
8183
|
+
"type": {
|
|
8184
|
+
"text": "void"
|
|
8185
|
+
}
|
|
8186
|
+
},
|
|
8187
|
+
"description": "Reports the value and the validity the host stands behind.\n\nThe family's verdict first, where it has one, because the input is\n`type=\"text\"` and knows nothing about what it holds: `min` and `max` on a\ntext input do nothing, and the typed kind is what was given up to own the\npicker. The platform's own verdict otherwise, copied rather than\nrecomputed, with the control as the anchor so a validity bubble points at\nthe text and not at the host."
|
|
8188
|
+
},
|
|
8189
|
+
{
|
|
8190
|
+
"kind": "field",
|
|
8191
|
+
"name": "handleKeydown",
|
|
8192
|
+
"privacy": "protected",
|
|
8193
|
+
"readonly": true,
|
|
8194
|
+
"description": "Escape shuts the panel without moving the value."
|
|
8195
|
+
},
|
|
8196
|
+
{
|
|
8197
|
+
"kind": "field",
|
|
8198
|
+
"name": "returning",
|
|
8199
|
+
"type": {
|
|
8200
|
+
"text": "boolean"
|
|
8201
|
+
},
|
|
8202
|
+
"privacy": "protected",
|
|
8203
|
+
"default": "false",
|
|
8204
|
+
"description": "Whether this element is moving the focus itself, right now.\n\nFocus opens the panel on the families that open on arrival, so handing\nfocus back after a pick reopens the thing that was just answered.\n`relatedTarget` was the guard and it is not enough on its own: it catches\na hand-off from the trigger, and it does not catch this, because the cell\nor the option that had focus is gone by the time the caret moves and the\ndocument has fallen back to something outside this element.\n\n**Reasoned in a browser and measured in the test runtime, and worth\nsaying which is which.** In a focused document: the reader presses a day,\nthe cell has focus, the panel is hidden, the browser moves focus off the\nremoved cell to the body, and the caret is then put back here with\n`relatedTarget` pointing at the body, which is outside this element and\nreads as an arrival. Every step is ordinary browser behavior, and none of\nit can be driven from a browser pane, where `focus()` dispatches nothing\nbecause the document is not focused. happy-dom is the exception, and it\nis what the specs run under: it dispatches `focus` from `focus()`\nsynchronously and with no `relatedTarget`, measured on 20.11.2, so the\nmixin's spec asks the hand-off directly, and two of its tests fail with\nthis guard removed.\n\nA flag rather than a better guess, because this element is the one moving\nthe focus and is the only thing that can know so. Cleared synchronously,\nsince `focus()` dispatches before it returns."
|
|
8205
|
+
},
|
|
8206
|
+
{
|
|
8207
|
+
"kind": "method",
|
|
8208
|
+
"name": "returnFocus",
|
|
8209
|
+
"privacy": "protected",
|
|
8210
|
+
"return": {
|
|
8211
|
+
"type": {
|
|
8212
|
+
"text": "void"
|
|
8213
|
+
}
|
|
8214
|
+
},
|
|
8215
|
+
"description": "Puts the caret back in the field without the field reopening the panel."
|
|
8216
|
+
},
|
|
8217
|
+
{
|
|
8218
|
+
"kind": "method",
|
|
8219
|
+
"name": "focus",
|
|
8220
|
+
"return": {
|
|
8221
|
+
"type": {
|
|
8222
|
+
"text": "void"
|
|
8223
|
+
}
|
|
8224
|
+
},
|
|
8225
|
+
"parameters": [
|
|
8226
|
+
{
|
|
8227
|
+
"name": "options",
|
|
8228
|
+
"optional": true,
|
|
8229
|
+
"type": {
|
|
8230
|
+
"text": "FocusOptions"
|
|
8231
|
+
}
|
|
8232
|
+
}
|
|
8233
|
+
],
|
|
8234
|
+
"description": "Puts the caret in the field, the way a label pointing at one would."
|
|
8235
|
+
}
|
|
8236
|
+
],
|
|
8237
|
+
"parameters": [
|
|
8238
|
+
{
|
|
8239
|
+
"name": "Base",
|
|
8240
|
+
"type": {
|
|
8241
|
+
"text": "T"
|
|
8242
|
+
}
|
|
8243
|
+
}
|
|
8244
|
+
]
|
|
8245
|
+
}
|
|
8246
|
+
],
|
|
8247
|
+
"exports": [
|
|
8248
|
+
{
|
|
8249
|
+
"kind": "js",
|
|
8250
|
+
"name": "MixinPickerFieldInterface",
|
|
8251
|
+
"declaration": {
|
|
8252
|
+
"name": "MixinPickerFieldInterface",
|
|
8253
|
+
"module": "src/mixins/mixin-picker-field/mixin-picker-field.ts"
|
|
8254
|
+
}
|
|
8255
|
+
},
|
|
8256
|
+
{
|
|
8257
|
+
"kind": "js",
|
|
8258
|
+
"name": "MixinPickerField",
|
|
8259
|
+
"declaration": {
|
|
8260
|
+
"name": "MixinPickerField",
|
|
8261
|
+
"module": "src/mixins/mixin-picker-field/mixin-picker-field.ts"
|
|
8262
|
+
}
|
|
8263
|
+
}
|
|
8264
|
+
]
|
|
8265
|
+
},
|
|
7513
8266
|
{
|
|
7514
8267
|
"kind": "javascript-module",
|
|
7515
8268
|
"path": "src/mixins/mixin-tokens/mixin-tokens.ts",
|
|
@@ -7958,40 +8711,6 @@
|
|
|
7958
8711
|
}
|
|
7959
8712
|
]
|
|
7960
8713
|
},
|
|
7961
|
-
{
|
|
7962
|
-
"kind": "javascript-module",
|
|
7963
|
-
"path": "src/utils/close-markdown/close-markdown.ts",
|
|
7964
|
-
"declarations": [
|
|
7965
|
-
{
|
|
7966
|
-
"kind": "function",
|
|
7967
|
-
"name": "closeMarkdown",
|
|
7968
|
-
"return": {
|
|
7969
|
-
"type": {
|
|
7970
|
-
"text": "string"
|
|
7971
|
-
}
|
|
7972
|
-
},
|
|
7973
|
-
"parameters": [
|
|
7974
|
-
{
|
|
7975
|
-
"name": "partial",
|
|
7976
|
-
"type": {
|
|
7977
|
-
"text": "string"
|
|
7978
|
-
}
|
|
7979
|
-
}
|
|
7980
|
-
],
|
|
7981
|
-
"description": "A prefix of a markdown document, made safe to render as it arrives.\n\n**A streamed answer is a prefix, and a prefix is rarely valid markdown.** The\nmoment a model writes an opening fence, everything after it is code that has\nnot been told it is code: a renderer handed that prefix draws paragraphs,\nthen redraws the whole block when the closing fence lands three seconds\nlater. The same holds for a backtick, a `**`, and a link whose target is\nstill being typed — each renders as punctuation until its partner arrives.\n\nSo this closes what is open. It does not parse markdown and does not render\nit: it returns a string the caller's own renderer can be handed, in which\nevery construct that was opened is also closed.\n\n**What it does not do is remove anything a reader can already read.** The\nexception is a link or image whose brackets are still open, because there is\nno closing that: a target arrives character by character, and `[the docs](ht`\nhas no valid completion that is not a guess at a URL. That fragment is\nwithheld until it is whole, which is the one case where a word appears a beat\nlater than it was received.\n\n**Inside a fence nothing else applies**, which is why closing one returns\nimmediately. The characters in a code block are code: a stray backtick or a\nlone asterisk in a shell command is not an unclosed span, and treating it as\none would append punctuation into somebody's code.\n\n**Underscores are left alone.** `_` opens emphasis in markdown and also sits\ninside `snake_case`, `__init__` and a filename, and a prefix gives no way to\ntell which: closing one turns an identifier into italics for as long as the\nrest of the word takes to arrive, which is worse than the punctuation it was\nmeant to hide. `*` does not have that problem, being punctuation everywhere\nit is not emphasis.\n\nStable across a growing prefix, which is the property that matters: calling\nthis on each frame of a stream cannot make text move that has already\nsettled, because everything it adds is at the end and everything it withholds\nis a fragment that has not been shown yet."
|
|
7982
|
-
}
|
|
7983
|
-
],
|
|
7984
|
-
"exports": [
|
|
7985
|
-
{
|
|
7986
|
-
"kind": "js",
|
|
7987
|
-
"name": "closeMarkdown",
|
|
7988
|
-
"declaration": {
|
|
7989
|
-
"name": "closeMarkdown",
|
|
7990
|
-
"module": "src/utils/close-markdown/close-markdown.ts"
|
|
7991
|
-
}
|
|
7992
|
-
}
|
|
7993
|
-
]
|
|
7994
|
-
},
|
|
7995
8714
|
{
|
|
7996
8715
|
"kind": "javascript-module",
|
|
7997
8716
|
"path": "src/utils/closest-instance/closest-instance.ts",
|
|
@@ -8165,7 +8884,7 @@
|
|
|
8165
8884
|
}
|
|
8166
8885
|
}
|
|
8167
8886
|
],
|
|
8168
|
-
"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/
|
|
8887
|
+
"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/shared/glyph/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."
|
|
8169
8888
|
}
|
|
8170
8889
|
],
|
|
8171
8890
|
"exports": [
|