ooxml-ui 0.15.0 → 0.16.1
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-2XJDHLPW.js} +418 -90
- 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) => {
|
|
@@ -1841,8 +1845,8 @@ var defineButton = definer("office-ui-button", () => {
|
|
|
1841
1845
|
button;
|
|
1842
1846
|
svg;
|
|
1843
1847
|
text;
|
|
1844
|
-
caret;
|
|
1845
|
-
badge;
|
|
1848
|
+
#caret;
|
|
1849
|
+
#badge;
|
|
1846
1850
|
constructor() {
|
|
1847
1851
|
super();
|
|
1848
1852
|
const doc = this.ownerDocument;
|
|
@@ -1855,13 +1859,13 @@ var defineButton = definer("office-ui-button", () => {
|
|
|
1855
1859
|
this.svg.classList.add("glyph");
|
|
1856
1860
|
this.text = doc.createElement("span");
|
|
1857
1861
|
this.text.className = "label";
|
|
1858
|
-
this
|
|
1859
|
-
this
|
|
1860
|
-
paintIcon(this
|
|
1861
|
-
this
|
|
1862
|
-
this
|
|
1863
|
-
this
|
|
1864
|
-
this.button.append(this.svg, this.text, this
|
|
1862
|
+
this.#caret = createIconSvg(doc);
|
|
1863
|
+
this.#caret.classList.add("caret");
|
|
1864
|
+
paintIcon(this.#caret, "chevronDown");
|
|
1865
|
+
this.#badge = doc.createElement("span");
|
|
1866
|
+
this.#badge.className = "badge";
|
|
1867
|
+
this.#badge.setAttribute("aria-hidden", "true");
|
|
1868
|
+
this.button.append(this.svg, this.text, this.#badge);
|
|
1865
1869
|
root.append(this.button);
|
|
1866
1870
|
this.button.addEventListener("keydown", (event) => {
|
|
1867
1871
|
if ((event.key === " " || event.key === "Enter") && !event.ctrlKey && !event.metaKey && !event.altKey)
|
|
@@ -1904,6 +1908,10 @@ var defineButton = definer("office-ui-button", () => {
|
|
|
1904
1908
|
iconName() {
|
|
1905
1909
|
return this.getAttribute("icon");
|
|
1906
1910
|
}
|
|
1911
|
+
/** The tooltip: `title`, else the label of an icon-only button; a product may always show it. */
|
|
1912
|
+
tooltip(label, iconOnly) {
|
|
1913
|
+
return this.getAttribute("title") ?? (iconOnly ? label : "");
|
|
1914
|
+
}
|
|
1907
1915
|
/** Whether the trailing menu chevron shows. */
|
|
1908
1916
|
showsCaret() {
|
|
1909
1917
|
const caret = this.getAttribute("caret");
|
|
@@ -1913,20 +1921,20 @@ var defineButton = definer("office-ui-button", () => {
|
|
|
1913
1921
|
const label = this.getAttribute("label") ?? "";
|
|
1914
1922
|
const iconOnly = this.hasAttribute("icon-only");
|
|
1915
1923
|
this.text.textContent = label;
|
|
1916
|
-
this.text.append(this
|
|
1917
|
-
this
|
|
1924
|
+
this.text.append(this.#caret);
|
|
1925
|
+
this.#caret.toggleAttribute("hidden", !this.showsCaret());
|
|
1918
1926
|
this.text.hidden = iconOnly;
|
|
1919
1927
|
if (iconOnly && label) this.button.setAttribute("aria-label", label);
|
|
1920
1928
|
else this.button.removeAttribute("aria-label");
|
|
1921
|
-
this.button.title = this.
|
|
1929
|
+
this.button.title = this.tooltip(label, iconOnly);
|
|
1922
1930
|
this.button.disabled = this.disabled;
|
|
1923
1931
|
const shortcuts = this.getAttribute("keyshortcuts");
|
|
1924
1932
|
if (shortcuts) this.button.setAttribute("aria-keyshortcuts", shortcuts);
|
|
1925
1933
|
else this.button.removeAttribute("aria-keyshortcuts");
|
|
1926
1934
|
if (paintIcon(this.svg, this.iconName())) this.svg.setAttribute("data-painted", "");
|
|
1927
1935
|
else this.svg.removeAttribute("data-painted");
|
|
1928
|
-
this
|
|
1929
|
-
this
|
|
1936
|
+
this.#badge.textContent = this.getAttribute("badge") ?? "";
|
|
1937
|
+
this.#badge.hidden = !this.#badge.textContent;
|
|
1930
1938
|
for (const attr of ["pressed", "expanded"]) {
|
|
1931
1939
|
const value = this.getAttribute(attr);
|
|
1932
1940
|
if (value === null) this.button.removeAttribute(`aria-${attr}`);
|
|
@@ -2091,7 +2099,7 @@ var defineDialog = definer("office-ui-dialog", () => {
|
|
|
2091
2099
|
class OfficeUiDialog extends HTMLElement {
|
|
2092
2100
|
static observedAttributes = ["open", "heading"];
|
|
2093
2101
|
box;
|
|
2094
|
-
heading;
|
|
2102
|
+
#heading;
|
|
2095
2103
|
closeButton;
|
|
2096
2104
|
footer;
|
|
2097
2105
|
returnFocus = null;
|
|
@@ -2108,8 +2116,8 @@ var defineDialog = definer("office-ui-dialog", () => {
|
|
|
2108
2116
|
this.box.setAttribute("aria-modal", "true");
|
|
2109
2117
|
this.box.tabIndex = -1;
|
|
2110
2118
|
const header = doc.createElement("header");
|
|
2111
|
-
this
|
|
2112
|
-
this
|
|
2119
|
+
this.#heading = doc.createElement("h2");
|
|
2120
|
+
this.#heading.id = "title";
|
|
2113
2121
|
this.box.setAttribute("aria-labelledby", "title");
|
|
2114
2122
|
this.closeButton = doc.createElement("button");
|
|
2115
2123
|
this.closeButton.type = "button";
|
|
@@ -2118,7 +2126,7 @@ var defineDialog = definer("office-ui-dialog", () => {
|
|
|
2118
2126
|
const icon2 = createIconSvg(doc);
|
|
2119
2127
|
paintIcon(icon2, "close");
|
|
2120
2128
|
this.closeButton.append(icon2);
|
|
2121
|
-
header.append(this
|
|
2129
|
+
header.append(this.#heading, this.closeButton);
|
|
2122
2130
|
const body = doc.createElement("div");
|
|
2123
2131
|
body.className = "body";
|
|
2124
2132
|
body.append(doc.createElement("slot"));
|
|
@@ -2133,14 +2141,14 @@ var defineDialog = definer("office-ui-dialog", () => {
|
|
|
2133
2141
|
this.addEventListener("keydown", (event) => this.onKey(event));
|
|
2134
2142
|
}
|
|
2135
2143
|
attributeChangedCallback(name, old, value) {
|
|
2136
|
-
if (name === "heading") this
|
|
2144
|
+
if (name === "heading") this.#heading.textContent = value ?? "";
|
|
2137
2145
|
if (name === "open" && old === null !== (value === null)) {
|
|
2138
2146
|
if (value !== null) this.onOpen();
|
|
2139
2147
|
else this.onClose();
|
|
2140
2148
|
}
|
|
2141
2149
|
}
|
|
2142
2150
|
connectedCallback() {
|
|
2143
|
-
this
|
|
2151
|
+
this.#heading.textContent = this.getAttribute("heading") ?? "";
|
|
2144
2152
|
if (this.open) this.onOpen();
|
|
2145
2153
|
}
|
|
2146
2154
|
get open() {
|
|
@@ -2398,21 +2406,85 @@ var defineCommandSearch = definer("office-ui-command-search", () => {
|
|
|
2398
2406
|
return OfficeUiCommandSearch;
|
|
2399
2407
|
});
|
|
2400
2408
|
|
|
2409
|
+
// src/menu-model.ts
|
|
2410
|
+
var EMPTY_MENU_STATE = { x: 0, y: 0, label: "", items: [] };
|
|
2411
|
+
function nextEnabledIndex(items, from, step) {
|
|
2412
|
+
const count = items.length;
|
|
2413
|
+
for (let offset = 1; offset <= count; offset += 1) {
|
|
2414
|
+
const index = ((from + step * offset) % count + count) % count;
|
|
2415
|
+
if (!items[index]?.disabled) return index;
|
|
2416
|
+
}
|
|
2417
|
+
return -1;
|
|
2418
|
+
}
|
|
2419
|
+
function typeAheadIndex(items, from, query) {
|
|
2420
|
+
const needle = query.toLowerCase();
|
|
2421
|
+
const cycling = [...needle].every((char) => char === needle[0]);
|
|
2422
|
+
const prefix = cycling ? needle[0] : needle;
|
|
2423
|
+
for (let offset = cycling ? 1 : 0; offset <= items.length; offset += 1) {
|
|
2424
|
+
const index = (from + offset + items.length) % items.length;
|
|
2425
|
+
const item = items[index];
|
|
2426
|
+
if (item && !item.disabled && item.label.trim().toLowerCase().startsWith(prefix ?? ""))
|
|
2427
|
+
return index;
|
|
2428
|
+
}
|
|
2429
|
+
return -1;
|
|
2430
|
+
}
|
|
2431
|
+
function clampFlyoutPosition(input) {
|
|
2432
|
+
const margin = input.margin ?? 8;
|
|
2433
|
+
const maxLeft = input.viewportWidth - input.width - margin;
|
|
2434
|
+
const maxTop = input.viewportHeight - input.height - margin;
|
|
2435
|
+
return {
|
|
2436
|
+
left: Math.max(margin, input.width > 0 ? Math.min(input.x, maxLeft) : input.x),
|
|
2437
|
+
top: Math.max(margin, input.height > 0 ? Math.min(input.y, maxTop) : input.y)
|
|
2438
|
+
};
|
|
2439
|
+
}
|
|
2440
|
+
|
|
2401
2441
|
// src/context-menu.ts
|
|
2402
2442
|
var CSS13 = `
|
|
2403
2443
|
:host { display: contents; }
|
|
2444
|
+
:host([data-controlled]) { display: block; position: fixed; z-index: ${tok("--office-z-popover")};
|
|
2445
|
+
color: ${tok("--office-popover-foreground")}; font: ${tok("--office-font-size-sm")}/${tok("--office-line-height")} ${tok("--office-font")}; }
|
|
2446
|
+
:host([data-controlled][hidden]) { display: none; }
|
|
2404
2447
|
.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
2448
|
background: ${tok("--office-background")}; color: ${tok("--office-foreground")};
|
|
2406
2449
|
border: ${tok("--office-border-width")} solid ${tok("--office-border")}; border-radius: ${tok("--office-radius")};
|
|
2407
2450
|
box-shadow: ${tok("--office-shadow")}; font-family: ${tok("--office-font")}; }
|
|
2408
2451
|
.panel[hidden] { display: none; }
|
|
2409
|
-
|
|
2452
|
+
/* Controlled mode: the host is the fixed box; rows are drawn here from \`state\`. */
|
|
2453
|
+
.menu { box-sizing: border-box; display: flex; flex-direction: column; min-width: ${tok("--office-menu-min-width")};
|
|
2454
|
+
max-height: calc(100vh - 2 * ${tok("--office-space-2")}); overflow-y: auto; padding: ${tok("--office-space-1-5")} 0;
|
|
2455
|
+
border: ${tok("--office-border-width")} solid ${tok("--office-border")}; border-radius: ${tok("--office-radius-md")};
|
|
2456
|
+
background: ${tok("--office-popover")}; color: inherit; box-shadow: ${tok("--office-shadow-lg")}; user-select: none; }
|
|
2457
|
+
.menu:focus { outline: none; }
|
|
2458
|
+
.item { box-sizing: border-box; display: flex; align-items: center; gap: ${tok("--office-space-1-5")}; width: 100%;
|
|
2459
|
+
min-height: ${tok("--office-field-height")}; padding: ${tok("--office-space-1-5")} ${tok("--office-space-3")}; border: 0;
|
|
2460
|
+
background: transparent; color: inherit; font: inherit; text-align: start; white-space: nowrap; cursor: pointer; }
|
|
2461
|
+
.item:hover:not(:disabled), .item:focus:not(:disabled) { background: ${tok("--office-selected")}; outline: none; }
|
|
2462
|
+
.item:focus-visible { outline: ${tok("--office-focus-width")} solid ${tok("--office-ring")}; outline-offset: calc(-1 * ${tok("--office-focus-width")}); }
|
|
2463
|
+
.item:disabled { opacity: .45; cursor: default; }
|
|
2464
|
+
.item.danger { color: ${tok("--office-danger")}; }
|
|
2465
|
+
.item svg { width: ${tok("--office-icon-size-md")}; height: ${tok("--office-icon-size-md")}; flex: none; fill: none; stroke: currentColor;
|
|
2466
|
+
stroke-width: ${tok("--office-icon-stroke")}; stroke-linecap: round; stroke-linejoin: round; }
|
|
2467
|
+
.check { flex: none; width: ${tok("--office-icon-size")}; text-align: center; }
|
|
2468
|
+
.separator { height: ${tok("--office-border-width")}; margin: ${tok("--office-space-1")} 0; background: ${tok("--office-border")}; }
|
|
2469
|
+
.heading { padding: ${tok("--office-space-1-5")} ${tok("--office-space-3")} ${tok("--office-space-0")}; color: ${tok("--office-muted-foreground")};
|
|
2470
|
+
font-size: ${tok("--office-font-size-2xs")}; font-weight: ${tok("--office-font-weight-bold")}; letter-spacing: .06em; text-transform: uppercase; }
|
|
2471
|
+
@media (pointer: coarse) { .item { min-height: ${tok("--office-target-size-touch")}; } }
|
|
2472
|
+
@media (forced-colors: active) {
|
|
2473
|
+
.panel, .menu { border-color: CanvasText; background: Canvas; color: CanvasText; box-shadow: none; }
|
|
2474
|
+
.item, .item.danger { color: CanvasText; }
|
|
2475
|
+
.item:disabled { color: GrayText; opacity: 1; }
|
|
2476
|
+
.item:hover:not(:disabled), .item:focus:not(:disabled) { background: Highlight; color: HighlightText; }
|
|
2477
|
+
.separator { background: CanvasText; }
|
|
2478
|
+
.heading { color: CanvasText; }
|
|
2479
|
+
}
|
|
2410
2480
|
`;
|
|
2411
2481
|
var SEPARATOR_CSS = `
|
|
2412
2482
|
:host { display: block; height: ${tok("--office-border-width")}; margin: ${tok("--office-space-1")} ${tok("--office-space-1-5")}; background: ${tok("--office-border")}; }
|
|
2413
2483
|
@media (forced-colors: active) { :host { background: CanvasText; } }
|
|
2414
2484
|
`;
|
|
2415
2485
|
var ITEMS = "office-ui-menu-item:not([disabled]):not([hidden])";
|
|
2486
|
+
var TYPE_AHEAD_MS = 700;
|
|
2487
|
+
var openMenus = /* @__PURE__ */ new WeakMap();
|
|
2416
2488
|
var defineMenuSeparator = definer("office-ui-menu-separator", () => {
|
|
2417
2489
|
class OfficeUiMenuSeparator extends HTMLElement {
|
|
2418
2490
|
constructor() {
|
|
@@ -2427,10 +2499,25 @@ var defineMenuSeparator = definer("office-ui-menu-separator", () => {
|
|
|
2427
2499
|
});
|
|
2428
2500
|
var defineContextMenu = definer("office-ui-context-menu", () => {
|
|
2429
2501
|
class OfficeUiContextMenu extends HTMLElement {
|
|
2502
|
+
static requestEvent = "office-menu-request";
|
|
2503
|
+
static closeEvent = "office-menu-close";
|
|
2504
|
+
static markerPattern = /^data-[a-z0-9-]+$/;
|
|
2430
2505
|
static observedAttributes = ["label"];
|
|
2431
2506
|
panel;
|
|
2507
|
+
menu;
|
|
2432
2508
|
returnFocus = null;
|
|
2433
2509
|
outside;
|
|
2510
|
+
model = EMPTY_MENU_STATE;
|
|
2511
|
+
controlled = false;
|
|
2512
|
+
rows = [];
|
|
2513
|
+
active = -1;
|
|
2514
|
+
focused = false;
|
|
2515
|
+
query = "";
|
|
2516
|
+
queryTimer;
|
|
2517
|
+
markers = [];
|
|
2518
|
+
listening = false;
|
|
2519
|
+
signature = "";
|
|
2520
|
+
opener = null;
|
|
2434
2521
|
constructor() {
|
|
2435
2522
|
super();
|
|
2436
2523
|
const doc = this.ownerDocument;
|
|
@@ -2443,22 +2530,49 @@ var defineContextMenu = definer("office-ui-context-menu", () => {
|
|
|
2443
2530
|
this.panel.setAttribute("popover", "auto");
|
|
2444
2531
|
else this.panel.hidden = true;
|
|
2445
2532
|
this.panel.append(doc.createElement("slot"));
|
|
2446
|
-
|
|
2533
|
+
this.menu = doc.createElement("div");
|
|
2534
|
+
this.menu.className = "menu";
|
|
2535
|
+
this.menu.setAttribute("role", "menu");
|
|
2536
|
+
this.menu.setAttribute("aria-orientation", "vertical");
|
|
2537
|
+
this.menu.tabIndex = -1;
|
|
2538
|
+
this.menu.hidden = true;
|
|
2539
|
+
root.append(this.panel, this.menu);
|
|
2447
2540
|
this.panel.addEventListener("toggle", (event) => {
|
|
2448
2541
|
if (event.newState === "closed") this.closed(false);
|
|
2449
2542
|
});
|
|
2450
|
-
this.panel.addEventListener("keydown", (event) => this.
|
|
2543
|
+
this.panel.addEventListener("keydown", (event) => this.onChildKey(event));
|
|
2544
|
+
this.menu.addEventListener("keydown", (event) => this.onRowKey(event));
|
|
2545
|
+
this.menu.addEventListener("pointerover", (event) => {
|
|
2546
|
+
const row = event.target?.closest("button");
|
|
2547
|
+
const index = row ? this.rows.indexOf(row) : -1;
|
|
2548
|
+
if (index >= 0 && !row?.disabled && index !== this.active) this.focusRow(index);
|
|
2549
|
+
});
|
|
2550
|
+
this.menu.addEventListener("contextmenu", (event) => event.preventDefault());
|
|
2451
2551
|
this.addEventListener("office-command", () => this.close());
|
|
2452
2552
|
}
|
|
2453
2553
|
connectedCallback() {
|
|
2454
2554
|
this.panel.setAttribute("aria-label", this.getAttribute("label") ?? "Context menu");
|
|
2555
|
+
if (this.controlled) {
|
|
2556
|
+
this.opener = this.deepActive();
|
|
2557
|
+
this.render();
|
|
2558
|
+
}
|
|
2455
2559
|
}
|
|
2456
2560
|
attributeChangedCallback() {
|
|
2457
2561
|
this.panel.setAttribute("aria-label", this.getAttribute("label") ?? "Context menu");
|
|
2458
2562
|
}
|
|
2459
2563
|
disconnectedCallback() {
|
|
2460
2564
|
this.close();
|
|
2565
|
+
if (!this.controlled) return;
|
|
2566
|
+
this.stopListening();
|
|
2567
|
+
clearTimeout(this.queryTimer);
|
|
2568
|
+
this.focused = false;
|
|
2569
|
+
const opener = this.opener;
|
|
2570
|
+
this.opener = null;
|
|
2571
|
+
const active = this.ownerDocument.activeElement;
|
|
2572
|
+
if (opener?.isConnected && (!active || active === this.ownerDocument.body))
|
|
2573
|
+
opener.focus({ preventScroll: true });
|
|
2461
2574
|
}
|
|
2575
|
+
// ---- Children mode ------------------------------------------------------------------
|
|
2462
2576
|
get open() {
|
|
2463
2577
|
return this.hasAttribute("data-open");
|
|
2464
2578
|
}
|
|
@@ -2481,12 +2595,17 @@ var defineContextMenu = definer("office-ui-context-menu", () => {
|
|
|
2481
2595
|
}
|
|
2482
2596
|
this.setAttribute("data-open", "");
|
|
2483
2597
|
const view = doc.defaultView;
|
|
2484
|
-
const
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2598
|
+
const { left, top } = clampFlyoutPosition({
|
|
2599
|
+
x,
|
|
2600
|
+
y,
|
|
2601
|
+
width: this.panel.offsetWidth,
|
|
2602
|
+
height: this.panel.offsetHeight,
|
|
2603
|
+
viewportWidth: view?.innerWidth ?? x,
|
|
2604
|
+
viewportHeight: view?.innerHeight ?? y,
|
|
2605
|
+
margin: 4
|
|
2606
|
+
});
|
|
2607
|
+
this.panel.style.left = `${Math.round(left)}px`;
|
|
2608
|
+
this.panel.style.top = `${Math.round(top)}px`;
|
|
2490
2609
|
this.items()[0]?.focus();
|
|
2491
2610
|
}
|
|
2492
2611
|
close() {
|
|
@@ -2507,7 +2626,7 @@ var defineContextMenu = definer("office-ui-context-menu", () => {
|
|
|
2507
2626
|
if (restoreFocus) this.returnFocus?.focus?.();
|
|
2508
2627
|
this.returnFocus = null;
|
|
2509
2628
|
}
|
|
2510
|
-
|
|
2629
|
+
onChildKey(event) {
|
|
2511
2630
|
const items = this.items();
|
|
2512
2631
|
const from = items.findIndex(
|
|
2513
2632
|
(item) => item === event.target || item.contains(event.target)
|
|
@@ -2523,8 +2642,217 @@ var defineContextMenu = definer("office-ui-context-menu", () => {
|
|
|
2523
2642
|
else if (event.key === "Escape" || event.key === "Tab") {
|
|
2524
2643
|
if (event.key === "Escape") event.preventDefault();
|
|
2525
2644
|
this.close();
|
|
2645
|
+
} else if (event.key.length === 1 && event.key !== " " && !event.ctrlKey && !event.metaKey && !event.altKey) {
|
|
2646
|
+
const labels = items.map((item) => ({
|
|
2647
|
+
label: item.getAttribute("label") ?? item.textContent ?? ""
|
|
2648
|
+
}));
|
|
2649
|
+
const target = this.typeAhead(labels, from, event.key);
|
|
2650
|
+
if (target >= 0) move(target);
|
|
2651
|
+
}
|
|
2652
|
+
}
|
|
2653
|
+
// ---- Controlled mode ----------------------------------------------------------------
|
|
2654
|
+
get state() {
|
|
2655
|
+
return this.model;
|
|
2656
|
+
}
|
|
2657
|
+
set state(value) {
|
|
2658
|
+
const signature = JSON.stringify(value);
|
|
2659
|
+
this.model = value;
|
|
2660
|
+
if (!this.controlled) {
|
|
2661
|
+
this.controlled = true;
|
|
2662
|
+
this.toggleAttribute("data-controlled", true);
|
|
2663
|
+
this.panel.remove();
|
|
2664
|
+
if (this.isConnected) this.opener = this.deepActive();
|
|
2665
|
+
}
|
|
2666
|
+
if (signature !== this.signature) {
|
|
2667
|
+
this.signature = signature;
|
|
2668
|
+
this.render();
|
|
2526
2669
|
}
|
|
2527
2670
|
}
|
|
2671
|
+
config() {
|
|
2672
|
+
return this.constructor;
|
|
2673
|
+
}
|
|
2674
|
+
deepActive() {
|
|
2675
|
+
let node = this.ownerDocument.activeElement;
|
|
2676
|
+
while (node?.shadowRoot?.activeElement) node = node.shadowRoot.activeElement;
|
|
2677
|
+
return node instanceof HTMLElement && node !== this.ownerDocument.body ? node : null;
|
|
2678
|
+
}
|
|
2679
|
+
render() {
|
|
2680
|
+
const state = this.model;
|
|
2681
|
+
const items = state.items;
|
|
2682
|
+
this.hidden = items.length === 0;
|
|
2683
|
+
this.menu.hidden = items.length === 0;
|
|
2684
|
+
this.applyMarkers(state.markers ?? []);
|
|
2685
|
+
if (state.zIndex !== void 0) this.style.zIndex = String(state.zIndex);
|
|
2686
|
+
else this.style.removeProperty("z-index");
|
|
2687
|
+
const same = items[this.active];
|
|
2688
|
+
this.active = same && !same.disabled ? this.active : nextEnabledIndex(items, -1, 1);
|
|
2689
|
+
this.renderRows();
|
|
2690
|
+
if (items.length === 0) {
|
|
2691
|
+
this.stopListening();
|
|
2692
|
+
this.focused = false;
|
|
2693
|
+
}
|
|
2694
|
+
if (!this.isConnected || items.length === 0) return;
|
|
2695
|
+
this.place();
|
|
2696
|
+
this.listen();
|
|
2697
|
+
if (!this.focused && state.autoFocus !== false) {
|
|
2698
|
+
this.focused = true;
|
|
2699
|
+
this.focusRow(nextEnabledIndex(items, -1, 1));
|
|
2700
|
+
} else if (this.focused && this.active >= 0)
|
|
2701
|
+
this.rows[this.active]?.focus({ preventScroll: true });
|
|
2702
|
+
}
|
|
2703
|
+
renderRows() {
|
|
2704
|
+
const doc = this.ownerDocument;
|
|
2705
|
+
const state = this.model;
|
|
2706
|
+
this.menu.setAttribute("aria-label", state.label);
|
|
2707
|
+
this.rows = [];
|
|
2708
|
+
let container = this.menu;
|
|
2709
|
+
const nodes = [];
|
|
2710
|
+
const place = (node) => container === this.menu ? nodes.push(node) : container.append(node);
|
|
2711
|
+
state.items.forEach((item, index) => {
|
|
2712
|
+
if (item.separatorBefore || item.heading) container = this.menu;
|
|
2713
|
+
if (item.separatorBefore) {
|
|
2714
|
+
const rule = doc.createElement("div");
|
|
2715
|
+
rule.className = "separator";
|
|
2716
|
+
rule.setAttribute("role", "separator");
|
|
2717
|
+
place(rule);
|
|
2718
|
+
}
|
|
2719
|
+
if (item.heading) {
|
|
2720
|
+
const group = doc.createElement("div");
|
|
2721
|
+
group.setAttribute("role", "group");
|
|
2722
|
+
group.setAttribute("aria-label", item.heading);
|
|
2723
|
+
const title = doc.createElement("div");
|
|
2724
|
+
title.className = "heading";
|
|
2725
|
+
title.setAttribute("aria-hidden", "true");
|
|
2726
|
+
title.textContent = item.heading;
|
|
2727
|
+
group.append(title);
|
|
2728
|
+
place(group);
|
|
2729
|
+
container = group;
|
|
2730
|
+
}
|
|
2731
|
+
const row = doc.createElement("button");
|
|
2732
|
+
row.type = "button";
|
|
2733
|
+
row.className = item.danger ? "item danger" : "item";
|
|
2734
|
+
row.dataset.itemId = item.id;
|
|
2735
|
+
row.setAttribute("role", item.checked === void 0 ? "menuitem" : "menuitemcheckbox");
|
|
2736
|
+
if (item.checked !== void 0) {
|
|
2737
|
+
row.setAttribute("aria-checked", String(item.checked));
|
|
2738
|
+
const check = doc.createElement("span");
|
|
2739
|
+
check.className = "check";
|
|
2740
|
+
check.setAttribute("aria-hidden", "true");
|
|
2741
|
+
check.textContent = item.checked ? "\u2713" : "";
|
|
2742
|
+
row.append(check);
|
|
2743
|
+
}
|
|
2744
|
+
if (item.icon) {
|
|
2745
|
+
const glyph = createIconSvg(doc);
|
|
2746
|
+
paintIcon(glyph, item.icon);
|
|
2747
|
+
row.append(glyph);
|
|
2748
|
+
}
|
|
2749
|
+
row.append(doc.createTextNode(item.label));
|
|
2750
|
+
row.tabIndex = index === this.active ? 0 : -1;
|
|
2751
|
+
if (item.disabled) {
|
|
2752
|
+
row.disabled = true;
|
|
2753
|
+
row.setAttribute("aria-disabled", "true");
|
|
2754
|
+
}
|
|
2755
|
+
row.addEventListener(
|
|
2756
|
+
"click",
|
|
2757
|
+
() => this.dispatchEvent(
|
|
2758
|
+
new CustomEvent(this.config().requestEvent, {
|
|
2759
|
+
detail: { id: item.id },
|
|
2760
|
+
bubbles: true,
|
|
2761
|
+
composed: true
|
|
2762
|
+
})
|
|
2763
|
+
)
|
|
2764
|
+
);
|
|
2765
|
+
this.rows.push(row);
|
|
2766
|
+
place(row);
|
|
2767
|
+
});
|
|
2768
|
+
this.menu.replaceChildren(...nodes);
|
|
2769
|
+
}
|
|
2770
|
+
applyMarkers(next) {
|
|
2771
|
+
for (const name of this.markers) this.removeAttribute(name);
|
|
2772
|
+
const pattern = this.config().markerPattern;
|
|
2773
|
+
this.markers = next.filter((name) => pattern.test(name));
|
|
2774
|
+
for (const name of this.markers) this.setAttribute(name, "true");
|
|
2775
|
+
}
|
|
2776
|
+
place() {
|
|
2777
|
+
const view = this.ownerDocument.defaultView;
|
|
2778
|
+
this.style.left = `${this.model.x}px`;
|
|
2779
|
+
this.style.top = `${this.model.y}px`;
|
|
2780
|
+
const box = this.getBoundingClientRect();
|
|
2781
|
+
const { left, top } = clampFlyoutPosition({
|
|
2782
|
+
x: this.model.x,
|
|
2783
|
+
y: this.model.y,
|
|
2784
|
+
width: box.width,
|
|
2785
|
+
height: box.height,
|
|
2786
|
+
viewportWidth: view?.innerWidth ?? box.right,
|
|
2787
|
+
viewportHeight: view?.innerHeight ?? box.bottom
|
|
2788
|
+
});
|
|
2789
|
+
this.style.left = `${left}px`;
|
|
2790
|
+
this.style.top = `${top}px`;
|
|
2791
|
+
}
|
|
2792
|
+
focusRow(index) {
|
|
2793
|
+
if (index < 0) return;
|
|
2794
|
+
this.active = index;
|
|
2795
|
+
this.rows.forEach((row, at) => row.tabIndex = at === index ? 0 : -1);
|
|
2796
|
+
this.rows[index]?.focus({ preventScroll: true });
|
|
2797
|
+
}
|
|
2798
|
+
typeAhead(items, from, key) {
|
|
2799
|
+
this.query += key;
|
|
2800
|
+
clearTimeout(this.queryTimer);
|
|
2801
|
+
this.queryTimer = setTimeout(() => this.query = "", TYPE_AHEAD_MS);
|
|
2802
|
+
return typeAheadIndex(items, from, this.query);
|
|
2803
|
+
}
|
|
2804
|
+
onRowKey(event) {
|
|
2805
|
+
const items = this.model.items;
|
|
2806
|
+
let target = -2;
|
|
2807
|
+
if (event.key === "ArrowDown") target = nextEnabledIndex(items, this.active, 1);
|
|
2808
|
+
else if (event.key === "ArrowUp") target = nextEnabledIndex(items, this.active, -1);
|
|
2809
|
+
else if (event.key === "Home") target = nextEnabledIndex(items, -1, 1);
|
|
2810
|
+
else if (event.key === "End") target = nextEnabledIndex(items, items.length, -1);
|
|
2811
|
+
else if (event.key.length === 1 && event.key !== " " && !event.ctrlKey && !event.metaKey && !event.altKey)
|
|
2812
|
+
target = this.typeAhead(items, this.active, event.key);
|
|
2813
|
+
if (target === -2) return;
|
|
2814
|
+
event.preventDefault();
|
|
2815
|
+
this.focusRow(target);
|
|
2816
|
+
}
|
|
2817
|
+
dismiss(reason) {
|
|
2818
|
+
this.dispatchEvent(
|
|
2819
|
+
new CustomEvent(this.config().closeEvent, {
|
|
2820
|
+
detail: { reason },
|
|
2821
|
+
bubbles: true,
|
|
2822
|
+
composed: true
|
|
2823
|
+
})
|
|
2824
|
+
);
|
|
2825
|
+
}
|
|
2826
|
+
onDocumentKey = (event) => {
|
|
2827
|
+
if (openMenus.get(this.ownerDocument)?.at(-1) !== this) return;
|
|
2828
|
+
if (event.key === "Escape") {
|
|
2829
|
+
event.preventDefault();
|
|
2830
|
+
event.stopPropagation();
|
|
2831
|
+
this.dismiss("escape");
|
|
2832
|
+
} else if (event.key === "Tab") this.dismiss("tab");
|
|
2833
|
+
};
|
|
2834
|
+
onDocumentPointer = (event) => {
|
|
2835
|
+
if (!event.composedPath().includes(this)) this.dismiss("outside");
|
|
2836
|
+
};
|
|
2837
|
+
listen() {
|
|
2838
|
+
if (this.listening) return;
|
|
2839
|
+
this.listening = true;
|
|
2840
|
+
const doc = this.ownerDocument;
|
|
2841
|
+
openMenus.set(doc, [...openMenus.get(doc) ?? [], this]);
|
|
2842
|
+
doc.addEventListener("keydown", this.onDocumentKey, true);
|
|
2843
|
+
doc.addEventListener("pointerdown", this.onDocumentPointer, true);
|
|
2844
|
+
}
|
|
2845
|
+
stopListening() {
|
|
2846
|
+
if (!this.listening) return;
|
|
2847
|
+
this.listening = false;
|
|
2848
|
+
const doc = this.ownerDocument;
|
|
2849
|
+
openMenus.set(
|
|
2850
|
+
doc,
|
|
2851
|
+
(openMenus.get(doc) ?? []).filter((menu) => menu !== this)
|
|
2852
|
+
);
|
|
2853
|
+
doc.removeEventListener("keydown", this.onDocumentKey, true);
|
|
2854
|
+
doc.removeEventListener("pointerdown", this.onDocumentPointer, true);
|
|
2855
|
+
}
|
|
2528
2856
|
}
|
|
2529
2857
|
return OfficeUiContextMenu;
|
|
2530
2858
|
});
|
|
@@ -3172,13 +3500,13 @@ var defineRibbonGroup = definer("office-ui-ribbon-group", () => {
|
|
|
3172
3500
|
"icon",
|
|
3173
3501
|
"data-open"
|
|
3174
3502
|
];
|
|
3175
|
-
caption;
|
|
3176
|
-
launcher;
|
|
3177
|
-
face;
|
|
3178
|
-
faceIcon;
|
|
3179
|
-
faceLabel;
|
|
3180
|
-
slotEl;
|
|
3181
|
-
observer;
|
|
3503
|
+
#caption;
|
|
3504
|
+
#launcher;
|
|
3505
|
+
#face;
|
|
3506
|
+
#faceIcon;
|
|
3507
|
+
#faceLabel;
|
|
3508
|
+
#slotEl;
|
|
3509
|
+
#observer;
|
|
3182
3510
|
constructor() {
|
|
3183
3511
|
super();
|
|
3184
3512
|
const doc = this.ownerDocument;
|
|
@@ -3189,19 +3517,19 @@ var defineRibbonGroup = definer("office-ui-ribbon-group", () => {
|
|
|
3189
3517
|
group.className = "group";
|
|
3190
3518
|
const row = doc.createElement("div");
|
|
3191
3519
|
row.className = "row";
|
|
3192
|
-
this
|
|
3193
|
-
this
|
|
3194
|
-
row.append(this
|
|
3195
|
-
this
|
|
3196
|
-
this
|
|
3197
|
-
this
|
|
3198
|
-
this
|
|
3199
|
-
this
|
|
3520
|
+
this.#slotEl = doc.createElement("slot");
|
|
3521
|
+
this.#slotEl.addEventListener("slotchange", () => this.#observe());
|
|
3522
|
+
row.append(this.#slotEl);
|
|
3523
|
+
this.#caption = doc.createElement("span");
|
|
3524
|
+
this.#caption.className = "caption";
|
|
3525
|
+
this.#launcher = doc.createElement("button");
|
|
3526
|
+
this.#launcher.type = "button";
|
|
3527
|
+
this.#launcher.className = "launcher";
|
|
3200
3528
|
const glyph = createIconSvg(doc);
|
|
3201
3529
|
paintIcon(glyph, "launcher");
|
|
3202
|
-
this
|
|
3203
|
-
this
|
|
3204
|
-
if (this
|
|
3530
|
+
this.#launcher.append(glyph);
|
|
3531
|
+
this.#launcher.addEventListener("click", () => {
|
|
3532
|
+
if (this.#launcher.disabled) return;
|
|
3205
3533
|
const detail = this.launcherDetail();
|
|
3206
3534
|
if (detail)
|
|
3207
3535
|
this.dispatchEvent(
|
|
@@ -3210,36 +3538,36 @@ var defineRibbonGroup = definer("office-ui-ribbon-group", () => {
|
|
|
3210
3538
|
});
|
|
3211
3539
|
const foot = doc.createElement("div");
|
|
3212
3540
|
foot.className = "foot";
|
|
3213
|
-
foot.append(this
|
|
3214
|
-
this
|
|
3215
|
-
this
|
|
3216
|
-
this
|
|
3217
|
-
this
|
|
3218
|
-
this
|
|
3219
|
-
this
|
|
3541
|
+
foot.append(this.#caption, this.#launcher);
|
|
3542
|
+
this.#face = doc.createElement("button");
|
|
3543
|
+
this.#face.type = "button";
|
|
3544
|
+
this.#face.className = "face";
|
|
3545
|
+
this.#face.setAttribute("aria-haspopup", "true");
|
|
3546
|
+
this.#faceIcon = createIconSvg(doc);
|
|
3547
|
+
this.#faceLabel = doc.createElement("span");
|
|
3220
3548
|
const chevron = createIconSvg(doc);
|
|
3221
3549
|
chevron.classList.add("chev");
|
|
3222
3550
|
paintIcon(chevron, "chevronDown");
|
|
3223
|
-
this
|
|
3224
|
-
this
|
|
3551
|
+
this.#face.append(this.#faceIcon, this.#faceLabel, chevron);
|
|
3552
|
+
this.#face.addEventListener(
|
|
3225
3553
|
"click",
|
|
3226
3554
|
() => this.dispatchEvent(
|
|
3227
3555
|
new CustomEvent(config3().collapseEvent, { bubbles: true, composed: true })
|
|
3228
3556
|
)
|
|
3229
3557
|
);
|
|
3230
|
-
group.append(this
|
|
3558
|
+
group.append(this.#face, row, foot);
|
|
3231
3559
|
root.append(group);
|
|
3232
3560
|
}
|
|
3233
3561
|
connectedCallback() {
|
|
3234
3562
|
this.setAttribute("role", "group");
|
|
3235
|
-
this
|
|
3236
|
-
this
|
|
3563
|
+
this.#sync();
|
|
3564
|
+
this.#observe();
|
|
3237
3565
|
}
|
|
3238
3566
|
disconnectedCallback() {
|
|
3239
|
-
this
|
|
3567
|
+
this.#observer?.disconnect();
|
|
3240
3568
|
}
|
|
3241
3569
|
attributeChangedCallback() {
|
|
3242
|
-
this
|
|
3570
|
+
this.#sync();
|
|
3243
3571
|
}
|
|
3244
3572
|
/** The launcher's event detail; null emits nothing. */
|
|
3245
3573
|
launcherDetail() {
|
|
@@ -3250,15 +3578,15 @@ var defineRibbonGroup = definer("office-ui-ribbon-group", () => {
|
|
|
3250
3578
|
iconName() {
|
|
3251
3579
|
return this.getAttribute("icon") ?? "grid";
|
|
3252
3580
|
}
|
|
3253
|
-
observe() {
|
|
3254
|
-
this
|
|
3581
|
+
#observe() {
|
|
3582
|
+
this.#observer?.disconnect();
|
|
3255
3583
|
if (!this.isConnected) return;
|
|
3256
3584
|
const Observer = this.ownerDocument.defaultView?.ResizeObserver;
|
|
3257
|
-
if (Observer) this
|
|
3258
|
-
for (const el of this
|
|
3259
|
-
this
|
|
3585
|
+
if (Observer) this.#observer ??= new Observer(() => this.#measure());
|
|
3586
|
+
for (const el of this.#slotEl.assignedElements()) this.#observer?.observe(el);
|
|
3587
|
+
this.#measure();
|
|
3260
3588
|
}
|
|
3261
|
-
measure() {
|
|
3589
|
+
#measure() {
|
|
3262
3590
|
const children = [...this.children];
|
|
3263
3591
|
const stackable = children.filter((el) => {
|
|
3264
3592
|
const gallery = el.matches('[mode="dropdown"]') ? el : el.querySelector('[mode="dropdown"]');
|
|
@@ -3275,20 +3603,20 @@ var defineRibbonGroup = definer("office-ui-ribbon-group", () => {
|
|
|
3275
3603
|
tallest <= tokenPx(this, "--office-ribbon-compact-row-max", 36)
|
|
3276
3604
|
);
|
|
3277
3605
|
}
|
|
3278
|
-
sync() {
|
|
3606
|
+
#sync() {
|
|
3279
3607
|
const label = this.getAttribute("label") ?? "";
|
|
3280
|
-
this
|
|
3608
|
+
this.#caption.textContent = label;
|
|
3281
3609
|
this.setAttribute("aria-label", label);
|
|
3282
3610
|
const launcherLabel = this.getAttribute("launcher-label") ?? `${label} options`;
|
|
3283
|
-
this
|
|
3284
|
-
this
|
|
3285
|
-
this
|
|
3286
|
-
this
|
|
3287
|
-
this
|
|
3288
|
-
this
|
|
3289
|
-
this
|
|
3290
|
-
this
|
|
3291
|
-
paintIcon(this
|
|
3611
|
+
this.#launcher.hidden = !this.hasAttribute("launcher");
|
|
3612
|
+
this.#launcher.disabled = this.hasAttribute("launcher-disabled");
|
|
3613
|
+
this.#launcher.setAttribute("aria-label", launcherLabel);
|
|
3614
|
+
this.#launcher.title = launcherLabel;
|
|
3615
|
+
this.#faceLabel.textContent = label;
|
|
3616
|
+
this.#face.title = label;
|
|
3617
|
+
this.#face.setAttribute("aria-label", label);
|
|
3618
|
+
this.#face.setAttribute("aria-expanded", String(this.hasAttribute("data-open")));
|
|
3619
|
+
paintIcon(this.#faceIcon, this.iconName());
|
|
3292
3620
|
}
|
|
3293
3621
|
}
|
|
3294
3622
|
return OfficeUiRibbonGroup;
|
|
@@ -4157,7 +4485,7 @@ var defineZoomSlider = definer("office-ui-zoom-slider", () => {
|
|
|
4157
4485
|
in;
|
|
4158
4486
|
range;
|
|
4159
4487
|
output;
|
|
4160
|
-
fit;
|
|
4488
|
+
#fit;
|
|
4161
4489
|
constructor() {
|
|
4162
4490
|
super();
|
|
4163
4491
|
const doc = this.ownerDocument;
|
|
@@ -4177,12 +4505,12 @@ var defineZoomSlider = definer("office-ui-zoom-slider", () => {
|
|
|
4177
4505
|
this.range.type = "range";
|
|
4178
4506
|
this.range.setAttribute("aria-label", "Zoom");
|
|
4179
4507
|
this.output = doc.createElement("output");
|
|
4180
|
-
this
|
|
4181
|
-
this
|
|
4508
|
+
this.#fit = button("Fit", "");
|
|
4509
|
+
this.#fit.className = "fit";
|
|
4182
4510
|
const svg = createIconSvg(doc);
|
|
4183
4511
|
paintIcon(svg, "fitPage");
|
|
4184
|
-
this
|
|
4185
|
-
root.append(this.out, this.range, this.in, this.output, this
|
|
4512
|
+
this.#fit.append(svg);
|
|
4513
|
+
root.append(this.out, this.range, this.in, this.output, this.#fit);
|
|
4186
4514
|
this.out.addEventListener("click", () => this.stepBy(-1));
|
|
4187
4515
|
this.in.addEventListener("click", () => this.stepBy(1));
|
|
4188
4516
|
this.range.addEventListener("input", () => this.commit(this.range.valueAsNumber, "input"));
|
|
@@ -4190,7 +4518,7 @@ var defineZoomSlider = definer("office-ui-zoom-slider", () => {
|
|
|
4190
4518
|
"change",
|
|
4191
4519
|
() => this.dispatchEvent(new Event("change", { bubbles: true, composed: true }))
|
|
4192
4520
|
);
|
|
4193
|
-
this
|
|
4521
|
+
this.#fit.addEventListener(
|
|
4194
4522
|
"click",
|
|
4195
4523
|
() => emit(this, "office-command", { command: "zoom-fit" })
|
|
4196
4524
|
);
|
|
@@ -4248,9 +4576,9 @@ var defineZoomSlider = definer("office-ui-zoom-slider", () => {
|
|
|
4248
4576
|
this.in.disabled = disabled || value >= max;
|
|
4249
4577
|
this.range.disabled = disabled;
|
|
4250
4578
|
const fit = this.getAttribute("fit");
|
|
4251
|
-
this
|
|
4252
|
-
this
|
|
4253
|
-
this
|
|
4579
|
+
this.#fit.disabled = disabled;
|
|
4580
|
+
this.#fit.setAttribute("aria-label", fit || "Fit");
|
|
4581
|
+
this.#fit.title = fit || "Fit";
|
|
4254
4582
|
}
|
|
4255
4583
|
}
|
|
4256
4584
|
return OfficeUiZoomSlider;
|
|
@@ -4442,4 +4770,4 @@ function registerControls(registry) {
|
|
|
4442
4770
|
for (const define of CONTROL_DEFINERS) define(registry);
|
|
4443
4771
|
}
|
|
4444
4772
|
|
|
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 };
|
|
4773
|
+
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-2XJDHLPW.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-2XJDHLPW.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-2XJDHLPW.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.1",
|
|
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
|
},
|