ooxml-ui 0.6.0 → 0.8.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 +23 -18
- package/dist/{chunk-RT6XKAM4.js → chunk-L5FYB6M7.js} +145 -7
- package/dist/command-search.d.ts +2 -0
- package/dist/controls.d.ts +1 -0
- package/dist/controls.js +1 -1
- package/dist/index.js +2 -2
- package/dist/keytips.d.ts +19 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -58,24 +58,29 @@ with an incompatible build of this package.
|
|
|
58
58
|
|
|
59
59
|
## Features: elements
|
|
60
60
|
|
|
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` | `options` `[{ value, label, disabled? }]`, `value`, `selectedIndex`, `disabled`
|
|
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`; `openAt(x, y)`, `close()`, `open`; `office-ui-menu-item` and separator children
|
|
75
|
-
| `office-ui-command-search` | `commands` `[{ id, label, keywords?, disabled?, title? }]`, `placeholder`, `label`, `limit` (Office's "Tell me what you want to do")
|
|
76
|
-
| `office-ui-presence` | `participants`, `max`, `label`
|
|
77
|
-
| `office-ui-smartart` | `drawing` (core `DiagramDrawing`), `schemeColors`, `label`
|
|
78
|
-
| `office-ui-icon` | `name`, `label`
|
|
61
|
+
| Tag | Attributes / properties | Events (all bubble, composed) |
|
|
62
|
+
| ----------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
|
|
63
|
+
| `office-ui-button` | `label`, `icon`, `command`, `disabled`, `pressed`, `expanded`, `icon-only`, `variant="stacked"`, `keyshortcuts` | `office-command` `{ command }` |
|
|
64
|
+
| `office-ui-checkbox`, `office-ui-switch` | `checked`, `disabled`, `value`, `aria-label`; form-associated | `input`, `change` |
|
|
65
|
+
| `office-ui-select` | `options` `[{ value, label, disabled? }]`, `value`, `selectedIndex`, `disabled` | `input`, `change` |
|
|
66
|
+
| `office-ui-ribbon-group` | `label`, `launcher` (dialog launcher command), `launcher-disabled`; default slot | launcher: `office-command` `{ command }` |
|
|
67
|
+
| `office-ui-ribbon-stack` | `orientation="horizontal"`; default slot (three-row column of small commands by default) | none |
|
|
68
|
+
| `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 }` |
|
|
69
|
+
| `office-ui-toolbar` | `aria-label`, `aria-orientation`; arrow-key focus movement | none |
|
|
70
|
+
| `office-ui-dialog` | `open`, `heading`, `dismissible="false"`, `show()`, `close()`; slots default, `footer` | `office-dialog-close` `{ reason }` (cancelable) |
|
|
71
|
+
| `office-ui-status-bar` / `-status-item` | `label`, `value`, `interactive`, `id` | `office-status-activate` `{ id }` |
|
|
72
|
+
| `office-ui-zoom-slider` | `value` (percent), `min`, `max`, `step`, `disabled`, `fit` (fit button name), `label` | `input`, `change`; fit: `office-command` `{ command: 'zoom-fit' }` |
|
|
73
|
+
| `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' }` |
|
|
74
|
+
| `office-ui-context-menu` / `office-ui-menu-separator` | `label`; `openAt(x, y)`, `close()`, `open`; `office-ui-menu-item` and separator children | item choice: `office-command` `{ command }` |
|
|
75
|
+
| `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 }` |
|
|
76
|
+
| `office-ui-presence` | `participants`, `max`, `label` | `office-presence-select` `{ id }` |
|
|
77
|
+
| `office-ui-smartart` | `drawing` (core `DiagramDrawing`), `schemeColors`, `label` | `office-smartart-render` (render report) |
|
|
78
|
+
| `office-ui-icon` | `name`, `label` | none |
|
|
79
|
+
|
|
80
|
+
`attachKeyTips(scope)` (from `ooxml-ui/controls`) adds Office KeyTips to any element or shadow
|
|
81
|
+
root: press and release Alt to show badges on controls marked `data-keytip="H"`, type a badge to
|
|
82
|
+
activate it, and use `data-keytip-panel` / `data-keytip-level` for a tab's second level. Escape
|
|
83
|
+
steps back; disabled controls are dimmed and never run.
|
|
79
84
|
|
|
80
85
|
Setting a property never emits an event; only user activation does. Controls honour
|
|
81
86
|
`prefers-color-scheme`, `forced-colors: active` (system colours and a visible focus ring) and
|
|
@@ -452,7 +452,10 @@ var defineCommandSearch = definer("office-ui-command-search", () => {
|
|
|
452
452
|
const query = this.input.value.trim().toLowerCase();
|
|
453
453
|
if (!query) return this.hide();
|
|
454
454
|
const limit = Math.max(1, Number(this.getAttribute("limit")) || 8);
|
|
455
|
-
|
|
455
|
+
const rank = (item) => (item.disabled ? 2 : 0) + (item.label.toLowerCase().startsWith(query) ? 0 : 1);
|
|
456
|
+
this.found = this.items.map((item, order) => ({ item, order })).filter(
|
|
457
|
+
({ item }) => `${item.label} ${item.keywords ?? ""} ${item.description ?? ""}`.toLowerCase().includes(query)
|
|
458
|
+
).sort((a, b) => rank(a.item) - rank(b.item) || a.order - b.order).map(({ item }) => item).slice(0, limit);
|
|
456
459
|
this.active = this.found.findIndex((item) => !item.disabled);
|
|
457
460
|
this.render();
|
|
458
461
|
this.show();
|
|
@@ -480,11 +483,12 @@ var defineCommandSearch = definer("office-ui-command-search", () => {
|
|
|
480
483
|
const label = doc.createElement("span");
|
|
481
484
|
label.textContent = item.label;
|
|
482
485
|
option.append(label);
|
|
483
|
-
if (item.disabled)
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
486
|
+
if (item.disabled) option.setAttribute("aria-disabled", "true");
|
|
487
|
+
const detail = item.disabled ? item.title ?? "Not available" : item.description;
|
|
488
|
+
if (detail) {
|
|
489
|
+
const line = doc.createElement("small");
|
|
490
|
+
line.textContent = detail;
|
|
491
|
+
option.append(line);
|
|
488
492
|
}
|
|
489
493
|
return option;
|
|
490
494
|
})
|
|
@@ -1728,6 +1732,140 @@ var defineZoomSlider = definer("office-ui-zoom-slider", () => {
|
|
|
1728
1732
|
return OfficeUiZoomSlider;
|
|
1729
1733
|
});
|
|
1730
1734
|
|
|
1735
|
+
// src/keytips.ts
|
|
1736
|
+
var BADGE_CSS = "position:fixed;inset:auto;margin:0;padding:0;border:0;background:transparent;overflow:visible;pointer-events:none";
|
|
1737
|
+
var TIP_CSS = 'position:fixed;transform:translate(-50%,-30%);min-width:14px;padding:1px 4px;border:1px solid #8a8886;border-radius:2px;background:#fff;color:#1f1f1f;font:600 11px/14px "Segoe UI",system-ui,sans-serif;text-align:center;box-shadow:0 1px 3px rgb(0 0 0 / 25%)';
|
|
1738
|
+
var isDisabled = (el) => el.hasAttribute("disabled") || el.getAttribute("aria-disabled") === "true";
|
|
1739
|
+
var visible = (el) => {
|
|
1740
|
+
const box = el.getBoundingClientRect();
|
|
1741
|
+
return box.width > 0 && box.height > 0;
|
|
1742
|
+
};
|
|
1743
|
+
function activate(el) {
|
|
1744
|
+
const inner = el.shadowRoot?.querySelector(".main, button");
|
|
1745
|
+
(inner ?? el).click();
|
|
1746
|
+
}
|
|
1747
|
+
function attachKeyTips(scope) {
|
|
1748
|
+
const doc = (scope instanceof ShadowRoot ? scope.host : scope).ownerDocument;
|
|
1749
|
+
const view = doc.defaultView;
|
|
1750
|
+
const layer = doc.createElement("div");
|
|
1751
|
+
layer.setAttribute("aria-hidden", "true");
|
|
1752
|
+
layer.style.cssText = BADGE_CSS;
|
|
1753
|
+
const topLayer = typeof layer.showPopover === "function";
|
|
1754
|
+
if (topLayer) layer.setAttribute("popover", "manual");
|
|
1755
|
+
else layer.hidden = true;
|
|
1756
|
+
scope.append(layer);
|
|
1757
|
+
let levels = [];
|
|
1758
|
+
let typed = "";
|
|
1759
|
+
let altAlone = false;
|
|
1760
|
+
const tipsAt = (container) => [...(container ?? scope).querySelectorAll("[data-keytip]")].filter((el) => {
|
|
1761
|
+
const owner = el.parentElement?.closest("[data-keytip-level]") ?? null;
|
|
1762
|
+
return owner === container && visible(el);
|
|
1763
|
+
});
|
|
1764
|
+
const current = () => tipsAt(levels.at(-1) ?? null);
|
|
1765
|
+
const render = () => {
|
|
1766
|
+
if (!handle.active) return;
|
|
1767
|
+
layer.replaceChildren(
|
|
1768
|
+
...current().map((el) => {
|
|
1769
|
+
const box = el.getBoundingClientRect();
|
|
1770
|
+
const tip = doc.createElement("span");
|
|
1771
|
+
tip.textContent = el.dataset.keytip;
|
|
1772
|
+
tip.style.cssText = `${TIP_CSS};left:${Math.round(box.left + box.width / 2)}px;top:${Math.round(box.bottom - 4)}px;opacity:${isDisabled(el) || typed && !el.dataset.keytip.startsWith(typed) ? "0.45" : "1"}`;
|
|
1773
|
+
return tip;
|
|
1774
|
+
})
|
|
1775
|
+
);
|
|
1776
|
+
};
|
|
1777
|
+
const show = () => {
|
|
1778
|
+
if (topLayer && !layer.matches(":popover-open")) layer.showPopover?.();
|
|
1779
|
+
else layer.hidden = false;
|
|
1780
|
+
render();
|
|
1781
|
+
};
|
|
1782
|
+
const stop = () => {
|
|
1783
|
+
levels = [];
|
|
1784
|
+
typed = "";
|
|
1785
|
+
if (topLayer) {
|
|
1786
|
+
try {
|
|
1787
|
+
layer.hidePopover?.();
|
|
1788
|
+
} catch {
|
|
1789
|
+
}
|
|
1790
|
+
} else layer.hidden = true;
|
|
1791
|
+
layer.replaceChildren();
|
|
1792
|
+
handle.active = false;
|
|
1793
|
+
};
|
|
1794
|
+
const start = () => {
|
|
1795
|
+
levels = [];
|
|
1796
|
+
typed = "";
|
|
1797
|
+
handle.active = true;
|
|
1798
|
+
show();
|
|
1799
|
+
};
|
|
1800
|
+
const choose = (el) => {
|
|
1801
|
+
typed = "";
|
|
1802
|
+
if (isDisabled(el)) return render();
|
|
1803
|
+
const panel = el.dataset.keytipPanel;
|
|
1804
|
+
activate(el);
|
|
1805
|
+
const next = panel ? [...scope.querySelectorAll("[data-keytip-level]")].find((el2) => el2.id === panel) ?? null : null;
|
|
1806
|
+
if (next) {
|
|
1807
|
+
levels.push(next);
|
|
1808
|
+
view?.requestAnimationFrame ? view.requestAnimationFrame(render) : render();
|
|
1809
|
+
} else stop();
|
|
1810
|
+
};
|
|
1811
|
+
const onKeyDown = (event) => {
|
|
1812
|
+
const key = event;
|
|
1813
|
+
if (key.key === "Alt") {
|
|
1814
|
+
altAlone = !key.ctrlKey && !key.metaKey && !key.shiftKey;
|
|
1815
|
+
return;
|
|
1816
|
+
}
|
|
1817
|
+
altAlone = false;
|
|
1818
|
+
if (!handle.active) return;
|
|
1819
|
+
if (key.key === "Escape") {
|
|
1820
|
+
key.preventDefault();
|
|
1821
|
+
key.stopPropagation();
|
|
1822
|
+
typed = "";
|
|
1823
|
+
if (levels.length) {
|
|
1824
|
+
levels.pop();
|
|
1825
|
+
render();
|
|
1826
|
+
} else stop();
|
|
1827
|
+
return;
|
|
1828
|
+
}
|
|
1829
|
+
if (key.key.length !== 1 || key.ctrlKey || key.metaKey) return stop();
|
|
1830
|
+
key.preventDefault();
|
|
1831
|
+
key.stopPropagation();
|
|
1832
|
+
typed += key.key.toUpperCase();
|
|
1833
|
+
const candidates = current().filter((el) => el.dataset.keytip.toUpperCase().startsWith(typed));
|
|
1834
|
+
const exact = candidates.find((el) => el.dataset.keytip.toUpperCase() === typed);
|
|
1835
|
+
if (exact) choose(exact);
|
|
1836
|
+
else if (!candidates.length) typed = "";
|
|
1837
|
+
render();
|
|
1838
|
+
};
|
|
1839
|
+
const onKeyUp = (event) => {
|
|
1840
|
+
const key = event;
|
|
1841
|
+
if (key.key !== "Alt" || !altAlone) return;
|
|
1842
|
+
altAlone = false;
|
|
1843
|
+
key.preventDefault();
|
|
1844
|
+
if (handle.active) stop();
|
|
1845
|
+
else start();
|
|
1846
|
+
};
|
|
1847
|
+
const onPointer = () => {
|
|
1848
|
+
if (handle.active) stop();
|
|
1849
|
+
};
|
|
1850
|
+
const target = scope;
|
|
1851
|
+
target.addEventListener("keydown", onKeyDown, true);
|
|
1852
|
+
target.addEventListener("keyup", onKeyUp, true);
|
|
1853
|
+
target.addEventListener("pointerdown", onPointer, true);
|
|
1854
|
+
view?.addEventListener("blur", onPointer);
|
|
1855
|
+
const handle = {
|
|
1856
|
+
active: false,
|
|
1857
|
+
dispose() {
|
|
1858
|
+
stop();
|
|
1859
|
+
target.removeEventListener("keydown", onKeyDown, true);
|
|
1860
|
+
target.removeEventListener("keyup", onKeyUp, true);
|
|
1861
|
+
target.removeEventListener("pointerdown", onPointer, true);
|
|
1862
|
+
view?.removeEventListener("blur", onPointer);
|
|
1863
|
+
layer.remove();
|
|
1864
|
+
}
|
|
1865
|
+
};
|
|
1866
|
+
return handle;
|
|
1867
|
+
}
|
|
1868
|
+
|
|
1731
1869
|
// src/controls.ts
|
|
1732
1870
|
var CONTROL_DEFINERS = [
|
|
1733
1871
|
defineIcon,
|
|
@@ -1753,4 +1891,4 @@ function registerControls(registry) {
|
|
|
1753
1891
|
for (const define of CONTROL_DEFINERS) define(registry);
|
|
1754
1892
|
}
|
|
1755
1893
|
|
|
1756
|
-
export { CONTROL_DEFINERS, defineButton, defineCheckbox, defineCommandSearch, defineContextMenu, defineDialog, defineMenuButton, defineMenuItem, defineMenuSeparator, defineRibbonGroup, defineRibbonStack, defineSelect, defineStatusBar, defineStatusItem, defineSwitch, defineTabStrip, defineToolbar, defineZoomSlider, registerControls };
|
|
1894
|
+
export { CONTROL_DEFINERS, attachKeyTips, defineButton, defineCheckbox, defineCommandSearch, defineContextMenu, defineDialog, defineMenuButton, defineMenuItem, defineMenuSeparator, defineRibbonGroup, defineRibbonStack, defineSelect, defineStatusBar, defineStatusItem, defineSwitch, defineTabStrip, defineToolbar, defineZoomSlider, registerControls };
|
package/dist/command-search.d.ts
CHANGED
package/dist/controls.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ export type { OfficeSelectOption } from './select.js';
|
|
|
17
17
|
export type { OfficeStatusActivateEvent } from './status-bar.js';
|
|
18
18
|
export type { OfficeTab, OfficeTabSelectEvent } from './tab-strip.js';
|
|
19
19
|
export type { OfficeSearchCommand } from './command-search.js';
|
|
20
|
+
export { attachKeyTips, type KeyTipsHandle } from './keytips.js';
|
|
20
21
|
/** Every control of this entry. */
|
|
21
22
|
export declare const CONTROL_DEFINERS: readonly [import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer];
|
|
22
23
|
/** Idempotent, SSR-safe (no-op without a DOM). */
|
package/dist/controls.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { CONTROL_DEFINERS, defineButton, defineCheckbox, defineCommandSearch, defineContextMenu, defineDialog, defineMenuButton, defineMenuItem, defineMenuSeparator, defineRibbonGroup, defineRibbonStack, defineSelect, defineStatusBar, defineStatusItem, defineSwitch, defineTabStrip, defineToolbar, defineZoomSlider, registerControls } from './chunk-
|
|
1
|
+
export { CONTROL_DEFINERS, attachKeyTips, defineButton, defineCheckbox, defineCommandSearch, defineContextMenu, defineDialog, defineMenuButton, defineMenuItem, defineMenuSeparator, defineRibbonGroup, defineRibbonStack, defineSelect, defineStatusBar, defineStatusItem, defineSwitch, defineTabStrip, defineToolbar, defineZoomSlider, registerControls } from './chunk-L5FYB6M7.js';
|
|
2
2
|
export { defineIcon } from './chunk-PCSUQPMC.js';
|
|
3
3
|
import './chunk-EY266IK3.js';
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { installOfficeUiTheme } from './chunk-H4KFVIGT.js';
|
|
2
2
|
export { THEME_CSS, THEME_STYLE_ID, installOfficeUiTheme } from './chunk-H4KFVIGT.js';
|
|
3
|
-
import { registerControls } from './chunk-
|
|
4
|
-
export { CONTROL_DEFINERS, defineButton, defineCheckbox, defineCommandSearch, defineContextMenu, defineDialog, defineMenuButton, defineMenuItem, defineMenuSeparator, defineRibbonGroup, defineRibbonStack, defineSelect, defineStatusBar, defineStatusItem, defineSwitch, defineTabStrip, defineToolbar, defineZoomSlider, registerControls } from './chunk-
|
|
3
|
+
import { registerControls } from './chunk-L5FYB6M7.js';
|
|
4
|
+
export { CONTROL_DEFINERS, attachKeyTips, defineButton, defineCheckbox, defineCommandSearch, defineContextMenu, defineDialog, defineMenuButton, defineMenuItem, defineMenuSeparator, defineRibbonGroup, defineRibbonStack, defineSelect, defineStatusBar, defineStatusItem, defineSwitch, defineTabStrip, defineToolbar, defineZoomSlider, registerControls } from './chunk-L5FYB6M7.js';
|
|
5
5
|
export { ICON_CSS, createIconSvg, defineIcon, getIcon, listIcons, paintIcon, registerIcon } from './chunk-PCSUQPMC.js';
|
|
6
6
|
import { definePresence } from './chunk-RLPL7Q6J.js';
|
|
7
7
|
export { definePresence, initialsOf, participantsFromAwareness } from './chunk-RLPL7Q6J.js';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Office KeyTips: press and release Alt to show letter badges on ribbon controls, then type a
|
|
3
|
+
* badge to activate it. Products annotate controls only:
|
|
4
|
+
* - `data-keytip="H"` marks a control (one or two characters);
|
|
5
|
+
* - `data-keytip-panel="home-panel"` on a control (a ribbon tab) makes the controls inside the
|
|
6
|
+
* element with that id the next level after it is activated.
|
|
7
|
+
* First-level tips are those not inside any `[data-keytip-level]` container; a panel element
|
|
8
|
+
* carries `data-keytip-level` so its tips only appear after its tab. Escape steps back a level;
|
|
9
|
+
* Alt, a click or focus leaving the scope exits. Disabled controls show dimmed and never run.
|
|
10
|
+
* Badges render in a `popover` top layer, so containment and overflow never misplace them.
|
|
11
|
+
*/
|
|
12
|
+
export interface KeyTipsHandle {
|
|
13
|
+
/** Whether badges are currently shown. */
|
|
14
|
+
readonly active: boolean;
|
|
15
|
+
dispose(): void;
|
|
16
|
+
}
|
|
17
|
+
type Root = ShadowRoot | HTMLElement;
|
|
18
|
+
export declare function attachKeyTips(scope: Root): KeyTipsHandle;
|
|
19
|
+
export {};
|