ooxml-ui 0.26.0 → 0.27.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.
@@ -4620,6 +4620,68 @@ function attachKeyTips(scope) {
4620
4620
  return handle;
4621
4621
  }
4622
4622
 
4623
+ // src/ribbon/keytip-run.ts
4624
+ var clash = (used, key) => used.some((other) => other.startsWith(key) || key.startsWith(other));
4625
+ function assignKeyTips(targets, label) {
4626
+ const used = [];
4627
+ for (const target of targets) {
4628
+ if (target.key && !clash(used, target.key)) used.push(target.key);
4629
+ else target.key = "";
4630
+ }
4631
+ for (const target of targets.filter((item) => !item.key)) {
4632
+ const source = label(target).toUpperCase().replace(/[^A-Z0-9]/g, "") || "ZZ";
4633
+ let key = "";
4634
+ for (let a = 0; a < source.length && !key; a++)
4635
+ for (let b = a + 1; b < source.length && !key; b++) {
4636
+ const candidate = source[a] + source[b];
4637
+ if (!clash(used, candidate)) key = candidate;
4638
+ }
4639
+ for (let n = 10; !key; n++) if (!clash(used, String(n))) key = String(n);
4640
+ used.push(key);
4641
+ target.key = key;
4642
+ }
4643
+ }
4644
+ function runKeyTips(root, targets, onDone, className) {
4645
+ const doc = root.ownerDocument;
4646
+ const shown = targets.map((target) => {
4647
+ const node = doc.createElement("span");
4648
+ node.className = className;
4649
+ node.textContent = target.key;
4650
+ node.setAttribute("aria-hidden", "true");
4651
+ const box = target.element.getBoundingClientRect();
4652
+ node.style.position = "fixed";
4653
+ node.style.left = `${box.left + box.width / 2}px`;
4654
+ node.style.top = `${box.bottom - 10}px`;
4655
+ root.append(node);
4656
+ return { node, target };
4657
+ });
4658
+ let typed = "";
4659
+ const stop = () => {
4660
+ for (const { node } of shown) node.remove();
4661
+ root.removeEventListener("keydown", onKey, true);
4662
+ root.removeEventListener("pointerdown", stop, true);
4663
+ onDone();
4664
+ };
4665
+ function onKey(event) {
4666
+ if (event.key === "Alt" || event.key === "Shift") return;
4667
+ event.preventDefault();
4668
+ event.stopPropagation();
4669
+ if (event.key === "Escape" || event.ctrlKey || event.metaKey) return stop();
4670
+ typed += event.key.toUpperCase();
4671
+ const matches = shown.filter(({ target }) => target.key.startsWith(typed));
4672
+ if (!matches.length) return stop();
4673
+ for (const { node, target } of shown) node.hidden = !target.key.startsWith(typed);
4674
+ const exact = matches.find(({ target }) => target.key === typed);
4675
+ if (exact) {
4676
+ stop();
4677
+ exact.target.activate();
4678
+ }
4679
+ }
4680
+ root.addEventListener("keydown", onKey, true);
4681
+ root.addEventListener("pointerdown", stop, true);
4682
+ return stop;
4683
+ }
4684
+
4623
4685
  // src/ribbon/overflow.ts
4624
4686
  function createRibbonOverflow(options) {
4625
4687
  let closeOpen;
@@ -4791,4 +4853,4 @@ function registerControls(registry) {
4791
4853
  for (const define of CONTROL_DEFINERS) define(registry);
4792
4854
  }
4793
4855
 
4794
- export { CONTROL_DEFINERS, DEFAULT_OFFICE_PROFILE, EMPTY_MENU_STATE, OFFICE_AVATAR_SWATCHES, OFFICE_PROFILE_STORAGE_KEY, OFFICE_TITLE_BAR_SEARCH_LIMIT, OFFICE_TOAST_VISIBLE_LIMIT, attachKeyTips, clampFlyoutPosition, clampOptionNumber, clearOfficeProfile, createRibbonOverflow, defineAccount, defineBackstage, defineButton, defineCheckbox, defineCommandSearch, defineContextMenu, defineDialog, defineDialogFooter, defineFindBar, defineGallery, defineIcon, defineMenuButton, defineMenuItem, defineMenuSeparator, defineOptionsDialog, definePasteOptions, definePrintPreview, defineRadio, defineReadOnlyBanner, defineRibbon, defineRibbonGroup, defineRibbonSection, defineRibbonStack, defineRibbonToggle, defineRuler, defineSearchField, defineSelect, defineStatusBar, defineStatusItem, defineSwitch, defineTabStrip, defineTitleBar, defineToasts, defineToolbar, defineZoomSlider, glyph, nextEnabledIndex, parseSvgPreview, profileInitials, readOfficeProfile, registerControls, rulerDivisions, sanitizeOfficeProfile, typeAheadIndex, writeOfficeProfile };
4856
+ export { CONTROL_DEFINERS, DEFAULT_OFFICE_PROFILE, EMPTY_MENU_STATE, OFFICE_AVATAR_SWATCHES, OFFICE_PROFILE_STORAGE_KEY, OFFICE_TITLE_BAR_SEARCH_LIMIT, OFFICE_TOAST_VISIBLE_LIMIT, assignKeyTips, attachKeyTips, clampFlyoutPosition, clampOptionNumber, clearOfficeProfile, createRibbonOverflow, defineAccount, defineBackstage, defineButton, defineCheckbox, defineCommandSearch, defineContextMenu, defineDialog, defineDialogFooter, defineFindBar, defineGallery, defineIcon, defineMenuButton, defineMenuItem, defineMenuSeparator, defineOptionsDialog, definePasteOptions, definePrintPreview, defineRadio, defineReadOnlyBanner, defineRibbon, defineRibbonGroup, defineRibbonSection, defineRibbonStack, defineRibbonToggle, defineRuler, defineSearchField, defineSelect, defineStatusBar, defineStatusItem, defineSwitch, defineTabStrip, defineTitleBar, defineToasts, defineToolbar, defineZoomSlider, glyph, nextEnabledIndex, parseSvgPreview, profileInitials, readOfficeProfile, registerControls, rulerDivisions, runKeyTips, sanitizeOfficeProfile, typeAheadIndex, writeOfficeProfile };
@@ -45,6 +45,8 @@ export { attachKeyTips, type KeyTipsHandle } from './keytips.js';
45
45
  export type { OfficeBackstageCloseEvent, OfficeBackstageItem, OfficeBackstageSelectEvent, } from './chrome/backstage.js';
46
46
  export type { OfficeFindInputEvent, OfficeFindStepEvent } from './chrome/find-bar.js';
47
47
  export type { OfficePrintPreviewPageEvent } from './chrome/print-preview.js';
48
+ export { assignKeyTips, runKeyTips } from './ribbon/keytip-run.js';
49
+ export type { KeyTipTarget } from './ribbon/keytip-run.js';
48
50
  export { createRibbonOverflow } from './ribbon/overflow.js';
49
51
  export type { RibbonOverflow, RibbonOverflowOptions } from './ribbon/overflow.js';
50
52
  export type { OfficeRibbonSelectEvent } from './ribbon/ribbon-tabs.js';
package/dist/controls.js CHANGED
@@ -1,4 +1,4 @@
1
- export { CONTROL_DEFINERS, DEFAULT_OFFICE_PROFILE, EMPTY_MENU_STATE, OFFICE_AVATAR_SWATCHES, OFFICE_PROFILE_STORAGE_KEY, OFFICE_TITLE_BAR_SEARCH_LIMIT, OFFICE_TOAST_VISIBLE_LIMIT, attachKeyTips, clampFlyoutPosition, clampOptionNumber, clearOfficeProfile, createRibbonOverflow, defineAccount, defineBackstage, defineButton, defineCheckbox, defineCommandSearch, defineContextMenu, defineDialog, defineDialogFooter, defineFindBar, defineGallery, defineIcon, defineMenuButton, defineMenuItem, defineMenuSeparator, defineOptionsDialog, definePasteOptions, definePrintPreview, defineRadio, defineReadOnlyBanner, defineRibbon, defineRibbonGroup, defineRibbonSection, defineRibbonStack, defineRibbonToggle, defineRuler, defineSearchField, defineSelect, defineStatusBar, defineStatusItem, defineSwitch, defineTabStrip, defineTitleBar, defineToasts, defineToolbar, defineZoomSlider, nextEnabledIndex, parseSvgPreview, profileInitials, readOfficeProfile, registerControls, rulerDivisions, sanitizeOfficeProfile, typeAheadIndex, writeOfficeProfile } from './chunk-4R4CHY5X.js';
1
+ export { CONTROL_DEFINERS, DEFAULT_OFFICE_PROFILE, EMPTY_MENU_STATE, OFFICE_AVATAR_SWATCHES, OFFICE_PROFILE_STORAGE_KEY, OFFICE_TITLE_BAR_SEARCH_LIMIT, OFFICE_TOAST_VISIBLE_LIMIT, assignKeyTips, attachKeyTips, clampFlyoutPosition, clampOptionNumber, clearOfficeProfile, createRibbonOverflow, defineAccount, defineBackstage, defineButton, defineCheckbox, defineCommandSearch, defineContextMenu, defineDialog, defineDialogFooter, defineFindBar, defineGallery, defineIcon, defineMenuButton, defineMenuItem, defineMenuSeparator, defineOptionsDialog, definePasteOptions, definePrintPreview, defineRadio, defineReadOnlyBanner, defineRibbon, defineRibbonGroup, defineRibbonSection, defineRibbonStack, defineRibbonToggle, defineRuler, defineSearchField, defineSelect, defineStatusBar, defineStatusItem, defineSwitch, defineTabStrip, defineTitleBar, defineToasts, defineToolbar, defineZoomSlider, nextEnabledIndex, parseSvgPreview, profileInitials, readOfficeProfile, registerControls, rulerDivisions, runKeyTips, sanitizeOfficeProfile, typeAheadIndex, writeOfficeProfile } from './chunk-4PBFBPOH.js';
2
2
  import './chunk-HZ422LTR.js';
3
3
  import './chunk-V6W5DKJ6.js';
4
4
  import './chunk-ZWBP2WTC.js';
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { installOfficeUiTheme } from './chunk-7QLJS57B.js';
2
2
  export { THEME_CSS, THEME_STYLE_ID, installOfficeUiTheme, shadcnBridge, themeBridge } from './chunk-7QLJS57B.js';
3
- import { registerControls } from './chunk-4R4CHY5X.js';
4
- export { CONTROL_DEFINERS, DEFAULT_OFFICE_PROFILE, EMPTY_MENU_STATE, OFFICE_AVATAR_SWATCHES, OFFICE_PROFILE_STORAGE_KEY, OFFICE_TITLE_BAR_SEARCH_LIMIT, OFFICE_TOAST_VISIBLE_LIMIT, attachKeyTips, clampFlyoutPosition, clampOptionNumber, clearOfficeProfile, createRibbonOverflow, defineAccount, defineBackstage, defineButton, defineCheckbox, defineCommandSearch, defineContextMenu, defineDialog, defineDialogFooter, defineFindBar, defineGallery, defineIcon, defineMenuButton, defineMenuItem, defineMenuSeparator, defineOptionsDialog, definePasteOptions, definePrintPreview, defineRadio, defineReadOnlyBanner, defineRibbon, defineRibbonGroup, defineRibbonSection, defineRibbonStack, defineRibbonToggle, defineRuler, defineSearchField, defineSelect, defineStatusBar, defineStatusItem, defineSwitch, defineTabStrip, defineTitleBar, defineToasts, defineToolbar, defineZoomSlider, glyph, nextEnabledIndex, parseSvgPreview, profileInitials, readOfficeProfile, registerControls, rulerDivisions, sanitizeOfficeProfile, typeAheadIndex, writeOfficeProfile } from './chunk-4R4CHY5X.js';
3
+ import { registerControls } from './chunk-4PBFBPOH.js';
4
+ export { CONTROL_DEFINERS, DEFAULT_OFFICE_PROFILE, EMPTY_MENU_STATE, OFFICE_AVATAR_SWATCHES, OFFICE_PROFILE_STORAGE_KEY, OFFICE_TITLE_BAR_SEARCH_LIMIT, OFFICE_TOAST_VISIBLE_LIMIT, assignKeyTips, attachKeyTips, clampFlyoutPosition, clampOptionNumber, clearOfficeProfile, createRibbonOverflow, defineAccount, defineBackstage, defineButton, defineCheckbox, defineCommandSearch, defineContextMenu, defineDialog, defineDialogFooter, defineFindBar, defineGallery, defineIcon, defineMenuButton, defineMenuItem, defineMenuSeparator, defineOptionsDialog, definePasteOptions, definePrintPreview, defineRadio, defineReadOnlyBanner, defineRibbon, defineRibbonGroup, defineRibbonSection, defineRibbonStack, defineRibbonToggle, defineRuler, defineSearchField, defineSelect, defineStatusBar, defineStatusItem, defineSwitch, defineTabStrip, defineTitleBar, defineToasts, defineToolbar, defineZoomSlider, glyph, nextEnabledIndex, parseSvgPreview, profileInitials, readOfficeProfile, registerControls, rulerDivisions, runKeyTips, sanitizeOfficeProfile, typeAheadIndex, writeOfficeProfile } from './chunk-4PBFBPOH.js';
5
5
  import { defineSmartArt } from './chunk-4VQ6S7QJ.js';
6
6
  export { OfficeUiSmartArt, defineSmartArt, renderDiagramDrawing } from './chunk-4VQ6S7QJ.js';
7
7
  import { TEAMS_TAGS, registerTeams } from './chunk-LE4FTRWB.js';
@@ -0,0 +1,27 @@
1
+ /**
2
+ * The second level of Office KeyTips for products that derive their tips from a ribbon panel: give
3
+ * each visible command a key (the product's own Office keys where the command exists, otherwise two
4
+ * letters of its label, never the prefix of another), show a badge over each and run the one whose
5
+ * letters are typed. Word and Excel use the same loop and differ only in the key table and in how a
6
+ * control is found and operated, so those stay with the product.
7
+ */
8
+ export interface KeyTipTarget {
9
+ /** The letters or digits to type; empty before {@link assignKeyTips}. */
10
+ key: string;
11
+ /** The element the badge sits under. */
12
+ element: HTMLElement;
13
+ /** What the tip does: open the control, or click it. */
14
+ activate(): void;
15
+ }
16
+ /**
17
+ * Makes every key unique and unambiguous. A key that is already set stays unless an earlier one
18
+ * clashes with it (Office's own keys differ per tab, so two commands can share one); the others get
19
+ * two letters from `label(target)`, then a number.
20
+ */
21
+ export declare function assignKeyTips(targets: readonly KeyTipTarget[], label: (target: KeyTipTarget) => string): void;
22
+ /**
23
+ * Shows fixed badges over `targets` (in `root`, so product CSS styles them through `className`) and
24
+ * runs the one whose letters are typed. Escape, a pointer press or a key with no match ends it;
25
+ * `onDone` runs after any end. Returns a function that stops it.
26
+ */
27
+ export declare function runKeyTips(root: HTMLElement, targets: readonly KeyTipTarget[], onDone: () => void, className: string): () => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ooxml-ui",
3
- "version": "0.26.0",
3
+ "version": "0.27.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",
@@ -85,7 +85,7 @@
85
85
  },
86
86
  "dependencies": {
87
87
  "lit": "^3.3.3",
88
- "ooxml-core": "^0.17.0"
88
+ "ooxml-core": "^0.18.0"
89
89
  },
90
90
  "devDependencies": {
91
91
  "@types/jsdom": "^30.0.0",