@fusion.dev/helix 0.144.0 → 0.145.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 (113) hide show
  1. package/custom-elements.json +9978 -916
  2. package/dist/accordion/item/accordion-item.css.js +14 -3
  3. package/dist/accordion/item/accordion-item.d.ts +2 -0
  4. package/dist/aura/palette.d.ts +38 -0
  5. package/dist/aura/palette.js +22 -0
  6. package/dist/aura/root/aura-root.css.js +24 -3
  7. package/dist/aura/root/aura-root.d.ts +42 -7
  8. package/dist/aura/root/aura-root.js +31 -25
  9. package/dist/breadcrumbs/breadcrumb/breadcrumb.css.js +7 -7
  10. package/dist/breadcrumbs/breadcrumb/breadcrumb.d.ts +5 -0
  11. package/dist/breadcrumbs/root/breadcrumbs-root.css.js +1 -1
  12. package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +3 -0
  13. package/dist/breadcrumbs/root/breadcrumbs-root.js +2 -0
  14. package/dist/button-group/root/button-group-root.d.ts +3 -0
  15. package/dist/canvas/root/canvas-root.css.js +1 -0
  16. package/dist/carousel/root/carousel-root.css.js +17 -1
  17. package/dist/data-table/root/data-table-root.css.js +63 -0
  18. package/dist/data-table/root/data-table-root.d.ts +1 -0
  19. package/dist/description-list/item/description-list-item.css.js +11 -0
  20. package/dist/drilldown/item/drilldown-item.css.js +2 -1
  21. package/dist/drilldown/root/drilldown-root.css.js +2 -1
  22. package/dist/element-events.generated.js +58 -9
  23. package/dist/flex/root/flex-root.css.js +134 -9
  24. package/dist/flex/root/flex-root.d.ts +51 -5
  25. package/dist/flex/root/flex-root.js +17 -1
  26. package/dist/grid/root/grid-root.css.js +114 -11
  27. package/dist/grid/root/grid-root.d.ts +37 -0
  28. package/dist/grid/root/grid-root.js +13 -1
  29. package/dist/list/item/list-item.css.js +21 -1
  30. package/dist/list/item/list-item.d.ts +3 -0
  31. package/dist/list/root/list-root.css.js +13 -1
  32. package/dist/menu/index.d.ts +1 -0
  33. package/dist/menu/index.js +1 -0
  34. package/dist/menu/item/menu-item.css.js +15 -1
  35. package/dist/menu/item/menu-item.d.ts +3 -0
  36. package/dist/menu/item/menu-item.js +2 -0
  37. package/dist/menu/section/menu-section.css.d.ts +1 -0
  38. package/dist/menu/section/menu-section.css.js +14 -0
  39. package/dist/menu/section/menu-section.d.ts +24 -0
  40. package/dist/menu/section/menu-section.js +16 -0
  41. package/dist/navigation/root/navigation-root.css.js +3 -2
  42. package/dist/navigation/root/navigation-root.d.ts +6 -0
  43. package/dist/notifications/root/notifications-root.css.js +24 -1
  44. package/dist/notifications/root/notifications-root.d.ts +1 -0
  45. package/dist/object-inspector/root/object-inspector-root.css.js +36 -1
  46. package/dist/object-inspector/root/object-inspector-root.d.ts +4 -1
  47. package/dist/object-inspector/root/object-inspector-root.js +2 -1
  48. package/dist/orb/index.d.ts +1 -1
  49. package/dist/orb/index.js +1 -1
  50. package/dist/orb/root/orb-root.d.ts +31 -5
  51. package/dist/orb/root/orb-root.js +33 -4
  52. package/dist/outline/root/outline-root.css.js +10 -0
  53. package/dist/outline/root/outline-root.d.ts +7 -0
  54. package/dist/sandbox/frame.d.ts +63 -0
  55. package/dist/sandbox/frame.js +132 -0
  56. package/dist/sandbox/index.d.ts +1 -0
  57. package/dist/sandbox/index.js +1 -0
  58. package/dist/sandbox/levels.d.ts +10 -0
  59. package/dist/sandbox/levels.js +5 -0
  60. package/dist/sandbox/root/sandbox-root.d.ts +3 -0
  61. package/dist/sandbox/root/sandbox-root.js +13 -3
  62. package/dist/sandbox/source/sandbox-source.d.ts +1 -0
  63. package/dist/sandbox/source/sandbox-source.js +7 -3
  64. package/dist/sandbox/terminal/sandbox-terminal.css.js +39 -0
  65. package/dist/sandbox/terminal/sandbox-terminal.d.ts +42 -1
  66. package/dist/sandbox/terminal/sandbox-terminal.js +47 -3
  67. package/dist/scroll-area/root/scroll-area-root.css.js +83 -1
  68. package/dist/scroll-area/root/scroll-area-root.d.ts +6 -0
  69. package/dist/skip-link/root/skip-link-root.css.js +8 -8
  70. package/dist/skip-link/root/skip-link-root.d.ts +9 -0
  71. package/dist/speed-dial/item/speed-dial-item.css.js +11 -4
  72. package/dist/speed-dial/item/speed-dial-item.d.ts +4 -0
  73. package/dist/speed-dial/root/speed-dial-root.css.js +7 -3
  74. package/dist/speed-dial/root/speed-dial-root.d.ts +9 -0
  75. package/dist/speed-dial/root/speed-dial-root.js +4 -0
  76. package/dist/steps/step/step.js +2 -1
  77. package/dist/table/root/table-root.css.js +18 -0
  78. package/dist/table/root/table-root.d.ts +6 -0
  79. package/dist/table/root/table-root.js +2 -0
  80. package/dist/table/row/table-row.css.js +18 -0
  81. package/dist/table/row/table-row.d.ts +2 -0
  82. package/dist/table/row/table-row.js +2 -0
  83. package/dist/tabs/panel/tab-panel.css.js +5 -1
  84. package/dist/tabs/root/tabs-root.css.js +56 -1
  85. package/dist/tabs/tab/tab.css.js +5 -1
  86. package/dist/text/clamp.d.ts +8 -0
  87. package/dist/text/clamp.js +1 -0
  88. package/dist/text/root/text-root.css.js +85 -45
  89. package/dist/text/root/text-root.d.ts +48 -7
  90. package/dist/text/root/text-root.js +17 -11
  91. package/dist/timeline/group/timeline-group.css.d.ts +1 -0
  92. package/dist/timeline/group/timeline-group.css.js +32 -0
  93. package/dist/timeline/group/timeline-group.d.ts +25 -0
  94. package/dist/timeline/group/timeline-group.js +16 -0
  95. package/dist/timeline/index.d.ts +1 -0
  96. package/dist/timeline/index.js +1 -0
  97. package/dist/timeline/item/timeline-item.css.js +43 -16
  98. package/dist/timeline/root/timeline-root.css.js +56 -0
  99. package/dist/timeline/root/timeline-root.d.ts +26 -0
  100. package/dist/timeline/root/timeline-root.js +7 -0
  101. package/dist/toolbar/root/toolbar-root.css.js +3 -0
  102. package/dist/toolbar/root/toolbar-root.d.ts +3 -0
  103. package/dist/tree/item/tree-item.css.js +72 -0
  104. package/dist/tree/item/tree-item.d.ts +10 -0
  105. package/dist/video/root/video-root.css.js +6 -0
  106. package/dist/video/root/video-root.d.ts +3 -0
  107. package/dist/virtual-list/root/virtual-list-root.css.js +5 -0
  108. package/dist/virtual-list/root/virtual-list-root.d.ts +4 -3
  109. package/lint.json +1 -1
  110. package/package.json +6 -6
  111. package/types/jsx.d.ts +4033 -671
  112. package/types/svelte.d.ts +2 -0
  113. package/types/vue.d.ts +1078 -202
@@ -8,7 +8,7 @@ import { customElement, HelixElement, reportRuntime } from '@fusion.dev/helix-co
8
8
  import { property } from 'lit/decorators.js';
9
9
  import { html, unsafeStatic } from 'lit/static-html.js';
10
10
  import { styles } from './grid-root.css.js';
11
- const UNINHERITED = '--grid-columns: initial; --_grid-template: initial;';
11
+ const UNINHERITED = '--grid-areas: initial; --grid-columns: initial; --grid-rows: initial; --_grid-template: initial;';
12
12
  const NUMBER = /^-?(?:\d+\.?\d*|\.\d+)(?:px|r?em|r?ex|r?ch|r?lh|r?ic|r?cap|%|[sdl]?v(?:w|h|i|b|min|max)|cq(?:w|h|i|b|min|max)|cm|mm|in|pt|pc|q)?$/i;
13
13
  const TOKEN = /\s+|(?:calc|clamp|min|max)\(|var\(--[\w-]+|-?(?:\d+\.?\d*|\.\d+)[a-z%]*|[(),+*/-]/giy;
14
14
  const lengthOf = (value) => {
@@ -75,15 +75,27 @@ let HelixGrid = class HelixGrid extends HelixElement {
75
75
  __decorate([
76
76
  property({ attribute: 'align-items', reflect: true })
77
77
  ], HelixGrid.prototype, "alignItems", void 0);
78
+ __decorate([
79
+ property({ attribute: 'auto-flow', reflect: true })
80
+ ], HelixGrid.prototype, "autoFlow", void 0);
81
+ __decorate([
82
+ property({ attribute: 'column-gap', reflect: true })
83
+ ], HelixGrid.prototype, "columnGap", void 0);
78
84
  __decorate([
79
85
  property({ reflect: true, type: Number })
80
86
  ], HelixGrid.prototype, "columns", void 0);
81
87
  __decorate([
82
88
  property({ reflect: true })
83
89
  ], HelixGrid.prototype, "gap", void 0);
90
+ __decorate([
91
+ property({ attribute: 'justify-items', reflect: true })
92
+ ], HelixGrid.prototype, "justifyItems", void 0);
84
93
  __decorate([
85
94
  property()
86
95
  ], HelixGrid.prototype, "min", void 0);
96
+ __decorate([
97
+ property({ attribute: 'row-gap', reflect: true })
98
+ ], HelixGrid.prototype, "rowGap", void 0);
87
99
  HelixGrid = __decorate([
88
100
  customElement('helix-grid')
89
101
  ], HelixGrid);
@@ -3,7 +3,7 @@ export const styles = createSheet(`:host {
3
3
  display: block;
4
4
  }
5
5
 
6
- [part="row"] {
6
+ [part~="row"] {
7
7
  align-items: center;
8
8
  display: grid;
9
9
 
@@ -72,4 +72,24 @@ grid-row: 1 / span 2;
72
72
  grid-template-columns: subgrid;
73
73
  grid-template-rows: subgrid;
74
74
  text-decoration: none;
75
+ }
76
+
77
+ [part~="row-current"] {
78
+ background-color: var(--list-item-current-background-color, var(--helix-color-well));
79
+ border-radius: var(--helix-radii-sm);
80
+ }
81
+
82
+ [part~="row"]:focus-visible {
83
+ border-radius: var(--helix-radii-sm);
84
+ outline: var(--helix-size-focus-ring) solid var(--helix-color-focus-ring);
85
+ outline-offset: calc(var(--helix-size-focus-offset) * -1);
86
+ }
87
+
88
+ :host(:state(selected)) [part~="row"] {
89
+ background-color: var(--list-item-selected-background-color, var(--helix-color-primary-subtle));
90
+ border-radius: var(--helix-radii-sm);
91
+ }
92
+
93
+ :host([disabled]) {
94
+ opacity: var(--list-item-disabled-opacity, 0.5);
75
95
  }`);
@@ -14,9 +14,12 @@ import { type CSSResultGroup, type TemplateResult } from 'lit';
14
14
  *
15
15
  * @csspart rail - The cell that holds the number in a railed list.
16
16
  *
17
+ * @cssproperty --list-item-current-background-color - The fill behind a row that is `current`.
18
+ * @cssproperty --list-item-disabled-opacity - The opacity of a `disabled` row.
17
19
  * @cssproperty --list-item-padding - The padding inside the row.
18
20
  * @cssproperty --list-item-rail-content - What the rail cell shows. The list sets it.
19
21
  * @cssproperty --list-item-rail-display - Whether the row has a rail. The list sets it.
22
+ * @cssproperty --list-item-selected-background-color - The fill behind a selected row, in a list that selects.
20
23
  * @cssproperty --list-item-term-weight - The font weight of a term in a description list.
21
24
  */
22
25
  export declare class HelixListItem extends HelixHeadlessListItem {
@@ -47,6 +47,14 @@ list-style-type: upper-roman;
47
47
  list-style-type: disc;
48
48
  }
49
49
 
50
+ :host([kind="ordered"]) ::slotted(*) {
51
+ counter-increment: list-item var(--list-step, 1);
52
+ }
53
+
54
+ :host([kind="ordered"]) ::slotted(:first-child) {
55
+ counter-set: list-item var(--list-first);
56
+ }
57
+
50
58
  :host([marker="rail"]) {
51
59
  counter-reset: list-rail;
52
60
 
@@ -57,7 +65,11 @@ padding-inline-start: var(--helix-space-none);
57
65
  --list-item-rail-content: counter(list-rail, var(--list-rail-style, decimal-leading-zero));
58
66
 
59
67
  --list-item-rail-display: block;
60
- counter-increment: list-rail;
68
+ counter-increment: list-rail var(--list-step, 1);
69
+ }
70
+
71
+ :host([marker="rail"]) ::slotted(:first-child) {
72
+ counter-set: list-rail var(--list-first);
61
73
  }
62
74
 
63
75
  :host([kind="ordered"][marker="rail"]) ::slotted(*),
@@ -1,2 +1,3 @@
1
1
  export * from './item/menu-item.js';
2
2
  export * from './root/menu-root.js';
3
+ export * from './section/menu-section.js';
@@ -1,2 +1,3 @@
1
1
  export * from './item/menu-item.js';
2
2
  export * from './root/menu-root.js';
3
+ export * from './section/menu-section.js';
@@ -20,6 +20,7 @@ font-weight: var(--helix-weight-medium);
20
20
  grid-template-columns:
21
21
  var(--menu-item-start, 0px)
22
22
  minmax(0, 1fr)
23
+ auto
23
24
  var(--menu-item-end, 0px);
24
25
 
25
26
  min-block-size: var(--helix-size-control);
@@ -72,8 +73,21 @@ grid-column: 2;
72
73
  min-inline-size: 0;
73
74
  }
74
75
 
75
- [part="mark"] {
76
+ [part="end"] {
77
+ align-items: center;
78
+ color: var(--menu-item-detail-color, var(--helix-color-foreground-subtle));
79
+ display: flex;
80
+ gap: var(--helix-space-2xs);
76
81
  grid-column: 3;
82
+ padding-inline-start: var(--helix-space-sm);
83
+ }
84
+
85
+ [part="end"][data-empty] {
86
+ display: none;
87
+ }
88
+
89
+ [part="mark"] {
90
+ grid-column: 4;
77
91
  }
78
92
 
79
93
  [part="start"][data-empty] {
@@ -1,5 +1,6 @@
1
1
  import { HelixHeadlessMenuItem } from '@fusion.dev/helix-headless/menu';
2
2
  import type { CSSResultGroup } from 'lit';
3
+ import '../../kbd/index.js';
3
4
  /**
4
5
  * @summary One row in a menu: a command, a choice, or a way into a submenu.
5
6
  *
@@ -16,11 +17,13 @@ import type { CSSResultGroup } from 'lit';
16
17
  * @aliases Menu option, Menu row
17
18
  * @documentation https://fusion.dev/helix/components/menu
18
19
  *
20
+ * @cssproperty --menu-item-detail-color - Color of the shortcut and the words in the `end` slot.
19
21
  * @cssproperty --menu-item-end - Width of the trailing column, including the gap before it, which holds a check mark or a submenu caret.
20
22
  * @cssproperty --menu-item-hover-color - Fill under the pointer.
21
23
  * @cssproperty --menu-item-start - Width of the leading column, including the gap after it, for a row with more than a mark. The menu sets it for each page, and `0` removes the column.
22
24
  */
23
25
  export declare class HelixMenuItem extends HelixHeadlessMenuItem {
26
+ static tier: string;
24
27
  static styles: CSSResultGroup;
25
28
  }
26
29
  declare global {
@@ -6,8 +6,10 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
6
6
  };
7
7
  import { customElement } from '@fusion.dev/helix-core';
8
8
  import { HelixHeadlessMenuItem } from '@fusion.dev/helix-headless/menu';
9
+ import '../../kbd/index.js';
9
10
  import { styles } from './menu-item.css.js';
10
11
  let HelixMenuItem = class HelixMenuItem extends HelixHeadlessMenuItem {
12
+ static { this.tier = 'helix-'; }
11
13
  static { this.styles = styles; }
12
14
  };
13
15
  HelixMenuItem = __decorate([
@@ -0,0 +1 @@
1
+ export declare const styles: import("lit").CSSResult;
@@ -0,0 +1,14 @@
1
+ import { createSheet } from '@fusion.dev/helix-core';
2
+ export const styles = createSheet(`:host {
3
+ display: block;
4
+ }
5
+
6
+ [part="heading"] {
7
+ color: var(--menu-section-heading-color, var(--helix-color-foreground-subtle));
8
+ font-size: var(--helix-text-xs);
9
+ font-weight: var(--helix-weight-medium);
10
+ line-height: var(--helix-leading-normal);
11
+ padding-block: var(--helix-space-xs) var(--helix-space-2xs);
12
+ padding-inline: var(--helix-space-sm);
13
+ user-select: none;
14
+ }`);
@@ -0,0 +1,24 @@
1
+ import { HelixHeadlessMenuSection } from '@fusion.dev/helix-headless/menu';
2
+ import type { CSSResultGroup } from 'lit';
3
+ /**
4
+ * @summary A group of rows in a menu, under a heading.
5
+ *
6
+ * @description
7
+ * The heading is set in the menu's small type, quieter than the rows, with the
8
+ * rows' own inset, so it reads as the name of what follows.
9
+ *
10
+ * @since 0.1.0
11
+ * @status stable
12
+ * @aliases Menu group, Menu heading
13
+ * @documentation https://fusion.dev/helix/components/menu
14
+ *
15
+ * @cssproperty --menu-section-heading-color - Color of the heading.
16
+ */
17
+ export declare class HelixMenuSection extends HelixHeadlessMenuSection {
18
+ static styles: CSSResultGroup;
19
+ }
20
+ declare global {
21
+ interface HTMLElementTagNameMap {
22
+ 'helix-menu-section': HelixMenuSection;
23
+ }
24
+ }
@@ -0,0 +1,16 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
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
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { customElement } from '@fusion.dev/helix-core';
8
+ import { HelixHeadlessMenuSection } from '@fusion.dev/helix-headless/menu';
9
+ import { styles } from './menu-section.css.js';
10
+ let HelixMenuSection = class HelixMenuSection extends HelixHeadlessMenuSection {
11
+ static { this.styles = styles; }
12
+ };
13
+ HelixMenuSection = __decorate([
14
+ customElement('helix-menu-section')
15
+ ], HelixMenuSection);
16
+ export { HelixMenuSection };
@@ -6,7 +6,7 @@ display: block;
6
6
  [part="nav"] {
7
7
  align-items: center;
8
8
 
9
- block-size: var(--helix-size-control-sm);
9
+ block-size: var(--navigation-block-size, var(--helix-size-control-sm));
10
10
  display: flex;
11
11
  gap: var(--navigation-gap, var(--helix-space-2xs));
12
12
 
@@ -19,7 +19,8 @@ position: relative;
19
19
  [part="indicator"] {
20
20
  background-color: var(--navigation-indicator-color, var(--helix-color-surface-sunken));
21
21
  block-size: var(--indicator-block-size, 0);
22
- border-radius: var(--helix-radii-sm);
22
+ border-radius: var(--navigation-indicator-radius, var(--helix-radii-sm));
23
+ box-shadow: var(--navigation-indicator-shadow, none);
23
24
  inline-size: var(--indicator-inline-size, 0);
24
25
  inset-block-start: 50%;
25
26
  inset-inline-start: 0;
@@ -14,8 +14,14 @@ import type { CSSResultGroup } from 'lit';
14
14
  * @aliases Nav, NavList, Tabs
15
15
  * @documentation https://fusion.dev/helix/components/navigation
16
16
  *
17
+ * @cssproperty --navigation-block-size - Height of the bar in a row. Each destination fills it.
17
18
  * @cssproperty --navigation-gap - Space between destinations.
18
19
  * @cssproperty --navigation-indicator-color - Fill of the marker on the current destination.
20
+ * @cssproperty --navigation-indicator-radius - Corner radius of the marker.
21
+ * @cssproperty --navigation-indicator-shadow - Shadow under the marker, for a marker that sits
22
+ * raised on the bar.
23
+ * @cssproperty --navigation-item-color - Text color of a destination that is not the current one. Read by the page's stylesheet, which styles the links you slot.
24
+ * @cssproperty --navigation-item-current-color - Text color of the current destination, the one marked `aria-current="page"`.
19
25
  */
20
26
  export declare class HelixNavigation extends HelixHeadlessNavigation {
21
27
  static styles: CSSResultGroup;
@@ -71,6 +71,28 @@ transition: color var(--helix-duration-fast) var(--helix-easing-standard);
71
71
  color: var(--helix-color-foreground);
72
72
  }
73
73
 
74
+ [part="more"] {
75
+ background: none;
76
+ border: 0;
77
+ border-block-start: var(--helix-border-thin) solid var(--helix-color-border);
78
+ color: var(--helix-color-foreground-muted);
79
+ cursor: pointer;
80
+ font-family: var(--helix-font-sans);
81
+ font-size: var(--helix-text-sm);
82
+ inline-size: 100%;
83
+ padding-block: var(--helix-space-sm);
84
+ transition: color var(--helix-duration-fast) var(--helix-easing-standard);
85
+ }
86
+
87
+ [part="more"]:hover {
88
+ color: var(--helix-color-foreground);
89
+ }
90
+
91
+ [part="more"]:focus-visible {
92
+ outline: var(--helix-size-focus-ring) solid var(--helix-color-focus-ring);
93
+ outline-offset: calc(var(--helix-size-focus-offset) * -1);
94
+ }
95
+
74
96
  [part="mark-all"]:focus-visible {
75
97
  outline: var(--helix-size-focus-ring) solid var(--helix-color-focus-ring);
76
98
  outline-offset: var(--helix-size-focus-offset);
@@ -91,7 +113,8 @@ max-block-size: none;
91
113
  overflow-y: visible;
92
114
  }
93
115
 
94
- [part="mark-all"] {
116
+ [part="mark-all"],
117
+ [part="more"] {
95
118
  display: none;
96
119
  }
97
120
  }`);
@@ -25,6 +25,7 @@ import '../notification/notification.js';
25
25
  * @csspart list - The list itself.
26
26
  * @csspart live - A copy of the empty and loading messages, in a live region that screen readers announce when they change. Visually hidden in the styled tier.
27
27
  * @csspart mark-all - The control that marks everything read.
28
+ * @csspart more - The button after the list that asks for more, while `load-more` is set and the feed is not loading.
28
29
  *
29
30
  * @cssproperty --notifications-max-block-size - How tall the feed may get before the list scrolls.
30
31
  * @cssproperty --notifications-media-column - Width of the media column that every item keeps when any item in the feed has media.
@@ -42,7 +42,31 @@ line-height: var(--helix-leading-normal);
42
42
  padding-block: var(--helix-space-xs);
43
43
  }
44
44
 
45
- [part="header"] + [part="frame"] [part="tree"] {
45
+ [part="search-field"] {
46
+ appearance: none;
47
+ background-color: var(--object-inspector-background-color, var(--helix-color-background));
48
+ border: var(--helix-border-thin) solid
49
+ var(--object-inspector-border-color, var(--helix-color-border));
50
+ border-block-end: none;
51
+ border-start-end-radius: var(--object-inspector-radius, var(--helix-radii-lg));
52
+ border-start-start-radius: var(--object-inspector-radius, var(--helix-radii-lg));
53
+ box-sizing: border-box;
54
+ color: var(--helix-color-foreground);
55
+ font-family: var(--helix-font-sans);
56
+ font-size: var(--helix-text-sm);
57
+ inline-size: 100%;
58
+ margin: 0;
59
+ padding-block: var(--helix-space-xs);
60
+ padding-inline: var(--helix-space-md);
61
+ }
62
+
63
+ [part="search-field"]:focus-visible {
64
+ outline: var(--helix-size-focus-ring) solid var(--helix-color-focus-ring);
65
+ outline-offset: calc(var(--helix-size-focus-offset) * -1);
66
+ }
67
+
68
+ [part="header"] + [part="search-field"],
69
+ :is([part="header"], [part="search-field"]) ~ [part="frame"] [part="tree"] {
46
70
  border-start-end-radius: var(--helix-radii-none);
47
71
  border-start-start-radius: var(--helix-radii-none);
48
72
  }
@@ -90,6 +114,13 @@ outline: var(--helix-size-focus-ring) solid var(--helix-color-focus-ring);
90
114
  outline-offset: calc(var(--helix-size-focus-offset) * -1);
91
115
  }
92
116
 
117
+ [part~="row-match"] {
118
+ background-color: var(
119
+ --object-inspector-match-background-color,
120
+ var(--helix-color-accent-subtle)
121
+ );
122
+ }
123
+
93
124
  [part="toggle"] {
94
125
  block-size: 1em;
95
126
  color: var(--helix-color-foreground-muted);
@@ -102,6 +133,10 @@ vertical-align: -0.125em;
102
133
  color: var(--helix-color-syntax-name);
103
134
  }
104
135
 
136
+ [part~="row-match"] [part="key"] {
137
+ color: var(--helix-color-foreground);
138
+ }
139
+
105
140
  [part="string"] {
106
141
  color: var(--helix-color-syntax-string);
107
142
  }
@@ -9,7 +9,9 @@ import '../../copy-button/index.js';
9
9
  * The styled tier draws the tree in the Code Block frame. Keys and each type of
10
10
  * value take their colors from the syntax colors code blocks use. Each row is
11
11
  * one line, and a long string ends in an ellipsis, so every row has the same
12
- * height and a windowed tree does not measure rows one by one.
12
+ * height and a windowed tree does not measure rows one by one. A filter's
13
+ * matches take a tinted ground, and the filter field is a band of the same
14
+ * frame, under the label.
13
15
  *
14
16
  * @since 0.1.0
15
17
  * @status stable
@@ -21,6 +23,7 @@ import '../../copy-button/index.js';
21
23
  * @cssproperty --object-inspector-block-size - The height of the scrolling box when `windowed` is set.
22
24
  * @cssproperty --object-inspector-border-color - The color of the edge around the tree and its header.
23
25
  * @cssproperty --object-inspector-header-background-color - The background of the bar that holds the label.
26
+ * @cssproperty --object-inspector-match-background-color - The background of an entry a filter matched.
24
27
  * @cssproperty --object-inspector-radius - The corner radius of the tree.
25
28
  */
26
29
  export declare class HelixObjectInspector extends HelixHeadlessObjectInspector {
@@ -6,11 +6,12 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
6
6
  };
7
7
  import { customElement } from '@fusion.dev/helix-core';
8
8
  import { HelixHeadlessObjectInspector } from '@fusion.dev/helix-headless/object-inspector';
9
+ import { styles as liveStyles } from '../../shared/live/live.css.js';
9
10
  import { styles } from './object-inspector-root.css.js';
10
11
  import '../../copy-button/index.js';
11
12
  let HelixObjectInspector = class HelixObjectInspector extends HelixHeadlessObjectInspector {
12
13
  static { this.tier = 'helix-'; }
13
- static { this.styles = styles; }
14
+ static { this.styles = [liveStyles, styles]; }
14
15
  };
15
16
  HelixObjectInspector = __decorate([
16
17
  customElement('helix-object-inspector')
@@ -1,2 +1,2 @@
1
1
  export * from './root/orb-root.js';
2
- export * from './shapes.js';
2
+ export { ORB_STATES, type OrbState } from './shapes.js';
package/dist/orb/index.js CHANGED
@@ -1,2 +1,2 @@
1
1
  export * from './root/orb-root.js';
2
- export * from './shapes.js';
2
+ export { ORB_STATES } from './shapes.js';
@@ -36,6 +36,10 @@ import { type OrbState } from '../shapes.js';
36
36
  * drawing of your own, the headless `Loader` holds the same busy progress bar
37
37
  * and its name.
38
38
  *
39
+ * Each state is also a custom state, such as `:state(thinking)` or
40
+ * `:state(done)`, so a page can style what sits around an orb by what it shows,
41
+ * whether the state was written as an attribute or set from script.
42
+ *
39
43
  * @since 0.8.0
40
44
  * @status stable
41
45
  * @category feedback
@@ -43,13 +47,31 @@ import { type OrbState } from '../shapes.js';
43
47
  * @documentation https://fusion.dev/helix/components/orb
44
48
  *
45
49
  * @csspart canvas - The canvas the dots are drawn on.
50
+ * @csspart live - The live region that says the new state when `announce` is set. It is rendered from the first change of state and clipped out of view.
46
51
  *
47
52
  * @cssproperty --orb-color - The color of the nearest dots. Defaults to `currentColor`.
48
53
  * @cssproperty --orb-ground - The color the farthest dots fade toward. Defaults to the page's background.
49
54
  * @cssproperty --orb-size - The diameter. Overrides `size`.
55
+ *
56
+ * @cssstate connecting - The orb shows `connecting`.
57
+ * @cssstate done - The orb shows `done`.
58
+ * @cssstate fetching - The orb shows `fetching`.
59
+ * @cssstate listening - The orb shows `listening`.
60
+ * @cssstate thinking - The orb shows `thinking`, which is also what a state it does not draw shows.
61
+ * @cssstate waiting - The orb shows `waiting`.
62
+ * @cssstate working - The orb shows `working`.
50
63
  */
51
64
  export declare class HelixOrb extends HelixElement {
52
65
  static styles: CSSResultGroup;
66
+ /**
67
+ * Says each new state through a polite live region, such as "Working" and
68
+ * then "Done".
69
+ *
70
+ * Off by default, because the name and the busy state already change with
71
+ * the state, and an orb beside a stream of messages would otherwise talk
72
+ * over them. Set it on an orb that is the only sign of progress on the page.
73
+ */
74
+ announce: boolean;
53
75
  /**
54
76
  * The name read by screen readers. Defaults to the name of the state, such
55
77
  * as "Thinking".
@@ -82,18 +104,22 @@ export declare class HelixOrb extends HelixElement {
82
104
  * verb we have not made a shape for should cost a reader a less specific
83
105
  * indicator, not an empty box where the indicator was.
84
106
  *
85
- * Not reflected: no rule selects on it, because the state is drawn rather than
86
- * styled. A consumer writing the attribute can still select on their own
87
- * markup.
107
+ * Not reflected, because a state set from script would then write an
108
+ * attribute onto the host after a server sent it without one. Each state is
109
+ * a custom state instead, such as `:state(working)`.
88
110
  */
89
111
  state: OrbState;
90
112
  /**
91
113
  * The word for each state, for a page in another language.
92
114
  *
93
- * A state left out keeps its English word, and `label` wins over both. It is
94
- * a property with no attribute, keyed by state, such as `{ thinking: '…' }`.
115
+ * A state left out keeps its English word, and `label` wins over both.
116
+ * Keyed by state, such as `{ thinking: '…' }`. As an attribute it is that
117
+ * object as JSON, such as `state-labels='{"done":"Terminé"}'`, so server
118
+ * markup and plain HTML can carry the words too.
95
119
  */
96
120
  stateLabels: Partial<Record<OrbState, string>>;
121
+ /** The region `announce` speaks in. */
122
+ private readonly status;
97
123
  private canvas;
98
124
  private context;
99
125
  /**
@@ -4,9 +4,10 @@ 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, HelixElement, hostAria, PaintGateController, readColor, } from '@fusion.dev/helix-core';
7
+ import { customElement, drawStatus, HelixElement, hostAria, PaintGateController, readColor, StatusController, } from '@fusion.dev/helix-core';
8
8
  import { html } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
+ import { styles as liveStyles } from '../../shared/live/live.css.js';
10
11
  import { blendStaged, evenSphere, fibonacci, meshFor, ORB_STATES, orbPoint, paramsFor, project, smoother, stateDistance, TRAIL, } from '../shapes.js';
11
12
  import { styles } from './orb-root.css.js';
12
13
  const MORPH_NEAR = 380;
@@ -22,13 +23,28 @@ const LABELS = {
22
23
  waiting: 'Waiting',
23
24
  working: 'Working',
24
25
  };
26
+ const labelsConverter = {
27
+ fromAttribute: (value) => {
28
+ try {
29
+ const parsed = JSON.parse(value ?? '');
30
+ return parsed && typeof parsed === 'object' && !Array.isArray(parsed)
31
+ ? parsed
32
+ : {};
33
+ }
34
+ catch {
35
+ return {};
36
+ }
37
+ },
38
+ };
25
39
  const GRAY = [128, 128, 128];
26
40
  let HelixOrb = class HelixOrb extends HelixElement {
27
41
  constructor() {
28
42
  super(...arguments);
43
+ this.announce = false;
29
44
  this.label = '';
30
45
  this.state = 'thinking';
31
46
  this.stateLabels = {};
47
+ this.status = new StatusController(this);
32
48
  this.context = null;
33
49
  this.gate = new PaintGateController(this, {
34
50
  canRun: () => !!this.context && !this.lost,
@@ -67,7 +83,7 @@ let HelixOrb = class HelixOrb extends HelixElement {
67
83
  this.gate.play();
68
84
  };
69
85
  }
70
- static { this.styles = styles; }
86
+ static { this.styles = [liveStyles, styles]; }
71
87
  willUpdate(changed) {
72
88
  super.willUpdate(changed);
73
89
  const state = ORB_STATES.includes(this.state)
@@ -78,12 +94,22 @@ let HelixOrb = class HelixOrb extends HelixElement {
78
94
  role: state === 'done' ? 'img' : 'progressbar',
79
95
  });
80
96
  this.internals.ariaBusy = state === 'done' ? 'false' : 'true';
97
+ this.toggleState('connecting', state === 'connecting');
98
+ this.toggleState('done', state === 'done');
99
+ this.toggleState('fetching', state === 'fetching');
100
+ this.toggleState('listening', state === 'listening');
101
+ this.toggleState('thinking', state === 'thinking');
102
+ this.toggleState('waiting', state === 'waiting');
103
+ this.toggleState('working', state === 'working');
81
104
  if (changed.has('state') && changed.get('state') !== undefined) {
82
105
  this.turn();
106
+ if (this.announce) {
107
+ this.status.say(this.label || this.stateLabels[state] || LABELS[state]);
108
+ }
83
109
  }
84
110
  }
85
111
  render() {
86
- return html `<canvas part="canvas" aria-hidden="true"></canvas>`;
112
+ return html `<canvas part="canvas" aria-hidden="true"></canvas>${drawStatus(this.status)}`;
87
113
  }
88
114
  firstUpdated(changed) {
89
115
  super.firstUpdated(changed);
@@ -236,6 +262,9 @@ let HelixOrb = class HelixOrb extends HelixElement {
236
262
  }
237
263
  }
238
264
  };
265
+ __decorate([
266
+ property({ type: Boolean })
267
+ ], HelixOrb.prototype, "announce", void 0);
239
268
  __decorate([
240
269
  property()
241
270
  ], HelixOrb.prototype, "label", void 0);
@@ -246,7 +275,7 @@ __decorate([
246
275
  property()
247
276
  ], HelixOrb.prototype, "state", void 0);
248
277
  __decorate([
249
- property({ attribute: false })
278
+ property({ attribute: 'state-labels', converter: labelsConverter })
250
279
  ], HelixOrb.prototype, "stateLabels", void 0);
251
280
  HelixOrb = __decorate([
252
281
  customElement('helix-orb')
@@ -123,6 +123,16 @@ var(--outline-indent, var(--helix-space-sm))
123
123
  );
124
124
  }
125
125
 
126
+ ::slotted([slot="heading"]) {
127
+ color: var(--helix-color-foreground);
128
+ font-size: var(--helix-text-xs);
129
+ font-weight: var(--helix-weight-semibold);
130
+ line-height: var(--helix-leading-normal);
131
+ margin-block: 0 var(--helix-space-xs);
132
+ margin-inline: 0;
133
+ padding-inline-start: calc(var(--outline-rail) + var(--helix-space-sm));
134
+ }
135
+
126
136
  @media print {
127
137
  :host {
128
138
  print-color-adjust: economy;
@@ -12,6 +12,13 @@ import type { CSSResultGroup } from 'lit';
12
12
  * `data-level` is at the top level. The outline does not read heading levels
13
13
  * from the document, because the headings are not always in the document.
14
14
  *
15
+ * Links in a nested `<ul>` take their indentation from your own stylesheet:
16
+ * the outline's styles reach the elements slotted into it and nothing inside
17
+ * them. Write the links flat with `data-level` for the indentation drawn here,
18
+ * and screen readers still hear them as nested lists.
19
+ *
20
+ * A heading slotted into `heading` is set above the links, lined up with them.
21
+ *
15
22
  * @since 0.1.0
16
23
  * @status stable
17
24
  * @category navigation