ooxml-ui 0.19.0 → 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,40 +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-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-presence` | `participants`, `max`, `label` | `office-presence-select` `{ id }` |
95
- | `office-ui-smartart` | `drawing` (core `DiagramDrawing`), `schemeColors`, `label` | `office-smartart-render` (render report) |
96
- | `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 |
97
98
 
98
99
  The local profile behind `office-ui-account` is stored on the device only, under one suite-wide
99
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")};
@@ -1590,6 +1590,413 @@ var defineRibbonSection = definer("office-ui-ribbon-section", () => {
1590
1590
  return OfficeUiRibbonSection;
1591
1591
  });
1592
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
+
1593
2000
  // src/ruler.ts
1594
2001
  var CSS9 = `
1595
2002
  :host { display: block; box-sizing: border-box; background: ${tok("--office-background")};
@@ -5553,10 +5960,11 @@ var CONTROL_DEFINERS = [
5553
5960
  defineReadOnlyBanner,
5554
5961
  definePasteOptions,
5555
5962
  defineTitleBar,
5556
- defineRibbonSection
5963
+ defineRibbonSection,
5964
+ defineGallery
5557
5965
  ];
5558
5966
  function registerControls(registry) {
5559
5967
  for (const define of CONTROL_DEFINERS) define(registry);
5560
5968
  }
5561
5969
 
5562
- 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, defineRibbonSection, 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 };
@@ -8,6 +8,7 @@ import { defineFindBar } from './find-bar.js';
8
8
  import { definePrintPreview } from './print-preview.js';
9
9
  import { defineRibbon } from './ribbon-tabs.js';
10
10
  import { defineRibbonSection } from './ribbon-section.js';
11
+ import { defineGallery } from './gallery.js';
11
12
  import { defineRuler } from './ruler.js';
12
13
  import { defineAccount } from './account.js';
13
14
  import { defineButton } from './button.js';
@@ -24,7 +25,7 @@ import { defineStatusBar, defineStatusItem } from './status-bar.js';
24
25
  import { defineTabStrip } from './tab-strip.js';
25
26
  import { defineTitleBar } from './title-bar.js';
26
27
  import { defineZoomSlider } from './zoom-slider.js';
27
- 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, defineRibbonSection, 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, };
28
29
  export type { OfficeCommandEvent } from './button.js';
29
30
  export type { OfficeDialogCloseEvent, OfficeDialogCloseReason } from './dialog.js';
30
31
  export type { OfficeSelectOption } from './select.js';
@@ -38,6 +39,7 @@ export type { OfficeFindInputEvent, OfficeFindStepEvent } from './find-bar.js';
38
39
  export type { OfficePrintPreviewPageEvent } from './print-preview.js';
39
40
  export type { OfficeRibbonSelectEvent } from './ribbon-tabs.js';
40
41
  export type { OfficeRibbonCommandView, OfficeRibbonGroupView } from './ribbon-section.js';
42
+ export { parseSvgPreview, type OfficeGalleryItem, type OfficeGalleryPickEvent, type OfficeGallerySection, type OfficeGalleryState, } from './gallery.js';
41
43
  export { rulerDivisions } from './ruler.js';
42
44
  export { clampFlyoutPosition, EMPTY_MENU_STATE, nextEnabledIndex, typeAheadIndex, type FlyoutPositionInput, type OfficeMenuCloseReason, type OfficeMenuItem, type OfficeMenuState, } from './menu-model.js';
43
45
  export { OFFICE_TOAST_VISIBLE_LIMIT, type OfficeDialogFooterAction, type OfficeDialogFooterState, type OfficeDialogFooterVariant, type OfficeToast, type OfficeToastsState, } from './chrome-controls.js';
@@ -45,6 +47,6 @@ export type { OfficePasteOption, OfficePasteOptionsState, OfficeReadOnlyBannerIn
45
47
  export { clearOfficeProfile, DEFAULT_OFFICE_PROFILE, OFFICE_AVATAR_SWATCHES, OFFICE_PROFILE_STORAGE_KEY, profileInitials, readOfficeProfile, sanitizeOfficeProfile, writeOfficeProfile, type OfficeProfile, type OfficeProfileChangeEvent, } from './account.js';
46
48
  export { clampOptionNumber, type OfficeOptionCategory, type OfficeOptionChoice, type OfficeOptionControl, type OfficeOptionSection, type OfficeOptionsChangeEvent, type OfficeOptionValue, type OfficeOptionValues, } from './options.js';
47
49
  /** Every control of this entry. */
48
- 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];
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];
49
51
  /** Idempotent, SSR-safe (no-op without a DOM). */
50
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, defineRibbonSection, defineRibbonStack, defineRibbonToggle, defineRuler, defineSearchField, defineSelect, defineStatusBar, defineStatusItem, defineSwitch, defineTabStrip, defineTitleBar, defineToasts, defineToolbar, defineZoomSlider, nextEnabledIndex, profileInitials, readOfficeProfile, registerControls, rulerDivisions, sanitizeOfficeProfile, typeAheadIndex, writeOfficeProfile } from './chunk-6DZC4M2H.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-ribbon-section", "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-6DZC4M2H.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, defineRibbonSection, defineRibbonStack, defineRibbonToggle, defineRuler, defineSearchField, defineSelect, defineStatusBar, defineStatusItem, defineSwitch, defineTabStrip, defineTitleBar, defineToasts, defineToolbar, defineZoomSlider, nextEnabledIndex, profileInitials, readOfficeProfile, registerControls, rulerDivisions, sanitizeOfficeProfile, typeAheadIndex, writeOfficeProfile } from './chunk-6DZC4M2H.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 = [
@@ -46,6 +46,7 @@ var OFFICE_UI_TAGS = [
46
46
  "office-ui-paste-options",
47
47
  "office-ui-title-bar",
48
48
  "office-ui-ribbon-section",
49
+ "office-ui-gallery",
49
50
  "office-ui-presence",
50
51
  "office-ui-smartart"
51
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 @@
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.19.0",
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",