@fusion.dev/helix 0.43.0 → 0.45.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 (33) hide show
  1. package/custom-elements.json +138 -73
  2. package/dist/chat/composer/chat-composer.d.ts +1 -1
  3. package/dist/chat/message/chat-message.d.ts +1 -1
  4. package/dist/chat/root/chat-root.d.ts +1 -1
  5. package/dist/element-events.generated.js +1 -7
  6. package/dist/filter-input/chip/filter-chip.d.ts +1 -1
  7. package/dist/filter-input/field/filter-field.d.ts +1 -1
  8. package/dist/filter-input/menu/filter-menu.d.ts +1 -1
  9. package/dist/filter-input/operator/filter-operator.d.ts +1 -1
  10. package/dist/filter-input/root/filter-input-root.d.ts +1 -1
  11. package/dist/notifications/group/notification-group.d.ts +1 -1
  12. package/dist/notifications/notification/notification.d.ts +1 -1
  13. package/dist/notifications/root/notifications-root.d.ts +1 -1
  14. package/dist/option/group/option-group.d.ts +1 -1
  15. package/dist/option/root/option-root.d.ts +1 -1
  16. package/dist/radio/group/radio-group.d.ts +1 -1
  17. package/dist/radio/root/radio-root.d.ts +1 -1
  18. package/dist/sandbox/preview/sandbox-preview.d.ts +15 -0
  19. package/dist/sandbox/preview/sandbox-preview.js +2 -2
  20. package/dist/sandbox/root/sandbox-root.d.ts +43 -4
  21. package/dist/sandbox/root/sandbox-root.js +33 -12
  22. package/dist/sandbox/status-bar/sandbox-status-bar.js +1 -1
  23. package/dist/skip-link/root/skip-link-root.d.ts +2 -1
  24. package/dist/speed-dial/item/speed-dial-item.css.js +1 -5
  25. package/dist/speed-dial/item/speed-dial-item.d.ts +1 -1
  26. package/dist/speed-dial/root/speed-dial-root.css.js +4 -0
  27. package/dist/speed-dial/root/speed-dial-root.d.ts +1 -1
  28. package/dist/text/root/text-root.d.ts +1 -1
  29. package/dist/toast/item/toast-item.d.ts +1 -1
  30. package/dist/toast/root/toast-root.d.ts +2 -2
  31. package/package.json +6 -6
  32. package/types/jsx.d.ts +154 -20
  33. package/types/vue.d.ts +40 -7
@@ -9,7 +9,7 @@ import type { CSSResultGroup } from 'lit';
9
9
  * tells you which list, not something to read on its own.
10
10
  *
11
11
  * @since 0.1.0
12
- * @status experimental
12
+ * @status stable
13
13
  * @aliases OptGroup, Section
14
14
  * @documentation https://fusion.dev/helix/components/option
15
15
  */
@@ -10,7 +10,7 @@ import type { CSSResultGroup } from 'lit';
10
10
  * picked from what they are looking at.
11
11
  *
12
12
  * @since 0.1.0
13
- * @status experimental
13
+ * @status stable
14
14
  * @category forms
15
15
  * @aliases Item, Choice
16
16
  * @documentation https://fusion.dev/helix/components/option
@@ -10,7 +10,7 @@ import type { CSSResultGroup } from 'lit';
10
10
  * group keeps its question above the row rather than beside the first choice.
11
11
  *
12
12
  * @since 0.1.0
13
- * @status experimental
13
+ * @status stable
14
14
  * @aliases RadioButtons, Choice group
15
15
  * @documentation https://fusion.dev/helix/components/radio
16
16
  *
@@ -14,7 +14,7 @@ import type { CSSResultGroup } from 'lit';
14
14
  * and being chosen is an answer rather than a state.
15
15
  *
16
16
  * @since 0.1.0
17
- * @status experimental
17
+ * @status stable
18
18
  * @category forms
19
19
  * @aliases Option, Choice
20
20
  * @documentation https://fusion.dev/helix/components/radio
@@ -87,6 +87,11 @@ export declare class HelixSandboxPreview extends HelixElement {
87
87
  colorMode?: 'dark' | 'light';
88
88
  /**
89
89
  * Writing direction inside the frame.
90
+ *
91
+ * Not reflected. It is payload for the render message and nothing selects on
92
+ * it, here or anywhere: a frame is a document of its own and what is written
93
+ * on this host reaches nothing inside it, which is the same reason
94
+ * `colorMode` has to be sent rather than set.
90
95
  */
91
96
  direction?: 'rtl';
92
97
  /**
@@ -95,6 +100,16 @@ export declare class HelixSandboxPreview extends HelixElement {
95
100
  label: string;
96
101
  /**
97
102
  * How the example is placed in the frame.
103
+ *
104
+ * `padded` insets it and leaves it at the top, which is the resting case and
105
+ * what an absent value sends. `centered` gives it a measure and centers that
106
+ * box in the frame. `hug` shrinks the example to its own content and centers
107
+ * what is left, which is the difference that matters for a component whose
108
+ * root is a full-width block. `fullscreen` is the whole frame with no inset.
109
+ *
110
+ * Not reflected, for `direction`'s reason: the placement is applied by the
111
+ * document inside the frame, against its own root, so no rule on this side
112
+ * could read it.
98
113
  */
99
114
  layout?: 'padded' | 'centered' | 'fullscreen' | 'hug';
100
115
  /**
@@ -114,13 +114,13 @@ __decorate([
114
114
  property({ attribute: 'color-mode' })
115
115
  ], HelixSandboxPreview.prototype, "colorMode", void 0);
116
116
  __decorate([
117
- property({ reflect: true })
117
+ property()
118
118
  ], HelixSandboxPreview.prototype, "direction", void 0);
119
119
  __decorate([
120
120
  property()
121
121
  ], HelixSandboxPreview.prototype, "label", void 0);
122
122
  __decorate([
123
- property({ reflect: true })
123
+ property()
124
124
  ], HelixSandboxPreview.prototype, "layout", void 0);
125
125
  __decorate([
126
126
  property()
@@ -95,6 +95,11 @@ export declare class HelixSandbox extends HelixElement {
95
95
  lead: 'source' | 'preview';
96
96
  /**
97
97
  * Whether the panes sit side by side or stacked.
98
+ *
99
+ * Not reflected, for `lead`'s reason above: no rule selects on it. The axis
100
+ * reaches the stylesheet as the inner splitter's own `orientation`, which is
101
+ * where the panes are laid out, and this element's sheet names no host
102
+ * attribute at all.
98
103
  */
99
104
  orientation?: 'horizontal' | 'vertical';
100
105
  /**
@@ -230,7 +235,7 @@ export declare class HelixSandbox extends HelixElement {
230
235
  */
231
236
  private get axis();
232
237
  /**
233
- * Says the panes' divider has settled, so a consumer can keep it.
238
+ * Asks for the panes' divider to settle here, and moves it unless refused.
234
239
  *
235
240
  * When it settles, not while it moves. A drag is a stream of positions and
236
241
  * only the one it ends at is a preference; announcing each would ask whoever
@@ -241,13 +246,25 @@ export declare class HelixSandbox extends HelixElement {
241
246
  * wrote to storage on its own would be deciding for all of them under a key
242
247
  * it chose.
243
248
  *
249
+ * **Through `requestChange`, and never the other way round.** Both of these
250
+ * fired after `split` and `panelSize` had already been written, with the
251
+ * answer dropped, so a consumer calling `preventDefault()` on an event whose
252
+ * own line says refusing it takes the decision changed nothing whatever: the
253
+ * divider stayed where the drag left it and their handler read a value they
254
+ * had just declined. `SandboxSource.edit` two files away already carries the
255
+ * argument, that assigning first turns a `before` event into one that has
256
+ * already happened, and `Splitter`, whose `helix-before-resize` these two were
257
+ * split out of, has always announced through the audited path. Refusing one
258
+ * now leaves `.position` bound to the value this element still holds, so the
259
+ * divider goes back where it was.
260
+ *
244
261
  * **A verb each, rather than one `helix-before-resize` naming which of the two
245
262
  * moved.** Both dividers are this element's, so `composedPath()[0]` is the same
246
263
  * host for either and the event name is the only thing that can separate them.
247
264
  */
248
- private splitSettled;
249
- /** As `splitSettled`, for the panel, whose value is pixels rather than a share. */
250
- private panelSettled;
265
+ private requestSplit;
266
+ /** As `requestSplit`, for the panel, whose value is pixels rather than a share. */
267
+ private requestPanelSize;
251
268
  /**
252
269
  * Answers a divider that has asked to move.
253
270
  *
@@ -261,9 +278,31 @@ export declare class HelixSandbox extends HelixElement {
261
278
  * speaking for itself is one of ours, and only those are stopped: the sandbox
262
279
  * announces `helix-before-split` and `helix-before-panel-resize` in their
263
280
  * place, and a consumer never sees the two splitters inside it.
281
+ *
282
+ * **Refused as well as stopped, which is what "controlled from here" costs.**
283
+ * A splitter nobody refuses applies the move itself and says so in its own
284
+ * docblock, so the sentence above was true only while nothing downstream ever
285
+ * declined: refusing `helix-before-split` left `split` at fifty and the
286
+ * divider drawn at fifty-two, one element holding the arrangement and the
287
+ * other showing it. Refusing the inner request first makes this element the
288
+ * single answer.
289
+ *
290
+ * **And the divider is written back, because a refusal writes nothing.** A
291
+ * splitter draws itself from where the gesture reached until its `position` is
292
+ * assigned, which is the setter's stated job, and a bound property Lit did not
293
+ * change is a property Lit does not write. So the answer is assigned either
294
+ * way, which for an accepted move is the number the binding is about to carry
295
+ * anyway.
264
296
  */
265
297
  private readonly handlePanesChange;
266
298
  private readonly handlePanelChange;
299
+ /**
300
+ * Puts a divider where this element says it is.
301
+ *
302
+ * Typed by what is used rather than by the class, which is the whole of the
303
+ * coupling: a splitter this does not import is one that can be replaced.
304
+ */
305
+ private answer;
267
306
  connectedCallback(): void;
268
307
  /** Watches the body, whose height is what the pane sizes are computed from. */
269
308
  private watchBody;
@@ -4,7 +4,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { customElement, HelixBeforePanelResizeEvent, HelixBeforeSplitEvent, HelixElement, } from '@fusion.dev/helix-core';
7
+ import { customElement, HelixBeforePanelResizeEvent, HelixBeforeSplitEvent, HelixElement, requestChange, } from '@fusion.dev/helix-core';
8
8
  import '../../splitter/index.js';
9
9
  import { html } from 'lit';
10
10
  import { property, state } from 'lit/decorators.js';
@@ -71,8 +71,9 @@ let HelixSandbox = class HelixSandbox extends HelixElement {
71
71
  }
72
72
  const { value } = event.detail;
73
73
  event.stopPropagation();
74
- this.split = Number(value);
75
- this.splitSettled();
74
+ event.preventDefault();
75
+ this.requestSplit(Number(value));
76
+ this.answer(event.currentTarget, this.split);
76
77
  };
77
78
  this.handlePanelChange = (event) => {
78
79
  if (event.target !== event.currentTarget) {
@@ -80,11 +81,11 @@ let HelixSandbox = class HelixSandbox extends HelixElement {
80
81
  }
81
82
  const { value } = event.detail;
82
83
  event.stopPropagation();
83
- if (this.bodyHeight <= 0) {
84
- return;
84
+ event.preventDefault();
85
+ if (this.bodyHeight > 0) {
86
+ this.requestPanelSize(Math.max(0, ((100 - Number(value)) / 100) * this.bodyHeight));
85
87
  }
86
- this.panelSize = Math.max(0, ((100 - Number(value)) / 100) * this.bodyHeight);
87
- this.panelSettled();
88
+ this.answer(event.currentTarget, this.panelPosition);
88
89
  };
89
90
  this.readPanel = () => {
90
91
  this.hasPanel = this.querySelector(':scope > [slot="panel"]') !== null;
@@ -135,11 +136,31 @@ let HelixSandbox = class HelixSandbox extends HelixElement {
135
136
  get axis() {
136
137
  return this.orientation ?? 'horizontal';
137
138
  }
138
- splitSettled() {
139
- this.dispatchEvent(new HelixBeforeSplitEvent({ value: String(this.split) }));
139
+ requestSplit(next) {
140
+ return requestChange({
141
+ apply: (value) => {
142
+ this.split = value;
143
+ },
144
+ event: (value) => new HelixBeforeSplitEvent({ value: String(value) }),
145
+ host: this,
146
+ next,
147
+ });
148
+ }
149
+ requestPanelSize(next) {
150
+ return requestChange({
151
+ apply: (value) => {
152
+ this.panelSize = value;
153
+ },
154
+ event: (value) => new HelixBeforePanelResizeEvent({ value: String(value) }),
155
+ host: this,
156
+ next,
157
+ });
140
158
  }
141
- panelSettled() {
142
- this.dispatchEvent(new HelixBeforePanelResizeEvent({ value: String(this.panelSize) }));
159
+ answer(divider, position) {
160
+ const target = divider;
161
+ if (target && Number.isFinite(position)) {
162
+ target.position = position;
163
+ }
143
164
  }
144
165
  connectedCallback() {
145
166
  super.connectedCallback();
@@ -233,7 +254,7 @@ __decorate([
233
254
  property()
234
255
  ], HelixSandbox.prototype, "lead", void 0);
235
256
  __decorate([
236
- property({ reflect: true })
257
+ property()
237
258
  ], HelixSandbox.prototype, "orientation", void 0);
238
259
  __decorate([
239
260
  property({ attribute: 'panel-collapsed-size', type: Number })
@@ -28,7 +28,7 @@ let HelixSandboxStatusBar = class HelixSandboxStatusBar extends HelixElement {
28
28
  ${position === undefined ? nothing : html `<span part="caret">${position}</span>`}
29
29
  ${language === undefined
30
30
  ? nothing
31
- : html `<span part="language">${LABELS[language] ?? language}</span>`}
31
+ : html `<span part="language">${Object.hasOwn(LABELS, language) ? LABELS[language] : language}</span>`}
32
32
  <slot name="end"></slot>`;
33
33
  }
34
34
  static { this.styles = styles; }
@@ -20,8 +20,9 @@ import type { CSSResultGroup } from 'lit';
20
20
  * region the id its `href` names.
21
21
  *
22
22
  * @since 0.1.0
23
- * @status experimental
23
+ * @status stable
24
24
  * @category navigation
25
+ * @aliases Skip navigation, Skip to content
25
26
  * @documentation https://fusion.dev/helix/components/skip-link
26
27
  *
27
28
  * @cssproperty --skip-link-border-color - Color of the revealed link's edge.
@@ -10,16 +10,12 @@ border: none;
10
10
  color: inherit;
11
11
  cursor: pointer;
12
12
  display: inline-flex;
13
- flex-direction: row-reverse;
13
+ flex-direction: var(--_speed-dial-row, row-reverse);
14
14
  font: inherit;
15
15
  gap: var(--helix-space-sm);
16
16
  padding: var(--helix-space-none);
17
17
  }
18
18
 
19
- :host-context([data-placement$="-start"]) [part="item"] {
20
- flex-direction: row;
21
- }
22
-
23
19
  [part="item"]:disabled {
24
20
  cursor: not-allowed;
25
21
  opacity: 0.5;
@@ -9,7 +9,7 @@ import type { CSSResultGroup } from 'lit';
9
9
  * over. Everything about choosing it is the base class.
10
10
  *
11
11
  * @since 0.1.0
12
- * @status experimental
12
+ * @status stable
13
13
  * @category actions
14
14
  * @aliases Speed dial action, FAB action, Quick action
15
15
  * @documentation https://fusion.dev/helix/components/speed-dial
@@ -15,10 +15,14 @@ padding: var(--helix-space-none);
15
15
  }
16
16
 
17
17
  [part="actions"] {
18
+ --_speed-dial-row: row-reverse;
19
+
18
20
  align-items: flex-end;
19
21
  }
20
22
 
21
23
  [part="actions"][data-placement$="-start"] {
24
+ --_speed-dial-row: row;
25
+
22
26
  align-items: flex-start;
23
27
  }
24
28
 
@@ -10,7 +10,7 @@ import '../../icon/index.js';
10
10
  * moves through it is the base class.
11
11
  *
12
12
  * @since 0.1.0
13
- * @status experimental
13
+ * @status stable
14
14
  * @category actions
15
15
  * @aliases FAB, Floating action button, Action button, Quick actions
16
16
  * @documentation https://fusion.dev/helix/components/speed-dial
@@ -33,7 +33,7 @@ import type { CSSResultGroup } from 'lit';
33
33
  * cross product, which is the explosion a named ramp exists to prevent.
34
34
  *
35
35
  * @since 0.1.0
36
- * @status experimental
36
+ * @status stable
37
37
  * @category typography
38
38
  * @aliases Paragraph, Copy, Label, Caption, Heading, Title
39
39
  * @documentation https://fusion.dev/helix/components/text
@@ -10,7 +10,7 @@ import type { CSSResultGroup } from 'lit';
10
10
  * costs contrast for something the mark already says.
11
11
  *
12
12
  * @since 0.1.0
13
- * @status experimental
13
+ * @status stable
14
14
  * @documentation https://fusion.dev/helix/components/toast
15
15
  *
16
16
  * @cssproperty --toast-border-color - Color of the panel's edge.
@@ -18,9 +18,9 @@ import type { CSSResultGroup } from 'lit';
18
18
  * into the top layer.
19
19
  *
20
20
  * @since 0.1.0
21
- * @status experimental
21
+ * @status stable
22
22
  * @category overlays
23
- * @aliases Toaster, Snackbar, Notifications
23
+ * @aliases Toaster, Snackbar
24
24
  * @documentation https://fusion.dev/helix/components/toast
25
25
  *
26
26
  * @cssproperty --toast-gap - Space between one message and the next.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@fusion.dev/helix",
3
3
  "description": "Styled component tier. Extends the headless tier with token-driven presentation.",
4
- "version": "0.43.0",
4
+ "version": "0.45.0",
5
5
  "license": "MIT",
6
6
  "author": "Ross Sheppard <ross.sheppard@fusion.dev>",
7
7
  "repository": {
@@ -47,14 +47,14 @@
47
47
  },
48
48
  "bugs": "https://github.com/project-fusion/fusion/issues",
49
49
  "dependencies": {
50
- "@fusion.dev/helix-core": "0.43.0",
51
- "@fusion.dev/helix-headless": "0.43.0",
52
- "@fusion.dev/helix-styles": "0.43.0"
50
+ "@fusion.dev/helix-core": "0.45.0",
51
+ "@fusion.dev/helix-headless": "0.45.0",
52
+ "@fusion.dev/helix-styles": "0.45.0"
53
53
  },
54
54
  "devDependencies": {
55
55
  "@custom-elements-manifest/analyzer": "^0.11.0",
56
- "@fusion.dev/helix-cem": "0.43.0",
57
- "@fusion.dev/helix-testing": "0.43.0",
56
+ "@fusion.dev/helix-cem": "0.45.0",
57
+ "@fusion.dev/helix-testing": "0.45.0",
58
58
  "@fusion.dev/scripts": "0.0.0-dev",
59
59
  "@happy-dom/global-registrator": "^20.0.0",
60
60
  "@lit-labs/ssr": "^4.1.0",