@fusion.dev/helix-headless 0.47.0 → 0.48.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.
@@ -9611,6 +9611,10 @@
9611
9611
  "description": "The size one pane is laid out at. A sheet sets it and the component measures the run with it.",
9612
9612
  "name": "--carousel-pane"
9613
9613
  },
9614
+ {
9615
+ "description": "How many slides go across, written onto the track by the component so a sheet divides the track by the same number the positions are counted from. Read it rather than selecting on `per-view`, which cannot be enumerated without a ceiling. See `perView`.",
9616
+ "name": "--carousel-per-view"
9617
+ },
9614
9618
  {
9615
9619
  "description": "How far short of a whole pixel the run ends, on the last slide alone, for a sheet to take up as `margin-inline-end`. See `runEnd`.",
9616
9620
  "name": "--carousel-run-end"
@@ -9806,10 +9810,20 @@
9806
9810
  "type": {
9807
9811
  "text": "number | undefined"
9808
9812
  },
9809
- "description": "How many slides are shown across the track at once. Absent shows one.\n\n**Here rather than on the styled tier, because it decides how many places\nthe track can stop.** From the stylesheet it looks like a width, one rule\nper value setting a custom property that the slides divide the track by.\nBut a carousel showing four of six slides has three positions, not six, and\neverything that counts positions is in this file. Declared up there, `goTo`\nclamps to the last *slide*, so three of the six indicators point at an\noffset the track has already reached: pressing next walks the dots to the\nend while the slides stop moving a third of the way through.\n\nNo default, because it reflects. A reflected property with a value writes\nits attribute on upgrade, and the host then carries something a consumer's\nserver markup never had, which React reports as a mismatch. The one-across\ncase is the absent attribute, and the styles read it that way.",
9813
+ "description": "How many slides are shown across the track at once. Absent shows one.\n\n**Here rather than on the styled tier, because it decides how many places\nthe track can stop.** From the stylesheet it looks like a width, one rule\nper value setting a custom property that the slides divide the track by.\nBut a carousel showing four of six slides has three positions, not six, and\neverything that counts positions is in this file. Declared up there, `goTo`\nclamps to the last *slide*, so three of the six indicators point at an\noffset the track has already reached: pressing next walks the dots to the\nend while the slides stop moving a third of the way through.\n\n**The number is published to the styles rather than enumerated by them**,\nas `--carousel-per-view` on the track, which is what keeps a width and a\ncount from disagreeing. A sheet can only name a value it wrote a rule for,\nso the styled tier enumerated `per-view=\"2\"` through `5` and called five a\njudgment; above it the pane fell back to one across while this file went on\ncounting positions. Measured in Chromium over eight slides, six across gave\nthree dots, a pane taking the whole track and five slides reachable only by\ndragging. Written from here there is no ceiling to exceed, and a consumer's\nown sheet reads the same declaration the styled one does. `runEnd` publishes\nits correction the same way and for the same reason.\n\n**On the track and not on the host.** A custom property on the host is a\nreflected attribute by another name: it would arrive on upgrade, and a\nconsumer's server markup never had it. Inside the component's own shadow\nroot it serializes with the rest of the template on the server, and the\ntrack's own declaration beats anything a consumer inherits in, so the\nattribute is the one answer to how wide a pane is.\n\nA value the track cannot honor is taken to the nearest one it can, by\n`across`, and both tiers read that rather than this.\n\nNo default, because it reflects. A reflected property with a value writes\nits attribute on upgrade, and the host then carries something a consumer's\nserver markup never had, which React reports as a mismatch. The one-across\ncase is the absent attribute, and the styles read it that way.",
9810
9814
  "attribute": "per-view",
9811
9815
  "reflects": true
9812
9816
  },
9817
+ {
9818
+ "kind": "field",
9819
+ "name": "across",
9820
+ "type": {
9821
+ "text": "number"
9822
+ },
9823
+ "privacy": "private",
9824
+ "description": "`perView` as both tiers use it: a whole number of slides, one at least.\n\n**The clamp is here because the arithmetic is here**, and the two readers\nof this number have to be given the same one. A fraction is floored, since\na position is a whole slide along: one and a half across leaves a last\nposition the track runs out before reaching, which is the fault `goTo`\nalready carries a comment about. Zero and a negative divide the track into\nnothing and into a pane facing the wrong way, and a non-numeric attribute\nparses to `NaN`, which `Math.max` propagates: it counted `NaN` positions,\ndrew no indicators at all and left `index` at `NaN`. All of them read as\none across, which is what a carousel with nothing sayable asked for.\n\nNot clamped to the number of slides. Six across four slides is four panes\nat a sixth of the track each and the one place to stand, which is what was\nasked for as nearly as it can be had, and the slide count is a fact the\nserver does not have: clamping to it would draw one width there and another\non upgrade.",
9825
+ "readonly": true
9826
+ },
9813
9827
  {
9814
9828
  "kind": "field",
9815
9829
  "name": "positions",
@@ -10477,7 +10491,7 @@
10477
10491
  "type": {
10478
10492
  "text": "number | undefined"
10479
10493
  },
10480
- "description": "How many slides are shown across the track at once. Absent shows one.\n\n**Here rather than on the styled tier, because it decides how many places\nthe track can stop.** From the stylesheet it looks like a width, one rule\nper value setting a custom property that the slides divide the track by.\nBut a carousel showing four of six slides has three positions, not six, and\neverything that counts positions is in this file. Declared up there, `goTo`\nclamps to the last *slide*, so three of the six indicators point at an\noffset the track has already reached: pressing next walks the dots to the\nend while the slides stop moving a third of the way through.\n\nNo default, because it reflects. A reflected property with a value writes\nits attribute on upgrade, and the host then carries something a consumer's\nserver markup never had, which React reports as a mismatch. The one-across\ncase is the absent attribute, and the styles read it that way.",
10494
+ "description": "How many slides are shown across the track at once. Absent shows one.\n\n**Here rather than on the styled tier, because it decides how many places\nthe track can stop.** From the stylesheet it looks like a width, one rule\nper value setting a custom property that the slides divide the track by.\nBut a carousel showing four of six slides has three positions, not six, and\neverything that counts positions is in this file. Declared up there, `goTo`\nclamps to the last *slide*, so three of the six indicators point at an\noffset the track has already reached: pressing next walks the dots to the\nend while the slides stop moving a third of the way through.\n\n**The number is published to the styles rather than enumerated by them**,\nas `--carousel-per-view` on the track, which is what keeps a width and a\ncount from disagreeing. A sheet can only name a value it wrote a rule for,\nso the styled tier enumerated `per-view=\"2\"` through `5` and called five a\njudgment; above it the pane fell back to one across while this file went on\ncounting positions. Measured in Chromium over eight slides, six across gave\nthree dots, a pane taking the whole track and five slides reachable only by\ndragging. Written from here there is no ceiling to exceed, and a consumer's\nown sheet reads the same declaration the styled one does. `runEnd` publishes\nits correction the same way and for the same reason.\n\n**On the track and not on the host.** A custom property on the host is a\nreflected attribute by another name: it would arrive on upgrade, and a\nconsumer's server markup never had it. Inside the component's own shadow\nroot it serializes with the rest of the template on the server, and the\ntrack's own declaration beats anything a consumer inherits in, so the\nattribute is the one answer to how wide a pane is.\n\nA value the track cannot honor is taken to the nearest one it can, by\n`across`, and both tiers read that rather than this.\n\nNo default, because it reflects. A reflected property with a value writes\nits attribute on upgrade, and the host then carries something a consumer's\nserver markup never had, which React reports as a mismatch. The one-across\ncase is the absent attribute, and the styles read it that way.",
10481
10495
  "fieldName": "perView"
10482
10496
  }
10483
10497
  ],
@@ -19129,6 +19143,28 @@
19129
19143
  "description": "Whether to leave the value out, for a picker whose value is stated elsewhere.\n\nThe row reads the color as text and lets it be typed or pasted, which is\nwhat makes this element complete standing on a page: a square and two ramps\ncan build a color and cannot state one, and a reader who has a hex already\nshould not have to find it by dragging.\n\nColor Input sets this, because its field is that input. Two editable fields\nfor one value is the outcome worth avoiding: two places to type, and no\nanswer to which one is authoritative or which has the caret. Do not close it\nthe other way round, with Color Input dropping its own field: the value\nwould then be unreadable and unpasteable without opening a panel.",
19130
19144
  "attribute": "no-value"
19131
19145
  },
19146
+ {
19147
+ "kind": "field",
19148
+ "name": "readOnly",
19149
+ "type": {
19150
+ "text": "boolean"
19151
+ },
19152
+ "default": "false",
19153
+ "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 color somebody\nelse set needs.\n\n**One gate is not enough here, and the second is `move`.** This picker\nholds a model beside its value, which Date Picker and Time Picker do not:\n`moved` is the HSB the square is drawn from, and it is written before the\nvalue is requested. Gating only the request would leave the square under\nthe reader's pointer and the value where it was, which is a control that\nrefuses and looks like it accepted.",
19154
+ "attribute": "readonly",
19155
+ "reflects": true
19156
+ },
19157
+ {
19158
+ "kind": "field",
19159
+ "name": "required",
19160
+ "type": {
19161
+ "text": "boolean"
19162
+ },
19163
+ "default": "false",
19164
+ "description": "Whether the form refuses to submit while no color is chosen.\n\n**A color is exactly as requirable as a date**, which is the comparison\nthat settles it: this element extends `HelixFormElement`, carries `name`\nand reports its value, so a consumer writing\n`<helix-color-picker name=\"brand\" required>` inside a form has every reason\nto expect the form to refuse an empty one. Its two siblings in the same\ncomposition position, Date Picker and Time Picker, both check it.\n\nWritten out rather than taken from `MixinField`, for the reason those two\nrecord: the mixin brings a label, a hint and a feedback region, and this is\na panel composed *into* a field that already has all three, so taking it\nwould give one control two of each. What is left is the validity call and\nthe anchor the browser points its bubble at.\n\n**Emptiness is the only fault reported, and bad input deliberately is\nnot.** The value row is typed into a character at a time and every\nkeystroke reaches `requestValue`, so `#0`, `#00` and `#00f` would each be a\nreported fault on the way to `#00ff00`. Date Picker and Time Picker can\nreport bad input because their value moves only on a commit. Color Input\nreports it for this family instead, once, against the field the reader\ntyped into.",
19165
+ "attribute": "required",
19166
+ "reflects": true
19167
+ },
19132
19168
  {
19133
19169
  "kind": "field",
19134
19170
  "name": "swatches",
@@ -19214,6 +19250,31 @@
19214
19250
  "readonly": true,
19215
19251
  "description": "Takes what was typed, and lets the square follow only a whole color."
19216
19252
  },
19253
+ {
19254
+ "kind": "method",
19255
+ "name": "requestValue",
19256
+ "return": {
19257
+ "type": {
19258
+ "text": "boolean"
19259
+ }
19260
+ },
19261
+ "parameters": [
19262
+ {
19263
+ "name": "next",
19264
+ "type": {
19265
+ "text": "string"
19266
+ }
19267
+ }
19268
+ ],
19269
+ "description": "Refuses every change while read-only. See `readOnly`.",
19270
+ "inheritedFrom": {
19271
+ "name": "MixinControllerValue",
19272
+ "module": "src/mixins/mixin-controller-value/mixin-controller-value.ts"
19273
+ },
19274
+ "type": {
19275
+ "text": "requestValue(next: string) => boolean"
19276
+ }
19277
+ },
19217
19278
  {
19218
19279
  "kind": "field",
19219
19280
  "name": "move",
@@ -19266,7 +19327,18 @@
19266
19327
  "text": "void"
19267
19328
  }
19268
19329
  },
19269
- "description": "Reports the color to the form.\n\n**The one thing a form-associated element owes, and this element owed it\nfrom the start without paying.** It extends `HelixFormElement`, takes\n`MixinControllerValue` and carries `name`, so a consumer writing\n`<helix-color-picker name=\"brand\">` inside a form has every reason to\nexpect an entry, and the form carried none: no error, nothing in the\nmarkup to look at, and a field silently missing from the submission. Its\ntwo siblings in the same composition position, Color Input and Slider,\nboth report.\n\n`null` rather than an empty string where there is no color, which is the\ndifference between a control that submits nothing and one that submits a\nblank. There is no `setValidity` beside it: this element does not take\n`MixinField`, and every validity member of `ElementInternals` is the\nconsumer's to reach through the field that wraps it."
19330
+ "description": "Reports the color to the form.\n\n**The one thing a form-associated element owes, and this element owed it\nfrom the start without paying.** It extends `HelixFormElement`, takes\n`MixinControllerValue` and carries `name`, so a consumer writing\n`<helix-color-picker name=\"brand\">` inside a form has every reason to\nexpect an entry, and the form carried none: no error, nothing in the\nmarkup to look at, and a field silently missing from the submission. Its\ntwo siblings in the same composition position, Color Input and Slider,\nboth report.\n\n`null` rather than an empty string where there is no color, which is the\ndifference between a control that submits nothing and one that submits a\nblank.\n\nThe verdict goes beside it, because `required` is this element's own claim\nand nothing else can answer it: a picker standing on a page has no field\naround it to check on its behalf. What it is *not* is a second opinion on\neverything else, which is why bad input is left to Color Input. See\n`required`."
19331
+ },
19332
+ {
19333
+ "kind": "method",
19334
+ "name": "reportRequired",
19335
+ "privacy": "private",
19336
+ "return": {
19337
+ "type": {
19338
+ "text": "void"
19339
+ }
19340
+ },
19341
+ "description": "Reports \"required and empty\", or clears it.\n\nAnchored on the square, which is where a reader would go to answer: it is\nthe first control in the panel and the one `focus` puts the keyboard on, so\nthe browser's bubble points at the thing to do rather than at the row that\nstates the result."
19270
19342
  },
19271
19343
  {
19272
19344
  "kind": "method",
@@ -19352,6 +19424,31 @@
19352
19424
  ],
19353
19425
  "description": "One axis of the area, taken the way `takeChannel` takes a rail.\n\n**Named rather than inline because of the first line.** The `<input\ntype=\"range\">` behind each axis sends its own composed `input`, which\nreaches a consumer listening on this element beside this element's own\nunless it is stopped: a consumer dragging the area receives the range's\nevent and not this component's."
19354
19426
  },
19427
+ {
19428
+ "kind": "method",
19429
+ "name": "putBack",
19430
+ "privacy": "private",
19431
+ "return": {
19432
+ "type": {
19433
+ "text": "void"
19434
+ }
19435
+ },
19436
+ "parameters": [
19437
+ {
19438
+ "name": "control",
19439
+ "type": {
19440
+ "text": "{ value: string }"
19441
+ }
19442
+ },
19443
+ {
19444
+ "name": "at",
19445
+ "type": {
19446
+ "text": "number"
19447
+ }
19448
+ }
19449
+ ],
19450
+ "description": "Returns a control that moved itself to what the model still holds.\n\n**A refusal has to undo something, and here it is a handle.** Every other\ncontrol in this picker is drawn from the model, so refusing the change\nleaves the picture right on its own. The two area ranges and the two\nchannel sliders are not: each moved before it announced, and each is bound\nwith `.value`, which lit dirty-checks against the value it last committed.\nThe model never changed, so that binding writes nothing and the handle\nstays where the reader dragged it, on a control that refused. Carousel\nsettles the same question the same way: a refusal puts the track back on\nthe slide the index still holds."
19451
+ },
19355
19452
  {
19356
19453
  "kind": "method",
19357
19454
  "name": "takeChannel",
@@ -19459,31 +19556,6 @@
19459
19556
  "module": "src/mixins/mixin-controller-value/mixin-controller-value.ts"
19460
19557
  }
19461
19558
  },
19462
- {
19463
- "kind": "method",
19464
- "name": "requestValue",
19465
- "return": {
19466
- "type": {
19467
- "text": "boolean"
19468
- }
19469
- },
19470
- "parameters": [
19471
- {
19472
- "name": "next",
19473
- "type": {
19474
- "text": "string"
19475
- }
19476
- }
19477
- ],
19478
- "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.",
19479
- "inheritedFrom": {
19480
- "name": "MixinControllerValue",
19481
- "module": "src/mixins/mixin-controller-value/mixin-controller-value.ts"
19482
- },
19483
- "type": {
19484
- "text": "requestValue(next: string) => boolean"
19485
- }
19486
- },
19487
19559
  {
19488
19560
  "kind": "method",
19489
19561
  "name": "formResetCallback",
@@ -20120,6 +20192,24 @@
20120
20192
  "description": "Whether to leave the value out, for a picker whose value is stated elsewhere.\n\nThe row reads the color as text and lets it be typed or pasted, which is\nwhat makes this element complete standing on a page: a square and two ramps\ncan build a color and cannot state one, and a reader who has a hex already\nshould not have to find it by dragging.\n\nColor Input sets this, because its field is that input. Two editable fields\nfor one value is the outcome worth avoiding: two places to type, and no\nanswer to which one is authoritative or which has the caret. Do not close it\nthe other way round, with Color Input dropping its own field: the value\nwould then be unreadable and unpasteable without opening a panel.",
20121
20193
  "fieldName": "noValue"
20122
20194
  },
20195
+ {
20196
+ "name": "readonly",
20197
+ "type": {
20198
+ "text": "boolean"
20199
+ },
20200
+ "default": "false",
20201
+ "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 color somebody\nelse set needs.\n\n**One gate is not enough here, and the second is `move`.** This picker\nholds a model beside its value, which Date Picker and Time Picker do not:\n`moved` is the HSB the square is drawn from, and it is written before the\nvalue is requested. Gating only the request would leave the square under\nthe reader's pointer and the value where it was, which is a control that\nrefuses and looks like it accepted.",
20202
+ "fieldName": "readOnly"
20203
+ },
20204
+ {
20205
+ "name": "required",
20206
+ "type": {
20207
+ "text": "boolean"
20208
+ },
20209
+ "default": "false",
20210
+ "description": "Whether the form refuses to submit while no color is chosen.\n\n**A color is exactly as requirable as a date**, which is the comparison\nthat settles it: this element extends `HelixFormElement`, carries `name`\nand reports its value, so a consumer writing\n`<helix-color-picker name=\"brand\" required>` inside a form has every reason\nto expect the form to refuse an empty one. Its two siblings in the same\ncomposition position, Date Picker and Time Picker, both check it.\n\nWritten out rather than taken from `MixinField`, for the reason those two\nrecord: the mixin brings a label, a hint and a feedback region, and this is\na panel composed *into* a field that already has all three, so taking it\nwould give one control two of each. What is left is the validity call and\nthe anchor the browser points its bubble at.\n\n**Emptiness is the only fault reported, and bad input deliberately is\nnot.** The value row is typed into a character at a time and every\nkeystroke reaches `requestValue`, so `#0`, `#00` and `#00f` would each be a\nreported fault on the way to `#00ff00`. Date Picker and Time Picker can\nreport bad input because their value moves only on a commit. Color Input\nreports it for this family instead, once, against the field the reader\ntyped into.",
20211
+ "fieldName": "required"
20212
+ },
20123
20213
  {
20124
20214
  "name": "swatches",
20125
20215
  "type": {
@@ -72097,11 +72187,11 @@
72097
72187
  "name": "--rating-part"
72098
72188
  },
72099
72189
  {
72100
- "description": "The width of one step, as a fraction of a mark.",
72190
+ "description": "Which step along the row a target is, counting from one, whatever `min` leaves open.",
72101
72191
  "name": "--rating-step"
72102
72192
  },
72103
72193
  {
72104
- "description": "How many steps one mark is divided into.",
72194
+ "description": "How many steps the whole row holds, which is `max` over `step`.",
72105
72195
  "name": "--rating-steps"
72106
72196
  }
72107
72197
  ],
@@ -72110,6 +72200,10 @@
72110
72200
  "description": "What is wrong with it.",
72111
72201
  "name": "feedback"
72112
72202
  },
72203
+ {
72204
+ "description": "The row: the marks, and the score beside them.",
72205
+ "name": "field"
72206
+ },
72113
72207
  {
72114
72208
  "description": "The filled marks, clipped to the score.",
72115
72209
  "name": "fill"
@@ -72176,7 +72270,7 @@
72176
72270
  "text": "number"
72177
72271
  },
72178
72272
  "default": "0",
72179
- "description": "The lowest score a reader can give, which is what clearing returns to.\n\nZero rather than one, because \"no rating\" and \"the worst rating\" are\ndifferent answers and a control that cannot express the first has to\npretend the second. A survey that requires an answer says so with\n`required`, not by making one unreachable.",
72273
+ "description": "The lowest score a reader can give, which is what clearing returns to.\n\nZero rather than one, because \"no rating\" and \"the worst rating\" are\ndifferent answers and a control that cannot express the first has to\npretend the second. A survey that requires an answer says so with\n`required`, not by making one unreachable.\n\n**It is the floor of the scale, and every edge follows from that.**\n\n*Clearing* returns the row to it. An empty rating, a value nothing can\nparse, and a form reset with nothing declared are all the same situation,\nand all three draw `min` filled: at the default of zero that is the empty\nrow this always drew, and at `min=\"2\"` it is two marks, the way an empty\n`Slider` sits at its own minimum rather than at zero. The value is still\n`\"\"` through all of it, so `required` still refuses it and `valueAsNumber`\nis still `NaN`: what the row shows is the bottom of the scale, not an\nanswer somebody gave.\n\n*The steps* are the scores from `step` up to `max` that are not below it,\nso `min=\"2\"` on five marks offers 2 to 5 and leaves the first two marks\nfilled and unpressable. At zero nothing is dropped, which is why the\ndefault row is unchanged.\n\n*The keyboard* moves through those steps and no others. `wrap` is already\nfalse here, so arrowing down from the lowest one holds its ground rather\nthan reaching a score this property forbids, and the tab stop an unrated\nrating carries sits on the lowest score offered rather than on the first\nmark.\n\n*A `min` between two steps* is a floor and not a step: `min=\"1.5\"` with\nwhole marks clamps the value at 1.5 and offers 2 upward, since 1.5 is not\nsomewhere the row can be pressed. That is a real thing to ask for and is\nleft to mean what it says.\n\n*A `min` outside the marks is refused rather than obeyed*, and says so\nonce on the console. Below zero and anything that is not a number are read\nas zero, there being no mark to draw for a negative score; above `max` is\nread as `max`, which collapses the scale to its top score rather than\nleaving a rating with nothing to press. A property that silently accepts\nnonsense is the fault this pays off, so neither case is quietly ignored.",
72180
72274
  "attribute": "min"
72181
72275
  },
72182
72276
  {
@@ -72258,6 +72352,16 @@
72258
72352
  "readonly": true,
72259
72353
  "default": "new KeyboardNavigationController(this, { items: () => this.options, selects: () => true, wrap: false, })"
72260
72354
  },
72355
+ {
72356
+ "kind": "field",
72357
+ "name": "floor",
72358
+ "type": {
72359
+ "text": "number"
72360
+ },
72361
+ "privacy": "private",
72362
+ "description": "The floor the row actually uses, which is `min` where `min` is one.\n\nBetween zero and `max`, and zero for anything that is not a number, per\nthe note on `min`. Derived on read rather than corrected into the property,\nso `rating.min` still reports what the consumer set and the warning below\ncan tell the two apart.",
72363
+ "readonly": true
72364
+ },
72261
72365
  {
72262
72366
  "kind": "field",
72263
72367
  "name": "score",
@@ -72267,6 +72371,16 @@
72267
72371
  "description": "The score, as a number, clamped to what the marks can show.",
72268
72372
  "readonly": true
72269
72373
  },
72374
+ {
72375
+ "kind": "field",
72376
+ "name": "positions",
72377
+ "type": {
72378
+ "text": "number[]"
72379
+ },
72380
+ "privacy": "private",
72381
+ "description": "Every score the marks can show, which is `max / step` of them.\n\nThe whole row rather than the part `min` leaves open, because this is what\nthe stylesheet lays the targets out against: `--rating-steps` is the pitch\nand a step's own place in this list is where it sits along the row. Counted\nfrom the part a reader can press instead, a floor above zero would widen\nevery target and slide the row left.",
72382
+ "readonly": true
72383
+ },
72270
72384
  {
72271
72385
  "kind": "field",
72272
72386
  "name": "steps",
@@ -72274,7 +72388,7 @@
72274
72388
  "text": "number[]"
72275
72389
  },
72276
72390
  "privacy": "private",
72277
- "description": "Every score a reader can choose, which is `max / step` of them.",
72391
+ "description": "Every score a reader can choose, which is the positions `min` leaves open.",
72278
72392
  "readonly": true
72279
72393
  },
72280
72394
  {
@@ -72389,7 +72503,7 @@
72389
72503
  "text": "void"
72390
72504
  }
72391
72505
  },
72392
- "description": "Reports the value, and whether the form may go without one.\n\n**`required` arrives from the mixin, so it prints on the reference page\nwhether or not anything here enforces it.** Without a `setValidity` call a\nform holding an unrated required rating submits, `:valid` true and the\nentry present but empty. `reportRequired` is what makes the property real.\n\n**Empty is `value === ''` rather than a score of zero**, because zero is a\nrating a reader can deliberately give when `min` allows it, and refusing to\nsubmit it would be the control disagreeing with the property that permits\nit. What `required` asks is whether they answered at all.\n\n`Slider` is deliberately not given the same treatment: a native\n`<input type=\"range\" required>` is always valid, because a range always\nholds a number, and matching the platform there is the point."
72506
+ "description": "Reports the value, and whether the form may go without one.\n\n**`required` arrives from the mixin, so it prints on the reference page\nwhether or not anything here enforces it.** Without a `setValidity` call a\nform holding an unrated required rating submits, `:valid` true and the\nentry present but empty. `reportRequired` is what makes the property real.\n\n**Empty is `value === ''` rather than a score at the floor**, and the two\nare not the same thing: an unanswered row draws `min`, per the note on that\nproperty, so a control that read its own picture would call every rating\nwith `min=\"2\"` answered the moment it rendered. What `required` asks is\nwhether the reader answered at all, which only the value knows. A consumer\nwho writes `value=\"0\"` has answered, and is not refused.\n\n`Slider` is deliberately not given the same treatment: a native\n`<input type=\"range\" required>` is always valid, because a range always\nholds a number, and matching the platform there is the point."
72393
72507
  },
72394
72508
  {
72395
72509
  "kind": "field",
@@ -72409,6 +72523,16 @@
72409
72523
  "privacy": "private",
72410
72524
  "readonly": true
72411
72525
  },
72526
+ {
72527
+ "kind": "field",
72528
+ "name": "warned",
72529
+ "type": {
72530
+ "text": "boolean"
72531
+ },
72532
+ "privacy": "private",
72533
+ "default": "false",
72534
+ "description": "Whether the console has already been told about a `min` off the scale."
72535
+ },
72412
72536
  {
72413
72537
  "kind": "field",
72414
72538
  "name": "valueAsNumber",
@@ -73287,7 +73411,7 @@
73287
73411
  "text": "number"
73288
73412
  },
73289
73413
  "default": "0",
73290
- "description": "The lowest score a reader can give, which is what clearing returns to.\n\nZero rather than one, because \"no rating\" and \"the worst rating\" are\ndifferent answers and a control that cannot express the first has to\npretend the second. A survey that requires an answer says so with\n`required`, not by making one unreachable.",
73414
+ "description": "The lowest score a reader can give, which is what clearing returns to.\n\nZero rather than one, because \"no rating\" and \"the worst rating\" are\ndifferent answers and a control that cannot express the first has to\npretend the second. A survey that requires an answer says so with\n`required`, not by making one unreachable.\n\n**It is the floor of the scale, and every edge follows from that.**\n\n*Clearing* returns the row to it. An empty rating, a value nothing can\nparse, and a form reset with nothing declared are all the same situation,\nand all three draw `min` filled: at the default of zero that is the empty\nrow this always drew, and at `min=\"2\"` it is two marks, the way an empty\n`Slider` sits at its own minimum rather than at zero. The value is still\n`\"\"` through all of it, so `required` still refuses it and `valueAsNumber`\nis still `NaN`: what the row shows is the bottom of the scale, not an\nanswer somebody gave.\n\n*The steps* are the scores from `step` up to `max` that are not below it,\nso `min=\"2\"` on five marks offers 2 to 5 and leaves the first two marks\nfilled and unpressable. At zero nothing is dropped, which is why the\ndefault row is unchanged.\n\n*The keyboard* moves through those steps and no others. `wrap` is already\nfalse here, so arrowing down from the lowest one holds its ground rather\nthan reaching a score this property forbids, and the tab stop an unrated\nrating carries sits on the lowest score offered rather than on the first\nmark.\n\n*A `min` between two steps* is a floor and not a step: `min=\"1.5\"` with\nwhole marks clamps the value at 1.5 and offers 2 upward, since 1.5 is not\nsomewhere the row can be pressed. That is a real thing to ask for and is\nleft to mean what it says.\n\n*A `min` outside the marks is refused rather than obeyed*, and says so\nonce on the console. Below zero and anything that is not a number are read\nas zero, there being no mark to draw for a negative score; above `max` is\nread as `max`, which collapses the scale to its top score rather than\nleaving a rating with nothing to press. A property that silently accepts\nnonsense is the fault this pays off, so neither case is quietly ignored.",
73291
73415
  "fieldName": "min"
73292
73416
  },
73293
73417
  {
@@ -93647,7 +93771,7 @@
93647
93771
  },
93648
93772
  {
93649
93773
  "kind": "class",
93650
- "description": "**A list rather than three wheels**, and the reason is what a list already\nis. `helix-listbox` brings the keyboard, the typeahead, the scroll into view\nand the announcement of a set of options, and a time at a step is a set of\noptions. Three little wheels for hours, minutes and a meridiem are three\ncontrols to build, three to test, and a tab stop each for something a reader\nanswers once.\n\n**A step is what makes it a list at all.** Fifteen minutes is ninety-six rows,\nwhich a reader scrolls or types into; one minute is one thousand four hundred\nand forty, which is a listbox in name only. So the list is for the times a\nproduct actually offers, and arbitrary times are the field's job in Input\nTime, the same division Date Input draws between typing a date and using the\ncalendar.\n\n**The value is `HH:mm` on a twenty-four hour clock, always.** That is what a\nform submits and what `min` and `max` compare against, and it sorts as a\nstring, which is the whole reason the shape is that one. What each row *says*\nis the reader's own convention, from `Intl`.",
93774
+ "description": "**A list rather than three wheels**, and the reason is what a list already\nis. `helix-listbox` brings the keyboard, the typeahead, the scroll into view\nand the announcement of a set of options, and a time at a step is a set of\noptions. Three little wheels for hours, minutes and a meridiem are three\ncontrols to build, three to test, and a tab stop each for something a reader\nanswers once.\n\n**A step is what makes it a list at all.** Fifteen minutes is ninety-six rows,\nwhich a reader scrolls or types into; one minute is one thousand four hundred\nand forty, which is a listbox in name only. So the list is for the times a\nproduct actually offers, and arbitrary times are the field's job in Input\nTime, the same division Date Input draws between typing a date and using the\ncalendar.\n\n**The value is `HH:mm` on a twenty-four hour clock, always.** That is what a\nform submits and what `min` and `max` compare against, and it sorts as a\nstring, which is the whole reason the shape is that one. What each row *says*\nis the reader's own convention, from `Intl`.\n\n**The chosen row is marked in the markup, not worked out on upgrade.** The\nlistbox is handed the answer as `.value`, and lit-ssr serializes no property\nbinding, so a served `value=\"09:30\"` shipped ninety-six rows with nothing on\nany of them saying which one it was: the mark arrived when the listbox\nupgraded and ran `place`. So each option is given `selected` as well, which\nis an attribute binding and does serve, and which the listbox then agrees\nwith rather than fights, `place` writing the same answer from the same value.\n`selected` is the declaration a consumer writes on `Option` anywhere else in\nthe library, and Date Picker expresses its own choice as markup for the same\nreason: a picker whose answer is invisible until a script runs is a picker\nwhose answer is not served at all. Both readings do it, the list and the\nwheels, a wheel being a listbox like the list is.",
93651
93775
  "name": "HelixHeadlessTimePicker",
93652
93776
  "cssParts": [
93653
93777
  {
@@ -44,6 +44,7 @@ import { type PropertyValues, type TemplateResult } from 'lit';
44
44
  *
45
45
  * @cssproperty --carousel-gap - Space between slides. A sheet sets it and the component measures the run with it.
46
46
  * @cssproperty --carousel-pane - The size one pane is laid out at. A sheet sets it and the component measures the run with it.
47
+ * @cssproperty --carousel-per-view - How many slides go across, written onto the track by the component so a sheet divides the track by the same number the positions are counted from. Read it rather than selecting on `per-view`, which cannot be enumerated without a ceiling. See `perView`.
47
48
  * @cssproperty --carousel-run-end - How far short of a whole pixel the run ends, on the last slide alone, for a sheet to take up as `margin-inline-end`. See `runEnd`.
48
49
  */
49
50
  export declare class HelixHeadlessCarousel extends HelixElement {
@@ -161,12 +162,53 @@ export declare class HelixHeadlessCarousel extends HelixElement {
161
162
  * offset the track has already reached: pressing next walks the dots to the
162
163
  * end while the slides stop moving a third of the way through.
163
164
  *
165
+ * **The number is published to the styles rather than enumerated by them**,
166
+ * as `--carousel-per-view` on the track, which is what keeps a width and a
167
+ * count from disagreeing. A sheet can only name a value it wrote a rule for,
168
+ * so the styled tier enumerated `per-view="2"` through `5` and called five a
169
+ * judgment; above it the pane fell back to one across while this file went on
170
+ * counting positions. Measured in Chromium over eight slides, six across gave
171
+ * three dots, a pane taking the whole track and five slides reachable only by
172
+ * dragging. Written from here there is no ceiling to exceed, and a consumer's
173
+ * own sheet reads the same declaration the styled one does. `runEnd` publishes
174
+ * its correction the same way and for the same reason.
175
+ *
176
+ * **On the track and not on the host.** A custom property on the host is a
177
+ * reflected attribute by another name: it would arrive on upgrade, and a
178
+ * consumer's server markup never had it. Inside the component's own shadow
179
+ * root it serializes with the rest of the template on the server, and the
180
+ * track's own declaration beats anything a consumer inherits in, so the
181
+ * attribute is the one answer to how wide a pane is.
182
+ *
183
+ * A value the track cannot honor is taken to the nearest one it can, by
184
+ * `across`, and both tiers read that rather than this.
185
+ *
164
186
  * No default, because it reflects. A reflected property with a value writes
165
187
  * its attribute on upgrade, and the host then carries something a consumer's
166
188
  * server markup never had, which React reports as a mismatch. The one-across
167
189
  * case is the absent attribute, and the styles read it that way.
168
190
  */
169
191
  perView?: number;
192
+ /**
193
+ * `perView` as both tiers use it: a whole number of slides, one at least.
194
+ *
195
+ * **The clamp is here because the arithmetic is here**, and the two readers
196
+ * of this number have to be given the same one. A fraction is floored, since
197
+ * a position is a whole slide along: one and a half across leaves a last
198
+ * position the track runs out before reaching, which is the fault `goTo`
199
+ * already carries a comment about. Zero and a negative divide the track into
200
+ * nothing and into a pane facing the wrong way, and a non-numeric attribute
201
+ * parses to `NaN`, which `Math.max` propagates: it counted `NaN` positions,
202
+ * drew no indicators at all and left `index` at `NaN`. All of them read as
203
+ * one across, which is what a carousel with nothing sayable asked for.
204
+ *
205
+ * Not clamped to the number of slides. Six across four slides is four panes
206
+ * at a sixth of the track each and the one place to stand, which is what was
207
+ * asked for as nearly as it can be had, and the slide count is a fact the
208
+ * server does not have: clamping to it would draw one width there and another
209
+ * on upgrade.
210
+ */
211
+ private get across();
170
212
  /**
171
213
  * How many distinct views the track holds, which is what the indicators count.
172
214
  *
@@ -95,9 +95,12 @@ let HelixHeadlessCarousel = class HelixHeadlessCarousel extends HelixElement {
95
95
  this.indexState = next;
96
96
  this.requestUpdate('index', previous);
97
97
  }
98
+ get across() {
99
+ const asked = this.perView ?? 1;
100
+ return Number.isFinite(asked) ? Math.max(1, Math.floor(asked)) : 1;
101
+ }
98
102
  get positions() {
99
- const across = Math.max(1, Math.floor(this.perView ?? 1));
100
- return Math.max(1, this.slides.length - across + 1);
103
+ return Math.max(1, this.slides.length - this.across + 1);
101
104
  }
102
105
  get panes() {
103
106
  return [...(this.renderRoot?.querySelectorAll?.('[part="slide"]') ?? [])];
@@ -305,6 +308,7 @@ let HelixHeadlessCarousel = class HelixHeadlessCarousel extends HelixElement {
305
308
  <div
306
309
  data-scroller
307
310
  part="track"
311
+ style=${`--carousel-per-view: ${this.across}`}
308
312
  @scroll=${this.handleTrackScroll}
309
313
  @scrollend=${this.handleScroll}
310
314
  @pointerdown=${this.handleTake}
@@ -128,6 +128,52 @@ export declare class HelixHeadlessColorPicker extends HelixHeadlessColorPicker_b
128
128
  * would then be unreadable and unpasteable without opening a panel.
129
129
  */
130
130
  noValue: boolean;
131
+ /**
132
+ * Whether the control refuses changes while still submitting its value.
133
+ *
134
+ * **Enforced by refusing every request in one place**, which is the seam this
135
+ * component already has: `requestValue` is what every path here comes through,
136
+ * and gating it once is what stops the next call site from being written
137
+ * without the check.
138
+ *
139
+ * Not `disabled`, which is the confusion worth naming: a disabled control
140
+ * submits nothing and leaves the tab order, and a read-only one submits its
141
+ * value and stays reachable, which is what a form showing a color somebody
142
+ * else set needs.
143
+ *
144
+ * **One gate is not enough here, and the second is `move`.** This picker
145
+ * holds a model beside its value, which Date Picker and Time Picker do not:
146
+ * `moved` is the HSB the square is drawn from, and it is written before the
147
+ * value is requested. Gating only the request would leave the square under
148
+ * the reader's pointer and the value where it was, which is a control that
149
+ * refuses and looks like it accepted.
150
+ */
151
+ readOnly: boolean;
152
+ /**
153
+ * Whether the form refuses to submit while no color is chosen.
154
+ *
155
+ * **A color is exactly as requirable as a date**, which is the comparison
156
+ * that settles it: this element extends `HelixFormElement`, carries `name`
157
+ * and reports its value, so a consumer writing
158
+ * `<helix-color-picker name="brand" required>` inside a form has every reason
159
+ * to expect the form to refuse an empty one. Its two siblings in the same
160
+ * composition position, Date Picker and Time Picker, both check it.
161
+ *
162
+ * Written out rather than taken from `MixinField`, for the reason those two
163
+ * record: the mixin brings a label, a hint and a feedback region, and this is
164
+ * a panel composed *into* a field that already has all three, so taking it
165
+ * would give one control two of each. What is left is the validity call and
166
+ * the anchor the browser points its bubble at.
167
+ *
168
+ * **Emptiness is the only fault reported, and bad input deliberately is
169
+ * not.** The value row is typed into a character at a time and every
170
+ * keystroke reaches `requestValue`, so `#0`, `#00` and `#00f` would each be a
171
+ * reported fault on the way to `#00ff00`. Date Picker and Time Picker can
172
+ * report bad input because their value moves only on a commit. Color Input
173
+ * reports it for this family instead, once, against the field the reader
174
+ * typed into.
175
+ */
176
+ required: boolean;
131
177
  /**
132
178
  * Colors offered under the picker, as a comma-separated list.
133
179
  */
@@ -183,6 +229,8 @@ export declare class HelixHeadlessColorPicker extends HelixHeadlessColorPicker_b
183
229
  private settled;
184
230
  /** Takes what was typed, and lets the square follow only a whole color. */
185
231
  private readonly handleValueInput;
232
+ /** Refuses every change while read-only. See `readOnly`. */
233
+ requestValue(next: string): boolean;
186
234
  /** Moves part of the model and announces the value that follows from it. */
187
235
  private readonly move;
188
236
  /**
@@ -237,11 +285,24 @@ export declare class HelixHeadlessColorPicker extends HelixHeadlessColorPicker_b
237
285
  *
238
286
  * `null` rather than an empty string where there is no color, which is the
239
287
  * difference between a control that submits nothing and one that submits a
240
- * blank. There is no `setValidity` beside it: this element does not take
241
- * `MixinField`, and every validity member of `ElementInternals` is the
242
- * consumer's to reach through the field that wraps it.
288
+ * blank.
289
+ *
290
+ * The verdict goes beside it, because `required` is this element's own claim
291
+ * and nothing else can answer it: a picker standing on a page has no field
292
+ * around it to check on its behalf. What it is *not* is a second opinion on
293
+ * everything else, which is why bad input is left to Color Input. See
294
+ * `required`.
243
295
  */
244
296
  private sync;
297
+ /**
298
+ * Reports "required and empty", or clears it.
299
+ *
300
+ * Anchored on the square, which is where a reader would go to answer: it is
301
+ * the first control in the panel and the one `focus` puts the keyboard on, so
302
+ * the browser's bubble points at the thing to do rather than at the row that
303
+ * states the result.
304
+ */
305
+ private reportRequired;
245
306
  protected updated(changed: import('lit').PropertyValues): void;
246
307
  /** Puts the keyboard on the square, which is the control a reader wants. */
247
308
  focus(options?: FocusOptions): void;
@@ -262,6 +323,20 @@ export declare class HelixHeadlessColorPicker extends HelixHeadlessColorPicker_b
262
323
  * event and not this component's.
263
324
  */
264
325
  private takeArea;
326
+ /**
327
+ * Returns a control that moved itself to what the model still holds.
328
+ *
329
+ * **A refusal has to undo something, and here it is a handle.** Every other
330
+ * control in this picker is drawn from the model, so refusing the change
331
+ * leaves the picture right on its own. The two area ranges and the two
332
+ * channel sliders are not: each moved before it announced, and each is bound
333
+ * with `.value`, which lit dirty-checks against the value it last committed.
334
+ * The model never changed, so that binding writes nothing and the handle
335
+ * stays where the reader dragged it, on a control that refused. Carousel
336
+ * settles the same question the same way: a refusal puts the track back on
337
+ * the slide the index still holds.
338
+ */
339
+ private putBack;
265
340
  /**
266
341
  * A channel's new value, read off the slider that just applied it.
267
342
  *