@fusion.dev/helix-headless 0.22.0 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/custom-elements.json +48397 -26631
  2. package/dist/announcement/root/announcement-root.d.ts +19 -5
  3. package/dist/area-chart/index.d.ts +1 -0
  4. package/dist/area-chart/index.js +1 -0
  5. package/dist/area-chart/root/area-chart-root.d.ts +182 -0
  6. package/dist/area-chart/root/area-chart-root.js +205 -0
  7. package/dist/carousel/root/carousel-root.d.ts +1 -0
  8. package/dist/carousel/root/carousel-root.js +18 -2
  9. package/dist/chat/index.d.ts +1 -1
  10. package/dist/chat/message/chat-message.d.ts +7 -0
  11. package/dist/chat/message/chat-message.js +2 -1
  12. package/dist/chat/root/chat-root.d.ts +195 -4
  13. package/dist/chat/root/chat-root.js +316 -23
  14. package/dist/checkbox-group/root/checkbox-group-root.d.ts +2 -0
  15. package/dist/checkbox-group/root/checkbox-group-root.js +12 -2
  16. package/dist/code-block/index.d.ts +1 -0
  17. package/dist/code-block/index.js +1 -0
  18. package/dist/code-block/patch.d.ts +62 -0
  19. package/dist/code-block/patch.js +93 -0
  20. package/dist/code-block/root/code-block-root.d.ts +82 -17
  21. package/dist/code-block/root/code-block-root.js +83 -6
  22. package/dist/color-picker/root/color-picker-root.d.ts +4 -3
  23. package/dist/color-picker/root/color-picker-root.js +4 -1
  24. package/dist/data-table/root/data-table-root.d.ts +195 -23
  25. package/dist/data-table/root/data-table-root.js +308 -27
  26. package/dist/description-list/index.d.ts +2 -0
  27. package/dist/description-list/index.js +2 -0
  28. package/dist/description-list/item/description-list-item.d.ts +39 -0
  29. package/dist/description-list/item/description-list-item.js +26 -0
  30. package/dist/description-list/root/description-list-root.d.ts +56 -0
  31. package/dist/description-list/root/description-list-root.js +21 -0
  32. package/dist/element-events.generated.js +27 -6
  33. package/dist/filter-input/chip/filter-chip.d.ts +114 -0
  34. package/dist/filter-input/chip/filter-chip.js +61 -0
  35. package/dist/filter-input/field/filter-field.d.ts +128 -0
  36. package/dist/filter-input/field/filter-field.js +70 -0
  37. package/dist/filter-input/grammar.d.ts +96 -0
  38. package/dist/filter-input/grammar.js +133 -0
  39. package/dist/filter-input/index.d.ts +5 -0
  40. package/dist/filter-input/index.js +5 -0
  41. package/dist/filter-input/menu/filter-menu.d.ts +153 -0
  42. package/dist/filter-input/menu/filter-menu.js +164 -0
  43. package/dist/filter-input/operator/filter-operator.d.ts +105 -0
  44. package/dist/filter-input/operator/filter-operator.js +39 -0
  45. package/dist/filter-input/root/filter-input-root.d.ts +118 -9
  46. package/dist/filter-input/root/filter-input-root.js +96 -2
  47. package/dist/format-date/root/format-date-root.js +1 -1
  48. package/dist/index.d.ts +5 -0
  49. package/dist/index.js +5 -0
  50. package/dist/line-chart/root/line-chart-root.d.ts +9 -2
  51. package/dist/listbox/root/listbox-root.d.ts +8 -7
  52. package/dist/listbox/root/listbox-root.js +7 -2
  53. package/dist/menu/item/menu-item.d.ts +54 -6
  54. package/dist/menu/item/menu-item.js +31 -6
  55. package/dist/menu/root/menu-root.d.ts +23 -0
  56. package/dist/menu/root/menu-root.js +13 -2
  57. package/dist/notifications/group/notification-group.d.ts +129 -0
  58. package/dist/notifications/group/notification-group.js +106 -0
  59. package/dist/notifications/index.d.ts +1 -0
  60. package/dist/notifications/index.js +1 -0
  61. package/dist/notifications/notification/notification.d.ts +39 -13
  62. package/dist/notifications/notification/notification.js +11 -8
  63. package/dist/notifications/root/notifications-root.d.ts +57 -1
  64. package/dist/notifications/root/notifications-root.js +35 -4
  65. package/dist/number-input/root/number-input-root.d.ts +21 -1
  66. package/dist/number-input/root/number-input-root.js +18 -5
  67. package/dist/object-inspector/index.d.ts +1 -0
  68. package/dist/object-inspector/index.js +1 -0
  69. package/dist/object-inspector/root/object-inspector-root.d.ts +183 -0
  70. package/dist/object-inspector/root/object-inspector-root.js +348 -0
  71. package/dist/outline/root/outline-root.d.ts +16 -1
  72. package/dist/outline/root/outline-root.js +27 -9
  73. package/dist/radio/group/radio-group.d.ts +1 -0
  74. package/dist/scatter-chart/index.d.ts +1 -0
  75. package/dist/scatter-chart/index.js +1 -0
  76. package/dist/scatter-chart/root/scatter-chart-root.d.ts +144 -0
  77. package/dist/scatter-chart/root/scatter-chart-root.js +205 -0
  78. package/dist/skip-link/index.d.ts +1 -0
  79. package/dist/skip-link/index.js +1 -0
  80. package/dist/skip-link/root/skip-link-root.d.ts +81 -0
  81. package/dist/skip-link/root/skip-link-root.js +58 -0
  82. package/dist/speed-dial/root/speed-dial-root.d.ts +1 -0
  83. package/dist/speed-dial/root/speed-dial-root.js +6 -2
  84. package/dist/steps/root/steps-root.d.ts +1 -0
  85. package/dist/table/column/table-column.d.ts +79 -0
  86. package/dist/table/column/table-column.js +125 -5
  87. package/dist/table/root/table-root.d.ts +2 -0
  88. package/dist/table/root/table-root.js +12 -3
  89. package/dist/time-picker/root/time-picker-root.d.ts +9 -0
  90. package/dist/time-picker/root/time-picker-root.js +5 -0
  91. package/dist/toast/root/toast-root.d.ts +2 -0
  92. package/dist/tooltip/root/tooltip-root.js +1 -1
  93. package/dist/tour/root/tour-root.d.ts +1 -0
  94. package/dist/tree/item/tree-item.d.ts +7 -4
  95. package/dist/tree/item/tree-item.js +4 -1
  96. package/dist/video/root/video-root.d.ts +23 -1
  97. package/dist/video/root/video-root.js +42 -22
  98. package/dist/virtual-list/root/virtual-list-root.d.ts +10 -6
  99. package/dist/virtual-list/root/virtual-list-root.js +10 -4
  100. package/package.json +5 -5
  101. package/types/jsx.d.ts +4535 -346
  102. package/types/svelte.d.ts +11 -0
  103. package/types/vue.d.ts +737 -39
@@ -32,7 +32,33 @@ let HelixHeadlessNotifications = class HelixHeadlessNotifications extends MixinC
32
32
  return this.items.filter((item) => !item.read).length;
33
33
  }
34
34
  get items() {
35
- return [...(this.children ?? [])].filter((child) => 'isNotification' in child && child.isNotification === true);
35
+ const isItem = (child) => 'isNotification' in child && child.isNotification === true;
36
+ return this.knownChildren.flatMap((child) => {
37
+ if (isItem(child)) {
38
+ return [child];
39
+ }
40
+ const grouped = 'isNotificationGroup' in child ? [...(child.children ?? [])] : [];
41
+ return grouped.filter(isItem);
42
+ });
43
+ }
44
+ get rows() {
45
+ return this.knownChildren.filter((child) => ('isNotification' in child && child.isNotification === true) ||
46
+ 'isNotificationGroup' in child);
47
+ }
48
+ get groups() {
49
+ return this.knownChildren.filter((child) => 'isNotificationGroup' in child);
50
+ }
51
+ foldEveryGroup(folded = true) {
52
+ let moved = 0;
53
+ for (const group of this.groups) {
54
+ if (!group.collapsible || group.open !== folded) {
55
+ continue;
56
+ }
57
+ if (group.requestOpen(!folded)) {
58
+ moved += 1;
59
+ }
60
+ }
61
+ return moved;
36
62
  }
37
63
  markEveryoneRead() {
38
64
  if (!this.dispatchEvent(new HelixReadEvent({ read: true }))) {
@@ -53,8 +79,13 @@ let HelixHeadlessNotifications = class HelixHeadlessNotifications extends MixinC
53
79
  if (!list?.assign) {
54
80
  return;
55
81
  }
56
- const items = this.items;
57
- list.assign(...items);
82
+ if (this.assignsByName) {
83
+ for (const row of this.rows) {
84
+ this.route(row, 'items');
85
+ }
86
+ return;
87
+ }
88
+ list.assign(...this.rows);
58
89
  for (const name of ['header', 'footer']) {
59
90
  const slot = root?.querySelector?.(`slot[name="${name}"]`);
60
91
  slot?.assign?.(...[...this.children].filter((child) => child.getAttribute('slot') === name));
@@ -101,7 +132,7 @@ let HelixHeadlessNotifications = class HelixHeadlessNotifications extends MixinC
101
132
  }
102
133
  }
103
134
  render() {
104
- const hasItems = this.items.length > 0;
135
+ const hasItems = this.items.length > 0 || !this.childrenKnown;
105
136
  return html `<div part="header">
106
137
  <slot name="header"></slot>
107
138
  ${this.markAll && this.unread > 0
@@ -142,6 +142,18 @@ export declare class HelixHeadlessNumberInput extends HelixHeadlessNumberInput_b
142
142
  * stepping to 0 would be out of range before the reader had typed anything.
143
143
  */
144
144
  private nudge;
145
+ /**
146
+ * A value the reader moved to in one gesture, applied and committed.
147
+ *
148
+ * **A step is finished when it lands, so it commits.** The field sends
149
+ * `change` on blur for what the reader typed, and a step is written by
150
+ * script, so the browser never sends one for it: three presses of the plus
151
+ * and a move elsewhere reached a form listening on `change` as nothing at
152
+ * all. A native number field commits on every step, and so does this, for
153
+ * the arrows, the buttons, and `Home` and `End`. Only when the value moved: a
154
+ * refused step, or one pinned at a bound, finished nothing.
155
+ */
156
+ private land;
145
157
  /** One step up, or `PageUp`'s larger one. */
146
158
  stepUp(large?: boolean): void;
147
159
  /**
@@ -173,6 +185,8 @@ export declare class HelixHeadlessNumberInput extends HelixHeadlessNumberInput_b
173
185
  /** Where the pointer went down, and what the value was there. */
174
186
  private scrubFrom;
175
187
  private scrubValue;
188
+ /** The value when the press began, which is what a release is compared to. */
189
+ private scrubStart;
176
190
  /**
177
191
  * Press, and the value follows the pointer.
178
192
  *
@@ -193,7 +207,13 @@ export declare class HelixHeadlessNumberInput extends HelixHeadlessNumberInput_b
193
207
  * the value can only be where the pointer says it is.
194
208
  */
195
209
  private readonly handleScrubMove;
196
- /** Let go, and the capture goes with it. */
210
+ /**
211
+ * Let go, and the capture goes with it, and the drag commits.
212
+ *
213
+ * The same reason a step does: every frame of the drag was written by script,
214
+ * so the browser sends no `change` for any of it, and a drag that moved the
215
+ * value is finished when the pointer lets go.
216
+ */
197
217
  private readonly handleScrubEnd;
198
218
  /**
199
219
  * Every keystroke, cancelable, and put back where it is refused.
@@ -27,6 +27,7 @@ let HelixHeadlessNumberInput = class HelixHeadlessNumberInput extends MixinContr
27
27
  this.step = 1;
28
28
  this.scrubFrom = 0;
29
29
  this.scrubValue = 0;
30
+ this.scrubStart = '';
30
31
  this.handleScrubDown = (event) => {
31
32
  if (this.isDisabled || this.readOnly) {
32
33
  return;
@@ -35,6 +36,7 @@ let HelixHeadlessNumberInput = class HelixHeadlessNumberInput extends MixinContr
35
36
  event.currentTarget.setPointerCapture(event.pointerId);
36
37
  this.scrubFrom = event.clientX;
37
38
  this.scrubValue = this.numeric ?? this.min ?? 0;
39
+ this.scrubStart = this.value;
38
40
  event.preventDefault();
39
41
  };
40
42
  this.handleScrubMove = (event) => {
@@ -58,8 +60,12 @@ let HelixHeadlessNumberInput = class HelixHeadlessNumberInput extends MixinContr
58
60
  };
59
61
  this.handleScrubEnd = (event) => {
60
62
  const grip = event.currentTarget;
61
- if (grip.hasPointerCapture(event.pointerId)) {
62
- grip.releasePointerCapture(event.pointerId);
63
+ if (!grip.hasPointerCapture(event.pointerId)) {
64
+ return;
65
+ }
66
+ grip.releasePointerCapture(event.pointerId);
67
+ if (this.value !== this.scrubStart) {
68
+ this.dispatchEvent(new Event('change', { bubbles: true, composed: false }));
63
69
  }
64
70
  };
65
71
  this.handleInput = (event) => {
@@ -98,13 +104,13 @@ let HelixHeadlessNumberInput = class HelixHeadlessNumberInput extends MixinContr
98
104
  this.min !== undefined &&
99
105
  !this.isDisabled &&
100
106
  !this.readOnly) {
101
- this.requestValue(String(this.min));
107
+ this.land(String(this.min));
102
108
  }
103
109
  else if (event.key === 'End' &&
104
110
  this.max !== undefined &&
105
111
  !this.isDisabled &&
106
112
  !this.readOnly) {
107
- this.requestValue(String(this.max));
113
+ this.land(String(this.max));
108
114
  }
109
115
  else {
110
116
  return;
@@ -142,11 +148,18 @@ let HelixHeadlessNumberInput = class HelixHeadlessNumberInput extends MixinContr
142
148
  const step = Math.abs(this.step) || 1;
143
149
  const from = this.numeric ?? this.min ?? 0;
144
150
  const next = this.clamp(this.numeric === null ? from : from + steps * step);
145
- this.requestValue(String(next));
151
+ this.land(String(next));
152
+ }
153
+ land(next) {
154
+ const before = this.value;
155
+ const applied = this.requestValue(next);
146
156
  const control = this.control;
147
157
  if (control) {
148
158
  restoreValue(control, this.value);
149
159
  }
160
+ if (applied && this.value !== before) {
161
+ this.dispatchEvent(new Event('change', { bubbles: true, composed: false }));
162
+ }
150
163
  }
151
164
  stepUp(large = false) {
152
165
  this.nudge(large ? (this.largeStep ?? 10) : 1);
@@ -0,0 +1 @@
1
+ export * from './root/object-inspector-root.js';
@@ -0,0 +1 @@
1
+ export * from './root/object-inspector-root.js';
@@ -0,0 +1,183 @@
1
+ import { HelixElement } from '@fusion.dev/helix-core';
2
+ import { type PropertyValues, type TemplateResult } from 'lit';
3
+ import '../../copy-button/index.js';
4
+ /** One visible line of the tree: a value, where it sits, and whether it is open. */
5
+ interface Row {
6
+ branch: boolean;
7
+ depth: number;
8
+ /** The property name or array index this value is under; absent for the root. */
9
+ key?: string;
10
+ open: boolean;
11
+ path: string;
12
+ position: number;
13
+ siblings: number;
14
+ value: unknown;
15
+ }
16
+ /**
17
+ * @summary A value read as a tree: collapse what you do not need, count what
18
+ * you collapsed, copy the part you do.
19
+ *
20
+ * @description
21
+ * What a developer-facing product shows constantly is a structured value: an
22
+ * API response, a config, a row's raw record. As text in a code block, a reader
23
+ * scrolls a wall of JSON and cannot put away the branch they do not care about;
24
+ * as a Tree, every node is a label and a string reads the same as a number. This
25
+ * reads the value and draws each entry with its type visible.
26
+ *
27
+ * **It reads and never edits.** An inspector that edits is a different
28
+ * component, with validation, undo and a model of what changed, and the reading
29
+ * one is what is wanted.
30
+ *
31
+ * **The data is text in the page or a property.** `for` names a
32
+ * `<script type="application/json">` by id, the channel `VirtualList` and the
33
+ * charts already read: it survives a server, which has attributes and no
34
+ * children, and React's hydration, which skips object properties. `value` is
35
+ * there for a page that already holds the object, and wins when both are set.
36
+ *
37
+ * **One tab stop, and the rows are reached with the arrow keys**, the tree
38
+ * pattern: Up and Down move, Right opens a branch or enters it, Left closes it or
39
+ * goes to its parent, Home and End go to the ends. The tree keeps focus and
40
+ * points at the active row with `aria-activedescendant`, which is what lets a
41
+ * windowed tree drop rows from the page without dropping focus with them. Each
42
+ * row carries its real level, position and set size, so a reader on a windowed
43
+ * row hears where it is in the value rather than in the slice drawn.
44
+ *
45
+ * **Copying takes the active row**, as JSON for a branch and as itself for a
46
+ * string, from the copy button or from Command or Control with C while the tree
47
+ * has focus and nothing is selected. The button sits beside the tree rather than in each row, where a
48
+ * button would be an interactive control inside a tree item, which assistive
49
+ * technology cannot reach reliably.
50
+ *
51
+ * **`windowed` draws only the rows in view**, for a value of thousands of
52
+ * entries, through the same controller `VirtualList` and `DataTable` use. The
53
+ * box has to have a height for that to mean anything, which the styled tier
54
+ * gives it and a headless consumer has to.
55
+ *
56
+ * @since 0.1.0
57
+ * @status experimental
58
+ * @category data
59
+ * @aliases JSON viewer, Object viewer, Inspector, Data explorer
60
+ * @documentation https://helix.fusion.dev/components/object-inspector
61
+ *
62
+ * @event {HelixCopyEvent} helix-copy - A value was put on the clipboard, from the copy button or the keyboard.
63
+ *
64
+ * @csspart after - The room the rows after the window would take, when windowed.
65
+ * @csspart before - The room the rows before the window would take, when windowed.
66
+ * @csspart boolean - A `true` or `false`.
67
+ * @csspart copy - The copy button, which copies the active row.
68
+ * @csspart copy-button - The inner button.
69
+ * @csspart copy-mark - The clipboard glyph, and the confirmation that replaces it.
70
+ * @csspart copy-tooltip - The bubble, forwarded from the tooltip inside.
71
+ * @csspart copy-tooltip-arrow - The point, resting against the trigger.
72
+ * @csspart count - How many entries a branch holds.
73
+ * @csspart frame - The tree and the copy button beside it.
74
+ * @csspart header - The bar carrying the label, where there is one.
75
+ * @csspart key - A property name or an array index.
76
+ * @csspart label - The label.
77
+ * @csspart null - A `null`.
78
+ * @csspart number - A number.
79
+ * @csspart row - One entry, a tree item.
80
+ * @csspart string - A string, in quotes.
81
+ * @csspart summary - The brackets standing for a branch's contents.
82
+ * @csspart toggle - The caret on a branch: down when open, across when closed.
83
+ * @csspart tree - The tree, the one thing focus lands on.
84
+ *
85
+ * @cssproperty --object-inspector-level - How deep a row is, from 0 at the root, for indenting it.
86
+ */
87
+ export declare class HelixHeadlessObjectInspector extends HelixElement {
88
+ /**
89
+ * How many levels start open.
90
+ *
91
+ * One by default: the root is open and everything under it closed, so a
92
+ * reader sees the shape of the value before its contents. `0` starts with the
93
+ * root closed; a large number opens everything, which on a big value is the
94
+ * wall of text this exists to avoid.
95
+ */
96
+ defaultDepth: number;
97
+ /**
98
+ * The id of a `<script type="application/json">` holding the value.
99
+ *
100
+ * Read once the document exists, and again whenever this changes. Text that
101
+ * does not parse leaves the inspector empty rather than throwing, since a
102
+ * page's markup should not take the page down over a comma.
103
+ */
104
+ for: string;
105
+ /**
106
+ * Accessible name for the tree, and the text of the header where there is one.
107
+ */
108
+ label: string;
109
+ /**
110
+ * Whether to leave the copy button off.
111
+ *
112
+ * Negative for the reason Code Block's is: a boolean attribute defaulting to
113
+ * true could never be turned off from markup.
114
+ */
115
+ noCopy: boolean;
116
+ /**
117
+ * The value itself, for a page that already holds it.
118
+ *
119
+ * Takes precedence over `for`. Anything JSON can say is drawn; anything else
120
+ * is shown as its string.
121
+ */
122
+ value: unknown;
123
+ /**
124
+ * Whether to draw only the rows in view.
125
+ *
126
+ * For a value of thousands of entries. Reflected, because the box it scrolls
127
+ * needs a height, which is a stylesheet rule reading this attribute.
128
+ */
129
+ windowed: boolean;
130
+ /** The value read from `for`, when there is no `value`. */
131
+ private read;
132
+ /** The `for` that `read` came from, so it is read again only when that changes. */
133
+ private loadedFor;
134
+ /** Which branches are open, by path. */
135
+ private opened;
136
+ /** The row the arrow keys are on, by its place among the visible rows. */
137
+ private active;
138
+ /** Set by a keyboard move, so the next render brings the active row into view. */
139
+ private revealing;
140
+ private readonly virtualize;
141
+ private get root();
142
+ /** Every visible row, in order, worked out once per change rather than per read. */
143
+ private rows;
144
+ private readonly copier;
145
+ /** Every visible row, in order, for the tree as it stands. */
146
+ private flatten;
147
+ /** Opens every branch shallower than `defaultDepth`. */
148
+ private seed;
149
+ protected willUpdate(changed: PropertyValues): void;
150
+ protected firstUpdated(changed: PropertyValues): void;
151
+ protected updated(changed: PropertyValues): void;
152
+ private load;
153
+ /**
154
+ * Brings the active row into the box.
155
+ *
156
+ * **A windowed tree may not have drawn it, and a jump straight to where it
157
+ * should be does not land.** The controller places rows it has not measured at
158
+ * its estimate, so an offset computed from a real row's height points at a
159
+ * different row, and asking again from there asks the same wrong question: the
160
+ * first version of this looped until the page stopped. So each attempt steps
161
+ * from the rows that *are* drawn toward the one wanted, by how many rows lie
162
+ * between, which closes the gap every time whatever the estimate is, and gives
163
+ * up after a few rather than trusting that it always will.
164
+ */
165
+ private reveal;
166
+ /** What copying takes: a branch as indented JSON, a string as itself. */
167
+ private copyable;
168
+ private toggle;
169
+ private move;
170
+ private readonly handleKeydown;
171
+ private handleRowClick;
172
+ private renderValue;
173
+ private renderRow;
174
+ /** The copy button, behind the seam Code Block's uses, so each tier renders its own. */
175
+ protected renderCopyButton(row: Row | undefined): TemplateResult;
176
+ protected render(): TemplateResult;
177
+ }
178
+ declare global {
179
+ interface HTMLElementTagNameMap {
180
+ 'helix-headless-object-inspector': HelixHeadlessObjectInspector;
181
+ }
182
+ }
183
+ export {};