@unofficialbox/box-open-elements 0.20.0 → 0.22.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 (57) hide show
  1. package/dist/components/actions/menu-item.d.ts +2 -0
  2. package/dist/components/actions/menu-item.js +4 -0
  3. package/dist/components/collections/card.js +6 -0
  4. package/dist/components/collections/result-blocks.js +4 -1
  5. package/dist/components/feedback/alert.d.ts +2 -0
  6. package/dist/components/feedback/alert.js +17 -13
  7. package/dist/components/feedback/toast.d.ts +10 -1
  8. package/dist/components/feedback/toast.js +69 -27
  9. package/dist/components/forms/number-input.d.ts +1 -0
  10. package/dist/components/forms/number-input.js +9 -6
  11. package/dist/components/forms/search-field.js +16 -0
  12. package/dist/components/overlays/context-menu.d.ts +2 -0
  13. package/dist/components/overlays/context-menu.js +7 -0
  14. package/dist/components/overlays/dialog.js +19 -3
  15. package/dist/components/overlays/popover.js +6 -1
  16. package/dist/element-maps.d.ts +11 -1
  17. package/dist/foundations/a11y/announcer.d.ts +12 -0
  18. package/dist/foundations/a11y/announcer.js +75 -0
  19. package/dist/foundations/a11y/focus.js +46 -25
  20. package/dist/foundations/a11y/index.d.ts +2 -0
  21. package/dist/foundations/a11y/index.js +1 -0
  22. package/dist/foundations/icons/box-iconography.d.ts +472 -472
  23. package/dist/foundations/icons/box-iconography.generated.d.ts +1151 -679
  24. package/dist/foundations/icons/box-iconography.generated.js +1006 -3588
  25. package/dist/foundations/icons/glyphs/index.d.ts +1 -0
  26. package/dist/foundations/icons/glyphs/index.js +2 -0
  27. package/dist/foundations/icons/glyphs/package.json +1 -0
  28. package/dist/foundations/overlay/positioning.js +7 -0
  29. package/dist/foundations/status/index.d.ts +1 -1
  30. package/dist/foundations/status/index.js +8 -6
  31. package/dist/foundations/tokens/box-dark.js +4 -1
  32. package/dist/foundations/tokens/box-defaults.js +3 -0
  33. package/dist/foundations/tokens/registry.d.ts +3 -0
  34. package/dist/foundations/tokens/registry.js +3 -0
  35. package/dist/foundations/tokens/types.d.ts +3 -0
  36. package/dist/index.d.ts +2 -0
  37. package/dist/index.js +2 -0
  38. package/dist/patterns/agent-chat/agent-chat.js +12 -4
  39. package/dist/patterns/call-console/call-console.d.ts +3 -0
  40. package/dist/patterns/call-console/call-console.js +114 -20
  41. package/dist/patterns/content-explorer/adapters/action-menu.js +7 -5
  42. package/dist/patterns/content-explorer/adapters/toolbar.js +6 -2
  43. package/dist/patterns/file-request/file-request-builder.js +3 -0
  44. package/dist/patterns/flow-builder/flow-builder.d.ts +79 -0
  45. package/dist/patterns/flow-builder/flow-builder.js +243 -0
  46. package/dist/patterns/flow-builder/index.d.ts +3 -0
  47. package/dist/patterns/flow-builder/index.js +3 -0
  48. package/dist/patterns/flow-builder/model.d.ts +81 -0
  49. package/dist/patterns/flow-builder/model.js +40 -0
  50. package/dist/patterns/flow-builder/primitives.d.ts +57 -0
  51. package/dist/patterns/flow-builder/primitives.js +256 -0
  52. package/dist/patterns/lineage/lineage-graph.js +26 -6
  53. package/dist/patterns/notifications/notification-inbox.js +19 -3
  54. package/dist/patterns/preview/annotation-inspector.js +2 -2
  55. package/dist/patterns/undo/index.d.ts +19 -0
  56. package/dist/patterns/undo/index.js +106 -0
  57. package/package.json +11 -2
@@ -73,6 +73,9 @@ import type { FactList } from "./components/collections/fact-list.js";
73
73
  import type { Fieldset } from "./components/forms/fieldset.js";
74
74
  import type { FileRequestBuilder } from "./patterns/file-request/file-request-builder.js";
75
75
  import type { FilterBar } from "./patterns/search/filter-bar.js";
76
+ import type { FlowBuilder } from "./patterns/flow-builder/flow-builder.js";
77
+ import type { FlowCard } from "./patterns/flow-builder/primitives.js";
78
+ import type { FlowSpine } from "./patterns/flow-builder/primitives.js";
76
79
  import type { FormWizard } from "./patterns/form-wizard/form-wizard.js";
77
80
  import type { FormattedDate } from "./components/output/formatted-date.js";
78
81
  import type { FormattedDuration } from "./components/output/formatted-duration.js";
@@ -86,9 +89,11 @@ import type { HelpText } from "./components/feedback/help-text.js";
86
89
  import type { IconButton } from "./components/actions/icon-button.js";
87
90
  import type { Illustration } from "./components/visuals/illustration.js";
88
91
  import type { Indicator } from "./components/feedback/indicator.js";
92
+ import type { InsertPoint } from "./patterns/flow-builder/primitives.js";
89
93
  import type { InviteCollaboratorsModal } from "./patterns/share/invite-collaborators-modal.js";
90
94
  import type { ItemDetailsPanel } from "./patterns/item/item-details-panel.js";
91
95
  import type { ItemForm } from "./patterns/item/item-form.js";
96
+ import type { KindPicker } from "./patterns/flow-builder/primitives.js";
92
97
  import type { LineChart } from "./patterns/insights/line-chart.js";
93
98
  import type { LineageGraph } from "./patterns/lineage/lineage-graph.js";
94
99
  import type { LinkButton } from "./components/actions/link-button.js";
@@ -233,6 +238,9 @@ declare global {
233
238
  "box-fieldset": Fieldset;
234
239
  "box-file-request-builder": FileRequestBuilder;
235
240
  "box-filter-bar": FilterBar;
241
+ "box-flow-builder": FlowBuilder;
242
+ "box-flow-card": FlowCard;
243
+ "box-flow-spine": FlowSpine;
236
244
  "box-form-wizard": FormWizard;
237
245
  "box-formatted-date": FormattedDate;
238
246
  "box-formatted-duration": FormattedDuration;
@@ -246,9 +254,11 @@ declare global {
246
254
  "box-icon-button": IconButton;
247
255
  "box-illustration": Illustration;
248
256
  "box-indicator": Indicator;
257
+ "box-insert-point": InsertPoint;
249
258
  "box-invite-collaborators-modal": InviteCollaboratorsModal;
250
259
  "box-item-details-panel": ItemDetailsPanel;
251
260
  "box-item-form": ItemForm;
261
+ "box-kind-picker": KindPicker;
252
262
  "box-line-chart": LineChart;
253
263
  "box-lineage-graph": LineageGraph;
254
264
  "box-link-button": LinkButton;
@@ -327,4 +337,4 @@ declare global {
327
337
  }
328
338
  }
329
339
  /** Every element tag the library registers, for host-side narrowing. */
330
- export type BoxElementTagName = "box-access-stats" | "box-accordion" | "box-activity-density" | "box-agent-chat" | "box-agent-workspace" | "box-alert" | "box-annotation-inspector" | "box-annotation-thread" | "box-annotation-toolbar" | "box-app-shell" | "box-audit-log" | "box-avatar" | "box-badge" | "box-badgeable" | "box-bar-chart" | "box-breadcrumb" | "box-bulk-action-bar" | "box-button" | "box-button-group" | "box-calendar" | "box-call-console" | "box-card" | "box-carousel" | "box-category-selector" | "box-chart-panel" | "box-check-list" | "box-checkbox" | "box-checkbox-group" | "box-chip" | "box-code-block" | "box-collaborator-avatars" | "box-color-picker" | "box-combobox" | "box-command-palette" | "box-comment-thread" | "box-compare-view" | "box-contact-datalist-item" | "box-content-explorer" | "box-content-picker" | "box-content-sidebar" | "box-content-uploader" | "box-context-menu" | "box-datalist-item" | "box-date-field" | "box-dialog" | "box-diff-viewer" | "box-divider" | "box-document-list" | "box-donut-chart" | "box-draggable-list" | "box-drawer" | "box-drop-zone" | "box-dropdown" | "box-dual-listbox" | "box-due-badge" | "box-empty-state" | "box-error-mask" | "box-explorer-action-menu" | "box-explorer-breadcrumbs" | "box-explorer-items" | "box-explorer-list" | "box-explorer-table" | "box-explorer-toolbar" | "box-fact-list" | "box-fieldset" | "box-file-request-builder" | "box-filter-bar" | "box-form-wizard" | "box-formatted-date" | "box-formatted-duration" | "box-formatted-file-size" | "box-formatted-number" | "box-governance-panel" | "box-grid" | "box-grid-view" | "box-guide-tooltip" | "box-help-text" | "box-icon-button" | "box-illustration" | "box-indicator" | "box-invite-collaborators-modal" | "box-item-details-panel" | "box-item-form" | "box-line-chart" | "box-lineage-graph" | "box-link-button" | "box-menu" | "box-menu-item" | "box-metadata-filter-builder" | "box-metadata-inspector" | "box-metric-card" | "box-multi-select" | "box-nav-sidebar" | "box-notification-bell" | "box-notification-inbox" | "box-nudge" | "box-number-input" | "box-pagination" | "box-path" | "box-permission-matrix" | "box-persona" | "box-pill-cloud" | "box-pill-selector-dropdown" | "box-popover" | "box-presence" | "box-preview-element" | "box-preview-header" | "box-progress-bar" | "box-progress-ring" | "box-progress-steps" | "box-provenance-strip" | "box-radio-group" | "box-range-slider" | "box-rating" | "box-relative-time" | "box-result-blocks" | "box-review-queue-item" | "box-rich-text-input" | "box-run-summary" | "box-run-trace" | "box-saved-view-picker" | "box-search-field" | "box-search-results-header" | "box-section" | "box-segmented-control" | "box-select" | "box-share-panel" | "box-shortcuts-overlay" | "box-sidebar-toggle-button" | "box-signature-ceremony" | "box-skeleton" | "box-slider" | "box-spin-button" | "box-spinner" | "box-split-view" | "box-status-icon" | "box-switch" | "box-table" | "box-tabs" | "box-tag-input" | "box-task-assignment-panel" | "box-text-area" | "box-text-field" | "box-thumbnail-card" | "box-tile-group" | "box-time-field" | "box-timeline" | "box-toast" | "box-toolbar" | "box-tooltip" | "box-tree" | "box-tree-grid" | "box-unified-share-modal" | "box-version-graph" | "box-version-list" | "box-wizard-summary" | "box-work-queue" | "box-workload-board";
340
+ export type BoxElementTagName = "box-access-stats" | "box-accordion" | "box-activity-density" | "box-agent-chat" | "box-agent-workspace" | "box-alert" | "box-annotation-inspector" | "box-annotation-thread" | "box-annotation-toolbar" | "box-app-shell" | "box-audit-log" | "box-avatar" | "box-badge" | "box-badgeable" | "box-bar-chart" | "box-breadcrumb" | "box-bulk-action-bar" | "box-button" | "box-button-group" | "box-calendar" | "box-call-console" | "box-card" | "box-carousel" | "box-category-selector" | "box-chart-panel" | "box-check-list" | "box-checkbox" | "box-checkbox-group" | "box-chip" | "box-code-block" | "box-collaborator-avatars" | "box-color-picker" | "box-combobox" | "box-command-palette" | "box-comment-thread" | "box-compare-view" | "box-contact-datalist-item" | "box-content-explorer" | "box-content-picker" | "box-content-sidebar" | "box-content-uploader" | "box-context-menu" | "box-datalist-item" | "box-date-field" | "box-dialog" | "box-diff-viewer" | "box-divider" | "box-document-list" | "box-donut-chart" | "box-draggable-list" | "box-drawer" | "box-drop-zone" | "box-dropdown" | "box-dual-listbox" | "box-due-badge" | "box-empty-state" | "box-error-mask" | "box-explorer-action-menu" | "box-explorer-breadcrumbs" | "box-explorer-items" | "box-explorer-list" | "box-explorer-table" | "box-explorer-toolbar" | "box-fact-list" | "box-fieldset" | "box-file-request-builder" | "box-filter-bar" | "box-flow-builder" | "box-flow-card" | "box-flow-spine" | "box-form-wizard" | "box-formatted-date" | "box-formatted-duration" | "box-formatted-file-size" | "box-formatted-number" | "box-governance-panel" | "box-grid" | "box-grid-view" | "box-guide-tooltip" | "box-help-text" | "box-icon-button" | "box-illustration" | "box-indicator" | "box-insert-point" | "box-invite-collaborators-modal" | "box-item-details-panel" | "box-item-form" | "box-kind-picker" | "box-line-chart" | "box-lineage-graph" | "box-link-button" | "box-menu" | "box-menu-item" | "box-metadata-filter-builder" | "box-metadata-inspector" | "box-metric-card" | "box-multi-select" | "box-nav-sidebar" | "box-notification-bell" | "box-notification-inbox" | "box-nudge" | "box-number-input" | "box-pagination" | "box-path" | "box-permission-matrix" | "box-persona" | "box-pill-cloud" | "box-pill-selector-dropdown" | "box-popover" | "box-presence" | "box-preview-element" | "box-preview-header" | "box-progress-bar" | "box-progress-ring" | "box-progress-steps" | "box-provenance-strip" | "box-radio-group" | "box-range-slider" | "box-rating" | "box-relative-time" | "box-result-blocks" | "box-review-queue-item" | "box-rich-text-input" | "box-run-summary" | "box-run-trace" | "box-saved-view-picker" | "box-search-field" | "box-search-results-header" | "box-section" | "box-segmented-control" | "box-select" | "box-share-panel" | "box-shortcuts-overlay" | "box-sidebar-toggle-button" | "box-signature-ceremony" | "box-skeleton" | "box-slider" | "box-spin-button" | "box-spinner" | "box-split-view" | "box-status-icon" | "box-switch" | "box-table" | "box-tabs" | "box-tag-input" | "box-task-assignment-panel" | "box-text-area" | "box-text-field" | "box-thumbnail-card" | "box-tile-group" | "box-time-field" | "box-timeline" | "box-toast" | "box-toolbar" | "box-tooltip" | "box-tree" | "box-tree-grid" | "box-unified-share-modal" | "box-version-graph" | "box-version-list" | "box-wizard-summary" | "box-work-queue" | "box-workload-board";
@@ -0,0 +1,12 @@
1
+ export type Politeness = "polite" | "assertive";
2
+ /** Install once near application startup. The returned cleanup removes both regions. SSR-safe. */
3
+ export declare function installAnnouncer(doc?: Document | undefined): () => void;
4
+ /** Queue text, including repeated messages, into an already-mounted live region. */
5
+ export declare function announce(message: string, politeness?: Politeness, doc?: Document | undefined): void;
6
+ /** Coalesce synchronous property updates and avoid duplicate component announcements. */
7
+ export declare class FeedbackAnnouncement {
8
+ private previous;
9
+ private revision;
10
+ update(host: HTMLElement, message: string, politeness: Politeness): void;
11
+ reset(): void;
12
+ }
@@ -0,0 +1,75 @@
1
+ const instances = new WeakMap();
2
+ /** Install once near application startup. The returned cleanup removes both regions. SSR-safe. */
3
+ export function installAnnouncer(doc = globalThis.document) {
4
+ if (!doc?.body)
5
+ return () => { };
6
+ const existing = instances.get(doc);
7
+ if (existing?.host.isConnected)
8
+ return existing.dispose;
9
+ existing?.dispose();
10
+ const host = doc.createElement("div");
11
+ host.dataset.boeAnnouncer = "";
12
+ host.style.cssText = "position:fixed;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0;pointer-events:none";
13
+ const makeChannel = (politeness) => {
14
+ const region = doc.createElement("div");
15
+ region.setAttribute("role", politeness === "assertive" ? "alert" : "status");
16
+ region.setAttribute("aria-live", politeness);
17
+ region.setAttribute("aria-atomic", "true");
18
+ host.append(region);
19
+ return { region, queue: [] };
20
+ };
21
+ const channels = { polite: makeChannel("polite"), assertive: makeChannel("assertive") };
22
+ const dispose = () => {
23
+ for (const channel of Object.values(channels))
24
+ clearTimeout(channel.timer);
25
+ host.remove();
26
+ if (instances.get(doc)?.host === host)
27
+ instances.delete(doc);
28
+ };
29
+ doc.body.append(host);
30
+ instances.set(doc, { host, channels, dispose });
31
+ return dispose;
32
+ }
33
+ /** Queue text, including repeated messages, into an already-mounted live region. */
34
+ export function announce(message, politeness = "polite", doc = globalThis.document) {
35
+ if (!doc?.body || !message.trim())
36
+ return;
37
+ installAnnouncer(doc);
38
+ const channel = instances.get(doc).channels[politeness];
39
+ channel.queue.push(message);
40
+ if (channel.timer !== undefined)
41
+ return;
42
+ const next = () => {
43
+ channel.region.textContent = "";
44
+ // A separate rendering opportunity ensures an empty region exists first.
45
+ channel.timer = setTimeout(() => {
46
+ channel.region.textContent = channel.queue.shift() ?? "";
47
+ channel.timer = setTimeout(() => {
48
+ channel.timer = undefined;
49
+ if (channel.queue.length)
50
+ next();
51
+ }, 100);
52
+ }, 20);
53
+ };
54
+ next();
55
+ }
56
+ /** Coalesce synchronous property updates and avoid duplicate component announcements. */
57
+ export class FeedbackAnnouncement {
58
+ previous = "";
59
+ revision = 0;
60
+ update(host, message, politeness) {
61
+ const revision = ++this.revision;
62
+ if (!message) {
63
+ this.previous = "";
64
+ return;
65
+ }
66
+ queueMicrotask(() => {
67
+ const key = `${politeness}:${message}`;
68
+ if (revision !== this.revision || !host.isConnected || key === this.previous)
69
+ return;
70
+ this.previous = key;
71
+ announce(message, politeness, host.ownerDocument);
72
+ });
73
+ }
74
+ reset() { ++this.revision; this.previous = ""; }
75
+ }
@@ -9,37 +9,56 @@ const TABBABLE_SELECTOR = [
9
9
  "textarea:not([disabled])",
10
10
  "[tabindex]:not([tabindex='-1'])",
11
11
  ].join(", ");
12
- const isDisabled = (element) => element.hasAttribute("disabled") ||
12
+ const isDisabled = (element) => element.matches(":disabled") ||
13
+ element.hasAttribute("disabled") ||
13
14
  element.disabled === true ||
14
15
  element.getAttribute("aria-disabled") === "true";
15
16
  const isVisible = (element) => {
16
- if (element.hidden || element.getAttribute("aria-hidden") === "true") {
17
- return false;
18
- }
19
- // Closest [hidden] ancestor (common pattern for closed panels).
20
- if (element.closest("[hidden]")) {
21
- return false;
22
- }
23
- const style = element.ownerDocument.defaultView?.getComputedStyle(element);
24
- if (!style) {
25
- return true;
26
- }
27
- if (style.display === "none" || style.visibility === "hidden") {
28
- return false;
17
+ for (let current = element; current;) {
18
+ if (current.hasAttribute("hidden") || current.hasAttribute("inert") || current.getAttribute("aria-hidden") === "true")
19
+ return false;
20
+ const style = current.ownerDocument.defaultView?.getComputedStyle(current);
21
+ if (style?.display === "none" || style?.visibility === "hidden")
22
+ return false;
23
+ const root = current.getRootNode();
24
+ current = current.assignedSlot ?? current.parentElement ?? (root instanceof ShadowRoot ? root.host : null);
29
25
  }
30
26
  return true;
31
27
  };
28
+ const deepActiveElement = (root) => {
29
+ let active = root.activeElement;
30
+ while (active?.shadowRoot?.activeElement)
31
+ active = active.shadowRoot.activeElement;
32
+ return active;
33
+ };
32
34
  /** Visible, enabled tabbable controls inside `container` (light or shadow). */
33
35
  export const getTabbableElements = (container) => {
34
- return Array.from(container.querySelectorAll(TABBABLE_SELECTOR)).filter(element => {
35
- if (isDisabled(element)) {
36
- return false;
37
- }
38
- if (element.tabIndex < 0) {
39
- return false;
36
+ const result = [];
37
+ const visit = (node) => {
38
+ const children = node instanceof HTMLSlotElement
39
+ ? (node.assignedElements().length ? node.assignedElements() : Array.from(node.children))
40
+ : Array.from(node.children);
41
+ for (const child of children) {
42
+ if (!(child instanceof HTMLElement) || !isVisible(child))
43
+ continue;
44
+ const disabled = isDisabled(child);
45
+ // A disabled fieldset still permits controls in its first legend and
46
+ // non-form controls such as links. Let native :disabled filter each
47
+ // descendant instead of pruning the entire fieldset subtree.
48
+ if (disabled && (!(child instanceof HTMLFieldSetElement) || child.getAttribute("aria-disabled") === "true"))
49
+ continue;
50
+ if (!disabled && child.matches(TABBABLE_SELECTOR) && child.tabIndex >= 0)
51
+ result.push(child);
52
+ // An explicit negative tabindex removes a shadow host's entire focus
53
+ // scope from sequential navigation. Ordinary light-DOM containers with
54
+ // tabindex=-1 do not have that behavior.
55
+ if (child.shadowRoot && child.hasAttribute("tabindex") && child.tabIndex < 0)
56
+ continue;
57
+ visit(child.shadowRoot ?? child);
40
58
  }
41
- return isVisible(element);
42
- });
59
+ };
60
+ visit(container);
61
+ return result;
43
62
  };
44
63
  /**
45
64
  * Keep Tab / Shift+Tab cycling inside `container` while a modal is open.
@@ -57,7 +76,7 @@ export const trapTabKey = (event, container) => {
57
76
  const first = focusables[0];
58
77
  const last = focusables[focusables.length - 1];
59
78
  const root = container.getRootNode?.();
60
- const active = root?.activeElement ?? document.activeElement;
79
+ const active = deepActiveElement(root ?? document) ?? deepActiveElement(document);
61
80
  if (event.shiftKey) {
62
81
  if (active === first || !focusables.includes(active)) {
63
82
  event.preventDefault();
@@ -74,6 +93,8 @@ export const trapTabKey = (event, container) => {
74
93
  export class FocusRestore {
75
94
  previous = null;
76
95
  capture(from = document.activeElement) {
96
+ while (from?.shadowRoot?.activeElement)
97
+ from = from.shadowRoot.activeElement;
77
98
  this.previous = from instanceof HTMLElement ? from : null;
78
99
  }
79
100
  restore() {
@@ -83,8 +104,8 @@ export class FocusRestore {
83
104
  return;
84
105
  }
85
106
  queueMicrotask(() => {
86
- if (typeof target.focus === "function") {
87
- target.focus();
107
+ if (target.isConnected && isVisible(target) && !isDisabled(target)) {
108
+ target.focus({ preventScroll: true });
88
109
  }
89
110
  });
90
111
  }
@@ -1,3 +1,5 @@
1
+ export { announce, installAnnouncer } from "./announcer.js";
2
+ export type { Politeness } from "./announcer.js";
1
3
  export { applyRovingTabindex, focusRovingItem, handleRovingKeydown, nextRovingIndex, } from "./keyboard.js";
2
4
  export type { RovingKeyOptions, RovingOrientation } from "./keyboard.js";
3
5
  export { FocusRestore, getTabbableElements, trapTabKey } from "./focus.js";
@@ -1,3 +1,4 @@
1
+ export { announce, installAnnouncer } from "./announcer.js";
1
2
  export { applyRovingTabindex, focusRovingItem, handleRovingKeydown, nextRovingIndex, } from "./keyboard.js";
2
3
  export { FocusRestore, getTabbableElements, trapTabKey } from "./focus.js";
3
4
  export { boeHeadingResetStyles, headingCloseTag, headingOpenTag, renderHeadingHtml, } from "./heading.js";