ooxml-ui 0.15.0 → 0.16.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 +34 -32
- package/dist/{chunk-ZBFAPBNU.js → chunk-G2ZIAXOV.js} +336 -12
- package/dist/context-menu.d.ts +15 -5
- package/dist/controls.d.ts +1 -0
- package/dist/controls.js +1 -1
- package/dist/index.js +2 -2
- package/dist/menu-model.d.ts +75 -0
- package/package.json +13 -7
package/README.md
CHANGED
|
@@ -52,44 +52,46 @@ document.body.append(button);
|
|
|
52
52
|
| `ooxml-ui/presence` | `<office-ui-presence>` avatar stack for collaboration awareness |
|
|
53
53
|
| `ooxml-ui/smartart` | `<office-ui-smartart>`: draws a core `DiagramDrawing` as SVG |
|
|
54
54
|
|
|
55
|
+
Every entry declares an `import` and a `default` export condition, so CommonJS consumers on Node 20.19+ or 22.12+ load it through `require(esm)`.
|
|
56
|
+
|
|
55
57
|
Importing an entry never touches the DOM (SSR-safe). Elements are defined by the `define*` /
|
|
56
58
|
`register*` functions, which are idempotent, no-ops without a `window`, and refuse to coexist
|
|
57
59
|
with an incompatible build of this package.
|
|
58
60
|
|
|
59
61
|
## Features: elements
|
|
60
62
|
|
|
61
|
-
| Tag | Attributes / properties
|
|
62
|
-
| ----------------------------------------------------- |
|
|
63
|
-
| `office-ui-button` | `label`, `icon`, `command`, `disabled`, `pressed`, `expanded`, `icon-only`, `variant="stacked"`, `keyshortcuts`
|
|
64
|
-
| `office-ui-checkbox`, `office-ui-switch` | `checked`, `disabled`, `value`, `aria-label`; form-associated
|
|
65
|
-
| `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"
|
|
66
|
-
| `office-ui-ribbon-group` | `label`, `launcher` (dialog launcher command), `launcher-disabled`; default slot
|
|
67
|
-
| `office-ui-ribbon-stack` | `orientation="horizontal"`; default slot (three-row column of small commands by default)
|
|
68
|
-
| `office-ui-menu-button` / `-menu-item` | button: `label`, `icon`, `command` (split button), `variant`, `disabled`, `keyshortcuts`; item: `command`, `label`, `icon`, `disabled`, `checked`
|
|
69
|
-
| `office-ui-toolbar` | `aria-label`, `aria-orientation`; arrow-key focus movement
|
|
70
|
-
| `office-ui-dialog` | `open`, `heading`, `dismissible="false"`, `show()`, `close()`; slots default, `footer`
|
|
71
|
-
| `office-ui-status-bar` / `-status-item` | `label`, `value`, `interactive`, `id`
|
|
72
|
-
| `office-ui-zoom-slider` | `value` (percent), `min`, `max`, `step`, `disabled`, `fit` (fit button name), `label`
|
|
73
|
-
| `office-ui-tab-strip` | `tabs` `[{ id, label, title? }]`, `selected`, `label`, `previous-label`, `next-label`, `add-label`, `add-disabled`, `add-title`, `disabled`
|
|
74
|
-
| `office-ui-context-menu` / `office-ui-menu-separator` | `label
|
|
75
|
-
| `office-ui-command-search` | `commands` `[{ id, label, keywords?, description?, disabled?, title? }]`, `placeholder`, `label`, `limit` (Office's "Tell me what you want to do")
|
|
76
|
-
| `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()`
|
|
77
|
-
| `office-ui-account` | `profile` `{ displayName, avatarColor, initial? }`; slots `sign-in` and default (product sections)
|
|
78
|
-
| `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()`
|
|
79
|
-
| `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`
|
|
80
|
-
| `office-ui-find-bar` | `open`, `label`, `input-label`, `placeholder`, `maxlength`, `disabled`, `navigation-disabled`, `previous-label`, `next-label`, `close-label`; `value`, `status`, `statusTitle`, `show()`, `close()`
|
|
81
|
-
| `office-ui-ruler` | `orientation="vertical"`, `origin` (px offset of zero), `scale` (px per unit, default 96), `direction="reverse"`; decorative
|
|
82
|
-
| `office-ui-print-preview` | `pages` (rendered nodes; an inert clone of the current one is shown), `index`, `label`, `empty-label`
|
|
83
|
-
| `office-ui-radio` | `checked`, `disabled`, `value`, `name`; radios of one tag sharing a `name` form a roving-focus group; form-associated
|
|
84
|
-
| `office-ui-search` | `value`, `placeholder`, `disabled`, `aria-label`, `variant="titlebar"`; `focus()`, `select()`
|
|
85
|
-
| `office-ui-ribbon-toggle` | `label`, `checked`, `disabled`, `title`, `command` (a labelled ribbon checkbox row)
|
|
86
|
-
| `office-ui-dialog-footer` | `state` `{ actions: [{ id, label, variant?, icon?, disabled?, busy?, title?, align?, testId? }] }`, `focusAction(id)`
|
|
87
|
-
| `office-ui-toasts` | `state` `{ toasts: [{ id, code?, severity, message }], overflowCount?, labels? }`; hidden when empty, host positions it
|
|
88
|
-
| `office-ui-read-only-banner` | `state` `{ kind, message, passwordPromptOpen?, passwordError?, checkingPassword?, labels? }`
|
|
89
|
-
| `office-ui-paste-options` | `state` `{ left, top, options: [{ id, label }], label? }`; fixed 4px past the pasted object
|
|
90
|
-
| `office-ui-presence` | `participants`, `max`, `label`
|
|
91
|
-
| `office-ui-smartart` | `drawing` (core `DiagramDrawing`), `schemeColors`, `label`
|
|
92
|
-
| `office-ui-icon` | `name`, `label`
|
|
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` | `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-presence` | `participants`, `max`, `label` | `office-presence-select` `{ id }` |
|
|
93
|
+
| `office-ui-smartart` | `drawing` (core `DiagramDrawing`), `schemeColors`, `label` | `office-smartart-render` (render report) |
|
|
94
|
+
| `office-ui-icon` | `name`, `label` | none |
|
|
93
95
|
|
|
94
96
|
The local profile behind `office-ui-account` is stored on the device only, under one suite-wide
|
|
95
97
|
key (`readOfficeProfile`, `writeOfficeProfile`, `clearOfficeProfile`), so every Office viewer on
|
|
@@ -702,6 +702,8 @@ var defineRibbonToggle = definer("office-ui-ribbon-toggle", () => {
|
|
|
702
702
|
static requestEvent = "office-toggle";
|
|
703
703
|
static idAttribute = "command";
|
|
704
704
|
static detailKey = "command";
|
|
705
|
+
/** The checkbox drawn inside; a product subclass may use its own aliased tag. */
|
|
706
|
+
static checkboxTag = "office-ui-checkbox";
|
|
705
707
|
static get observedAttributes() {
|
|
706
708
|
return ["label", "checked", "disabled", "title"];
|
|
707
709
|
}
|
|
@@ -713,7 +715,9 @@ var defineRibbonToggle = definer("office-ui-ribbon-toggle", () => {
|
|
|
713
715
|
const root = this.attachShadow({ mode: "open" });
|
|
714
716
|
attachStyles(root, controlCss(CSS2));
|
|
715
717
|
const label = doc.createElement("label");
|
|
716
|
-
this.checkbox = doc.createElement(
|
|
718
|
+
this.checkbox = doc.createElement(
|
|
719
|
+
this.constructor.checkboxTag
|
|
720
|
+
);
|
|
717
721
|
this.text = doc.createTextNode("");
|
|
718
722
|
label.append(this.checkbox, this.text);
|
|
719
723
|
label.addEventListener("click", (event) => {
|
|
@@ -2398,21 +2402,85 @@ var defineCommandSearch = definer("office-ui-command-search", () => {
|
|
|
2398
2402
|
return OfficeUiCommandSearch;
|
|
2399
2403
|
});
|
|
2400
2404
|
|
|
2405
|
+
// src/menu-model.ts
|
|
2406
|
+
var EMPTY_MENU_STATE = { x: 0, y: 0, label: "", items: [] };
|
|
2407
|
+
function nextEnabledIndex(items, from, step) {
|
|
2408
|
+
const count = items.length;
|
|
2409
|
+
for (let offset = 1; offset <= count; offset += 1) {
|
|
2410
|
+
const index = ((from + step * offset) % count + count) % count;
|
|
2411
|
+
if (!items[index]?.disabled) return index;
|
|
2412
|
+
}
|
|
2413
|
+
return -1;
|
|
2414
|
+
}
|
|
2415
|
+
function typeAheadIndex(items, from, query) {
|
|
2416
|
+
const needle = query.toLowerCase();
|
|
2417
|
+
const cycling = [...needle].every((char) => char === needle[0]);
|
|
2418
|
+
const prefix = cycling ? needle[0] : needle;
|
|
2419
|
+
for (let offset = cycling ? 1 : 0; offset <= items.length; offset += 1) {
|
|
2420
|
+
const index = (from + offset + items.length) % items.length;
|
|
2421
|
+
const item = items[index];
|
|
2422
|
+
if (item && !item.disabled && item.label.trim().toLowerCase().startsWith(prefix ?? ""))
|
|
2423
|
+
return index;
|
|
2424
|
+
}
|
|
2425
|
+
return -1;
|
|
2426
|
+
}
|
|
2427
|
+
function clampFlyoutPosition(input) {
|
|
2428
|
+
const margin = input.margin ?? 8;
|
|
2429
|
+
const maxLeft = input.viewportWidth - input.width - margin;
|
|
2430
|
+
const maxTop = input.viewportHeight - input.height - margin;
|
|
2431
|
+
return {
|
|
2432
|
+
left: Math.max(margin, input.width > 0 ? Math.min(input.x, maxLeft) : input.x),
|
|
2433
|
+
top: Math.max(margin, input.height > 0 ? Math.min(input.y, maxTop) : input.y)
|
|
2434
|
+
};
|
|
2435
|
+
}
|
|
2436
|
+
|
|
2401
2437
|
// src/context-menu.ts
|
|
2402
2438
|
var CSS13 = `
|
|
2403
2439
|
:host { display: contents; }
|
|
2440
|
+
:host([data-controlled]) { display: block; position: fixed; z-index: ${tok("--office-z-popover")};
|
|
2441
|
+
color: ${tok("--office-popover-foreground")}; font: ${tok("--office-font-size-sm")}/${tok("--office-line-height")} ${tok("--office-font")}; }
|
|
2442
|
+
:host([data-controlled][hidden]) { display: none; }
|
|
2404
2443
|
.panel { position: fixed; inset: auto; margin: 0; min-width: ${tok("--office-context-menu-min-width")}; padding: ${tok("--office-space-1")}; box-sizing: border-box;
|
|
2405
2444
|
background: ${tok("--office-background")}; color: ${tok("--office-foreground")};
|
|
2406
2445
|
border: ${tok("--office-border-width")} solid ${tok("--office-border")}; border-radius: ${tok("--office-radius")};
|
|
2407
2446
|
box-shadow: ${tok("--office-shadow")}; font-family: ${tok("--office-font")}; }
|
|
2408
2447
|
.panel[hidden] { display: none; }
|
|
2409
|
-
|
|
2448
|
+
/* Controlled mode: the host is the fixed box; rows are drawn here from \`state\`. */
|
|
2449
|
+
.menu { box-sizing: border-box; display: flex; flex-direction: column; min-width: ${tok("--office-menu-min-width")};
|
|
2450
|
+
max-height: calc(100vh - 2 * ${tok("--office-space-2")}); overflow-y: auto; padding: ${tok("--office-space-1-5")} 0;
|
|
2451
|
+
border: ${tok("--office-border-width")} solid ${tok("--office-border")}; border-radius: ${tok("--office-radius-md")};
|
|
2452
|
+
background: ${tok("--office-popover")}; color: inherit; box-shadow: ${tok("--office-shadow-lg")}; user-select: none; }
|
|
2453
|
+
.menu:focus { outline: none; }
|
|
2454
|
+
.item { box-sizing: border-box; display: flex; align-items: center; gap: ${tok("--office-space-1-5")}; width: 100%;
|
|
2455
|
+
min-height: ${tok("--office-field-height")}; padding: ${tok("--office-space-1-5")} ${tok("--office-space-3")}; border: 0;
|
|
2456
|
+
background: transparent; color: inherit; font: inherit; text-align: start; white-space: nowrap; cursor: pointer; }
|
|
2457
|
+
.item:hover:not(:disabled), .item:focus:not(:disabled) { background: ${tok("--office-selected")}; outline: none; }
|
|
2458
|
+
.item:focus-visible { outline: ${tok("--office-focus-width")} solid ${tok("--office-ring")}; outline-offset: calc(-1 * ${tok("--office-focus-width")}); }
|
|
2459
|
+
.item:disabled { opacity: .45; cursor: default; }
|
|
2460
|
+
.item.danger { color: ${tok("--office-danger")}; }
|
|
2461
|
+
.item svg { width: ${tok("--office-icon-size-md")}; height: ${tok("--office-icon-size-md")}; flex: none; fill: none; stroke: currentColor;
|
|
2462
|
+
stroke-width: ${tok("--office-icon-stroke")}; stroke-linecap: round; stroke-linejoin: round; }
|
|
2463
|
+
.check { flex: none; width: ${tok("--office-icon-size")}; text-align: center; }
|
|
2464
|
+
.separator { height: ${tok("--office-border-width")}; margin: ${tok("--office-space-1")} 0; background: ${tok("--office-border")}; }
|
|
2465
|
+
.heading { padding: ${tok("--office-space-1-5")} ${tok("--office-space-3")} ${tok("--office-space-0")}; color: ${tok("--office-muted-foreground")};
|
|
2466
|
+
font-size: ${tok("--office-font-size-2xs")}; font-weight: ${tok("--office-font-weight-bold")}; letter-spacing: .06em; text-transform: uppercase; }
|
|
2467
|
+
@media (pointer: coarse) { .item { min-height: ${tok("--office-target-size-touch")}; } }
|
|
2468
|
+
@media (forced-colors: active) {
|
|
2469
|
+
.panel, .menu { border-color: CanvasText; background: Canvas; color: CanvasText; box-shadow: none; }
|
|
2470
|
+
.item, .item.danger { color: CanvasText; }
|
|
2471
|
+
.item:disabled { color: GrayText; opacity: 1; }
|
|
2472
|
+
.item:hover:not(:disabled), .item:focus:not(:disabled) { background: Highlight; color: HighlightText; }
|
|
2473
|
+
.separator { background: CanvasText; }
|
|
2474
|
+
.heading { color: CanvasText; }
|
|
2475
|
+
}
|
|
2410
2476
|
`;
|
|
2411
2477
|
var SEPARATOR_CSS = `
|
|
2412
2478
|
:host { display: block; height: ${tok("--office-border-width")}; margin: ${tok("--office-space-1")} ${tok("--office-space-1-5")}; background: ${tok("--office-border")}; }
|
|
2413
2479
|
@media (forced-colors: active) { :host { background: CanvasText; } }
|
|
2414
2480
|
`;
|
|
2415
2481
|
var ITEMS = "office-ui-menu-item:not([disabled]):not([hidden])";
|
|
2482
|
+
var TYPE_AHEAD_MS = 700;
|
|
2483
|
+
var openMenus = /* @__PURE__ */ new WeakMap();
|
|
2416
2484
|
var defineMenuSeparator = definer("office-ui-menu-separator", () => {
|
|
2417
2485
|
class OfficeUiMenuSeparator extends HTMLElement {
|
|
2418
2486
|
constructor() {
|
|
@@ -2427,10 +2495,25 @@ var defineMenuSeparator = definer("office-ui-menu-separator", () => {
|
|
|
2427
2495
|
});
|
|
2428
2496
|
var defineContextMenu = definer("office-ui-context-menu", () => {
|
|
2429
2497
|
class OfficeUiContextMenu extends HTMLElement {
|
|
2498
|
+
static requestEvent = "office-menu-request";
|
|
2499
|
+
static closeEvent = "office-menu-close";
|
|
2500
|
+
static markerPattern = /^data-[a-z0-9-]+$/;
|
|
2430
2501
|
static observedAttributes = ["label"];
|
|
2431
2502
|
panel;
|
|
2503
|
+
menu;
|
|
2432
2504
|
returnFocus = null;
|
|
2433
2505
|
outside;
|
|
2506
|
+
model = EMPTY_MENU_STATE;
|
|
2507
|
+
controlled = false;
|
|
2508
|
+
rows = [];
|
|
2509
|
+
active = -1;
|
|
2510
|
+
focused = false;
|
|
2511
|
+
query = "";
|
|
2512
|
+
queryTimer;
|
|
2513
|
+
markers = [];
|
|
2514
|
+
listening = false;
|
|
2515
|
+
signature = "";
|
|
2516
|
+
opener = null;
|
|
2434
2517
|
constructor() {
|
|
2435
2518
|
super();
|
|
2436
2519
|
const doc = this.ownerDocument;
|
|
@@ -2443,22 +2526,49 @@ var defineContextMenu = definer("office-ui-context-menu", () => {
|
|
|
2443
2526
|
this.panel.setAttribute("popover", "auto");
|
|
2444
2527
|
else this.panel.hidden = true;
|
|
2445
2528
|
this.panel.append(doc.createElement("slot"));
|
|
2446
|
-
|
|
2529
|
+
this.menu = doc.createElement("div");
|
|
2530
|
+
this.menu.className = "menu";
|
|
2531
|
+
this.menu.setAttribute("role", "menu");
|
|
2532
|
+
this.menu.setAttribute("aria-orientation", "vertical");
|
|
2533
|
+
this.menu.tabIndex = -1;
|
|
2534
|
+
this.menu.hidden = true;
|
|
2535
|
+
root.append(this.panel, this.menu);
|
|
2447
2536
|
this.panel.addEventListener("toggle", (event) => {
|
|
2448
2537
|
if (event.newState === "closed") this.closed(false);
|
|
2449
2538
|
});
|
|
2450
|
-
this.panel.addEventListener("keydown", (event) => this.
|
|
2539
|
+
this.panel.addEventListener("keydown", (event) => this.onChildKey(event));
|
|
2540
|
+
this.menu.addEventListener("keydown", (event) => this.onRowKey(event));
|
|
2541
|
+
this.menu.addEventListener("pointerover", (event) => {
|
|
2542
|
+
const row = event.target?.closest("button");
|
|
2543
|
+
const index = row ? this.rows.indexOf(row) : -1;
|
|
2544
|
+
if (index >= 0 && !row?.disabled && index !== this.active) this.focusRow(index);
|
|
2545
|
+
});
|
|
2546
|
+
this.menu.addEventListener("contextmenu", (event) => event.preventDefault());
|
|
2451
2547
|
this.addEventListener("office-command", () => this.close());
|
|
2452
2548
|
}
|
|
2453
2549
|
connectedCallback() {
|
|
2454
2550
|
this.panel.setAttribute("aria-label", this.getAttribute("label") ?? "Context menu");
|
|
2551
|
+
if (this.controlled) {
|
|
2552
|
+
this.opener = this.deepActive();
|
|
2553
|
+
this.render();
|
|
2554
|
+
}
|
|
2455
2555
|
}
|
|
2456
2556
|
attributeChangedCallback() {
|
|
2457
2557
|
this.panel.setAttribute("aria-label", this.getAttribute("label") ?? "Context menu");
|
|
2458
2558
|
}
|
|
2459
2559
|
disconnectedCallback() {
|
|
2460
2560
|
this.close();
|
|
2561
|
+
if (!this.controlled) return;
|
|
2562
|
+
this.stopListening();
|
|
2563
|
+
clearTimeout(this.queryTimer);
|
|
2564
|
+
this.focused = false;
|
|
2565
|
+
const opener = this.opener;
|
|
2566
|
+
this.opener = null;
|
|
2567
|
+
const active = this.ownerDocument.activeElement;
|
|
2568
|
+
if (opener?.isConnected && (!active || active === this.ownerDocument.body))
|
|
2569
|
+
opener.focus({ preventScroll: true });
|
|
2461
2570
|
}
|
|
2571
|
+
// ---- Children mode ------------------------------------------------------------------
|
|
2462
2572
|
get open() {
|
|
2463
2573
|
return this.hasAttribute("data-open");
|
|
2464
2574
|
}
|
|
@@ -2481,12 +2591,17 @@ var defineContextMenu = definer("office-ui-context-menu", () => {
|
|
|
2481
2591
|
}
|
|
2482
2592
|
this.setAttribute("data-open", "");
|
|
2483
2593
|
const view = doc.defaultView;
|
|
2484
|
-
const
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2594
|
+
const { left, top } = clampFlyoutPosition({
|
|
2595
|
+
x,
|
|
2596
|
+
y,
|
|
2597
|
+
width: this.panel.offsetWidth,
|
|
2598
|
+
height: this.panel.offsetHeight,
|
|
2599
|
+
viewportWidth: view?.innerWidth ?? x,
|
|
2600
|
+
viewportHeight: view?.innerHeight ?? y,
|
|
2601
|
+
margin: 4
|
|
2602
|
+
});
|
|
2603
|
+
this.panel.style.left = `${Math.round(left)}px`;
|
|
2604
|
+
this.panel.style.top = `${Math.round(top)}px`;
|
|
2490
2605
|
this.items()[0]?.focus();
|
|
2491
2606
|
}
|
|
2492
2607
|
close() {
|
|
@@ -2507,7 +2622,7 @@ var defineContextMenu = definer("office-ui-context-menu", () => {
|
|
|
2507
2622
|
if (restoreFocus) this.returnFocus?.focus?.();
|
|
2508
2623
|
this.returnFocus = null;
|
|
2509
2624
|
}
|
|
2510
|
-
|
|
2625
|
+
onChildKey(event) {
|
|
2511
2626
|
const items = this.items();
|
|
2512
2627
|
const from = items.findIndex(
|
|
2513
2628
|
(item) => item === event.target || item.contains(event.target)
|
|
@@ -2523,8 +2638,217 @@ var defineContextMenu = definer("office-ui-context-menu", () => {
|
|
|
2523
2638
|
else if (event.key === "Escape" || event.key === "Tab") {
|
|
2524
2639
|
if (event.key === "Escape") event.preventDefault();
|
|
2525
2640
|
this.close();
|
|
2641
|
+
} else if (event.key.length === 1 && event.key !== " " && !event.ctrlKey && !event.metaKey && !event.altKey) {
|
|
2642
|
+
const labels = items.map((item) => ({
|
|
2643
|
+
label: item.getAttribute("label") ?? item.textContent ?? ""
|
|
2644
|
+
}));
|
|
2645
|
+
const target = this.typeAhead(labels, from, event.key);
|
|
2646
|
+
if (target >= 0) move(target);
|
|
2526
2647
|
}
|
|
2527
2648
|
}
|
|
2649
|
+
// ---- Controlled mode ----------------------------------------------------------------
|
|
2650
|
+
get state() {
|
|
2651
|
+
return this.model;
|
|
2652
|
+
}
|
|
2653
|
+
set state(value) {
|
|
2654
|
+
const signature = JSON.stringify(value);
|
|
2655
|
+
this.model = value;
|
|
2656
|
+
if (!this.controlled) {
|
|
2657
|
+
this.controlled = true;
|
|
2658
|
+
this.toggleAttribute("data-controlled", true);
|
|
2659
|
+
this.panel.remove();
|
|
2660
|
+
if (this.isConnected) this.opener = this.deepActive();
|
|
2661
|
+
}
|
|
2662
|
+
if (signature !== this.signature) {
|
|
2663
|
+
this.signature = signature;
|
|
2664
|
+
this.render();
|
|
2665
|
+
}
|
|
2666
|
+
}
|
|
2667
|
+
config() {
|
|
2668
|
+
return this.constructor;
|
|
2669
|
+
}
|
|
2670
|
+
deepActive() {
|
|
2671
|
+
let node = this.ownerDocument.activeElement;
|
|
2672
|
+
while (node?.shadowRoot?.activeElement) node = node.shadowRoot.activeElement;
|
|
2673
|
+
return node instanceof HTMLElement && node !== this.ownerDocument.body ? node : null;
|
|
2674
|
+
}
|
|
2675
|
+
render() {
|
|
2676
|
+
const state = this.model;
|
|
2677
|
+
const items = state.items;
|
|
2678
|
+
this.hidden = items.length === 0;
|
|
2679
|
+
this.menu.hidden = items.length === 0;
|
|
2680
|
+
this.applyMarkers(state.markers ?? []);
|
|
2681
|
+
if (state.zIndex !== void 0) this.style.zIndex = String(state.zIndex);
|
|
2682
|
+
else this.style.removeProperty("z-index");
|
|
2683
|
+
const same = items[this.active];
|
|
2684
|
+
this.active = same && !same.disabled ? this.active : nextEnabledIndex(items, -1, 1);
|
|
2685
|
+
this.renderRows();
|
|
2686
|
+
if (items.length === 0) {
|
|
2687
|
+
this.stopListening();
|
|
2688
|
+
this.focused = false;
|
|
2689
|
+
}
|
|
2690
|
+
if (!this.isConnected || items.length === 0) return;
|
|
2691
|
+
this.place();
|
|
2692
|
+
this.listen();
|
|
2693
|
+
if (!this.focused && state.autoFocus !== false) {
|
|
2694
|
+
this.focused = true;
|
|
2695
|
+
this.focusRow(nextEnabledIndex(items, -1, 1));
|
|
2696
|
+
} else if (this.focused && this.active >= 0)
|
|
2697
|
+
this.rows[this.active]?.focus({ preventScroll: true });
|
|
2698
|
+
}
|
|
2699
|
+
renderRows() {
|
|
2700
|
+
const doc = this.ownerDocument;
|
|
2701
|
+
const state = this.model;
|
|
2702
|
+
this.menu.setAttribute("aria-label", state.label);
|
|
2703
|
+
this.rows = [];
|
|
2704
|
+
let container = this.menu;
|
|
2705
|
+
const nodes = [];
|
|
2706
|
+
const place = (node) => container === this.menu ? nodes.push(node) : container.append(node);
|
|
2707
|
+
state.items.forEach((item, index) => {
|
|
2708
|
+
if (item.separatorBefore || item.heading) container = this.menu;
|
|
2709
|
+
if (item.separatorBefore) {
|
|
2710
|
+
const rule = doc.createElement("div");
|
|
2711
|
+
rule.className = "separator";
|
|
2712
|
+
rule.setAttribute("role", "separator");
|
|
2713
|
+
place(rule);
|
|
2714
|
+
}
|
|
2715
|
+
if (item.heading) {
|
|
2716
|
+
const group = doc.createElement("div");
|
|
2717
|
+
group.setAttribute("role", "group");
|
|
2718
|
+
group.setAttribute("aria-label", item.heading);
|
|
2719
|
+
const title = doc.createElement("div");
|
|
2720
|
+
title.className = "heading";
|
|
2721
|
+
title.setAttribute("aria-hidden", "true");
|
|
2722
|
+
title.textContent = item.heading;
|
|
2723
|
+
group.append(title);
|
|
2724
|
+
place(group);
|
|
2725
|
+
container = group;
|
|
2726
|
+
}
|
|
2727
|
+
const row = doc.createElement("button");
|
|
2728
|
+
row.type = "button";
|
|
2729
|
+
row.className = item.danger ? "item danger" : "item";
|
|
2730
|
+
row.dataset.itemId = item.id;
|
|
2731
|
+
row.setAttribute("role", item.checked === void 0 ? "menuitem" : "menuitemcheckbox");
|
|
2732
|
+
if (item.checked !== void 0) {
|
|
2733
|
+
row.setAttribute("aria-checked", String(item.checked));
|
|
2734
|
+
const check = doc.createElement("span");
|
|
2735
|
+
check.className = "check";
|
|
2736
|
+
check.setAttribute("aria-hidden", "true");
|
|
2737
|
+
check.textContent = item.checked ? "\u2713" : "";
|
|
2738
|
+
row.append(check);
|
|
2739
|
+
}
|
|
2740
|
+
if (item.icon) {
|
|
2741
|
+
const glyph = createIconSvg(doc);
|
|
2742
|
+
paintIcon(glyph, item.icon);
|
|
2743
|
+
row.append(glyph);
|
|
2744
|
+
}
|
|
2745
|
+
row.append(doc.createTextNode(item.label));
|
|
2746
|
+
row.tabIndex = index === this.active ? 0 : -1;
|
|
2747
|
+
if (item.disabled) {
|
|
2748
|
+
row.disabled = true;
|
|
2749
|
+
row.setAttribute("aria-disabled", "true");
|
|
2750
|
+
}
|
|
2751
|
+
row.addEventListener(
|
|
2752
|
+
"click",
|
|
2753
|
+
() => this.dispatchEvent(
|
|
2754
|
+
new CustomEvent(this.config().requestEvent, {
|
|
2755
|
+
detail: { id: item.id },
|
|
2756
|
+
bubbles: true,
|
|
2757
|
+
composed: true
|
|
2758
|
+
})
|
|
2759
|
+
)
|
|
2760
|
+
);
|
|
2761
|
+
this.rows.push(row);
|
|
2762
|
+
place(row);
|
|
2763
|
+
});
|
|
2764
|
+
this.menu.replaceChildren(...nodes);
|
|
2765
|
+
}
|
|
2766
|
+
applyMarkers(next) {
|
|
2767
|
+
for (const name of this.markers) this.removeAttribute(name);
|
|
2768
|
+
const pattern = this.config().markerPattern;
|
|
2769
|
+
this.markers = next.filter((name) => pattern.test(name));
|
|
2770
|
+
for (const name of this.markers) this.setAttribute(name, "true");
|
|
2771
|
+
}
|
|
2772
|
+
place() {
|
|
2773
|
+
const view = this.ownerDocument.defaultView;
|
|
2774
|
+
this.style.left = `${this.model.x}px`;
|
|
2775
|
+
this.style.top = `${this.model.y}px`;
|
|
2776
|
+
const box = this.getBoundingClientRect();
|
|
2777
|
+
const { left, top } = clampFlyoutPosition({
|
|
2778
|
+
x: this.model.x,
|
|
2779
|
+
y: this.model.y,
|
|
2780
|
+
width: box.width,
|
|
2781
|
+
height: box.height,
|
|
2782
|
+
viewportWidth: view?.innerWidth ?? box.right,
|
|
2783
|
+
viewportHeight: view?.innerHeight ?? box.bottom
|
|
2784
|
+
});
|
|
2785
|
+
this.style.left = `${left}px`;
|
|
2786
|
+
this.style.top = `${top}px`;
|
|
2787
|
+
}
|
|
2788
|
+
focusRow(index) {
|
|
2789
|
+
if (index < 0) return;
|
|
2790
|
+
this.active = index;
|
|
2791
|
+
this.rows.forEach((row, at) => row.tabIndex = at === index ? 0 : -1);
|
|
2792
|
+
this.rows[index]?.focus({ preventScroll: true });
|
|
2793
|
+
}
|
|
2794
|
+
typeAhead(items, from, key) {
|
|
2795
|
+
this.query += key;
|
|
2796
|
+
clearTimeout(this.queryTimer);
|
|
2797
|
+
this.queryTimer = setTimeout(() => this.query = "", TYPE_AHEAD_MS);
|
|
2798
|
+
return typeAheadIndex(items, from, this.query);
|
|
2799
|
+
}
|
|
2800
|
+
onRowKey(event) {
|
|
2801
|
+
const items = this.model.items;
|
|
2802
|
+
let target = -2;
|
|
2803
|
+
if (event.key === "ArrowDown") target = nextEnabledIndex(items, this.active, 1);
|
|
2804
|
+
else if (event.key === "ArrowUp") target = nextEnabledIndex(items, this.active, -1);
|
|
2805
|
+
else if (event.key === "Home") target = nextEnabledIndex(items, -1, 1);
|
|
2806
|
+
else if (event.key === "End") target = nextEnabledIndex(items, items.length, -1);
|
|
2807
|
+
else if (event.key.length === 1 && event.key !== " " && !event.ctrlKey && !event.metaKey && !event.altKey)
|
|
2808
|
+
target = this.typeAhead(items, this.active, event.key);
|
|
2809
|
+
if (target === -2) return;
|
|
2810
|
+
event.preventDefault();
|
|
2811
|
+
this.focusRow(target);
|
|
2812
|
+
}
|
|
2813
|
+
dismiss(reason) {
|
|
2814
|
+
this.dispatchEvent(
|
|
2815
|
+
new CustomEvent(this.config().closeEvent, {
|
|
2816
|
+
detail: { reason },
|
|
2817
|
+
bubbles: true,
|
|
2818
|
+
composed: true
|
|
2819
|
+
})
|
|
2820
|
+
);
|
|
2821
|
+
}
|
|
2822
|
+
onDocumentKey = (event) => {
|
|
2823
|
+
if (openMenus.get(this.ownerDocument)?.at(-1) !== this) return;
|
|
2824
|
+
if (event.key === "Escape") {
|
|
2825
|
+
event.preventDefault();
|
|
2826
|
+
event.stopPropagation();
|
|
2827
|
+
this.dismiss("escape");
|
|
2828
|
+
} else if (event.key === "Tab") this.dismiss("tab");
|
|
2829
|
+
};
|
|
2830
|
+
onDocumentPointer = (event) => {
|
|
2831
|
+
if (!event.composedPath().includes(this)) this.dismiss("outside");
|
|
2832
|
+
};
|
|
2833
|
+
listen() {
|
|
2834
|
+
if (this.listening) return;
|
|
2835
|
+
this.listening = true;
|
|
2836
|
+
const doc = this.ownerDocument;
|
|
2837
|
+
openMenus.set(doc, [...openMenus.get(doc) ?? [], this]);
|
|
2838
|
+
doc.addEventListener("keydown", this.onDocumentKey, true);
|
|
2839
|
+
doc.addEventListener("pointerdown", this.onDocumentPointer, true);
|
|
2840
|
+
}
|
|
2841
|
+
stopListening() {
|
|
2842
|
+
if (!this.listening) return;
|
|
2843
|
+
this.listening = false;
|
|
2844
|
+
const doc = this.ownerDocument;
|
|
2845
|
+
openMenus.set(
|
|
2846
|
+
doc,
|
|
2847
|
+
(openMenus.get(doc) ?? []).filter((menu) => menu !== this)
|
|
2848
|
+
);
|
|
2849
|
+
doc.removeEventListener("keydown", this.onDocumentKey, true);
|
|
2850
|
+
doc.removeEventListener("pointerdown", this.onDocumentPointer, true);
|
|
2851
|
+
}
|
|
2528
2852
|
}
|
|
2529
2853
|
return OfficeUiContextMenu;
|
|
2530
2854
|
});
|
|
@@ -4442,4 +4766,4 @@ function registerControls(registry) {
|
|
|
4442
4766
|
for (const define of CONTROL_DEFINERS) define(registry);
|
|
4443
4767
|
}
|
|
4444
4768
|
|
|
4445
|
-
export { CONTROL_DEFINERS, DEFAULT_OFFICE_PROFILE, OFFICE_AVATAR_SWATCHES, OFFICE_PROFILE_STORAGE_KEY, OFFICE_TOAST_VISIBLE_LIMIT, attachKeyTips, 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, defineToasts, defineToolbar, defineZoomSlider, profileInitials, readOfficeProfile, registerControls, rulerDivisions, sanitizeOfficeProfile, writeOfficeProfile };
|
|
4769
|
+
export { CONTROL_DEFINERS, DEFAULT_OFFICE_PROFILE, EMPTY_MENU_STATE, OFFICE_AVATAR_SWATCHES, OFFICE_PROFILE_STORAGE_KEY, 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, defineToasts, defineToolbar, defineZoomSlider, nextEnabledIndex, profileInitials, readOfficeProfile, registerControls, rulerDivisions, sanitizeOfficeProfile, typeAheadIndex, writeOfficeProfile };
|
package/dist/context-menu.d.ts
CHANGED
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
/** A `role="separator"` rule between groups of menu items. */
|
|
2
2
|
export declare const defineMenuSeparator: import("./registry.js").Definer;
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* an item closes the menu and its `office-command` bubbles to the host.
|
|
4
|
+
* Office's right-click menu, in two modes sharing keyboard, type-ahead and dismissal:
|
|
5
|
+
*
|
|
6
|
+
* - **Children** (self-managed): `office-ui-menu-item` and `office-ui-menu-separator` children.
|
|
7
|
+
* `openAt(x, y)` shows it in the popover top layer, kept inside the viewport; `close()` hides it.
|
|
8
|
+
* Choosing an item closes the menu and its `office-command` bubbles to the host.
|
|
9
|
+
* - **Controlled** (moved from pptx-viewer `pptx-ui-context-menu`): set `state`
|
|
10
|
+
* (`{ x, y, label, items: [{ id, label, separatorBefore?, heading?, danger?, disabled?,
|
|
11
|
+
* checked?, icon? }], markers?, zIndex?, autoFocus? }`). The host is the fixed box at the
|
|
12
|
+
* pointer, clamped into the window. It emits `office-menu-request` `{ id }` when a row is chosen
|
|
13
|
+
* and `office-menu-close` `{ reason: 'escape' | 'outside' | 'tab' }` when dismissed, and never
|
|
14
|
+
* closes itself: the host removes it or clears its items. While open it takes focus on the first
|
|
15
|
+
* enabled row and returns focus to the opener when it goes away, unless something else took it.
|
|
16
|
+
*
|
|
17
|
+
* Arrow keys, Home, End and type-ahead (repeating a letter cycles) move between enabled rows.
|
|
18
|
+
* Static `requestEvent`, `closeEvent` and `markerPattern` let a product keep its published names.
|
|
9
19
|
*/
|
|
10
20
|
export declare const defineContextMenu: import("./registry.js").Definer;
|
package/dist/controls.d.ts
CHANGED
|
@@ -35,6 +35,7 @@ export type { OfficeFindInputEvent, OfficeFindStepEvent } from './find-bar.js';
|
|
|
35
35
|
export type { OfficePrintPreviewPageEvent } from './print-preview.js';
|
|
36
36
|
export type { OfficeRibbonSelectEvent } from './ribbon-tabs.js';
|
|
37
37
|
export { rulerDivisions } from './ruler.js';
|
|
38
|
+
export { clampFlyoutPosition, EMPTY_MENU_STATE, nextEnabledIndex, typeAheadIndex, type FlyoutPositionInput, type OfficeMenuCloseReason, type OfficeMenuItem, type OfficeMenuState, } from './menu-model.js';
|
|
38
39
|
export { OFFICE_TOAST_VISIBLE_LIMIT, type OfficeDialogFooterAction, type OfficeDialogFooterState, type OfficeDialogFooterVariant, type OfficeToast, type OfficeToastsState, } from './chrome-controls.js';
|
|
39
40
|
export type { OfficePasteOption, OfficePasteOptionsState, OfficeReadOnlyBannerIntent, OfficeReadOnlyBannerState, } from './document-notices.js';
|
|
40
41
|
export { clearOfficeProfile, DEFAULT_OFFICE_PROFILE, OFFICE_AVATAR_SWATCHES, OFFICE_PROFILE_STORAGE_KEY, profileInitials, readOfficeProfile, sanitizeOfficeProfile, writeOfficeProfile, type OfficeProfile, type OfficeProfileChangeEvent, } from './account.js';
|
package/dist/controls.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { CONTROL_DEFINERS, DEFAULT_OFFICE_PROFILE, OFFICE_AVATAR_SWATCHES, OFFICE_PROFILE_STORAGE_KEY, OFFICE_TOAST_VISIBLE_LIMIT, attachKeyTips, 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, defineToasts, defineToolbar, defineZoomSlider, profileInitials, readOfficeProfile, registerControls, rulerDivisions, sanitizeOfficeProfile, writeOfficeProfile } from './chunk-
|
|
1
|
+
export { CONTROL_DEFINERS, DEFAULT_OFFICE_PROFILE, EMPTY_MENU_STATE, OFFICE_AVATAR_SWATCHES, OFFICE_PROFILE_STORAGE_KEY, 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, defineToasts, defineToolbar, defineZoomSlider, nextEnabledIndex, profileInitials, readOfficeProfile, registerControls, rulerDivisions, sanitizeOfficeProfile, typeAheadIndex, writeOfficeProfile } from './chunk-G2ZIAXOV.js';
|
|
2
2
|
export { defineIcon } from './chunk-VUXNXH4Q.js';
|
|
3
3
|
import './chunk-VYF7LGXZ.js';
|
|
4
4
|
import './chunk-NDEB6EBU.js';
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { installOfficeUiTheme } from './chunk-F4TM7U4P.js';
|
|
2
2
|
export { THEME_CSS, THEME_STYLE_ID, installOfficeUiTheme } from './chunk-F4TM7U4P.js';
|
|
3
|
-
import { registerControls } from './chunk-
|
|
4
|
-
export { CONTROL_DEFINERS, DEFAULT_OFFICE_PROFILE, OFFICE_AVATAR_SWATCHES, OFFICE_PROFILE_STORAGE_KEY, OFFICE_TOAST_VISIBLE_LIMIT, attachKeyTips, 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, defineToasts, defineToolbar, defineZoomSlider, profileInitials, readOfficeProfile, registerControls, rulerDivisions, sanitizeOfficeProfile, writeOfficeProfile } from './chunk-
|
|
3
|
+
import { registerControls } from './chunk-G2ZIAXOV.js';
|
|
4
|
+
export { CONTROL_DEFINERS, DEFAULT_OFFICE_PROFILE, EMPTY_MENU_STATE, OFFICE_AVATAR_SWATCHES, OFFICE_PROFILE_STORAGE_KEY, 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, defineToasts, defineToolbar, defineZoomSlider, nextEnabledIndex, profileInitials, readOfficeProfile, registerControls, rulerDivisions, sanitizeOfficeProfile, typeAheadIndex, writeOfficeProfile } from './chunk-G2ZIAXOV.js';
|
|
5
5
|
export { ICON_CSS, createIconSvg, defineIcon, getIcon, listIcons, paintIcon, registerIcon } from './chunk-VUXNXH4Q.js';
|
|
6
6
|
import { definePresence } from './chunk-VYF7LGXZ.js';
|
|
7
7
|
export { definePresence, initialsOf, participantsFromAwareness } from './chunk-VYF7LGXZ.js';
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Menu data and the pure helpers both menu modes share. Moved from pptx-viewer
|
|
3
|
+
* (`web-components/context-menu-model.ts`, `render/flyout-position.ts`).
|
|
4
|
+
*/
|
|
5
|
+
/** One row of a controlled menu. Hosts decide `id`, wording, gating and what activation does. */
|
|
6
|
+
export interface OfficeMenuItem {
|
|
7
|
+
/** Stable command id, echoed by the request event. */
|
|
8
|
+
id: string;
|
|
9
|
+
/** Translated visible label. */
|
|
10
|
+
label: string;
|
|
11
|
+
/** Draw a rule before this row. */
|
|
12
|
+
separatorBefore?: boolean;
|
|
13
|
+
/** Group heading shown before this row; the row and the ones after it join that group. */
|
|
14
|
+
heading?: string;
|
|
15
|
+
/** Destructive command (Delete): tinted. */
|
|
16
|
+
danger?: boolean;
|
|
17
|
+
/** Offered but unavailable: announced and drawn dim, skipped by the arrow keys. */
|
|
18
|
+
disabled?: boolean;
|
|
19
|
+
/** A toggle (Grid, Ruler) in this state; omitted for one-shot commands. */
|
|
20
|
+
checked?: boolean;
|
|
21
|
+
/** A registered icon drawn before the label. */
|
|
22
|
+
icon?: string;
|
|
23
|
+
}
|
|
24
|
+
/** Everything a controlled menu needs to draw. */
|
|
25
|
+
export interface OfficeMenuState {
|
|
26
|
+
/** Pointer position, in viewport pixels; the menu clamps itself into the window. */
|
|
27
|
+
x: number;
|
|
28
|
+
y: number;
|
|
29
|
+
/** Accessible name. */
|
|
30
|
+
label: string;
|
|
31
|
+
items: readonly OfficeMenuItem[];
|
|
32
|
+
/** Test-hook attributes copied onto the host (names matching the element's `markerPattern`). */
|
|
33
|
+
markers?: readonly string[];
|
|
34
|
+
/** Stacking order; the `--office-z-popover` token applies when omitted. */
|
|
35
|
+
zIndex?: number;
|
|
36
|
+
/** Move focus onto the first enabled command on open. Default true. */
|
|
37
|
+
autoFocus?: boolean;
|
|
38
|
+
}
|
|
39
|
+
export type OfficeMenuCloseReason = 'escape' | 'outside' | 'tab';
|
|
40
|
+
export declare const EMPTY_MENU_STATE: OfficeMenuState;
|
|
41
|
+
/** Index of the next enabled row from `from` in `step` direction, wrapping; -1 if none. */
|
|
42
|
+
export declare function nextEnabledIndex(items: readonly {
|
|
43
|
+
disabled?: boolean;
|
|
44
|
+
}[], from: number, step: 1 | -1): number;
|
|
45
|
+
/**
|
|
46
|
+
* Type-ahead target: the next enabled row after `from` whose label starts with `query`.
|
|
47
|
+
* Repeating one character cycles through the rows that start with it.
|
|
48
|
+
*/
|
|
49
|
+
export declare function typeAheadIndex(items: readonly {
|
|
50
|
+
label: string;
|
|
51
|
+
disabled?: boolean;
|
|
52
|
+
}[], from: number, query: string): number;
|
|
53
|
+
/** Where a flyout wants to sit, how big it is, and what it must fit inside. */
|
|
54
|
+
export interface FlyoutPositionInput {
|
|
55
|
+
/** Anchor point in viewport coordinates (a pointer event's clientX/Y). */
|
|
56
|
+
x: number;
|
|
57
|
+
y: number;
|
|
58
|
+
/** Measured size; zero means "not measured yet". */
|
|
59
|
+
width: number;
|
|
60
|
+
height: number;
|
|
61
|
+
/** The box it must stay inside, normally the window's inner size. */
|
|
62
|
+
viewportWidth: number;
|
|
63
|
+
viewportHeight: number;
|
|
64
|
+
/** Gap kept from every edge, in px. Default 8. */
|
|
65
|
+
margin?: number;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* The top-left corner keeping a pointer-anchored flyout fully on screen. Flips inwards at the
|
|
69
|
+
* right and bottom edges, as desktop menus do, and never returns a negative coordinate, so a
|
|
70
|
+
* flyout larger than the viewport stays reachable from the top.
|
|
71
|
+
*/
|
|
72
|
+
export declare function clampFlyoutPosition(input: FlyoutPositionInput): {
|
|
73
|
+
left: number;
|
|
74
|
+
top: number;
|
|
75
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ooxml-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.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",
|
|
@@ -35,27 +35,33 @@
|
|
|
35
35
|
"exports": {
|
|
36
36
|
".": {
|
|
37
37
|
"types": "./dist/index.d.ts",
|
|
38
|
-
"import": "./dist/index.js"
|
|
38
|
+
"import": "./dist/index.js",
|
|
39
|
+
"default": "./dist/index.js"
|
|
39
40
|
},
|
|
40
41
|
"./theme": {
|
|
41
42
|
"types": "./dist/theme.d.ts",
|
|
42
|
-
"import": "./dist/theme.js"
|
|
43
|
+
"import": "./dist/theme.js",
|
|
44
|
+
"default": "./dist/theme.js"
|
|
43
45
|
},
|
|
44
46
|
"./icons": {
|
|
45
47
|
"types": "./dist/icons.d.ts",
|
|
46
|
-
"import": "./dist/icons.js"
|
|
48
|
+
"import": "./dist/icons.js",
|
|
49
|
+
"default": "./dist/icons.js"
|
|
47
50
|
},
|
|
48
51
|
"./controls": {
|
|
49
52
|
"types": "./dist/controls.d.ts",
|
|
50
|
-
"import": "./dist/controls.js"
|
|
53
|
+
"import": "./dist/controls.js",
|
|
54
|
+
"default": "./dist/controls.js"
|
|
51
55
|
},
|
|
52
56
|
"./presence": {
|
|
53
57
|
"types": "./dist/presence.d.ts",
|
|
54
|
-
"import": "./dist/presence.js"
|
|
58
|
+
"import": "./dist/presence.js",
|
|
59
|
+
"default": "./dist/presence.js"
|
|
55
60
|
},
|
|
56
61
|
"./smartart": {
|
|
57
62
|
"types": "./dist/smartart.d.ts",
|
|
58
|
-
"import": "./dist/smartart.js"
|
|
63
|
+
"import": "./dist/smartart.js",
|
|
64
|
+
"default": "./dist/smartart.js"
|
|
59
65
|
},
|
|
60
66
|
"./package.json": "./package.json"
|
|
61
67
|
},
|