@unofficialbox/box-open-elements 0.9.0 → 0.11.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.
- package/dist/components/feedback/alert.js +1 -16
- package/dist/components/feedback/path.d.ts +84 -0
- package/dist/components/feedback/path.js +455 -0
- package/dist/components/feedback/skeleton.d.ts +70 -0
- package/dist/components/feedback/skeleton.js +231 -1
- package/dist/components/feedback/toast.d.ts +38 -0
- package/dist/components/feedback/toast.js +189 -13
- package/dist/components/feedback/tone.d.ts +16 -0
- package/dist/components/feedback/tone.js +31 -0
- package/dist/components/layout/grid.d.ts +41 -0
- package/dist/components/layout/grid.js +152 -0
- package/dist/components/overlays/command-palette.d.ts +1 -0
- package/dist/components/overlays/command-palette.js +42 -3
- package/dist/components/overlays/context-menu.js +11 -1
- package/dist/components/overlays/dialog.d.ts +1 -0
- package/dist/components/overlays/dialog.js +43 -3
- package/dist/components/overlays/drawer.d.ts +1 -3
- package/dist/components/overlays/drawer.js +4 -20
- package/dist/components/overlays/guide-tooltip.js +15 -1
- package/dist/components/overlays/popover.js +16 -1
- package/dist/components/overlays/shortcuts-overlay.d.ts +1 -0
- package/dist/components/overlays/shortcuts-overlay.js +40 -3
- package/dist/components/overlays/tooltip.js +15 -1
- package/dist/element-maps.d.ts +5 -3
- package/dist/entries/grid.d.ts +1 -0
- package/dist/entries/grid.js +1 -0
- package/dist/entries/path.d.ts +1 -0
- package/dist/entries/path.js +1 -0
- package/dist/foundations/layout/grid.d.ts +70 -0
- package/dist/foundations/layout/grid.js +84 -0
- package/dist/foundations/layout/index.d.ts +1 -0
- package/dist/foundations/layout/index.js +3 -0
- package/dist/foundations/overlay/index.d.ts +1 -0
- package/dist/foundations/overlay/index.js +1 -0
- package/dist/foundations/overlay/top-layer.d.ts +62 -0
- package/dist/foundations/overlay/top-layer.js +95 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +5 -1
- package/dist/patterns/audit/audit-log.js +0 -1
- package/dist/patterns/lineage/lineage-graph.d.ts +7 -0
- package/dist/patterns/lineage/lineage-graph.js +67 -6
- package/dist/patterns/lineage/provenance-strip.js +106 -15
- package/dist/patterns/notifications/notification-inbox.js +2 -18
- package/dist/patterns/timeline/timeline.js +44 -12
- package/dist/patterns/versions/graph-arrows.d.ts +22 -0
- package/dist/patterns/versions/graph-arrows.js +13 -0
- package/dist/patterns/versions/index.d.ts +1 -0
- package/dist/patterns/versions/index.js +1 -0
- package/dist/patterns/versions/version-graph.d.ts +7 -0
- package/dist/patterns/versions/version-graph.js +54 -6
- package/package.json +1 -1
- package/dist/components/feedback/stage-path.d.ts +0 -44
- package/dist/components/feedback/stage-path.js +0 -235
- package/dist/entries/stage-path.d.ts +0 -1
- package/dist/entries/stage-path.js +0 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { groupShortcutCommands, isCommandDescriptorRecord, splitShortcutKeys, } from "./command-types.js";
|
|
2
2
|
import { BaseElement } from "../../core/index.js";
|
|
3
|
+
import { dismissModal, promoteModal } from "../../foundations/overlay/index.js";
|
|
3
4
|
import { FocusRestore, trapTabKey } from "../../foundations/a11y/index.js";
|
|
4
5
|
import { boeOverlay, boePanel, boeRadius } from "../../foundations/geometry/index.js";
|
|
5
6
|
const DEFAULT_TAG_NAME = "box-shortcuts-overlay";
|
|
@@ -37,6 +38,10 @@ const elementStyles = `
|
|
|
37
38
|
display: contents;
|
|
38
39
|
}
|
|
39
40
|
|
|
41
|
+
/* A <dialog> promoted with showModal() — see
|
|
42
|
+
foundations/overlay/top-layer.ts. The top layer keeps the scrim above
|
|
43
|
+
the page without moving the host node. UA border/margin/max-* reset
|
|
44
|
+
because this is the full-viewport scrim, not a centred card. */
|
|
40
45
|
[part="backdrop"] {
|
|
41
46
|
position: fixed;
|
|
42
47
|
inset: 0;
|
|
@@ -46,6 +51,24 @@ const elementStyles = `
|
|
|
46
51
|
padding: 1rem;
|
|
47
52
|
background: ${boeOverlay.modalBackdrop};
|
|
48
53
|
z-index: 1000;
|
|
54
|
+
border: 0;
|
|
55
|
+
margin: 0;
|
|
56
|
+
max-width: none;
|
|
57
|
+
max-height: none;
|
|
58
|
+
width: auto;
|
|
59
|
+
height: auto;
|
|
60
|
+
color: inherit;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/* The scrim paints itself; the UA pseudo must not double it up. */
|
|
64
|
+
[part="backdrop"]::backdrop {
|
|
65
|
+
background: transparent;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* Without showModal support the element stays hidden, which is the
|
|
69
|
+
correct closed state anyway. */
|
|
70
|
+
[part="backdrop"]:not([open]) {
|
|
71
|
+
display: none;
|
|
49
72
|
}
|
|
50
73
|
|
|
51
74
|
[part="sheet"] {
|
|
@@ -183,6 +206,7 @@ export class ShortcutsOverlay extends BaseElement {
|
|
|
183
206
|
return ["commands", "heading", "hotkey", "open"];
|
|
184
207
|
}
|
|
185
208
|
hostEl;
|
|
209
|
+
backdropEl = null;
|
|
186
210
|
focusRestore = new FocusRestore();
|
|
187
211
|
wasOpen = false;
|
|
188
212
|
commandsRaw = null;
|
|
@@ -333,6 +357,9 @@ export class ShortcutsOverlay extends BaseElement {
|
|
|
333
357
|
}
|
|
334
358
|
if (!this.open) {
|
|
335
359
|
const wasOpen = this.wasOpen;
|
|
360
|
+
// Leave the top layer before the element is discarded, not after.
|
|
361
|
+
dismissModal(this.backdropEl);
|
|
362
|
+
this.backdropEl = null;
|
|
336
363
|
this.hostEl.innerHTML = "";
|
|
337
364
|
this.wasOpen = false;
|
|
338
365
|
if (wasOpen) {
|
|
@@ -365,8 +392,8 @@ export class ShortcutsOverlay extends BaseElement {
|
|
|
365
392
|
})
|
|
366
393
|
.join("");
|
|
367
394
|
this.hostEl.innerHTML = `
|
|
368
|
-
<
|
|
369
|
-
<div part="sheet"
|
|
395
|
+
<dialog part="backdrop" aria-label="Keyboard shortcuts">
|
|
396
|
+
<div part="sheet">
|
|
370
397
|
<div part="header">
|
|
371
398
|
<h2 part="title">${escapeHtml(this.heading)}</h2>
|
|
372
399
|
<button type="button" part="close">Close</button>
|
|
@@ -375,8 +402,18 @@ export class ShortcutsOverlay extends BaseElement {
|
|
|
375
402
|
? `<ul part="groups" role="list">${sections}</ul>`
|
|
376
403
|
: `<div part="empty">No keyboard shortcuts are defined.</div>`}
|
|
377
404
|
</div>
|
|
378
|
-
</
|
|
405
|
+
</dialog>
|
|
379
406
|
`;
|
|
407
|
+
this.backdropEl = this.hostEl.querySelector('[part="backdrop"]');
|
|
408
|
+
if (this.backdropEl) {
|
|
409
|
+
// A modal dialog closes itself on Escape and fires `cancel`; route it
|
|
410
|
+
// through the component's own dismissal so state stays in sync.
|
|
411
|
+
this.backdropEl.addEventListener("cancel", event => {
|
|
412
|
+
event.preventDefault();
|
|
413
|
+
this.dismiss();
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
promoteModal(this.backdropEl);
|
|
380
417
|
if (justOpened) {
|
|
381
418
|
this.hostEl.querySelector('[part="close"]')?.focus();
|
|
382
419
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BaseElement } from "../../core/index.js";
|
|
2
|
+
import { dismissPopover, promotePopover } from "../../foundations/overlay/index.js";
|
|
2
3
|
import { boeRadius } from "../../foundations/geometry/index.js";
|
|
3
4
|
import { boeNeutralInteractiveStyles } from "../../foundations/tokens/index.js";
|
|
4
5
|
import { parsePlacement, trackAnchor, } from "../../foundations/overlay/index.js";
|
|
@@ -40,7 +41,12 @@ const tooltipStyles = `
|
|
|
40
41
|
|
|
41
42
|
/* Positioned by JS (foundations/overlay) as position: fixed, so it escapes
|
|
42
43
|
ancestor overflow and flips/shifts to stay in the viewport. */
|
|
44
|
+
/* display is stated explicitly because the element carries
|
|
45
|
+
popover="manual": the UA sheet hides a popover that is not open, and an
|
|
46
|
+
author declaration outranks it. If showPopover() is unavailable or fails,
|
|
47
|
+
this still renders as before and only the top layer is lost. */
|
|
43
48
|
[part="tooltip"] {
|
|
49
|
+
display: block;
|
|
44
50
|
position: fixed;
|
|
45
51
|
inset-block-start: 0;
|
|
46
52
|
inset-inline-start: 0;
|
|
@@ -180,7 +186,7 @@ export class Tooltip extends BaseElement {
|
|
|
180
186
|
<span part="trigger-host">
|
|
181
187
|
<slot><button type="button" part="trigger">?</button></slot>
|
|
182
188
|
</span>
|
|
183
|
-
<div id="${this.tooltipId}" part="tooltip" role="tooltip" hidden><span part="label"></span><slot name="content"></slot></div>
|
|
189
|
+
<div id="${this.tooltipId}" part="tooltip" popover="manual" role="tooltip" hidden><span part="label"></span><slot name="content"></slot></div>
|
|
184
190
|
</span>
|
|
185
191
|
`;
|
|
186
192
|
this.triggerHostEl = this.shadowRoot.querySelector('[part="trigger-host"]');
|
|
@@ -232,6 +238,14 @@ export class Tooltip extends BaseElement {
|
|
|
232
238
|
this.tooltipEl.setAttribute("data-theme", theme);
|
|
233
239
|
}
|
|
234
240
|
this.tooltipEl.hidden = !this.openValue;
|
|
241
|
+
// Top layer keeps it above the page even inside an ancestor with a
|
|
242
|
+
// transform/filter/contain, which position:fixed alone cannot escape.
|
|
243
|
+
if (this.openValue) {
|
|
244
|
+
promotePopover(this.tooltipEl);
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
dismissPopover(this.tooltipEl);
|
|
248
|
+
}
|
|
235
249
|
const trigger = this.resolveDescribedTrigger();
|
|
236
250
|
if (trigger === this.fallbackTriggerEl) {
|
|
237
251
|
this.fallbackTriggerEl.setAttribute("aria-label", this.triggerLabel);
|
package/dist/element-maps.d.ts
CHANGED
|
@@ -48,6 +48,7 @@ import type { DateField } from "./components/forms/date-field.js";
|
|
|
48
48
|
import type { Dialog } from "./components/overlays/dialog.js";
|
|
49
49
|
import type { DiffViewer } from "./patterns/diff/diff-viewer.js";
|
|
50
50
|
import type { Divider } from "./components/layout/divider.js";
|
|
51
|
+
import type { Grid } from "./components/layout/grid.js";
|
|
51
52
|
import type { DonutChart } from "./patterns/insights/donut-chart.js";
|
|
52
53
|
import type { DraggableList } from "./components/collections/draggable-list.js";
|
|
53
54
|
import type { Drawer } from "./components/overlays/drawer.js";
|
|
@@ -124,7 +125,7 @@ import type { Slider } from "./components/forms/slider.js";
|
|
|
124
125
|
import type { SpinButton } from "./components/forms/spin-button.js";
|
|
125
126
|
import type { Spinner } from "./components/feedback/spinner.js";
|
|
126
127
|
import type { SplitView } from "./components/layout/split-view.js";
|
|
127
|
-
import type {
|
|
128
|
+
import type { Path } from "./components/feedback/path.js";
|
|
128
129
|
import type { Switch } from "./components/forms/switch.js";
|
|
129
130
|
import type { Table } from "./components/collections/table.js";
|
|
130
131
|
import type { Tabs } from "./components/navigation/tabs.js";
|
|
@@ -189,6 +190,7 @@ declare global {
|
|
|
189
190
|
"box-dialog": Dialog;
|
|
190
191
|
"box-diff-viewer": DiffViewer;
|
|
191
192
|
"box-divider": Divider;
|
|
193
|
+
"box-grid": Grid;
|
|
192
194
|
"box-donut-chart": DonutChart;
|
|
193
195
|
"box-draggable-list": DraggableList;
|
|
194
196
|
"box-drawer": Drawer;
|
|
@@ -265,7 +267,7 @@ declare global {
|
|
|
265
267
|
"box-spin-button": SpinButton;
|
|
266
268
|
"box-spinner": Spinner;
|
|
267
269
|
"box-split-view": SplitView;
|
|
268
|
-
"box-
|
|
270
|
+
"box-path": Path;
|
|
269
271
|
"box-switch": Switch;
|
|
270
272
|
"box-table": Table;
|
|
271
273
|
"box-tabs": Tabs;
|
|
@@ -289,4 +291,4 @@ declare global {
|
|
|
289
291
|
}
|
|
290
292
|
}
|
|
291
293
|
/** Every element tag the library registers, for host-side narrowing. */
|
|
292
|
-
export type BoxElementTagName = "box-access-stats" | "box-accordion" | "box-activity-density" | "box-agent-chat" | "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-card" | "box-carousel" | "box-category-selector" | "box-chart-panel" | "box-checkbox" | "box-checkbox-group" | "box-chip" | "box-collaborator-avatars" | "box-color-picker" | "box-combobox" | "box-command-palette" | "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-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-fieldset" | "box-file-request-builder" | "box-filter-bar" | "box-form-wizard" | "box-governance-panel" | "box-grid-view" | "box-guide-tooltip" | "box-help-text" | "box-icon-button" | "box-illustration" | "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-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-review-queue-item" | "box-rich-text-input" | "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-
|
|
294
|
+
export type BoxElementTagName = "box-access-stats" | "box-accordion" | "box-activity-density" | "box-agent-chat" | "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-card" | "box-carousel" | "box-category-selector" | "box-chart-panel" | "box-checkbox" | "box-checkbox-group" | "box-chip" | "box-collaborator-avatars" | "box-color-picker" | "box-combobox" | "box-command-palette" | "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-grid" | "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-fieldset" | "box-file-request-builder" | "box-filter-bar" | "box-form-wizard" | "box-governance-panel" | "box-grid-view" | "box-guide-tooltip" | "box-help-text" | "box-icon-button" | "box-illustration" | "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-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-review-queue-item" | "box-rich-text-input" | "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-path" | "box-switch" | "box-table" | "box-tabs" | "box-tag-input" | "box-task-assignment-panel" | "box-text-area" | "box-text-field" | "box-thumbnail-card" | "box-time-field" | "box-timeline" | "box-toast" | "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 @@
|
|
|
1
|
+
export * from "../components/layout/grid.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../components/layout/grid.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../components/feedback/path.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../components/feedback/path.js";
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adobe Spectrum's responsive grid, as a foundation.
|
|
3
|
+
*
|
|
4
|
+
* Two surfaces build on this: `box-grid`, which lays out slotted content, and
|
|
5
|
+
* `box-skeleton`'s grid variant, which fills the same regions with shimmer
|
|
6
|
+
* bars. They must agree on what a column is worth and how wide a gutter is at
|
|
7
|
+
* a given viewport, so the model lives here rather than in either of them.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Columns in the grid.
|
|
11
|
+
*
|
|
12
|
+
* Twelve divides by 2, 3, 4 and 6, so halves, thirds, quarters and
|
|
13
|
+
* sidebar-plus-content all land on whole columns.
|
|
14
|
+
*/
|
|
15
|
+
export declare const BOE_GRID_COLUMNS = 12;
|
|
16
|
+
/**
|
|
17
|
+
* Spectrum's breakpoints and their gutters.
|
|
18
|
+
*
|
|
19
|
+
* Breakpoints are min-widths, so a viewport between two of them inherits the
|
|
20
|
+
* smaller one's dimensions. Gutters are fixed values per breakpoint rather
|
|
21
|
+
* than a proportion of the grid — that is Spectrum's rule, and it is why the
|
|
22
|
+
* gutter cannot simply be a percentage.
|
|
23
|
+
*/
|
|
24
|
+
export declare const BOE_GRID_BREAKPOINTS: readonly {
|
|
25
|
+
minWidth: number;
|
|
26
|
+
gutter: number;
|
|
27
|
+
}[];
|
|
28
|
+
/** The custom property every grid surface reads its gutter from. */
|
|
29
|
+
export declare const BOE_GRID_GUTTER_PROPERTY = "--boe-grid-gutter";
|
|
30
|
+
/**
|
|
31
|
+
* The gutter scale as CSS, scoped to a selector.
|
|
32
|
+
*
|
|
33
|
+
* Emitted rather than hand-written in each component so the two cannot drift,
|
|
34
|
+
* and so adding a breakpoint is one edit. A consumer overriding the property
|
|
35
|
+
* replaces the whole scale in one declaration.
|
|
36
|
+
*/
|
|
37
|
+
export declare const boeGridGutterStyles: (selector?: string) => string;
|
|
38
|
+
/**
|
|
39
|
+
* One region of the grid: a block spanning some columns and rows, optionally
|
|
40
|
+
* pushed right by an offset. Spectrum calls these layout regions.
|
|
41
|
+
*/
|
|
42
|
+
export interface BoeGridPlacement {
|
|
43
|
+
/** Columns to span. Clamped to what is left after `offset`. */
|
|
44
|
+
span?: number;
|
|
45
|
+
/** Rows to span. Clamped to the grid's `rows`, so a region cannot exceed it. */
|
|
46
|
+
rowSpan?: number;
|
|
47
|
+
/** Empty columns before this region. Clamped to leave room for one column. */
|
|
48
|
+
offset?: number;
|
|
49
|
+
}
|
|
50
|
+
/** A resolved region: every field present, every value in range. */
|
|
51
|
+
export interface ResolvedBoeGridPlacement {
|
|
52
|
+
span: number;
|
|
53
|
+
rowSpan: number;
|
|
54
|
+
offset: number;
|
|
55
|
+
}
|
|
56
|
+
/** Attribute payloads are author input — validate every record. */
|
|
57
|
+
export declare const isBoeGridPlacementRecord: (value: unknown) => value is BoeGridPlacement;
|
|
58
|
+
/**
|
|
59
|
+
* Fit a region to the grid.
|
|
60
|
+
*
|
|
61
|
+
* Every value is clamped rather than rejected. A layout that renders slightly
|
|
62
|
+
* wrong is recoverable; one that vanishes because a number was out of range is
|
|
63
|
+
* not, and the caller usually cannot tell which region was dropped. The clamps
|
|
64
|
+
* are what confine a region to the totals the author declared: a span of 9 in a
|
|
65
|
+
* three-column grid becomes 3, and a `rowSpan` of 5 in a three-row grid
|
|
66
|
+
* becomes 3.
|
|
67
|
+
*/
|
|
68
|
+
export declare const resolveBoeGridPlacement: (item: BoeGridPlacement, columns: number, rows: number) => ResolvedBoeGridPlacement;
|
|
69
|
+
/** Parse a positive integer attribute, falling back when it is absent or junk. */
|
|
70
|
+
export declare const resolveGridCount: (raw: string | null, fallback: number) => number;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adobe Spectrum's responsive grid, as a foundation.
|
|
3
|
+
*
|
|
4
|
+
* Two surfaces build on this: `box-grid`, which lays out slotted content, and
|
|
5
|
+
* `box-skeleton`'s grid variant, which fills the same regions with shimmer
|
|
6
|
+
* bars. They must agree on what a column is worth and how wide a gutter is at
|
|
7
|
+
* a given viewport, so the model lives here rather than in either of them.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Columns in the grid.
|
|
11
|
+
*
|
|
12
|
+
* Twelve divides by 2, 3, 4 and 6, so halves, thirds, quarters and
|
|
13
|
+
* sidebar-plus-content all land on whole columns.
|
|
14
|
+
*/
|
|
15
|
+
export const BOE_GRID_COLUMNS = 12;
|
|
16
|
+
/**
|
|
17
|
+
* Spectrum's breakpoints and their gutters.
|
|
18
|
+
*
|
|
19
|
+
* Breakpoints are min-widths, so a viewport between two of them inherits the
|
|
20
|
+
* smaller one's dimensions. Gutters are fixed values per breakpoint rather
|
|
21
|
+
* than a proportion of the grid — that is Spectrum's rule, and it is why the
|
|
22
|
+
* gutter cannot simply be a percentage.
|
|
23
|
+
*/
|
|
24
|
+
export const BOE_GRID_BREAKPOINTS = [
|
|
25
|
+
{ minWidth: 0, gutter: 16 },
|
|
26
|
+
{ minWidth: 768, gutter: 24 },
|
|
27
|
+
{ minWidth: 1280, gutter: 32 },
|
|
28
|
+
{ minWidth: 1768, gutter: 40 },
|
|
29
|
+
{ minWidth: 2160, gutter: 48 },
|
|
30
|
+
];
|
|
31
|
+
/** The custom property every grid surface reads its gutter from. */
|
|
32
|
+
export const BOE_GRID_GUTTER_PROPERTY = "--boe-grid-gutter";
|
|
33
|
+
/**
|
|
34
|
+
* The gutter scale as CSS, scoped to a selector.
|
|
35
|
+
*
|
|
36
|
+
* Emitted rather than hand-written in each component so the two cannot drift,
|
|
37
|
+
* and so adding a breakpoint is one edit. A consumer overriding the property
|
|
38
|
+
* replaces the whole scale in one declaration.
|
|
39
|
+
*/
|
|
40
|
+
export const boeGridGutterStyles = (selector = ":host") => BOE_GRID_BREAKPOINTS.map(({ minWidth, gutter }) => {
|
|
41
|
+
const declaration = `${selector} {\n ${BOE_GRID_GUTTER_PROPERTY}: ${gutter}px;\n }`;
|
|
42
|
+
return minWidth === 0
|
|
43
|
+
? ` ${declaration}`
|
|
44
|
+
: ` @media (min-width: ${minWidth}px) {\n ${declaration}\n }`;
|
|
45
|
+
}).join("\n\n");
|
|
46
|
+
/** Attribute payloads are author input — validate every record. */
|
|
47
|
+
export const isBoeGridPlacementRecord = (value) => {
|
|
48
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
const item = value;
|
|
52
|
+
// Absent is fine — each field has a default. Present-but-not-a-number is not:
|
|
53
|
+
// it means the host built the payload wrong, and silently substituting a
|
|
54
|
+
// default would hide that.
|
|
55
|
+
return ["span", "rowSpan", "offset"].every(key => {
|
|
56
|
+
const raw = item[key];
|
|
57
|
+
return raw === undefined || (typeof raw === "number" && Number.isFinite(raw));
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
const clamp = (value, min, max) => Math.min(Math.max(Math.trunc(value), min), max);
|
|
61
|
+
/**
|
|
62
|
+
* Fit a region to the grid.
|
|
63
|
+
*
|
|
64
|
+
* Every value is clamped rather than rejected. A layout that renders slightly
|
|
65
|
+
* wrong is recoverable; one that vanishes because a number was out of range is
|
|
66
|
+
* not, and the caller usually cannot tell which region was dropped. The clamps
|
|
67
|
+
* are what confine a region to the totals the author declared: a span of 9 in a
|
|
68
|
+
* three-column grid becomes 3, and a `rowSpan` of 5 in a three-row grid
|
|
69
|
+
* becomes 3.
|
|
70
|
+
*/
|
|
71
|
+
export const resolveBoeGridPlacement = (item, columns, rows) => {
|
|
72
|
+
// Leave at least one column for the region itself.
|
|
73
|
+
const offset = clamp(item.offset ?? 0, 0, Math.max(columns - 1, 0));
|
|
74
|
+
return {
|
|
75
|
+
offset,
|
|
76
|
+
span: clamp(item.span ?? 1, 1, Math.max(columns - offset, 1)),
|
|
77
|
+
rowSpan: clamp(item.rowSpan ?? 1, 1, Math.max(rows, 1)),
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
/** Parse a positive integer attribute, falling back when it is absent or junk. */
|
|
81
|
+
export const resolveGridCount = (raw, fallback) => {
|
|
82
|
+
const parsed = Number.parseInt(raw ?? "", 10);
|
|
83
|
+
return Number.isFinite(parsed) ? Math.max(parsed, 1) : fallback;
|
|
84
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./grid.js";
|
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
export { anchorFloating, parsePlacement, resolvePosition, trackAnchor, } from "./positioning.js";
|
|
2
|
+
export { dismissModal, dismissPopover, promoteModal, promotePopover, } from "./top-layer.js";
|
|
2
3
|
export type { OverlayAlign, OverlayPlacement, OverlaySide, PositionOptions, PositionResult, Rect, Size, } from "./positioning.js";
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Top-layer promotion for overlays.
|
|
3
|
+
*
|
|
4
|
+
* An overlay has to paint above the page, and `position: fixed` alone cannot
|
|
5
|
+
* promise that: an ancestor with a `transform`, `filter`, `perspective`,
|
|
6
|
+
* `contain`, or `will-change` becomes the containing block, and the overlay is
|
|
7
|
+
* positioned — and clipped — against that ancestor instead of the viewport.
|
|
8
|
+
*
|
|
9
|
+
* The old answer was to move the overlay's host node to `document.body`.
|
|
10
|
+
* `box-drawer` did exactly that and it broke every framework that owns the
|
|
11
|
+
* node: React unmounting a tree containing an open drawer threw
|
|
12
|
+
* `NotFoundError`, because the node it tried to remove was no longer its child.
|
|
13
|
+
*
|
|
14
|
+
* The top layer solves the same problem without touching the DOM tree. It is a
|
|
15
|
+
* rendering concern, so the host stays exactly where its framework put it.
|
|
16
|
+
*
|
|
17
|
+
* Two primitives, and the difference is modality rather than taste:
|
|
18
|
+
*
|
|
19
|
+
* - `showModal()` on a `<dialog>` — for overlays that own the screen while they
|
|
20
|
+
* are up, with a scrim, a focus trap, and the rest of the page inert.
|
|
21
|
+
* - `showPopover()` on a `[popover]` element — for anchored, non-modal surfaces
|
|
22
|
+
* (tooltips, menus, popovers) that must **not** trap focus or block the page.
|
|
23
|
+
*
|
|
24
|
+
* Using the modal primitive for an anchored surface would be a behaviour
|
|
25
|
+
* regression, not just an overreach, which is why these are separate calls.
|
|
26
|
+
*
|
|
27
|
+
* Every entry point is guarded rather than assumed. jsdom implements neither
|
|
28
|
+
* API, so the unit suite exercises everything around the promotion and the
|
|
29
|
+
* promotion itself is verified in a browser; and a detached or hidden element
|
|
30
|
+
* throws rather than opening, which is a normal state during teardown.
|
|
31
|
+
*/
|
|
32
|
+
/** An element that may be promotable as a modal dialog. */
|
|
33
|
+
type MaybeDialog = HTMLElement & {
|
|
34
|
+
showModal?: () => void;
|
|
35
|
+
close?: () => void;
|
|
36
|
+
open?: boolean;
|
|
37
|
+
};
|
|
38
|
+
/** An element that may be promotable as a popover. */
|
|
39
|
+
type MaybePopover = HTMLElement & {
|
|
40
|
+
showPopover?: () => void;
|
|
41
|
+
hidePopover?: () => void;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Promote a `<dialog>` into the top layer as a modal.
|
|
45
|
+
*
|
|
46
|
+
* Returns whether the promotion happened, so a caller can tell "not supported
|
|
47
|
+
* here" from "already open" if it needs to — most do not.
|
|
48
|
+
*/
|
|
49
|
+
export declare const promoteModal: (element: MaybeDialog | null) => boolean;
|
|
50
|
+
/** Close a modal `<dialog>`, leaving the top layer. */
|
|
51
|
+
export declare const dismissModal: (element: MaybeDialog | null) => void;
|
|
52
|
+
/**
|
|
53
|
+
* Promote an element into the top layer as a **non-modal** popover.
|
|
54
|
+
*
|
|
55
|
+
* Callers are expected to set `popover="manual"` on the element: `auto`
|
|
56
|
+
* popovers light-dismiss and close each other, which fights components that
|
|
57
|
+
* already own their own dismissal rules.
|
|
58
|
+
*/
|
|
59
|
+
export declare const promotePopover: (element: MaybePopover | null) => boolean;
|
|
60
|
+
/** Hide a popover, leaving the top layer. */
|
|
61
|
+
export declare const dismissPopover: (element: MaybePopover | null) => void;
|
|
62
|
+
export {};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Top-layer promotion for overlays.
|
|
3
|
+
*
|
|
4
|
+
* An overlay has to paint above the page, and `position: fixed` alone cannot
|
|
5
|
+
* promise that: an ancestor with a `transform`, `filter`, `perspective`,
|
|
6
|
+
* `contain`, or `will-change` becomes the containing block, and the overlay is
|
|
7
|
+
* positioned — and clipped — against that ancestor instead of the viewport.
|
|
8
|
+
*
|
|
9
|
+
* The old answer was to move the overlay's host node to `document.body`.
|
|
10
|
+
* `box-drawer` did exactly that and it broke every framework that owns the
|
|
11
|
+
* node: React unmounting a tree containing an open drawer threw
|
|
12
|
+
* `NotFoundError`, because the node it tried to remove was no longer its child.
|
|
13
|
+
*
|
|
14
|
+
* The top layer solves the same problem without touching the DOM tree. It is a
|
|
15
|
+
* rendering concern, so the host stays exactly where its framework put it.
|
|
16
|
+
*
|
|
17
|
+
* Two primitives, and the difference is modality rather than taste:
|
|
18
|
+
*
|
|
19
|
+
* - `showModal()` on a `<dialog>` — for overlays that own the screen while they
|
|
20
|
+
* are up, with a scrim, a focus trap, and the rest of the page inert.
|
|
21
|
+
* - `showPopover()` on a `[popover]` element — for anchored, non-modal surfaces
|
|
22
|
+
* (tooltips, menus, popovers) that must **not** trap focus or block the page.
|
|
23
|
+
*
|
|
24
|
+
* Using the modal primitive for an anchored surface would be a behaviour
|
|
25
|
+
* regression, not just an overreach, which is why these are separate calls.
|
|
26
|
+
*
|
|
27
|
+
* Every entry point is guarded rather than assumed. jsdom implements neither
|
|
28
|
+
* API, so the unit suite exercises everything around the promotion and the
|
|
29
|
+
* promotion itself is verified in a browser; and a detached or hidden element
|
|
30
|
+
* throws rather than opening, which is a normal state during teardown.
|
|
31
|
+
*/
|
|
32
|
+
/**
|
|
33
|
+
* Promote a `<dialog>` into the top layer as a modal.
|
|
34
|
+
*
|
|
35
|
+
* Returns whether the promotion happened, so a caller can tell "not supported
|
|
36
|
+
* here" from "already open" if it needs to — most do not.
|
|
37
|
+
*/
|
|
38
|
+
export const promoteModal = (element) => {
|
|
39
|
+
if (!element || typeof element.showModal !== "function" || element.open) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
element.showModal();
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// Detached, hidden, or already promoted by another path. The overlay still
|
|
48
|
+
// renders and behaves; it simply does not get the top layer.
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
/** Close a modal `<dialog>`, leaving the top layer. */
|
|
53
|
+
export const dismissModal = (element) => {
|
|
54
|
+
if (!element || typeof element.close !== "function" || !element.open) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
element.close();
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// Already closed or detached; nothing to undo.
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Promote an element into the top layer as a **non-modal** popover.
|
|
66
|
+
*
|
|
67
|
+
* Callers are expected to set `popover="manual"` on the element: `auto`
|
|
68
|
+
* popovers light-dismiss and close each other, which fights components that
|
|
69
|
+
* already own their own dismissal rules.
|
|
70
|
+
*/
|
|
71
|
+
export const promotePopover = (element) => {
|
|
72
|
+
if (!element || typeof element.showPopover !== "function") {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
try {
|
|
76
|
+
element.showPopover();
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
// Throws if already showing, or if the element is not connected.
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
/** Hide a popover, leaving the top layer. */
|
|
85
|
+
export const dismissPopover = (element) => {
|
|
86
|
+
if (!element || typeof element.hidePopover !== "function") {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
try {
|
|
90
|
+
element.hidePopover();
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
// Not currently showing; nothing to undo.
|
|
94
|
+
}
|
|
95
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export type { ResolvedTheme, ThemeChangeDetail, ThemeController, ThemeController
|
|
|
8
8
|
export { DESIGN_PROFILE_CHANGE_EVENT, DESIGN_PROFILE_VARIABLES, DEFAULT_DESIGN_PROFILE_STORAGE_KEY, applyDesignProfile, boxDefaultDesignProfile, compactNeutralDesignProfile, createDesignProfileController, createDesignProfileStyleText, getDesignProfile, listDesignProfiles, registerBuiltInDesignProfiles, registerDesignProfile, resolveDesignProfileProperties, } from "./foundations/profiles/index.js";
|
|
9
9
|
export type { ApplyDesignProfileOptions, DesignProfileChangeDetail, DesignProfileController, DesignProfileControllerOptions, DesignProfileDefinition, DesignProfileDensity, DesignProfileElevation, DesignProfileMotion, DesignProfileRadius, DesignProfileSpacing, DesignProfileTypography, } from "./foundations/profiles/index.js";
|
|
10
10
|
export { boxIconography, boxIconographyAliases } from "./foundations/icons/index.js";
|
|
11
|
+
export * from "./foundations/layout/index.js";
|
|
11
12
|
export { anchorFloating, parsePlacement, resolvePosition, trackAnchor, } from "./foundations/overlay/index.js";
|
|
12
13
|
export type { OverlayAlign, OverlayPlacement, OverlaySide, PositionOptions, PositionResult, } from "./foundations/overlay/index.js";
|
|
13
14
|
export * from "./components/actions/button.js";
|
|
@@ -42,10 +43,11 @@ export * from "./components/feedback/progress-ring.js";
|
|
|
42
43
|
export * from "./components/feedback/progress-steps.js";
|
|
43
44
|
export * from "./components/feedback/skeleton.js";
|
|
44
45
|
export * from "./components/feedback/spinner.js";
|
|
45
|
-
export * from "./components/feedback/
|
|
46
|
+
export * from "./components/feedback/path.js";
|
|
46
47
|
export * from "./components/feedback/toast.js";
|
|
47
48
|
export * from "./components/files/drop-zone.js";
|
|
48
49
|
export * from "./components/identity/avatar.js";
|
|
50
|
+
export * from "./components/identity/contact-datalist-item.js";
|
|
49
51
|
export * from "./components/identity/persona.js";
|
|
50
52
|
export * from "./components/navigation/accordion.js";
|
|
51
53
|
export * from "./components/navigation/breadcrumb.js";
|
|
@@ -80,6 +82,7 @@ export * from "./components/forms/text-area.js";
|
|
|
80
82
|
export * from "./components/forms/text-field.js";
|
|
81
83
|
export * from "./components/layout/app-shell.js";
|
|
82
84
|
export * from "./components/layout/divider.js";
|
|
85
|
+
export * from "./components/layout/grid.js";
|
|
83
86
|
export * from "./components/layout/nav-sidebar.js";
|
|
84
87
|
export * from "./components/layout/section.js";
|
|
85
88
|
export * from "./components/layout/sidebar-toggle-button.js";
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,8 @@ export { DESIGN_SYSTEM_CHANGE_EVENT, SEMANTIC_TOKEN_ALIASES, applyDesignTokens,
|
|
|
5
5
|
export { DARK_MODE_MEDIA_QUERY, DEFAULT_THEME_STORAGE_KEY, THEME_CHANGE_EVENT, createThemeController, createThemeInitializationScript, } from "./foundations/theming/index.js";
|
|
6
6
|
export { DESIGN_PROFILE_CHANGE_EVENT, DESIGN_PROFILE_VARIABLES, DEFAULT_DESIGN_PROFILE_STORAGE_KEY, applyDesignProfile, boxDefaultDesignProfile, compactNeutralDesignProfile, createDesignProfileController, createDesignProfileStyleText, getDesignProfile, listDesignProfiles, registerBuiltInDesignProfiles, registerDesignProfile, resolveDesignProfileProperties, } from "./foundations/profiles/index.js";
|
|
7
7
|
export { boxIconography, boxIconographyAliases } from "./foundations/icons/index.js";
|
|
8
|
+
// Foundations: Adobe Spectrum's responsive grid (shared by box-grid and box-skeleton)
|
|
9
|
+
export * from "./foundations/layout/index.js";
|
|
8
10
|
// Foundations: viewport-aware overlay positioning (for building custom overlays)
|
|
9
11
|
export { anchorFloating, parsePlacement, resolvePosition, trackAnchor, } from "./foundations/overlay/index.js";
|
|
10
12
|
// Components: actions
|
|
@@ -42,12 +44,13 @@ export * from "./components/feedback/progress-ring.js";
|
|
|
42
44
|
export * from "./components/feedback/progress-steps.js";
|
|
43
45
|
export * from "./components/feedback/skeleton.js";
|
|
44
46
|
export * from "./components/feedback/spinner.js";
|
|
45
|
-
export * from "./components/feedback/
|
|
47
|
+
export * from "./components/feedback/path.js";
|
|
46
48
|
export * from "./components/feedback/toast.js";
|
|
47
49
|
// Components: files
|
|
48
50
|
export * from "./components/files/drop-zone.js";
|
|
49
51
|
// Components: identity
|
|
50
52
|
export * from "./components/identity/avatar.js";
|
|
53
|
+
export * from "./components/identity/contact-datalist-item.js";
|
|
51
54
|
export * from "./components/identity/persona.js";
|
|
52
55
|
// Components: navigation
|
|
53
56
|
export * from "./components/navigation/accordion.js";
|
|
@@ -86,6 +89,7 @@ export * from "./components/forms/text-field.js";
|
|
|
86
89
|
// Components: layout
|
|
87
90
|
export * from "./components/layout/app-shell.js";
|
|
88
91
|
export * from "./components/layout/divider.js";
|
|
92
|
+
export * from "./components/layout/grid.js";
|
|
89
93
|
export * from "./components/layout/nav-sidebar.js";
|
|
90
94
|
export * from "./components/layout/section.js";
|
|
91
95
|
export * from "./components/layout/sidebar-toggle-button.js";
|
|
@@ -221,7 +221,6 @@ const elementStyles = `
|
|
|
221
221
|
gap: 0.25rem;
|
|
222
222
|
padding: 0.5rem 0.65rem;
|
|
223
223
|
border-top: 1px solid color-mix(in srgb, var(--boe-token-stroke-stroke, #e8e8e8) 55%, transparent);
|
|
224
|
-
border-left: 3px solid var(--audit-tone, transparent);
|
|
225
224
|
}
|
|
226
225
|
|
|
227
226
|
[part="event-topline"] {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { LineageNode } from "./types.js";
|
|
2
|
+
import type { GraphArrows } from "../versions/graph-arrows.js";
|
|
2
3
|
import { BaseElement } from "../../core/index.js";
|
|
3
4
|
/**
|
|
4
5
|
* Provenance DAG for clause lineage (opportunity 2): source clause →
|
|
@@ -13,6 +14,12 @@ import { BaseElement } from "../../core/index.js";
|
|
|
13
14
|
export declare class LineageGraph extends BaseElement {
|
|
14
15
|
static readonly tagName: string;
|
|
15
16
|
static get observedAttributes(): string[];
|
|
17
|
+
/**
|
|
18
|
+
* Which ends of each edge carry an arrowhead. Defaults to `end`, the head on
|
|
19
|
+
* the derived node, because the layout builds edges source → derived.
|
|
20
|
+
*/
|
|
21
|
+
get arrows(): GraphArrows;
|
|
22
|
+
set arrows(value: GraphArrows);
|
|
16
23
|
private nodesValue;
|
|
17
24
|
private rovingId;
|
|
18
25
|
private hostEl;
|