ooxml-ui 0.18.2 → 0.20.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/README.md CHANGED
@@ -60,39 +60,41 @@ with an incompatible build of this package.
60
60
 
61
61
  ## Features: elements
62
62
 
63
- | Tag | Attributes / properties | Events (all bubble, composed) |
64
- | ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
65
- | `office-ui-button` | `label`, `icon`, `command`, `disabled`, `pressed`, `expanded`, `icon-only`, `variant="stacked"`, `keyshortcuts` | `office-command` `{ command }` |
66
- | `office-ui-checkbox`, `office-ui-switch` | `checked`, `disabled`, `value`, `aria-label`; form-associated | `input`, `change` |
67
- | `office-ui-select` | `<option>` / `<optgroup>` children (`data-display-label`, `data-description`, font previews) or the `options` property `[{ value, label, disabled? }]`; `value`, `selectedIndex`, `disabled`, `aria-label`, `variant="ribbon-font" | "ribbon-icon"`, `data-font-picker`; `icon`and`custom` slots; arrows, Home, End, PageUp/PageDown, typeahead | `input`, `change` |
68
- | `office-ui-ribbon-group` | `label`, `launcher` (dialog launcher command), `launcher-disabled`; default slot | launcher: `office-command` `{ command }` |
69
- | `office-ui-ribbon-stack` | `orientation="horizontal"`; default slot (three-row column of small commands by default) | none |
70
- | `office-ui-menu-button` / `-menu-item` | button: `label`, `icon`, `command` (split button), `variant`, `disabled`, `keyshortcuts`; item: `command`, `label`, `icon`, `disabled`, `checked` | item choice: `office-command` `{ command }` |
71
- | `office-ui-toolbar` | `aria-label`, `aria-orientation`; arrow-key focus movement | none |
72
- | `office-ui-dialog` | `open`, `heading`, `dismissible="false"`, `show()`, `close()`; slots default, `footer` | `office-dialog-close` `{ reason }` (cancelable) |
73
- | `office-ui-status-bar` / `-status-item` | `label`, `value`, `interactive`, `id`; controlled bar: `state` `{ items?, toggles?, views?, zoom? }` with `collaboration` and `end` slots | `office-status-activate` `{ id }` |
74
- | `office-ui-zoom-slider` | `value` (percent), `min`, `max`, `step`, `disabled`, `fit` (fit button name), `label` | `input`, `change`; fit: `office-command` `{ command: 'zoom-fit' }` |
75
- | `office-ui-tab-strip` | `tabs` `[{ id, label, title? }]`, `selected`, `label`, `previous-label`, `next-label`, `add-label`, `add-disabled`, `add-title`, `disabled` | `office-tab-select` `{ id }` (cancelable); add: `office-command` `{ command: 'tab-add' }` |
76
- | `office-ui-context-menu` / `office-ui-menu-separator` | Children mode: `label`, `openAt(x, y)`, `close()`, `open` over `office-ui-menu-item` and separator children. Controlled mode: `state` `{ x, y, label, items: [{ id, label, separatorBefore?, heading?, danger?, disabled?, checked?, icon? }], markers?, zIndex?, autoFocus? }`; arrows, Home, End and type-ahead in both | children: item `office-command` `{ command }`; controlled: `office-menu-request` `{ id }`, `office-menu-close` `{ reason }` (never closes itself) |
77
- | `office-ui-command-search` | `commands` `[{ id, label, keywords?, description?, disabled?, title? }]`, `placeholder`, `label`, `limit` (Office's "Tell me what you want to do") | choice: `office-command` `{ command }` |
78
- | `office-ui-options-dialog` | `categories` `[{ id, label, description?, disabled?, sections: [{ id, title, controls }] }]` (controls: `toggle`, `select`, `number`, `text`, each optionally `disabled` with a reason), `values`, `category`, `open`, `heading`, `show()`, `close()` | OK: `office-options-change` `{ values, changed }` |
79
- | `office-ui-account` | `profile` `{ displayName, avatarColor, initial? }`; slots `sign-in` and default (product sections) | `office-profile-change` `{ profile }` |
80
- | `office-ui-ribbon` | Tab row over tab panels. Panels are children with `data-ribbon-tab`, `data-label`, optional `data-tab-keytip`; slots `quick-access`, `search`, `end`; `selected`, `label`, `file-label`, `no-file`, `file-expanded`, `file-keytip`; `focusFile()`, `focusTab()` | `office-ribbon-select` `{ tab }` (cancelable), `office-ribbon-file` |
81
- | `office-ui-backstage` | `items` `[{ id, label, group?: 'footer', disabled?, title? }]`, `open`, `selected`, `label`, `back-label`, `show(page?)`, `close()`; pages are children with `data-backstage-page` | `office-backstage-select` `{ id }` (cancelable), `office-backstage-close` `{ reason }` (cancelable) |
82
- | `office-ui-find-bar` | `open`, `label`, `input-label`, `placeholder`, `maxlength`, `disabled`, `navigation-disabled`, `previous-label`, `next-label`, `close-label`; `value`, `status`, `statusTitle`, `show()`, `close()` | `office-find-input` `{ query }`, `office-find-step` `{ direction }`, `office-find-close` |
83
- | `office-ui-ruler` | `orientation="vertical"`, `origin` (px offset of zero), `scale` (px per unit, default 96), `direction="reverse"`; decorative | none |
84
- | `office-ui-print-preview` | `pages` (rendered nodes; an inert clone of the current one is shown), `index`, `label`, `empty-label` | `office-print-preview-page` `{ index }` |
85
- | `office-ui-radio` | `checked`, `disabled`, `value`, `name`; radios of one tag sharing a `name` form a roving-focus group; form-associated | `input`, `change` |
86
- | `office-ui-search` | `value`, `placeholder`, `disabled`, `aria-label`, `variant="titlebar"`; `focus()`, `select()` | `input`, `change` |
87
- | `office-ui-ribbon-toggle` | `label`, `checked`, `disabled`, `title`, `command` (a labelled ribbon checkbox row; static `checkboxTag` picks the inner checkbox) | `office-toggle` `{ command, checked }` |
88
- | `office-ui-dialog-footer` | `state` `{ actions: [{ id, label, variant?, icon?, disabled?, busy?, title?, align?, testId? }] }`, `focusAction(id)` | `office-dialog-footer-request` `{ id }` |
89
- | `office-ui-toasts` | `state` `{ toasts: [{ id, code?, severity, message }], overflowCount?, labels? }`; hidden when empty, host positions it | `office-toasts-request` `{ id: 'dismiss', toastId }` or `{ id: 'dismissAll' }` |
90
- | `office-ui-read-only-banner` | `state` `{ kind, message, passwordPromptOpen?, passwordError?, checkingPassword?, labels? }` | `office-read-only-request` (Edit anyway, Dismiss, password submit or cancel) |
91
- | `office-ui-paste-options` | `state` `{ left, top, options: [{ id, label }], label? }`; fixed 4px past the pasted object | `office-paste-options-request` `{ format }`, `office-paste-options-dismiss` |
92
- | `office-ui-title-bar` | `state` `{ appMark?, fileName, status?, tone?, autosave?, quickAccess?: { label, items, showLabels? }, search? }`, `placement` (`titleBar`, `belowRibbon`); slots `collaboration`, `account`; tokens `--office-title-bar-*` | `office-autosave-toggle`, `office-command` `{ command }`, `office-command-search` `{ query, command? }` |
93
- | `office-ui-presence` | `participants`, `max`, `label` | `office-presence-select` `{ id }` |
94
- | `office-ui-smartart` | `drawing` (core `DiagramDrawing`), `schemeColors`, `label` | `office-smartart-render` (render report) |
95
- | `office-ui-icon` | `name`, `label` | none |
63
+ | Tag | Attributes / properties | Events (all bubble, composed) |
64
+ | ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
65
+ | `office-ui-button` | `label`, `icon`, `command`, `disabled`, `pressed`, `expanded`, `icon-only`, `variant="stacked"`, `keyshortcuts` | `office-command` `{ command }` |
66
+ | `office-ui-checkbox`, `office-ui-switch` | `checked`, `disabled`, `value`, `aria-label`; form-associated | `input`, `change` |
67
+ | `office-ui-select` | `<option>` / `<optgroup>` children (`data-display-label`, `data-description`, font previews) or the `options` property `[{ value, label, disabled? }]`; `value`, `selectedIndex`, `disabled`, `aria-label`, `variant="ribbon-font" | "ribbon-icon"`, `data-font-picker`; `icon`and`custom` slots; arrows, Home, End, PageUp/PageDown, typeahead | `input`, `change` |
68
+ | `office-ui-ribbon-group` | `label`, `launcher` (dialog launcher command), `launcher-disabled`; default slot | launcher: `office-command` `{ command }` |
69
+ | `office-ui-ribbon-stack` | `orientation="horizontal"`; default slot (three-row column of small commands by default) | none |
70
+ | `office-ui-menu-button` / `-menu-item` | button: `label`, `icon`, `command` (split button), `variant`, `disabled`, `keyshortcuts`; item: `command`, `label`, `icon`, `disabled`, `checked` | item choice: `office-command` `{ command }` |
71
+ | `office-ui-toolbar` | `aria-label`, `aria-orientation`; arrow-key focus movement | none |
72
+ | `office-ui-dialog` | `open`, `heading`, `dismissible="false"`, `show()`, `close()`; slots default, `footer` | `office-dialog-close` `{ reason }` (cancelable) |
73
+ | `office-ui-status-bar` / `-status-item` | `label`, `value`, `interactive`, `id`; controlled bar: `state` `{ items?, toggles?, views?, zoom? }` with `collaboration` and `end` slots | `office-status-activate` `{ id }` |
74
+ | `office-ui-zoom-slider` | `value` (percent), `min`, `max`, `step`, `disabled`, `fit` (fit button name), `label` | `input`, `change`; fit: `office-command` `{ command: 'zoom-fit' }` |
75
+ | `office-ui-tab-strip` | `tabs` `[{ id, label, title? }]`, `selected`, `label`, `previous-label`, `next-label`, `add-label`, `add-disabled`, `add-title`, `disabled` | `office-tab-select` `{ id }` (cancelable); add: `office-command` `{ command: 'tab-add' }` |
76
+ | `office-ui-context-menu` / `office-ui-menu-separator` | Children mode: `label`, `openAt(x, y)`, `close()`, `open` over `office-ui-menu-item` and separator children. Controlled mode: `state` `{ x, y, label, items: [{ id, label, separatorBefore?, heading?, danger?, disabled?, checked?, icon? }], markers?, zIndex?, autoFocus? }`; arrows, Home, End and type-ahead in both | children: item `office-command` `{ command }`; controlled: `office-menu-request` `{ id }`, `office-menu-close` `{ reason }` (never closes itself) |
77
+ | `office-ui-command-search` | `commands` `[{ id, label, keywords?, description?, disabled?, title? }]`, `placeholder`, `label`, `limit` (Office's "Tell me what you want to do") | choice: `office-command` `{ command }` |
78
+ | `office-ui-options-dialog` | `categories` `[{ id, label, description?, disabled?, sections: [{ id, title, controls }] }]` (controls: `toggle`, `select`, `number`, `text`, each optionally `disabled` with a reason), `values`, `category`, `open`, `heading`, `show()`, `close()` | OK: `office-options-change` `{ values, changed }` |
79
+ | `office-ui-account` | `profile` `{ displayName, avatarColor, initial? }`; slots `sign-in` and default (product sections) | `office-profile-change` `{ profile }` |
80
+ | `office-ui-ribbon` | Tab row over tab panels. Panels are children with `data-ribbon-tab`, `data-label`, optional `data-tab-keytip`; slots `quick-access`, `search`, `end`; `selected`, `label`, `file-label`, `no-file`, `file-expanded`, `file-keytip`; `focusFile()`, `focusTab()` | `office-ribbon-select` `{ tab }` (cancelable), `office-ribbon-file` |
81
+ | `office-ui-backstage` | `items` `[{ id, label, group?: 'footer', disabled?, title? }]`, `open`, `selected`, `label`, `back-label`, `show(page?)`, `close()`; pages are children with `data-backstage-page` | `office-backstage-select` `{ id }` (cancelable), `office-backstage-close` `{ reason }` (cancelable) |
82
+ | `office-ui-find-bar` | `open`, `label`, `input-label`, `placeholder`, `maxlength`, `disabled`, `navigation-disabled`, `previous-label`, `next-label`, `close-label`; `value`, `status`, `statusTitle`, `show()`, `close()` | `office-find-input` `{ query }`, `office-find-step` `{ direction }`, `office-find-close` |
83
+ | `office-ui-ruler` | `orientation="vertical"`, `origin` (px offset of zero), `scale` (px per unit, default 96), `direction="reverse"`; decorative | none |
84
+ | `office-ui-print-preview` | `pages` (rendered nodes; an inert clone of the current one is shown), `index`, `label`, `empty-label` | `office-print-preview-page` `{ index }` |
85
+ | `office-ui-radio` | `checked`, `disabled`, `value`, `name`; radios of one tag sharing a `name` form a roving-focus group; form-associated | `input`, `change` |
86
+ | `office-ui-search` | `value`, `placeholder`, `disabled`, `aria-label`, `variant="titlebar"`; `focus()`, `select()` | `input`, `change` |
87
+ | `office-ui-ribbon-toggle` | `label`, `checked`, `disabled`, `title`, `command` (a labelled ribbon checkbox row; static `checkboxTag` picks the inner checkbox) | `office-toggle` `{ command, checked }` |
88
+ | `office-ui-dialog-footer` | `state` `{ actions: [{ id, label, variant?, icon?, disabled?, busy?, title?, align?, testId? }] }`, `focusAction(id)` | `office-dialog-footer-request` `{ id }` |
89
+ | `office-ui-toasts` | `state` `{ toasts: [{ id, code?, severity, message }], overflowCount?, labels? }`; hidden when empty, host positions it | `office-toasts-request` `{ id: 'dismiss', toastId }` or `{ id: 'dismissAll' }` |
90
+ | `office-ui-read-only-banner` | `state` `{ kind, message, passwordPromptOpen?, passwordError?, checkingPassword?, labels? }` | `office-read-only-request` (Edit anyway, Dismiss, password submit or cancel) |
91
+ | `office-ui-paste-options` | `state` `{ left, top, options: [{ id, label }], label? }`; fixed 4px past the pasted object | `office-paste-options-request` `{ format }`, `office-paste-options-dismiss` |
92
+ | `office-ui-title-bar` | `state` `{ appMark?, fileName, status?, tone?, autosave?, quickAccess?: { label, items, showLabels? }, search? }`, `placement` (`titleBar`, `belowRibbon`); slots `collaboration`, `account`; tokens `--office-title-bar-*` | `office-autosave-toggle`, `office-command` `{ command }`, `office-command-search` `{ query, command? }` |
93
+ | `office-ui-ribbon-section` | `groups` `[{ id, label, commands: [{ id, label, icon, title?, size?, badge?, disabled?, active?, compact?, hidden?, caret?, pressed?, expanded?, column? }] }]`; keyed groups and commands in the light DOM | the commands' own events (`office-command`) |
94
+ | `office-ui-gallery` | `state` `{ id, label, moreLabel?, disabled?, command?, sections: [{ title?, columns, tileWidth, tileHeight, items: [{ id, label, applied?, preview? }] }], inline? }`, `mode` (`inline`), `chevron-only`, `icon`; `open`, `disabled`, `close()`; tiles in light DOM (`data-gallery-item`), previews parsed by `parseSvgPreview` | `office-gallery-pick` `{ gallery, itemId }` |
95
+ | `office-ui-presence` | `participants`, `max`, `label` | `office-presence-select` `{ id }` |
96
+ | `office-ui-smartart` | `drawing` (core `DiagramDrawing`), `schemeColors`, `label` | `office-smartart-render` (render report) |
97
+ | `office-ui-icon` | `name`, `label` | none |
96
98
 
97
99
  The local profile behind `office-ui-account` is stored on the device only, under one suite-wide
98
100
  key (`readOfficeProfile`, `writeOfficeProfile`, `clearOfficeProfile`), so every Office viewer on
@@ -1,5 +1,5 @@
1
- import { definer, attachStyles, controlCss, emit } from './chunk-UYPH4ESZ.js';
2
- import { tok } from './chunk-A3QNC6VS.js';
1
+ import { definer, attachStyles, controlCss, emit } from './chunk-UEJ4F33J.js';
2
+ import { tok } from './chunk-G3LAGZEW.js';
3
3
 
4
4
  // src/presence.ts
5
5
  function participantsFromAwareness(states, selfId) {
@@ -1,5 +1,5 @@
1
- import { definer, attachStyles, controlCss, emit } from './chunk-UYPH4ESZ.js';
2
- import { tok } from './chunk-A3QNC6VS.js';
1
+ import { definer, attachStyles, controlCss, emit } from './chunk-UEJ4F33J.js';
2
+ import { tok } from './chunk-G3LAGZEW.js';
3
3
  import { normalizeHexColor } from 'ooxml-core/color';
4
4
 
5
5
  var SVG_NS = "http://www.w3.org/2000/svg";
@@ -1,4 +1,4 @@
1
- import { OFFICE_TOKENS, TOUCH } from './chunk-A3QNC6VS.js';
1
+ import { OFFICE_TOKENS, TOUCH } from './chunk-G3LAGZEW.js';
2
2
 
3
3
  // src/theme.ts
4
4
  var THEME_STYLE_ID = "office-ui-theme";
@@ -207,6 +207,14 @@ var OFFICE_TOKENS = {
207
207
  "--office-avatar-color": "var(--office-muted-foreground, #6b7280)",
208
208
  "--office-toast-width": "360px",
209
209
  "--office-account-field-width": "320px",
210
+ // Component: galleries
211
+ "--office-gallery-trigger-height": "24px",
212
+ "--office-gallery-strip-background": "color-mix(in srgb, var(--office-surface, #f3f4f6) 30%, transparent)",
213
+ "--office-gallery-command-min-width": "54px",
214
+ "--office-gallery-command-max-width": "78px",
215
+ "--office-gallery-command-height": "58px",
216
+ "--office-gallery-command-icon": "24px",
217
+ "--office-gallery-popup-max-height": "65vh",
210
218
  // Component: title bar
211
219
  "--office-title-bar-height": "36px",
212
220
  "--office-title-bar-below-height": "28px",
@@ -1,4 +1,4 @@
1
- import { TOUCH, tok } from './chunk-A3QNC6VS.js';
1
+ import { TOUCH, tok } from './chunk-G3LAGZEW.js';
2
2
 
3
3
  // src/registry.ts
4
4
  var CONTRACT_REVISION = 1;
@@ -1,4 +1,4 @@
1
- import { definer, attachStyles, controlCss } from './chunk-UYPH4ESZ.js';
1
+ import { definer, attachStyles, controlCss } from './chunk-UEJ4F33J.js';
2
2
 
3
3
  // src/icons.ts
4
4
  var registry = /* @__PURE__ */ new Map();
@@ -1,7 +1,7 @@
1
- import { createIconSvg, paintIcon, defineIcon } from './chunk-GWAPPX66.js';
2
- import { initialsOf } from './chunk-DECL6RNI.js';
3
- import { definer, attachStyles, controlCss, present, emit } from './chunk-UYPH4ESZ.js';
4
- import { tok, FOCUS_RING, COMPACT, OFFICE_TOKENS } from './chunk-A3QNC6VS.js';
1
+ import { createIconSvg, paintIcon, defineIcon } from './chunk-W5PYFBEZ.js';
2
+ import { initialsOf } from './chunk-24MMSCKW.js';
3
+ import { definer, attachStyles, controlCss, present, emit } from './chunk-UEJ4F33J.js';
4
+ import { tok, FOCUS_RING, COMPACT, OFFICE_TOKENS } from './chunk-G3LAGZEW.js';
5
5
 
6
6
  // src/chrome-controls.ts
7
7
  var ICON = `svg { flex: none; width: ${tok("--office-icon-size")}; height: ${tok("--office-icon-size")}; fill: none; stroke: currentColor; stroke-width: ${tok("--office-icon-stroke")};
@@ -1486,8 +1486,519 @@ var defineRibbon = definer("office-ui-ribbon", () => {
1486
1486
  return OfficeUiRibbon;
1487
1487
  });
1488
1488
 
1489
- // src/ruler.ts
1489
+ // src/ribbon-section.ts
1490
1490
  var CSS8 = `
1491
+ :host { display: inline-flex; align-items: stretch; }
1492
+ ::slotted(*) { flex: none; }
1493
+ `;
1494
+ var COLUMN_STYLE = { display: "flex", flexDirection: "column", gap: tok("--office-space-0") };
1495
+ function setOptional(el, name, value) {
1496
+ if (value === void 0) el.removeAttribute(name);
1497
+ else el.setAttribute(name, String(value));
1498
+ }
1499
+ function syncCommand(el, command, idAttribute) {
1500
+ el.setAttribute(idAttribute, command.id);
1501
+ el.setAttribute("label", command.label);
1502
+ el.setAttribute("title", command.title ?? command.label);
1503
+ el.setAttribute("icon", command.icon);
1504
+ if (command.badge) el.setAttribute("badge", String(command.badge));
1505
+ else el.removeAttribute("badge");
1506
+ if (command.size) el.setAttribute("size", command.size);
1507
+ for (const name of ["disabled", "active", "compact", "hidden", "caret"])
1508
+ el.toggleAttribute(name, command[name] === true);
1509
+ setOptional(el, "pressed", command.pressed);
1510
+ setOptional(el, "expanded", command.expanded);
1511
+ }
1512
+ var defineRibbonSection = definer("office-ui-ribbon-section", () => {
1513
+ class OfficeUiRibbonSection extends HTMLElement {
1514
+ static groupTag = "office-ui-ribbon-group";
1515
+ static commandTag = "office-ui-button";
1516
+ static groupIdAttribute = "data-ribbon-group";
1517
+ static commandIdAttribute = "command";
1518
+ #groups = [];
1519
+ #groupNodes = /* @__PURE__ */ new Map();
1520
+ #commandNodes = /* @__PURE__ */ new Map();
1521
+ constructor() {
1522
+ super();
1523
+ const root = this.attachShadow({ mode: "open" });
1524
+ attachStyles(root, controlCss(CSS8));
1525
+ root.append(this.ownerDocument.createElement("slot"));
1526
+ }
1527
+ get groups() {
1528
+ return this.#groups;
1529
+ }
1530
+ set groups(value) {
1531
+ this.#groups = value ?? [];
1532
+ this.#render();
1533
+ }
1534
+ connectedCallback() {
1535
+ this.#render();
1536
+ }
1537
+ #render() {
1538
+ const statics = this.constructor;
1539
+ const doc = this.ownerDocument;
1540
+ const model = this.#groups;
1541
+ const wantedGroups = new Set(model.map((group) => group.id));
1542
+ const wantedCommands = new Set(model.flatMap((g) => g.commands.map((c) => c.id)));
1543
+ for (const [id, el] of this.#commandNodes)
1544
+ if (!wantedCommands.has(id)) {
1545
+ el.remove();
1546
+ this.#commandNodes.delete(id);
1547
+ }
1548
+ for (const [id, group] of this.#groupNodes)
1549
+ if (!wantedGroups.has(id)) {
1550
+ group.el.remove();
1551
+ this.#groupNodes.delete(id);
1552
+ }
1553
+ for (const [index, group] of model.entries()) {
1554
+ let node = this.#groupNodes.get(group.id);
1555
+ if (!node) {
1556
+ node = { el: doc.createElement(statics.groupTag), columns: /* @__PURE__ */ new Map() };
1557
+ this.#groupNodes.set(group.id, node);
1558
+ }
1559
+ node.el.setAttribute(statics.groupIdAttribute, group.id);
1560
+ node.el.setAttribute("label", group.label);
1561
+ if (this.children[index] !== node.el)
1562
+ this.insertBefore(node.el, this.children[index] ?? null);
1563
+ const offsets = /* @__PURE__ */ new Map();
1564
+ for (const command of group.commands) {
1565
+ let parent = node.el;
1566
+ if (command.column !== void 0) {
1567
+ let column = node.columns.get(command.column);
1568
+ if (!column) {
1569
+ column = doc.createElement("div");
1570
+ Object.assign(column.style, COLUMN_STYLE);
1571
+ node.columns.set(command.column, column);
1572
+ node.el.append(column);
1573
+ }
1574
+ parent = column;
1575
+ }
1576
+ let el = this.#commandNodes.get(command.id);
1577
+ if (!el) {
1578
+ el = doc.createElement(statics.commandTag);
1579
+ this.#commandNodes.set(command.id, el);
1580
+ }
1581
+ syncCommand(el, command, statics.commandIdAttribute);
1582
+ const offset = offsets.get(parent) ?? 0;
1583
+ if (parent.children[offset] !== el)
1584
+ parent.insertBefore(el, parent.children[offset] ?? null);
1585
+ offsets.set(parent, offset + 1);
1586
+ }
1587
+ }
1588
+ }
1589
+ }
1590
+ return OfficeUiRibbonSection;
1591
+ });
1592
+
1593
+ // src/gallery-styles.ts
1594
+ var H = "[data-office-gallery]";
1595
+ var GALLERY_LIGHT_CSS = `
1596
+ ${H} { display: inline-flex; position: relative; flex: none; color: ${tok("--office-foreground")}; }
1597
+ ${H} .gallery-view { display: contents; }
1598
+ ${H} button { box-sizing: border-box; font: inherit; color: inherit; cursor: pointer;
1599
+ border: ${tok("--office-border-width")} solid ${tok("--office-border")}; border-radius: ${tok("--office-radius")}; background: ${tok("--office-background")}; }
1600
+ ${H} button:hover:not(:disabled) { background: ${tok("--office-selected")}; }
1601
+ ${H} button:disabled { opacity: .4; cursor: not-allowed; }
1602
+ ${H} button:focus-visible { outline: ${tok("--office-focus-width")} solid ${tok("--office-ring")}; outline-offset: ${tok("--office-focus-offset")}; }
1603
+ ${H} .trigger { display: inline-flex; align-items: center; gap: ${tok("--office-space-1-5")}; min-height: ${tok("--office-gallery-trigger-height")};
1604
+ padding: 0 ${tok("--office-space-1-5")}; font-size: ${tok("--office-font-size-sm")}; white-space: nowrap; }
1605
+ ${H}:not([mode=inline]) .trigger { border-color: transparent; background: transparent; }
1606
+ ${H} .trigger svg { width: ${tok("--office-icon-size-md")}; height: ${tok("--office-icon-size-md")}; fill: none; stroke: currentColor;
1607
+ stroke-width: ${tok("--office-icon-stroke")}; stroke-linecap: round; stroke-linejoin: round; }
1608
+ ${H}[mode=inline] .trigger, ${H}[chevron-only] .trigger { align-self: stretch; padding: 0 ${tok("--office-space-1")}; }
1609
+ ${H} .strip { display: flex; gap: ${tok("--office-space-0")}; padding: ${tok("--office-space-0")}; align-items: center; }
1610
+ ${H} .tile { display: inline-flex; align-items: center; justify-content: center; flex: none; padding: ${tok("--office-space-0")}; }
1611
+ ${H} .tile[aria-pressed=true] { border: ${tok("--office-border-width-thick")} solid ${tok("--office-accent")};
1612
+ background: color-mix(in srgb, ${tok("--office-accent")} 15%, ${tok("--office-background")}); }
1613
+ ${H} .tile svg { max-width: 100%; max-height: 100%; }
1614
+ ${H}[mode=inline] .strip { gap: 0; border: ${tok("--office-border-width")} solid ${tok("--office-border")}; border-inline-end: 0;
1615
+ border-radius: ${tok("--office-radius-sm")} 0 0 ${tok("--office-radius-sm")}; background: ${tok("--office-gallery-strip-background")}; }
1616
+ ${H}[mode=inline] .trigger { border-radius: 0 ${tok("--office-radius-sm")} ${tok("--office-radius-sm")} 0; background: ${tok("--office-gallery-strip-background")}; }
1617
+ ${H} .trigger.command { border-color: transparent; background: transparent; justify-content: flex-start; }
1618
+ ${H} .trigger.command:hover:not(:disabled) { border-color: ${tok("--office-border")}; background: ${tok("--office-selected")}; }
1619
+ ${H} .trigger.command svg { color: ${tok("--office-command-icon-color")}; }
1620
+ ${H} .trigger.command-large { flex-direction: column; align-items: center; justify-content: flex-start; gap: ${tok("--office-space-0")};
1621
+ min-width: ${tok("--office-gallery-command-min-width")}; max-width: ${tok("--office-gallery-command-max-width")}; height: ${tok("--office-gallery-command-height")};
1622
+ padding: ${tok("--office-space-1")}; font-size: ${tok("--office-font-size-2xs")}; line-height: ${tok("--office-line-height-tight")}; white-space: normal; text-align: center; }
1623
+ ${H} .trigger.command-large svg { width: ${tok("--office-gallery-command-icon")}; height: ${tok("--office-gallery-command-icon")}; }
1624
+ ${H} .popup { box-sizing: border-box; position: fixed; z-index: ${tok("--office-z-popover")}; max-width: calc(100vw - ${tok("--office-space-4")});
1625
+ max-height: ${tok("--office-gallery-popup-max-height")}; overflow: auto; padding: ${tok("--office-space-2")};
1626
+ border: ${tok("--office-border-width")} solid ${tok("--office-border")}; border-radius: ${tok("--office-radius-md")};
1627
+ background: ${tok("--office-popover")}; color: ${tok("--office-popover-foreground")}; box-shadow: ${tok("--office-shadow-lg")}; }
1628
+ ${H} .popup[hidden] { display: none; }
1629
+ ${H} .grid { display: grid; gap: ${tok("--office-space-1")}; width: max-content; max-width: 100%; }
1630
+ ${H} .heading { margin: ${tok("--office-space-1")} 0 ${tok("--office-space-1-5")}; font-size: ${tok("--office-font-size-xs")}; font-weight: ${tok("--office-font-weight-bold")}; }
1631
+ ${H} .section + .section { margin-top: ${tok("--office-space-2-5")}; }
1632
+ @media (pointer: coarse), (max-width: 1023px) {
1633
+ ${H} .trigger, ${H} .tile { min-height: ${tok("--office-target-size-touch")}; min-width: ${tok("--office-target-size-touch")}; }
1634
+ }
1635
+ @media (forced-colors: active) {
1636
+ ${H} button, ${H} .popup { color: ButtonText; background: Canvas; border-color: ButtonText; }
1637
+ ${H} button:disabled { color: GrayText; opacity: 1; }
1638
+ ${H} button:focus-visible, ${H} .tile[aria-pressed=true] { outline: ${tok("--office-focus-width")} solid Highlight; border-color: Highlight; }
1639
+ }
1640
+ `;
1641
+ var injected = /* @__PURE__ */ new WeakSet();
1642
+ function attachGalleryStyles(host) {
1643
+ const root = host.getRootNode();
1644
+ if (injected.has(root)) return;
1645
+ const doc = host.ownerDocument;
1646
+ const Sheet = doc.defaultView?.CSSStyleSheet;
1647
+ if (Sheet && "adoptedStyleSheets" in root && "replaceSync" in Sheet.prototype) {
1648
+ try {
1649
+ const sheet = new Sheet();
1650
+ sheet.replaceSync(GALLERY_LIGHT_CSS);
1651
+ root.adoptedStyleSheets = [...root.adoptedStyleSheets, sheet];
1652
+ injected.add(root);
1653
+ return;
1654
+ } catch {
1655
+ }
1656
+ }
1657
+ const style = doc.createElement("style");
1658
+ style.dataset.officeGalleryStyles = "";
1659
+ style.textContent = GALLERY_LIGHT_CSS;
1660
+ (root.nodeType === 9 ? doc.head : root).append(style);
1661
+ injected.add(root);
1662
+ }
1663
+
1664
+ // src/safe-svg.ts
1665
+ var BLOCKED_ELEMENTS = /* @__PURE__ */ new Set(["script", "foreignobject", "iframe", "object", "embed"]);
1666
+ function parseSvgPreview(doc, svg) {
1667
+ const Parser = doc.defaultView?.DOMParser ?? globalThis.DOMParser;
1668
+ if (typeof Parser !== "function") return null;
1669
+ const parsed = new Parser().parseFromString(svg, "image/svg+xml");
1670
+ const root = parsed.documentElement;
1671
+ if (root.localName !== "svg" || parsed.getElementsByTagName("parsererror").length > 0)
1672
+ return null;
1673
+ for (const node of Array.from(root.querySelectorAll("*"))) {
1674
+ if (BLOCKED_ELEMENTS.has(node.localName.toLowerCase())) {
1675
+ node.remove();
1676
+ continue;
1677
+ }
1678
+ for (const attribute of Array.from(node.attributes))
1679
+ if (/^on/iu.test(attribute.name) || /^\s*javascript:/iu.test(attribute.value))
1680
+ node.removeAttribute(attribute.name);
1681
+ }
1682
+ for (const attribute of Array.from(root.attributes))
1683
+ if (/^on/iu.test(attribute.name) || /^\s*javascript:/iu.test(attribute.value))
1684
+ root.removeAttribute(attribute.name);
1685
+ return doc.importNode(root, true);
1686
+ }
1687
+
1688
+ // src/gallery-view.ts
1689
+ function createGalleryView(doc, hooks, pick, toggle) {
1690
+ const root = doc.createElement("span");
1691
+ root.className = "gallery-view";
1692
+ const strip = doc.createElement("div");
1693
+ strip.className = "strip";
1694
+ const trigger = doc.createElement("button");
1695
+ trigger.type = "button";
1696
+ trigger.className = "trigger";
1697
+ if (hooks.compactAttribute) trigger.setAttribute(hooks.compactAttribute, "");
1698
+ trigger.setAttribute("aria-haspopup", "dialog");
1699
+ trigger.addEventListener("click", toggle);
1700
+ const popup = doc.createElement("div");
1701
+ popup.className = "popup";
1702
+ popup.hidden = true;
1703
+ popup.setAttribute("role", "dialog");
1704
+ root.append(strip, trigger);
1705
+ const tile = (item, w, h, disabled) => {
1706
+ const button = doc.createElement("button");
1707
+ button.type = "button";
1708
+ button.className = "tile";
1709
+ if (hooks.compactAttribute) button.setAttribute(hooks.compactAttribute, "");
1710
+ button.setAttribute(hooks.itemAttribute, item.id);
1711
+ button.disabled = disabled;
1712
+ button.setAttribute("aria-pressed", String(item.applied === true));
1713
+ button.setAttribute("aria-label", item.label);
1714
+ button.title = item.label;
1715
+ button.style.width = `${w + 6}px`;
1716
+ button.style.height = `${h + 6}px`;
1717
+ const preview = item.preview ? parseSvgPreview(doc, item.preview) : null;
1718
+ if (preview) button.append(preview);
1719
+ button.addEventListener("click", () => pick(item.id));
1720
+ return button;
1721
+ };
1722
+ const label = (text2) => {
1723
+ const span = doc.createElement("span");
1724
+ span.textContent = text2;
1725
+ return span;
1726
+ };
1727
+ return {
1728
+ root,
1729
+ trigger,
1730
+ popup,
1731
+ clear() {
1732
+ strip.replaceChildren();
1733
+ popup.replaceChildren();
1734
+ trigger.removeAttribute(hooks.triggerAttribute);
1735
+ trigger.removeAttribute("aria-label");
1736
+ trigger.textContent = "";
1737
+ },
1738
+ setOpen(open) {
1739
+ popup.hidden = !open;
1740
+ if (open) root.append(popup);
1741
+ else popup.remove();
1742
+ },
1743
+ paint({ state, disabled, inline, chevronOnly, open, icon: icon2 }) {
1744
+ const title = state.label;
1745
+ trigger.setAttribute(hooks.triggerAttribute, state.id);
1746
+ popup.setAttribute(hooks.popupAttribute, state.id);
1747
+ trigger.title = inline ? state.moreLabel ?? `More ${title}` : title;
1748
+ trigger.setAttribute("aria-label", trigger.title);
1749
+ trigger.disabled = disabled;
1750
+ trigger.replaceChildren();
1751
+ const command = state.command;
1752
+ trigger.classList.toggle("command", Boolean(command));
1753
+ trigger.classList.toggle("command-large", Boolean(command?.large));
1754
+ if (command) {
1755
+ trigger.removeAttribute("aria-haspopup");
1756
+ trigger.removeAttribute("aria-expanded");
1757
+ trigger.title = command.hint ?? title;
1758
+ trigger.setAttribute("aria-label", title);
1759
+ trigger.append(icon2 ?? createIconSvg(doc), label(title));
1760
+ } else {
1761
+ trigger.setAttribute("aria-haspopup", "dialog");
1762
+ if (!inline && !chevronOnly) trigger.append(icon2 ?? createIconSvg(doc), label(title));
1763
+ const chevron = doc.createElement("span");
1764
+ chevron.textContent = "\u2304";
1765
+ chevron.setAttribute("aria-hidden", "true");
1766
+ trigger.append(chevron);
1767
+ }
1768
+ strip.hidden = !inline;
1769
+ strip.style.display = inline ? "" : "none";
1770
+ const first = state.sections[0];
1771
+ const inlineItems = state.inline ?? first?.items ?? [];
1772
+ strip.replaceChildren(
1773
+ ...inline ? inlineItems.map(
1774
+ (item) => tile(item, first?.tileWidth ?? 40, first?.tileHeight ?? 30, disabled)
1775
+ ) : []
1776
+ );
1777
+ popup.setAttribute("aria-label", title);
1778
+ popup.replaceChildren(
1779
+ ...(open ? state.sections : []).map((section) => {
1780
+ const container = doc.createElement("section");
1781
+ container.className = "section";
1782
+ if (section.title) {
1783
+ const heading = doc.createElement("div");
1784
+ heading.className = "heading";
1785
+ heading.textContent = section.title;
1786
+ container.append(heading);
1787
+ }
1788
+ const grid = doc.createElement("div");
1789
+ grid.className = "grid";
1790
+ grid.style.gridTemplateColumns = `repeat(${section.columns}, minmax(0, 1fr))`;
1791
+ grid.append(
1792
+ ...section.items.map(
1793
+ (item) => tile(item, section.tileWidth, section.tileHeight, disabled)
1794
+ )
1795
+ );
1796
+ container.append(grid);
1797
+ return container;
1798
+ })
1799
+ );
1800
+ }
1801
+ };
1802
+ }
1803
+
1804
+ // src/gallery.ts
1805
+ var HOST_CSS = `
1806
+ :host { display: inline-flex; position: relative; flex: none; }
1807
+ `;
1808
+ var defineGallery = definer("office-ui-gallery", () => {
1809
+ class OfficeUiGallery extends HTMLElement {
1810
+ static pickEvent = "office-gallery-pick";
1811
+ static triggerAttribute = "data-gallery";
1812
+ static popupAttribute = "data-gallery-popup";
1813
+ static itemAttribute = "data-gallery-item";
1814
+ static compactAttribute = null;
1815
+ static observedAttributes = ["mode", "chevron-only", "icon"];
1816
+ #state;
1817
+ #locked = false;
1818
+ #opened = false;
1819
+ #view;
1820
+ constructor() {
1821
+ super();
1822
+ const root = this.attachShadow({ mode: "open" });
1823
+ attachStyles(root, controlCss(HOST_CSS));
1824
+ root.append(this.ownerDocument.createElement("slot"));
1825
+ const statics = this.constructor;
1826
+ this.#view = createGalleryView(
1827
+ this.ownerDocument,
1828
+ statics,
1829
+ (itemId) => this.#pick(itemId),
1830
+ () => {
1831
+ if (this.#state?.command) {
1832
+ this.#pick(this.#state.sections[0]?.items[0]?.id ?? "");
1833
+ return;
1834
+ }
1835
+ this.open = !this.open;
1836
+ }
1837
+ );
1838
+ this.#view.root.addEventListener("keydown", (event) => {
1839
+ if (event.key === "Escape" && this.open) {
1840
+ event.stopPropagation();
1841
+ event.preventDefault();
1842
+ this.close();
1843
+ this.#view.trigger.focus();
1844
+ }
1845
+ if (event.key === "ArrowDown" && event.target === this.#view.trigger) {
1846
+ event.stopPropagation();
1847
+ event.preventDefault();
1848
+ this.open = true;
1849
+ this.#view.popup.querySelector("button:not(:disabled)")?.focus();
1850
+ }
1851
+ if (event.key === "Enter" || event.key === " ") event.stopPropagation();
1852
+ });
1853
+ }
1854
+ get state() {
1855
+ return this.#state;
1856
+ }
1857
+ set state(value) {
1858
+ this.#state = value ?? void 0;
1859
+ this.#paint();
1860
+ }
1861
+ get trigger() {
1862
+ return this.#view.trigger;
1863
+ }
1864
+ get popup() {
1865
+ return this.#view.popup;
1866
+ }
1867
+ get disabled() {
1868
+ return this.#locked;
1869
+ }
1870
+ set disabled(value) {
1871
+ this.#locked = present(value);
1872
+ this.#paint();
1873
+ }
1874
+ get open() {
1875
+ return this.#opened;
1876
+ }
1877
+ set open(value) {
1878
+ const next = present(value) && !this.#unavailable();
1879
+ if (next === this.#opened) return;
1880
+ this.#opened = next;
1881
+ this.#view.setOpen(next);
1882
+ this.#paint();
1883
+ this.#view.trigger.setAttribute("aria-expanded", String(next));
1884
+ this.#cleanup();
1885
+ if (next && this.isConnected) {
1886
+ const doc = this.ownerDocument;
1887
+ doc.addEventListener("pointerdown", this.#outside, true);
1888
+ doc.addEventListener("keydown", this.#escape);
1889
+ doc.defaultView?.addEventListener("resize", this.#position);
1890
+ doc.addEventListener("scroll", this.#position, true);
1891
+ this.#position();
1892
+ }
1893
+ }
1894
+ close() {
1895
+ this.open = false;
1896
+ }
1897
+ /** The trigger glyph: `command.icon` for a command, else the `icon` attribute. */
1898
+ triggerIcon() {
1899
+ const name = this.#state?.command?.icon ?? this.getAttribute("icon");
1900
+ if (!name) return null;
1901
+ const svg = createIconSvg(this.ownerDocument);
1902
+ return paintIcon(svg, name) ? svg : null;
1903
+ }
1904
+ connectedCallback() {
1905
+ this.setAttribute("data-office-gallery", "");
1906
+ attachGalleryStyles(this);
1907
+ this.append(this.#view.root);
1908
+ this.#paint();
1909
+ }
1910
+ disconnectedCallback() {
1911
+ this.close();
1912
+ this.#cleanup();
1913
+ }
1914
+ attributeChangedCallback() {
1915
+ this.#paint();
1916
+ }
1917
+ #unavailable() {
1918
+ const state = this.#state;
1919
+ return this.#locked || !state || state.disabled === true || !state.sections.some((section) => section.items.length > 0);
1920
+ }
1921
+ #paint() {
1922
+ const state = this.#state;
1923
+ if (!state) {
1924
+ this.close();
1925
+ this.#view.clear();
1926
+ this.#view.trigger.disabled = true;
1927
+ return;
1928
+ }
1929
+ const doc = this.ownerDocument;
1930
+ const hadFocus = this.contains(doc.activeElement);
1931
+ if (this.isConnected && this.#view.root.parentElement !== this) this.append(this.#view.root);
1932
+ const itemAttribute = this.constructor.itemAttribute;
1933
+ const focusedId = doc.activeElement?.getAttribute(itemAttribute);
1934
+ const focusInPopup = this.#view.popup.contains(doc.activeElement);
1935
+ const chevronOnly = this.hasAttribute("chevron-only");
1936
+ this.#view.paint({
1937
+ state,
1938
+ disabled: this.#unavailable(),
1939
+ inline: this.getAttribute("mode") === "inline" && !chevronOnly,
1940
+ chevronOnly,
1941
+ open: this.#opened,
1942
+ icon: this.triggerIcon()
1943
+ });
1944
+ if (state.command) this.#view.trigger.removeAttribute("aria-expanded");
1945
+ else this.#view.trigger.setAttribute("aria-expanded", String(this.#opened));
1946
+ if (this.isConnected) {
1947
+ this.toggleAttribute("data-command", Boolean(state.command));
1948
+ this.toggleAttribute("data-command-large", Boolean(state.command?.large));
1949
+ }
1950
+ if (this.#unavailable()) this.close();
1951
+ if (this.#opened) this.#position();
1952
+ if (focusedId && hadFocus)
1953
+ [
1954
+ ...(focusInPopup ? this.#view.popup : this).querySelectorAll(
1955
+ `[${itemAttribute}]`
1956
+ )
1957
+ ].find((node) => node.getAttribute(itemAttribute) === focusedId)?.focus();
1958
+ }
1959
+ #pick(itemId) {
1960
+ const state = this.#state;
1961
+ if (this.#unavailable() || !state?.sections.some((section) => section.items.some((item) => item.id === itemId)))
1962
+ return;
1963
+ this.close();
1964
+ this.#view.trigger.focus();
1965
+ emit(this, this.constructor.pickEvent, {
1966
+ gallery: state.id,
1967
+ itemId
1968
+ });
1969
+ }
1970
+ #outside = (event) => {
1971
+ if (!event.composedPath().includes(this)) this.close();
1972
+ };
1973
+ #escape = (event) => {
1974
+ if (event.key === "Escape") {
1975
+ event.stopPropagation();
1976
+ this.close();
1977
+ this.#view.trigger.focus();
1978
+ }
1979
+ };
1980
+ #position = () => {
1981
+ const window = this.ownerDocument.defaultView;
1982
+ if (!window) return;
1983
+ const popup = this.#view.popup;
1984
+ const anchor = this.#view.trigger.getBoundingClientRect();
1985
+ const box = popup.getBoundingClientRect();
1986
+ popup.style.left = `${Math.max(8, Math.min(anchor.left, window.innerWidth - box.width - 8))}px`;
1987
+ popup.style.top = `${Math.max(8, Math.min(anchor.bottom + 4, window.innerHeight - box.height - 8))}px`;
1988
+ };
1989
+ #cleanup() {
1990
+ const doc = this.ownerDocument;
1991
+ doc.removeEventListener("pointerdown", this.#outside, true);
1992
+ doc.removeEventListener("keydown", this.#escape);
1993
+ doc.defaultView?.removeEventListener("resize", this.#position);
1994
+ doc.removeEventListener("scroll", this.#position, true);
1995
+ }
1996
+ }
1997
+ return OfficeUiGallery;
1998
+ });
1999
+
2000
+ // src/ruler.ts
2001
+ var CSS9 = `
1491
2002
  :host { display: block; box-sizing: border-box; background: ${tok("--office-background")};
1492
2003
  color: ${tok("--office-muted-foreground")}; overflow: hidden;
1493
2004
  font-size: ${tok("--office-font-size-3xs")}; font-family: ${tok("--office-font")}; }
@@ -1507,7 +2018,7 @@ var defineRuler = definer("office-ui-ruler", () => {
1507
2018
  constructor() {
1508
2019
  super();
1509
2020
  const root = this.attachShadow({ mode: "open" });
1510
- attachStyles(root, controlCss(CSS8));
2021
+ attachStyles(root, controlCss(CSS9));
1511
2022
  this.#canvas = this.ownerDocument.createElement("canvas");
1512
2023
  root.append(this.#canvas);
1513
2024
  }
@@ -1644,7 +2155,7 @@ function clearOfficeProfile(storage = defaultStorage(), key = OFFICE_PROFILE_STO
1644
2155
  } catch {
1645
2156
  }
1646
2157
  }
1647
- var CSS9 = `
2158
+ var CSS10 = `
1648
2159
  :host { display: block; font-family: ${tok("--office-font")}; font-size: ${tok("--office-font-size")}; }
1649
2160
  h2 { margin: 0 0 ${tok("--office-space-3")}; font-size: ${tok("--office-font-size-lg")}; font-weight: 600; }
1650
2161
  .who { display: flex; align-items: center; gap: ${tok("--office-space-3")}; margin-bottom: ${tok("--office-space-3")}; }
@@ -1674,7 +2185,7 @@ var defineAccount = definer("office-ui-account", () => {
1674
2185
  super();
1675
2186
  const doc = this.ownerDocument;
1676
2187
  const root = this.attachShadow({ mode: "open" });
1677
- attachStyles(root, controlCss(CSS9));
2188
+ attachStyles(root, controlCss(CSS10));
1678
2189
  const heading = doc.createElement("h2");
1679
2190
  heading.textContent = "User Information";
1680
2191
  const who = doc.createElement("div");
@@ -1775,7 +2286,7 @@ var defineAccount = definer("office-ui-account", () => {
1775
2286
  });
1776
2287
 
1777
2288
  // src/button.ts
1778
- var CSS10 = `
2289
+ var CSS11 = `
1779
2290
  :host { display: inline-flex; vertical-align: middle; }
1780
2291
  button { box-sizing: border-box; position: relative; display: inline-flex; align-items: center; justify-content: center;
1781
2292
  gap: ${tok("--office-space-1-5")}; min-width: ${tok("--office-target-size")}; min-height: ${tok("--office-target-size")};
@@ -1854,7 +2365,7 @@ var defineButton = definer("office-ui-button", () => {
1854
2365
  super();
1855
2366
  const doc = this.ownerDocument;
1856
2367
  const root = this.attachShadow({ mode: "open", delegatesFocus: true });
1857
- attachStyles(root, controlCss(CSS10));
2368
+ attachStyles(root, controlCss(CSS11));
1858
2369
  this.button = doc.createElement("button");
1859
2370
  this.button.type = "button";
1860
2371
  this.button.setAttribute("part", "button");
@@ -2083,7 +2594,7 @@ var defineCheckbox = definer(
2083
2594
  var defineSwitch = definer("office-ui-switch", makeCheckable("switch", SWITCH_CSS));
2084
2595
 
2085
2596
  // src/dialog.ts
2086
- var CSS11 = `
2597
+ var CSS12 = `
2087
2598
  :host { display: none; position: fixed; inset: 0; z-index: 1000; align-items: center; justify-content: center; }
2088
2599
  :host([open]) { display: flex; }
2089
2600
  .backdrop { position: absolute; inset: 0; background: ${tok("--office-overlay")}; }
@@ -2116,7 +2627,7 @@ var defineDialog = definer("office-ui-dialog", () => {
2116
2627
  super();
2117
2628
  const doc = this.ownerDocument;
2118
2629
  const root = this.attachShadow({ mode: "open" });
2119
- attachStyles(root, controlCss(CSS11));
2630
+ attachStyles(root, controlCss(CSS12));
2120
2631
  const backdrop = doc.createElement("div");
2121
2632
  backdrop.className = "backdrop";
2122
2633
  this.box = doc.createElement("div");
@@ -2219,7 +2730,7 @@ var defineDialog = definer("office-ui-dialog", () => {
2219
2730
  });
2220
2731
 
2221
2732
  // src/command-search.ts
2222
- var CSS12 = `
2733
+ var CSS13 = `
2223
2734
  :host { display: inline-flex; align-items: center; min-width: 0; font-family: ${tok("--office-font")}; }
2224
2735
  .field { display: flex; align-items: center; gap: ${tok("--office-space-1-5")}; width: 100%; min-width: 0; height: ${tok("--office-target-size")};
2225
2736
  padding: 0 ${tok("--office-space-2")}; box-sizing: border-box; border: ${tok("--office-border-width")} solid transparent; border-radius: ${tok("--office-radius")};
@@ -2259,7 +2770,7 @@ var defineCommandSearch = definer("office-ui-command-search", () => {
2259
2770
  super();
2260
2771
  const doc = this.ownerDocument;
2261
2772
  const root = this.attachShadow({ mode: "open", delegatesFocus: true });
2262
- attachStyles(root, controlCss(CSS12));
2773
+ attachStyles(root, controlCss(CSS13));
2263
2774
  const field = doc.createElement("div");
2264
2775
  field.className = "field";
2265
2776
  const glass = createIconSvg(doc);
@@ -2448,7 +2959,7 @@ function clampFlyoutPosition(input) {
2448
2959
  }
2449
2960
 
2450
2961
  // src/context-menu.ts
2451
- var CSS13 = `
2962
+ var CSS14 = `
2452
2963
  :host { display: contents; }
2453
2964
  :host([data-controlled]) { display: block; position: fixed; z-index: ${tok("--office-z-popover")};
2454
2965
  color: ${tok("--office-popover-foreground")}; font: ${tok("--office-font-size-sm")}/${tok("--office-line-height")} ${tok("--office-font")}; }
@@ -2531,7 +3042,7 @@ var defineContextMenu = definer("office-ui-context-menu", () => {
2531
3042
  super();
2532
3043
  const doc = this.ownerDocument;
2533
3044
  const root = this.attachShadow({ mode: "open" });
2534
- attachStyles(root, controlCss(CSS13));
3045
+ attachStyles(root, controlCss(CSS14));
2535
3046
  this.panel = doc.createElement("div");
2536
3047
  this.panel.className = "panel";
2537
3048
  this.panel.setAttribute("role", "menu");
@@ -3182,7 +3693,7 @@ function clampOptionNumber(raw, min, max) {
3182
3693
  const parsed = Number(raw);
3183
3694
  return Number.isFinite(parsed) && raw.trim() !== "" ? Math.min(max, Math.max(min, parsed)) : void 0;
3184
3695
  }
3185
- var CSS14 = `
3696
+ var CSS15 = `
3186
3697
  :host { display: contents; }
3187
3698
  office-ui-dialog { --office-dialog-width: ${tok("--office-options-width")}; --office-dialog-max-width: ${tok("--office-options-width")}; }
3188
3699
  .layout { display: grid; grid-template-columns: ${tok("--office-options-nav-width")} minmax(0, 1fr); gap: 0; min-height: ${tok("--office-options-min-height")}; margin: calc(-1 * ${tok("--office-space-4")}); }
@@ -3231,7 +3742,7 @@ var defineOptionsDialog = definer("office-ui-options-dialog", () => {
3231
3742
  super();
3232
3743
  const doc = this.ownerDocument;
3233
3744
  const root = this.attachShadow({ mode: "open" });
3234
- attachStyles(root, controlCss(CSS14));
3745
+ attachStyles(root, controlCss(CSS15));
3235
3746
  this.#dialog = doc.createElement("office-ui-dialog");
3236
3747
  const layout = doc.createElement("div");
3237
3748
  layout.className = "layout";
@@ -4488,7 +4999,7 @@ var defineStatusItem = definer("office-ui-status-item", () => {
4488
4999
  });
4489
5000
 
4490
5001
  // src/tab-strip.ts
4491
- var CSS15 = `
5002
+ var CSS16 = `
4492
5003
  :host { display: flex; align-items: stretch; min-width: 0; min-height: ${tok("--office-tab-height")}; gap: ${tok("--office-space-0")}; padding: 0 ${tok("--office-space-1-5")};
4493
5004
  background: ${tok("--office-surface")}; color: ${tok("--office-muted-foreground")};
4494
5005
  border-top: ${tok("--office-border-width")} solid ${tok("--office-border")}; font-size: ${tok("--office-font-size-sm")};
@@ -4535,7 +5046,7 @@ var defineTabStrip = definer("office-ui-tab-strip", () => {
4535
5046
  super();
4536
5047
  const doc = this.ownerDocument;
4537
5048
  const root = this.attachShadow({ mode: "open" });
4538
- attachStyles(root, controlCss(CSS15));
5049
+ attachStyles(root, controlCss(CSS16));
4539
5050
  const step = (name, icon2) => {
4540
5051
  const button = doc.createElement("button");
4541
5052
  button.type = "button";
@@ -4900,7 +5411,7 @@ function createTitleBarSearch(doc, fieldTag, request) {
4900
5411
  }
4901
5412
 
4902
5413
  // src/title-bar.ts
4903
- var CSS16 = `
5414
+ var CSS17 = `
4904
5415
  :host { display: block; flex: none; }
4905
5416
  :host([data-empty]) { display: none !important; }
4906
5417
  [hidden] { display: none !important; }
@@ -5002,7 +5513,7 @@ var defineTitleBar = definer("office-ui-title-bar", () => {
5002
5513
  const doc = this.ownerDocument;
5003
5514
  const statics = this.constructor;
5004
5515
  const root = this.attachShadow({ mode: "open" });
5005
- attachStyles(root, controlCss(CSS16));
5516
+ attachStyles(root, controlCss(CSS17));
5006
5517
  const el = (tag, className) => {
5007
5518
  const node = doc.createElement(tag);
5008
5519
  node.className = className;
@@ -5137,7 +5648,7 @@ var defineTitleBar = definer("office-ui-title-bar", () => {
5137
5648
  });
5138
5649
 
5139
5650
  // src/zoom-slider.ts
5140
- var CSS17 = `
5651
+ var CSS18 = `
5141
5652
  :host { display: inline-flex; align-items: center; gap: ${tok("--office-space-0")}; font-size: ${tok("--office-font-size-xs")};
5142
5653
  color: ${tok("--office-foreground")}; font-family: ${tok("--office-font")}; }
5143
5654
  button { box-sizing: border-box; display: inline-grid; place-items: center; min-width: ${tok("--office-target-size")};
@@ -5173,7 +5684,7 @@ var defineZoomSlider = definer("office-ui-zoom-slider", () => {
5173
5684
  super();
5174
5685
  const doc = this.ownerDocument;
5175
5686
  const root = this.attachShadow({ mode: "open" });
5176
- attachStyles(root, controlCss(CSS17));
5687
+ attachStyles(root, controlCss(CSS18));
5177
5688
  const button = (name, text2) => {
5178
5689
  const element = doc.createElement("button");
5179
5690
  element.type = "button";
@@ -5448,10 +5959,12 @@ var CONTROL_DEFINERS = [
5448
5959
  defineToasts,
5449
5960
  defineReadOnlyBanner,
5450
5961
  definePasteOptions,
5451
- defineTitleBar
5962
+ defineTitleBar,
5963
+ defineRibbonSection,
5964
+ defineGallery
5452
5965
  ];
5453
5966
  function registerControls(registry) {
5454
5967
  for (const define of CONTROL_DEFINERS) define(registry);
5455
5968
  }
5456
5969
 
5457
- export { CONTROL_DEFINERS, DEFAULT_OFFICE_PROFILE, EMPTY_MENU_STATE, OFFICE_AVATAR_SWATCHES, OFFICE_PROFILE_STORAGE_KEY, OFFICE_TITLE_BAR_SEARCH_LIMIT, OFFICE_TOAST_VISIBLE_LIMIT, attachKeyTips, clampFlyoutPosition, clampOptionNumber, clearOfficeProfile, defineAccount, defineBackstage, defineButton, defineCheckbox, defineCommandSearch, defineContextMenu, defineDialog, defineDialogFooter, defineFindBar, defineMenuButton, defineMenuItem, defineMenuSeparator, defineOptionsDialog, definePasteOptions, definePrintPreview, defineRadio, defineReadOnlyBanner, defineRibbon, defineRibbonGroup, defineRibbonStack, defineRibbonToggle, defineRuler, defineSearchField, defineSelect, defineStatusBar, defineStatusItem, defineSwitch, defineTabStrip, defineTitleBar, defineToasts, defineToolbar, defineZoomSlider, nextEnabledIndex, profileInitials, readOfficeProfile, registerControls, rulerDivisions, sanitizeOfficeProfile, typeAheadIndex, writeOfficeProfile };
5970
+ export { CONTROL_DEFINERS, DEFAULT_OFFICE_PROFILE, EMPTY_MENU_STATE, OFFICE_AVATAR_SWATCHES, OFFICE_PROFILE_STORAGE_KEY, OFFICE_TITLE_BAR_SEARCH_LIMIT, OFFICE_TOAST_VISIBLE_LIMIT, attachKeyTips, clampFlyoutPosition, clampOptionNumber, clearOfficeProfile, defineAccount, defineBackstage, defineButton, defineCheckbox, defineCommandSearch, defineContextMenu, defineDialog, defineDialogFooter, defineFindBar, defineGallery, defineMenuButton, defineMenuItem, defineMenuSeparator, defineOptionsDialog, definePasteOptions, definePrintPreview, defineRadio, defineReadOnlyBanner, defineRibbon, defineRibbonGroup, defineRibbonSection, defineRibbonStack, defineRibbonToggle, defineRuler, defineSearchField, defineSelect, defineStatusBar, defineStatusItem, defineSwitch, defineTabStrip, defineTitleBar, defineToasts, defineToolbar, defineZoomSlider, nextEnabledIndex, parseSvgPreview, profileInitials, readOfficeProfile, registerControls, rulerDivisions, sanitizeOfficeProfile, typeAheadIndex, writeOfficeProfile };
@@ -7,6 +7,8 @@ import { defineBackstage } from './backstage.js';
7
7
  import { defineFindBar } from './find-bar.js';
8
8
  import { definePrintPreview } from './print-preview.js';
9
9
  import { defineRibbon } from './ribbon-tabs.js';
10
+ import { defineRibbonSection } from './ribbon-section.js';
11
+ import { defineGallery } from './gallery.js';
10
12
  import { defineRuler } from './ruler.js';
11
13
  import { defineAccount } from './account.js';
12
14
  import { defineButton } from './button.js';
@@ -23,7 +25,7 @@ import { defineStatusBar, defineStatusItem } from './status-bar.js';
23
25
  import { defineTabStrip } from './tab-strip.js';
24
26
  import { defineTitleBar } from './title-bar.js';
25
27
  import { defineZoomSlider } from './zoom-slider.js';
26
- export { defineAccount, defineDialogFooter, definePasteOptions, defineRadio, defineReadOnlyBanner, defineRibbonToggle, defineSearchField, defineToasts, defineBackstage, defineFindBar, definePrintPreview, defineRibbon, defineRuler, defineButton, defineCheckbox, defineCommandSearch, defineContextMenu, defineDialog, defineIcon, defineMenuButton, defineMenuItem, defineMenuSeparator, defineOptionsDialog, defineRibbonGroup, defineRibbonStack, defineSelect, defineStatusBar, defineStatusItem, defineSwitch, defineTabStrip, defineTitleBar, defineToolbar, defineZoomSlider, };
28
+ export { defineAccount, defineDialogFooter, definePasteOptions, defineRadio, defineReadOnlyBanner, defineRibbonToggle, defineSearchField, defineToasts, defineBackstage, defineFindBar, defineGallery, definePrintPreview, defineRibbon, defineRuler, defineButton, defineCheckbox, defineCommandSearch, defineContextMenu, defineDialog, defineIcon, defineMenuButton, defineMenuItem, defineMenuSeparator, defineOptionsDialog, defineRibbonGroup, defineRibbonSection, defineRibbonStack, defineSelect, defineStatusBar, defineStatusItem, defineSwitch, defineTabStrip, defineTitleBar, defineToolbar, defineZoomSlider, };
27
29
  export type { OfficeCommandEvent } from './button.js';
28
30
  export type { OfficeDialogCloseEvent, OfficeDialogCloseReason } from './dialog.js';
29
31
  export type { OfficeSelectOption } from './select.js';
@@ -36,6 +38,8 @@ export type { OfficeBackstageCloseEvent, OfficeBackstageItem, OfficeBackstageSel
36
38
  export type { OfficeFindInputEvent, OfficeFindStepEvent } from './find-bar.js';
37
39
  export type { OfficePrintPreviewPageEvent } from './print-preview.js';
38
40
  export type { OfficeRibbonSelectEvent } from './ribbon-tabs.js';
41
+ export type { OfficeRibbonCommandView, OfficeRibbonGroupView } from './ribbon-section.js';
42
+ export { parseSvgPreview, type OfficeGalleryItem, type OfficeGalleryPickEvent, type OfficeGallerySection, type OfficeGalleryState, } from './gallery.js';
39
43
  export { rulerDivisions } from './ruler.js';
40
44
  export { clampFlyoutPosition, EMPTY_MENU_STATE, nextEnabledIndex, typeAheadIndex, type FlyoutPositionInput, type OfficeMenuCloseReason, type OfficeMenuItem, type OfficeMenuState, } from './menu-model.js';
41
45
  export { OFFICE_TOAST_VISIBLE_LIMIT, type OfficeDialogFooterAction, type OfficeDialogFooterState, type OfficeDialogFooterVariant, type OfficeToast, type OfficeToastsState, } from './chrome-controls.js';
@@ -43,6 +47,6 @@ export type { OfficePasteOption, OfficePasteOptionsState, OfficeReadOnlyBannerIn
43
47
  export { clearOfficeProfile, DEFAULT_OFFICE_PROFILE, OFFICE_AVATAR_SWATCHES, OFFICE_PROFILE_STORAGE_KEY, profileInitials, readOfficeProfile, sanitizeOfficeProfile, writeOfficeProfile, type OfficeProfile, type OfficeProfileChangeEvent, } from './account.js';
44
48
  export { clampOptionNumber, type OfficeOptionCategory, type OfficeOptionChoice, type OfficeOptionControl, type OfficeOptionSection, type OfficeOptionsChangeEvent, type OfficeOptionValue, type OfficeOptionValues, } from './options.js';
45
49
  /** Every control of this entry. */
46
- export declare const CONTROL_DEFINERS: readonly [import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer];
50
+ export declare const CONTROL_DEFINERS: readonly [import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer];
47
51
  /** Idempotent, SSR-safe (no-op without a DOM). */
48
52
  export declare function registerControls(registry?: CustomElementRegistry): void;
package/dist/controls.js CHANGED
@@ -1,5 +1,5 @@
1
- export { CONTROL_DEFINERS, DEFAULT_OFFICE_PROFILE, EMPTY_MENU_STATE, OFFICE_AVATAR_SWATCHES, OFFICE_PROFILE_STORAGE_KEY, OFFICE_TITLE_BAR_SEARCH_LIMIT, OFFICE_TOAST_VISIBLE_LIMIT, attachKeyTips, clampFlyoutPosition, clampOptionNumber, clearOfficeProfile, defineAccount, defineBackstage, defineButton, defineCheckbox, defineCommandSearch, defineContextMenu, defineDialog, defineDialogFooter, defineFindBar, defineMenuButton, defineMenuItem, defineMenuSeparator, defineOptionsDialog, definePasteOptions, definePrintPreview, defineRadio, defineReadOnlyBanner, defineRibbon, defineRibbonGroup, defineRibbonStack, defineRibbonToggle, defineRuler, defineSearchField, defineSelect, defineStatusBar, defineStatusItem, defineSwitch, defineTabStrip, defineTitleBar, defineToasts, defineToolbar, defineZoomSlider, nextEnabledIndex, profileInitials, readOfficeProfile, registerControls, rulerDivisions, sanitizeOfficeProfile, typeAheadIndex, writeOfficeProfile } from './chunk-DGT2VJT5.js';
2
- export { defineIcon } from './chunk-GWAPPX66.js';
3
- import './chunk-DECL6RNI.js';
4
- import './chunk-UYPH4ESZ.js';
5
- import './chunk-A3QNC6VS.js';
1
+ export { CONTROL_DEFINERS, DEFAULT_OFFICE_PROFILE, EMPTY_MENU_STATE, OFFICE_AVATAR_SWATCHES, OFFICE_PROFILE_STORAGE_KEY, OFFICE_TITLE_BAR_SEARCH_LIMIT, OFFICE_TOAST_VISIBLE_LIMIT, attachKeyTips, clampFlyoutPosition, clampOptionNumber, clearOfficeProfile, defineAccount, defineBackstage, defineButton, defineCheckbox, defineCommandSearch, defineContextMenu, defineDialog, defineDialogFooter, defineFindBar, defineGallery, defineMenuButton, defineMenuItem, defineMenuSeparator, defineOptionsDialog, definePasteOptions, definePrintPreview, defineRadio, defineReadOnlyBanner, defineRibbon, defineRibbonGroup, defineRibbonSection, defineRibbonStack, defineRibbonToggle, defineRuler, defineSearchField, defineSelect, defineStatusBar, defineStatusItem, defineSwitch, defineTabStrip, defineTitleBar, defineToasts, defineToolbar, defineZoomSlider, nextEnabledIndex, parseSvgPreview, profileInitials, readOfficeProfile, registerControls, rulerDivisions, sanitizeOfficeProfile, typeAheadIndex, writeOfficeProfile } from './chunk-W7YI5DSJ.js';
2
+ export { defineIcon } from './chunk-W5PYFBEZ.js';
3
+ import './chunk-24MMSCKW.js';
4
+ import './chunk-UEJ4F33J.js';
5
+ import './chunk-G3LAGZEW.js';
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Light-DOM styles: the gallery renders its tiles beside the host's own children so products can
3
+ * query them, so the rules live in the host's root (document or shadow root), once per root.
4
+ */
5
+ export declare const GALLERY_LIGHT_CSS: string;
6
+ /** Add the light-DOM rules to the root holding `host` (a document or a shadow root), once. */
7
+ export declare function attachGalleryStyles(host: HTMLElement): void;
@@ -0,0 +1,53 @@
1
+ /** One tile. `preview` is SVG markup, parsed as an SVG document with executable parts removed. */
2
+ export interface OfficeGalleryItem {
3
+ id: string;
4
+ label: string;
5
+ applied?: boolean | undefined;
6
+ preview?: string | undefined;
7
+ }
8
+ export interface OfficeGallerySection {
9
+ title?: string | undefined;
10
+ columns: number;
11
+ tileWidth: number;
12
+ tileHeight: number;
13
+ items: readonly OfficeGalleryItem[];
14
+ }
15
+ /** A gallery, translated. With `command` it is a single button that picks the first item. */
16
+ export interface OfficeGalleryState {
17
+ id: string;
18
+ label: string;
19
+ /** Trigger name in the inline strip; defaults to "More <label>". */
20
+ moreLabel?: string | undefined;
21
+ disabled?: boolean | undefined;
22
+ command?: {
23
+ icon: string;
24
+ large?: boolean | undefined;
25
+ hint?: string | undefined;
26
+ } | undefined;
27
+ sections: readonly OfficeGallerySection[];
28
+ /** Tiles shown inline (`mode="inline"`); defaults to the first section's items. */
29
+ inline?: readonly OfficeGalleryItem[] | undefined;
30
+ }
31
+ export interface GalleryHooks {
32
+ triggerAttribute: string;
33
+ popupAttribute: string;
34
+ itemAttribute: string;
35
+ compactAttribute: string | null;
36
+ }
37
+ export interface GalleryPaint {
38
+ state: OfficeGalleryState;
39
+ disabled: boolean;
40
+ inline: boolean;
41
+ chevronOnly: boolean;
42
+ open: boolean;
43
+ icon: Element | null;
44
+ }
45
+ /** All gallery markup: the strip, the trigger and the popup. The element owns behaviour. */
46
+ export declare function createGalleryView(doc: Document, hooks: GalleryHooks, pick: (id: string) => void, toggle: () => void): {
47
+ root: HTMLSpanElement;
48
+ trigger: HTMLButtonElement;
49
+ popup: HTMLDivElement;
50
+ clear(): void;
51
+ setOpen(open: boolean): void;
52
+ paint({ state, disabled, inline, chevronOnly, open, icon }: GalleryPaint): void;
53
+ };
@@ -0,0 +1,20 @@
1
+ export type OfficeGalleryPickEvent = CustomEvent<{
2
+ gallery: string;
3
+ itemId: string;
4
+ }>;
5
+ /**
6
+ * `<office-ui-gallery>`: Office's ribbon gallery (Shape Styles, Themes, Table Styles). Set
7
+ * `state` (`OfficeGalleryState`, translated). `mode="inline"` shows a strip of tiles beside a
8
+ * More button; otherwise the trigger is a labelled dropdown (`chevron-only` keeps just the
9
+ * chevron, `icon` names its glyph). The popup opens below the trigger, keeps inside the window
10
+ * and closes on Escape, an outside press or a pick. ArrowDown on the trigger opens it and focuses
11
+ * the first tile. A pick emits `office-gallery-pick` `{ gallery, itemId }`.
12
+ *
13
+ * Tiles render in the light DOM beside the host's children so products can query them
14
+ * (`data-gallery-item`); the rules join the host's root once. Static `pickEvent`,
15
+ * `triggerAttribute`, `popupAttribute`, `itemAttribute` and `compactAttribute` keep a product's
16
+ * published names; override `triggerIcon()` to draw a product glyph.
17
+ */
18
+ export declare const defineGallery: import("./registry.js").Definer;
19
+ export type { OfficeGalleryItem, OfficeGallerySection, OfficeGalleryState, } from './gallery-view.js';
20
+ export { parseSvgPreview } from './safe-svg.js';
package/dist/icons.js CHANGED
@@ -1,3 +1,3 @@
1
- export { ICON_CSS, createIconSvg, defineIcon, getIcon, listIcons, paintIcon, registerIcon } from './chunk-GWAPPX66.js';
2
- import './chunk-UYPH4ESZ.js';
3
- import './chunk-A3QNC6VS.js';
1
+ export { ICON_CSS, createIconSvg, defineIcon, getIcon, listIcons, paintIcon, registerIcon } from './chunk-W5PYFBEZ.js';
2
+ import './chunk-UEJ4F33J.js';
3
+ import './chunk-G3LAGZEW.js';
package/dist/index.d.ts CHANGED
@@ -5,7 +5,7 @@ export * from './smartart.js';
5
5
  export * from './theme.js';
6
6
  export { CONTRACT_REVISION, type Definer } from './registry.js';
7
7
  /** Every ooxml-ui tag this package defines, in registration order. */
8
- export declare const OFFICE_UI_TAGS: readonly ["office-ui-icon", "office-ui-button", "office-ui-checkbox", "office-ui-switch", "office-ui-select", "office-ui-ribbon-group", "office-ui-ribbon-stack", "office-ui-menu-item", "office-ui-menu-button", "office-ui-menu-separator", "office-ui-context-menu", "office-ui-command-search", "office-ui-toolbar", "office-ui-dialog", "office-ui-status-bar", "office-ui-status-item", "office-ui-zoom-slider", "office-ui-tab-strip", "office-ui-options-dialog", "office-ui-account", "office-ui-ribbon", "office-ui-find-bar", "office-ui-ruler", "office-ui-backstage", "office-ui-print-preview", "office-ui-radio", "office-ui-search", "office-ui-ribbon-toggle", "office-ui-dialog-footer", "office-ui-toasts", "office-ui-read-only-banner", "office-ui-paste-options", "office-ui-title-bar", "office-ui-presence", "office-ui-smartart"];
8
+ export declare const OFFICE_UI_TAGS: readonly ["office-ui-icon", "office-ui-button", "office-ui-checkbox", "office-ui-switch", "office-ui-select", "office-ui-ribbon-group", "office-ui-ribbon-stack", "office-ui-menu-item", "office-ui-menu-button", "office-ui-menu-separator", "office-ui-context-menu", "office-ui-command-search", "office-ui-toolbar", "office-ui-dialog", "office-ui-status-bar", "office-ui-status-item", "office-ui-zoom-slider", "office-ui-tab-strip", "office-ui-options-dialog", "office-ui-account", "office-ui-ribbon", "office-ui-find-bar", "office-ui-ruler", "office-ui-backstage", "office-ui-print-preview", "office-ui-radio", "office-ui-search", "office-ui-ribbon-toggle", "office-ui-dialog-footer", "office-ui-toasts", "office-ui-read-only-banner", "office-ui-paste-options", "office-ui-title-bar", "office-ui-ribbon-section", "office-ui-gallery", "office-ui-presence", "office-ui-smartart"];
9
9
  /**
10
10
  * Install the theme tokens and define every element. Idempotent and safe to call from every
11
11
  * viewer binding; a no-op where there is no DOM (SSR).
package/dist/index.js CHANGED
@@ -1,14 +1,14 @@
1
- import { installOfficeUiTheme } from './chunk-5L3NYLAW.js';
2
- export { THEME_CSS, THEME_STYLE_ID, installOfficeUiTheme } from './chunk-5L3NYLAW.js';
3
- import { registerControls } from './chunk-DGT2VJT5.js';
4
- export { CONTROL_DEFINERS, DEFAULT_OFFICE_PROFILE, EMPTY_MENU_STATE, OFFICE_AVATAR_SWATCHES, OFFICE_PROFILE_STORAGE_KEY, OFFICE_TITLE_BAR_SEARCH_LIMIT, OFFICE_TOAST_VISIBLE_LIMIT, attachKeyTips, clampFlyoutPosition, clampOptionNumber, clearOfficeProfile, defineAccount, defineBackstage, defineButton, defineCheckbox, defineCommandSearch, defineContextMenu, defineDialog, defineDialogFooter, defineFindBar, defineMenuButton, defineMenuItem, defineMenuSeparator, defineOptionsDialog, definePasteOptions, definePrintPreview, defineRadio, defineReadOnlyBanner, defineRibbon, defineRibbonGroup, defineRibbonStack, defineRibbonToggle, defineRuler, defineSearchField, defineSelect, defineStatusBar, defineStatusItem, defineSwitch, defineTabStrip, defineTitleBar, defineToasts, defineToolbar, defineZoomSlider, nextEnabledIndex, profileInitials, readOfficeProfile, registerControls, rulerDivisions, sanitizeOfficeProfile, typeAheadIndex, writeOfficeProfile } from './chunk-DGT2VJT5.js';
5
- export { ICON_CSS, createIconSvg, defineIcon, getIcon, listIcons, paintIcon, registerIcon } from './chunk-GWAPPX66.js';
6
- import { definePresence } from './chunk-DECL6RNI.js';
7
- export { definePresence, initialsOf, participantsFromAwareness } from './chunk-DECL6RNI.js';
8
- import { defineSmartArt } from './chunk-OAGGHX23.js';
9
- export { defineSmartArt, renderDiagramDrawing } from './chunk-OAGGHX23.js';
10
- export { CONTRACT_REVISION } from './chunk-UYPH4ESZ.js';
11
- export { COMPACT, FOCUS_RING, OFFICE_TOKENS, TOUCH, tok } from './chunk-A3QNC6VS.js';
1
+ import { installOfficeUiTheme } from './chunk-7XBKSYGM.js';
2
+ export { THEME_CSS, THEME_STYLE_ID, installOfficeUiTheme } from './chunk-7XBKSYGM.js';
3
+ import { registerControls } from './chunk-W7YI5DSJ.js';
4
+ export { CONTROL_DEFINERS, DEFAULT_OFFICE_PROFILE, EMPTY_MENU_STATE, OFFICE_AVATAR_SWATCHES, OFFICE_PROFILE_STORAGE_KEY, OFFICE_TITLE_BAR_SEARCH_LIMIT, OFFICE_TOAST_VISIBLE_LIMIT, attachKeyTips, clampFlyoutPosition, clampOptionNumber, clearOfficeProfile, defineAccount, defineBackstage, defineButton, defineCheckbox, defineCommandSearch, defineContextMenu, defineDialog, defineDialogFooter, defineFindBar, defineGallery, defineMenuButton, defineMenuItem, defineMenuSeparator, defineOptionsDialog, definePasteOptions, definePrintPreview, defineRadio, defineReadOnlyBanner, defineRibbon, defineRibbonGroup, defineRibbonSection, defineRibbonStack, defineRibbonToggle, defineRuler, defineSearchField, defineSelect, defineStatusBar, defineStatusItem, defineSwitch, defineTabStrip, defineTitleBar, defineToasts, defineToolbar, defineZoomSlider, nextEnabledIndex, parseSvgPreview, profileInitials, readOfficeProfile, registerControls, rulerDivisions, sanitizeOfficeProfile, typeAheadIndex, writeOfficeProfile } from './chunk-W7YI5DSJ.js';
5
+ export { ICON_CSS, createIconSvg, defineIcon, getIcon, listIcons, paintIcon, registerIcon } from './chunk-W5PYFBEZ.js';
6
+ import { definePresence } from './chunk-24MMSCKW.js';
7
+ export { definePresence, initialsOf, participantsFromAwareness } from './chunk-24MMSCKW.js';
8
+ import { defineSmartArt } from './chunk-4JQLQROF.js';
9
+ export { defineSmartArt, renderDiagramDrawing } from './chunk-4JQLQROF.js';
10
+ export { CONTRACT_REVISION } from './chunk-UEJ4F33J.js';
11
+ export { COMPACT, FOCUS_RING, OFFICE_TOKENS, TOUCH, tok } from './chunk-G3LAGZEW.js';
12
12
 
13
13
  // src/index.ts
14
14
  var OFFICE_UI_TAGS = [
@@ -45,6 +45,8 @@ var OFFICE_UI_TAGS = [
45
45
  "office-ui-read-only-banner",
46
46
  "office-ui-paste-options",
47
47
  "office-ui-title-bar",
48
+ "office-ui-ribbon-section",
49
+ "office-ui-gallery",
48
50
  "office-ui-presence",
49
51
  "office-ui-smartart"
50
52
  ];
package/dist/presence.js CHANGED
@@ -1,3 +1,3 @@
1
- export { definePresence, initialsOf, participantsFromAwareness } from './chunk-DECL6RNI.js';
2
- import './chunk-UYPH4ESZ.js';
3
- import './chunk-A3QNC6VS.js';
1
+ export { definePresence, initialsOf, participantsFromAwareness } from './chunk-24MMSCKW.js';
2
+ import './chunk-UEJ4F33J.js';
3
+ import './chunk-G3LAGZEW.js';
@@ -0,0 +1,36 @@
1
+ /** One ribbon command, translated. Booleans map to the command element's attributes. */
2
+ export interface OfficeRibbonCommandView {
3
+ id: string;
4
+ label: string;
5
+ /** ScreenTip; defaults to `label`. */
6
+ title?: string | undefined;
7
+ icon: string;
8
+ badge?: string | number | undefined;
9
+ /** `large`, `small` or `icon`; omitted leaves the command element's default. */
10
+ size?: string | undefined;
11
+ disabled?: boolean | undefined;
12
+ active?: boolean | undefined;
13
+ compact?: boolean | undefined;
14
+ hidden?: boolean | undefined;
15
+ caret?: boolean | undefined;
16
+ /** Toggle state; undefined means not a toggle. */
17
+ pressed?: boolean | undefined;
18
+ /** Menu state; undefined means no menu. */
19
+ expanded?: boolean | undefined;
20
+ /** Stack commands with the same column number vertically. */
21
+ column?: number | undefined;
22
+ }
23
+ export interface OfficeRibbonGroupView {
24
+ id: string;
25
+ label: string;
26
+ commands: readonly OfficeRibbonCommandView[];
27
+ }
28
+ /**
29
+ * `<office-ui-ribbon-section>`: a run of ribbon groups from data. Set `groups`
30
+ * (`OfficeRibbonGroupView[]`); groups and commands are keyed by id and patched in place, so a
31
+ * focused command and every customization id survive updates. Commands with a `column` stack
32
+ * vertically. Children are real `office-ui-ribbon-group` and `office-ui-button` elements in the
33
+ * light DOM, so their events (`office-command` and so on) bubble as usual. Static `groupTag`,
34
+ * `commandTag`, `groupIdAttribute` and `commandIdAttribute` let a product keep its aliases.
35
+ */
36
+ export declare const defineRibbonSection: import("./registry.js").Definer;
@@ -0,0 +1 @@
1
+ export declare function parseSvgPreview(doc: Document, svg: string): Element | null;
package/dist/smartart.js CHANGED
@@ -1,3 +1,3 @@
1
- export { defineSmartArt, renderDiagramDrawing } from './chunk-OAGGHX23.js';
2
- import './chunk-UYPH4ESZ.js';
3
- import './chunk-A3QNC6VS.js';
1
+ export { defineSmartArt, renderDiagramDrawing } from './chunk-4JQLQROF.js';
2
+ import './chunk-UEJ4F33J.js';
3
+ import './chunk-G3LAGZEW.js';
package/dist/theme.js CHANGED
@@ -1,2 +1,2 @@
1
- export { THEME_CSS, THEME_STYLE_ID, installOfficeUiTheme } from './chunk-5L3NYLAW.js';
2
- export { COMPACT, FOCUS_RING, OFFICE_TOKENS, TOUCH, tok } from './chunk-A3QNC6VS.js';
1
+ export { THEME_CSS, THEME_STYLE_ID, installOfficeUiTheme } from './chunk-7XBKSYGM.js';
2
+ export { COMPACT, FOCUS_RING, OFFICE_TOKENS, TOUCH, tok } from './chunk-G3LAGZEW.js';
package/dist/tokens.d.ts CHANGED
@@ -202,6 +202,13 @@ export declare const OFFICE_TOKENS: {
202
202
  readonly '--office-avatar-color': "var(--office-muted-foreground, #6b7280)";
203
203
  readonly '--office-toast-width': "360px";
204
204
  readonly '--office-account-field-width': "320px";
205
+ readonly '--office-gallery-trigger-height': "24px";
206
+ readonly '--office-gallery-strip-background': "color-mix(in srgb, var(--office-surface, #f3f4f6) 30%, transparent)";
207
+ readonly '--office-gallery-command-min-width': "54px";
208
+ readonly '--office-gallery-command-max-width': "78px";
209
+ readonly '--office-gallery-command-height': "58px";
210
+ readonly '--office-gallery-command-icon': "24px";
211
+ readonly '--office-gallery-popup-max-height': "65vh";
205
212
  readonly '--office-title-bar-height': "36px";
206
213
  readonly '--office-title-bar-below-height': "28px";
207
214
  readonly '--office-title-bar-background': "var(--office-surface, #f3f4f6)";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ooxml-ui",
3
- "version": "0.18.2",
3
+ "version": "0.20.0",
4
4
  "description": "Shared, format-neutral web components and styles for the Office viewers (Word, PowerPoint, Excel)",
5
5
  "keywords": [
6
6
  "custom-elements",