ooxml-ui 0.16.3 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -89,6 +89,7 @@ with an incompatible build of this package.
89
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
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
91
  | `office-ui-paste-options` | `state` `{ left, top, options: [{ id, label }], label? }`; fixed 4px past the pasted object | `office-paste-options-request` `{ format }`, `office-paste-options-dismiss` |
92
+ | `office-ui-title-bar` | `state` `{ appMark?, fileName, status?, tone?, autosave?, quickAccess?: { label, items, showLabels? }, search? }`, `placement` (`titleBar`, `belowRibbon`); slots `collaboration`, `account`; tokens `--office-title-bar-*` | `office-autosave-toggle`, `office-command` `{ command }`, `office-command-search` `{ query, command? }` |
92
93
  | `office-ui-presence` | `participants`, `max`, `label` | `office-presence-select` `{ id }` |
93
94
  | `office-ui-smartart` | `drawing` (core `DiagramDrawing`), `schemeColors`, `label` | `office-smartart-render` (render report) |
94
95
  | `office-ui-icon` | `name`, `label` | none |
@@ -1,4 +1,4 @@
1
- import { OFFICE_TOKENS, TOUCH } from './chunk-4MT4OIAJ.js';
1
+ import { OFFICE_TOKENS, TOUCH } from './chunk-A3QNC6VS.js';
2
2
 
3
3
  // src/theme.ts
4
4
  var THEME_STYLE_ID = "office-ui-theme";
@@ -206,7 +206,20 @@ var OFFICE_TOKENS = {
206
206
  "--office-avatar-size": "48px",
207
207
  "--office-avatar-color": "var(--office-muted-foreground, #6b7280)",
208
208
  "--office-toast-width": "360px",
209
- "--office-account-field-width": "320px"
209
+ "--office-account-field-width": "320px",
210
+ // Component: title bar
211
+ "--office-title-bar-height": "36px",
212
+ "--office-title-bar-below-height": "28px",
213
+ "--office-title-bar-background": "var(--office-surface, #f3f4f6)",
214
+ "--office-title-bar-foreground": "var(--office-foreground, #1f2937)",
215
+ "--office-title-bar-border": "var(--office-border, #d1d5db)",
216
+ "--office-title-bar-mark-size": "20px",
217
+ "--office-title-bar-mark-background": "var(--office-accent, #2563eb)",
218
+ "--office-title-bar-mark-foreground": "var(--office-accent-foreground, #ffffff)",
219
+ "--office-title-bar-name-max-width": "240px",
220
+ "--office-title-bar-name-max-width-narrow": "140px",
221
+ "--office-title-bar-search-max-width": "448px",
222
+ "--office-title-bar-results-max-height": "256px"
210
223
  };
211
224
  function tok(name) {
212
225
  return `var(${name}, ${OFFICE_TOKENS[name]})`;
@@ -1,5 +1,5 @@
1
- import { definer, attachStyles, controlCss, emit } from './chunk-XPYONXNE.js';
2
- import { tok } from './chunk-4MT4OIAJ.js';
1
+ import { definer, attachStyles, controlCss, emit } from './chunk-UYPH4ESZ.js';
2
+ import { tok } from './chunk-A3QNC6VS.js';
3
3
 
4
4
  // src/presence.ts
5
5
  function participantsFromAwareness(states, selfId) {
@@ -1,7 +1,7 @@
1
- import { createIconSvg, paintIcon, defineIcon } from './chunk-YFT6FYOP.js';
2
- import { initialsOf } from './chunk-YM2DT6QD.js';
3
- import { definer, attachStyles, controlCss, present, emit } from './chunk-XPYONXNE.js';
4
- import { tok, FOCUS_RING, OFFICE_TOKENS } from './chunk-4MT4OIAJ.js';
1
+ import { createIconSvg, paintIcon, defineIcon } from './chunk-LI7NB7HR.js';
2
+ import { initialsOf } from './chunk-DECL6RNI.js';
3
+ import { definer, attachStyles, controlCss, present, emit } from './chunk-UYPH4ESZ.js';
4
+ import { tok, FOCUS_RING, COMPACT, OFFICE_TOKENS } from './chunk-A3QNC6VS.js';
5
5
 
6
6
  // src/chrome-controls.ts
7
7
  var ICON = `svg { flex: none; width: ${tok("--office-icon-size")}; height: ${tok("--office-icon-size")}; fill: none; stroke: currentColor; stroke-width: ${tok("--office-icon-stroke")};
@@ -4462,8 +4462,471 @@ var defineTabStrip = definer("office-ui-tab-strip", () => {
4462
4462
  return OfficeUiTabStrip;
4463
4463
  });
4464
4464
 
4465
- // src/zoom-slider.ts
4465
+ // src/title-bar-strip.ts
4466
+ function createQuickAccessStrip(doc, activate2) {
4467
+ const toolbar = doc.createElement("div");
4468
+ toolbar.className = "qat";
4469
+ toolbar.setAttribute("role", "toolbar");
4470
+ toolbar.setAttribute("part", "quick-access");
4471
+ const buttons = /* @__PURE__ */ new Map();
4472
+ let stop = "";
4473
+ const enabled = () => [...toolbar.querySelectorAll("button:not(:disabled)")];
4474
+ const syncRoving = () => {
4475
+ const list = enabled();
4476
+ const current = list.find((b) => b.dataset.command === stop) ?? list[0];
4477
+ for (const button of buttons.values()) button.tabIndex = button === current ? 0 : -1;
4478
+ };
4479
+ toolbar.addEventListener("focusin", (event) => {
4480
+ const target = event.target.closest("button");
4481
+ if (target?.dataset.command) {
4482
+ stop = target.dataset.command;
4483
+ syncRoving();
4484
+ }
4485
+ });
4486
+ toolbar.addEventListener("keydown", (event) => {
4487
+ if (event.ctrlKey || event.metaKey || event.altKey) return;
4488
+ const list = enabled();
4489
+ const index = list.findIndex((b) => b === event.target.closest("button"));
4490
+ const last = list.length - 1;
4491
+ const moves = {
4492
+ ArrowRight: (index + 1) % list.length,
4493
+ ArrowLeft: (index + last) % list.length,
4494
+ Home: 0,
4495
+ End: last
4496
+ };
4497
+ const next = moves[event.key] ?? -1;
4498
+ if (next >= 0 && index >= 0) {
4499
+ event.preventDefault();
4500
+ list[next]?.focus();
4501
+ }
4502
+ if (next >= 0 || event.key === " " || event.key === "Enter") event.stopPropagation();
4503
+ });
4504
+ const create = (id) => {
4505
+ const button = doc.createElement("button");
4506
+ button.type = "button";
4507
+ button.dataset.command = id;
4508
+ button.append(createIconSvg(doc));
4509
+ button.addEventListener("click", () => activate2(id));
4510
+ return button;
4511
+ };
4512
+ return {
4513
+ toolbar,
4514
+ render(items, label, showLabels) {
4515
+ toolbar.hidden = items.length === 0;
4516
+ toolbar.setAttribute("aria-label", label);
4517
+ for (const id of [...buttons.keys()]) {
4518
+ if (!items.some((item) => item.id === id)) {
4519
+ buttons.get(id)?.remove();
4520
+ buttons.delete(id);
4521
+ }
4522
+ }
4523
+ for (const item of items) {
4524
+ let button = buttons.get(item.id);
4525
+ if (!button) {
4526
+ button = create(item.id);
4527
+ buttons.set(item.id, button);
4528
+ }
4529
+ paintIcon(button.querySelector("svg"), item.icon);
4530
+ button.setAttribute("aria-label", item.label);
4531
+ if (item.title === void 0) button.removeAttribute("title");
4532
+ else button.title = item.title;
4533
+ button.disabled = item.disabled === true;
4534
+ let text2 = button.querySelector("small");
4535
+ if (showLabels) {
4536
+ text2 ??= button.appendChild(doc.createElement("small"));
4537
+ text2.textContent = item.label;
4538
+ } else {
4539
+ text2?.remove();
4540
+ }
4541
+ }
4542
+ const current = [...toolbar.children];
4543
+ if (items.some((item, index) => current[index] !== buttons.get(item.id)))
4544
+ toolbar.append(...items.map((item) => buttons.get(item.id)));
4545
+ syncRoving();
4546
+ }
4547
+ };
4548
+ }
4549
+
4550
+ // src/title-bar-search.ts
4551
+ var OFFICE_TITLE_BAR_SEARCH_LIMIT = 8;
4552
+ function labelMatches(search, query) {
4553
+ const needle = query.trim().toLowerCase();
4554
+ return (search.commands ?? []).filter((entry) => entry.label.toLowerCase().includes(needle));
4555
+ }
4556
+ function createTitleBarSearch(doc, fieldTag, request) {
4557
+ let model;
4558
+ const box = doc.createElement("div");
4559
+ box.className = "box";
4560
+ const input = doc.createElement(fieldTag);
4561
+ input.setAttribute("variant", "titlebar");
4562
+ input.setAttribute("part", "search");
4563
+ const results = doc.createElement("div");
4564
+ results.className = "results";
4565
+ results.setAttribute("role", "listbox");
4566
+ results.hidden = true;
4567
+ const live = doc.createElement("div");
4568
+ live.className = "sr";
4569
+ live.setAttribute("role", "status");
4570
+ box.append(input, results, live);
4571
+ let matches = [];
4572
+ let active = 0;
4573
+ const close = () => {
4574
+ results.hidden = true;
4575
+ results.replaceChildren();
4576
+ live.textContent = "";
4577
+ matches = [];
4578
+ };
4579
+ const commit = (entry) => {
4580
+ const query = input.value;
4581
+ input.value = "";
4582
+ close();
4583
+ request(entry ? { query, command: entry.id } : { query });
4584
+ };
4585
+ const row = (className, text2) => {
4586
+ const node = doc.createElement("div");
4587
+ node.className = className;
4588
+ node.textContent = text2;
4589
+ return node;
4590
+ };
4591
+ const option = (className, onPick) => {
4592
+ const button = doc.createElement("button");
4593
+ button.type = "button";
4594
+ button.tabIndex = -1;
4595
+ button.className = className;
4596
+ button.addEventListener("mousedown", (event) => {
4597
+ event.preventDefault();
4598
+ onPick();
4599
+ });
4600
+ return button;
4601
+ };
4602
+ const paint = () => {
4603
+ [...results.querySelectorAll('[role="option"]')].forEach(
4604
+ (node, index) => node.setAttribute("aria-selected", String(index === active))
4605
+ );
4606
+ };
4607
+ const open = () => {
4608
+ const query = input.value;
4609
+ if (!model || !query.trim()) {
4610
+ close();
4611
+ return;
4612
+ }
4613
+ const found = model.match ? [...model.match(query)] : labelMatches(model, query);
4614
+ matches = found.slice(0, OFFICE_TITLE_BAR_SEARCH_LIMIT);
4615
+ active = Math.min(active, Math.max(matches.length - 1, 0));
4616
+ results.replaceChildren();
4617
+ if (matches.length > 0) {
4618
+ results.append(row("heading", model.heading));
4619
+ matches.forEach((entry, index) => {
4620
+ const button = option("", () => commit(entry));
4621
+ button.setAttribute("role", "option");
4622
+ const label = doc.createElement("span");
4623
+ label.textContent = entry.label;
4624
+ const category = doc.createElement("span");
4625
+ category.className = "cat";
4626
+ category.textContent = entry.category ?? "";
4627
+ button.append(label, category);
4628
+ button.addEventListener("mouseenter", () => {
4629
+ active = index;
4630
+ paint();
4631
+ });
4632
+ results.append(button);
4633
+ });
4634
+ } else {
4635
+ results.append(row("empty", model.empty));
4636
+ }
4637
+ if (model.content) {
4638
+ const content = option("content", () => commit());
4639
+ const svg = createIconSvg(doc);
4640
+ paintIcon(svg, model.contentIcon ?? "search");
4641
+ const text2 = doc.createElement("span");
4642
+ text2.textContent = model.content(query);
4643
+ content.append(svg, text2);
4644
+ results.append(content);
4645
+ }
4646
+ results.hidden = false;
4647
+ live.textContent = matches.length > 0 ? model.heading : model.empty;
4648
+ paint();
4649
+ };
4650
+ input.addEventListener("input", () => {
4651
+ active = 0;
4652
+ open();
4653
+ });
4654
+ input.addEventListener("focusin", open);
4655
+ box.addEventListener("focusout", (event) => {
4656
+ const next = event.relatedTarget;
4657
+ if (!next || !box.contains(next)) close();
4658
+ });
4659
+ input.addEventListener("keydown", (event) => {
4660
+ const { key, ctrlKey, metaKey } = event;
4661
+ if (key === "Enter" && input.value.trim()) {
4662
+ commit(matches[active]);
4663
+ } else if (key === "Escape" && input.value) {
4664
+ input.value = "";
4665
+ close();
4666
+ } else if ((key === "ArrowDown" || key === "ArrowUp") && matches.length > 0) {
4667
+ event.preventDefault();
4668
+ active = (active + (key === "ArrowDown" ? 1 : matches.length - 1)) % matches.length;
4669
+ paint();
4670
+ }
4671
+ if (!ctrlKey && !metaKey) event.stopPropagation();
4672
+ });
4673
+ return {
4674
+ box,
4675
+ input,
4676
+ render(search) {
4677
+ model = search;
4678
+ box.hidden = !search;
4679
+ if (!search) {
4680
+ close();
4681
+ return;
4682
+ }
4683
+ input.setAttribute("placeholder", search.placeholder);
4684
+ input.setAttribute("aria-label", search.label);
4685
+ if (!results.hidden) open();
4686
+ },
4687
+ close
4688
+ };
4689
+ }
4690
+
4691
+ // src/title-bar.ts
4466
4692
  var CSS16 = `
4693
+ :host { display: block; flex: none; }
4694
+ :host([data-empty]) { display: none !important; }
4695
+ [hidden] { display: none !important; }
4696
+ .bar { box-sizing: border-box; display: flex; align-items: center; gap: ${tok("--office-space-1")}; width: 100%;
4697
+ height: ${tok("--office-title-bar-height")}; padding: 0 ${tok("--office-space-2")};
4698
+ border-bottom: ${tok("--office-border-width")} solid ${tok("--office-title-bar-border")};
4699
+ background: ${tok("--office-title-bar-background")}; color: ${tok("--office-title-bar-foreground")};
4700
+ font: ${tok("--office-font-size-xs")}/${tok("--office-line-height-tight")} ${tok("--office-font")}; user-select: none; }
4701
+ :host([placement="belowRibbon"]) .bar { height: auto; min-height: ${tok("--office-title-bar-below-height")}; padding-block: ${tok("--office-space-0")}; }
4702
+ .mark { flex: none; display: flex; align-items: center; justify-content: center;
4703
+ width: ${tok("--office-title-bar-mark-size")}; height: ${tok("--office-title-bar-mark-size")}; border-radius: ${tok("--office-radius-sm")};
4704
+ background: ${tok("--office-title-bar-mark-background")}; color: ${tok("--office-title-bar-mark-foreground")};
4705
+ font-size: ${tok("--office-font-size-2xs")}; font-weight: ${tok("--office-font-weight-bold")}; }
4706
+ .autosave { flex: none; display: flex; align-items: center; gap: ${tok("--office-space-1-5")};
4707
+ padding: 0 ${tok("--office-space-0")} 0 ${tok("--office-space-1-5")}; white-space: nowrap; }
4708
+ .label, .dot, .status { color: ${tok("--office-muted-foreground")}; white-space: nowrap; }
4709
+ .sep { flex: none; width: ${tok("--office-border-width")}; height: ${tok("--office-space-4")}; margin: 0 ${tok("--office-space-1")};
4710
+ background: ${tok("--office-title-bar-border")}; }
4711
+ .qat { display: flex; align-items: center; gap: ${tok("--office-space-0")}; min-width: 0; }
4712
+ .qat button, .results button { box-sizing: border-box; display: inline-flex; align-items: center; justify-content: center;
4713
+ gap: ${tok("--office-space-1")}; min-width: ${tok("--office-control-height-md")}; min-height: ${tok("--office-control-height-md")};
4714
+ padding: ${tok("--office-space-1")}; border: 0; border-radius: ${tok("--office-radius-sm")}; background: transparent;
4715
+ color: ${tok("--office-muted-foreground")}; font: inherit; cursor: pointer; touch-action: manipulation; }
4716
+ .qat button:hover:not(:disabled) { background: ${tok("--office-selected")}; }
4717
+ .qat button:active:not(:disabled) { opacity: .7; }
4718
+ .qat button:disabled { opacity: .4; cursor: not-allowed; }
4719
+ .qat small { font-size: ${tok("--office-font-size-xs")}; white-space: nowrap; }
4720
+ svg { flex: none; width: ${tok("--office-icon-size")}; height: ${tok("--office-icon-size")}; fill: none; stroke: currentColor;
4721
+ stroke-width: ${tok("--office-icon-stroke")}; stroke-linecap: round; stroke-linejoin: round; }
4722
+ .file { display: flex; align-items: baseline; gap: ${tok("--office-space-1-5")}; min-width: 0; padding: 0 ${tok("--office-space-1")}; flex: 0 1 auto; }
4723
+ .name { max-width: ${tok("--office-title-bar-name-max-width")}; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
4724
+ color: ${tok("--office-title-bar-foreground")}; font-size: ${tok("--office-font-size-sm")}; font-weight: ${tok("--office-font-weight-medium")}; }
4725
+ .status.saving { color: ${tok("--office-warning")}; }
4726
+ .status.error { color: ${tok("--office-danger")}; }
4727
+ .search { position: relative; flex: 1; display: flex; justify-content: center; min-width: 0; padding: 0 ${tok("--office-space-2")}; }
4728
+ .box { position: relative; width: 100%; max-width: ${tok("--office-title-bar-search-max-width")}; min-width: 0; }
4729
+ .box > [part="search"] { width: 100%; }
4730
+ .results { position: absolute; z-index: ${tok("--office-z-popover")}; top: calc(100% + ${tok("--office-space-1")}); right: 0; left: 0;
4731
+ max-height: ${tok("--office-title-bar-results-max-height")}; overflow-y: auto;
4732
+ border: ${tok("--office-border-width")} solid ${tok("--office-border")}; border-radius: ${tok("--office-radius-lg")};
4733
+ background: ${tok("--office-popover")}; color: ${tok("--office-popover-foreground")}; box-shadow: ${tok("--office-shadow-lg")}; }
4734
+ .heading { padding: ${tok("--office-space-1-5")} ${tok("--office-space-3")}; color: ${tok("--office-muted-foreground")};
4735
+ font-size: ${tok("--office-font-size-2xs")}; font-weight: ${tok("--office-font-weight-bold")}; letter-spacing: .05em; text-transform: uppercase; }
4736
+ .empty { padding: ${tok("--office-space-2")} ${tok("--office-space-3")}; color: ${tok("--office-muted-foreground")}; }
4737
+ .results button { display: flex; width: 100%; justify-content: flex-start; gap: ${tok("--office-space-2")};
4738
+ padding: ${tok("--office-space-1-5")} ${tok("--office-space-3")}; border-radius: 0; color: inherit; text-align: start; }
4739
+ .results button:hover, .results button[aria-selected="true"] { background: ${tok("--office-selected")}; }
4740
+ .results .cat { margin-inline-start: auto; color: ${tok("--office-muted-foreground")}; font-size: ${tok("--office-font-size-2xs")}; text-transform: capitalize; }
4741
+ .results .content { border-top: ${tok("--office-border-width")} solid ${tok("--office-border")}; }
4742
+ .end { flex: none; display: flex; align-items: center; justify-content: flex-end; gap: ${tok("--office-space-1")}; }
4743
+ .sr { position: absolute; width: ${tok("--office-space-px")}; height: ${tok("--office-space-px")}; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
4744
+ button:focus-visible { outline: ${tok("--office-focus-width")} solid ${tok("--office-ring")}; outline-offset: ${tok("--office-focus-offset")}; }
4745
+ @media ${COMPACT}, (max-width: 1023px) and (max-height: 520px) { :host(:not([placement="belowRibbon"])) { display: none !important; } }
4746
+ @media (max-width: 1100px) { .qat small { display: none; } .name { max-width: ${tok("--office-title-bar-name-max-width-narrow")}; } }
4747
+ @media (pointer: coarse) {
4748
+ .qat button, .results button { min-width: ${tok("--office-target-size-touch")}; min-height: ${tok("--office-target-size-touch")}; }
4749
+ .bar { height: auto; min-height: ${tok("--office-target-size-touch")}; }
4750
+ }
4751
+ @media (forced-colors: active) {
4752
+ .bar { border-bottom-color: CanvasText; background: Canvas; color: CanvasText; }
4753
+ .mark { border: ${tok("--office-border-width")} solid CanvasText; background: Canvas; color: CanvasText; }
4754
+ .label, .dot, .status, .name, .qat button, .results button { color: CanvasText; }
4755
+ .sep { background: CanvasText; }
4756
+ .qat button:hover:not(:disabled), .results button:hover, .results button[aria-selected="true"] { background: Highlight; color: HighlightText; }
4757
+ .qat button:disabled { color: GrayText; opacity: 1; }
4758
+ .results { border-color: CanvasText; background: Canvas; }
4759
+ button:focus-visible { outline-color: Highlight; }
4760
+ }
4761
+ `;
4762
+ var EMPTY = { fileName: "" };
4763
+ var defineTitleBar = definer("office-ui-title-bar", () => {
4764
+ class OfficeUiTitleBar extends HTMLElement {
4765
+ static autosaveEvent = "office-autosave-toggle";
4766
+ static commandEvent = "office-command";
4767
+ static searchEvent = "office-command-search";
4768
+ /** Inner controls; a product subclass may use its own aliased tags. */
4769
+ static switchTag = "office-ui-switch";
4770
+ static searchTag = "office-ui-search";
4771
+ static observedAttributes = ["placement"];
4772
+ #state = EMPTY;
4773
+ #bar;
4774
+ #full;
4775
+ #mark;
4776
+ #autosave;
4777
+ #autosaveLabel;
4778
+ #autosaveState;
4779
+ #switch;
4780
+ #sepAutosave;
4781
+ #sepStrip;
4782
+ #name;
4783
+ #dot;
4784
+ #status;
4785
+ #searchWrap;
4786
+ #strip;
4787
+ #search;
4788
+ #laidOut = "titleBar";
4789
+ constructor() {
4790
+ super();
4791
+ const doc = this.ownerDocument;
4792
+ const statics = this.constructor;
4793
+ const root = this.attachShadow({ mode: "open" });
4794
+ attachStyles(root, controlCss(CSS16));
4795
+ const el = (tag, className) => {
4796
+ const node = doc.createElement(tag);
4797
+ node.className = className;
4798
+ return node;
4799
+ };
4800
+ const sep = () => {
4801
+ const node = el("i", "sep");
4802
+ node.setAttribute("aria-hidden", "true");
4803
+ return node;
4804
+ };
4805
+ this.#mark = el("span", "mark");
4806
+ this.#mark.setAttribute("aria-hidden", "true");
4807
+ this.#autosaveLabel = el("span", "label");
4808
+ this.#switch = el(statics.switchTag, "switch");
4809
+ this.#switch.setAttribute("part", "autosave-switch");
4810
+ this.#switch.addEventListener("change", () => {
4811
+ emit(this, statics.autosaveEvent, null);
4812
+ this.#switch.checked = this.#state.autosave?.enabled === true;
4813
+ });
4814
+ this.#autosaveState = el("span", "label");
4815
+ this.#autosave = el("span", "autosave");
4816
+ this.#autosave.append(this.#autosaveLabel, this.#switch, this.#autosaveState);
4817
+ this.#sepAutosave = sep();
4818
+ this.#strip = createQuickAccessStrip(doc, (id) => this.activate(id));
4819
+ this.#sepStrip = sep();
4820
+ this.#name = el("span", "name");
4821
+ this.#name.setAttribute("part", "file-name");
4822
+ this.#dot = el("span", "dot");
4823
+ this.#dot.textContent = "\u2022";
4824
+ this.#dot.setAttribute("aria-hidden", "true");
4825
+ this.#status = el("span", "status");
4826
+ const file = el("span", "file");
4827
+ file.append(this.#name, this.#dot, this.#status);
4828
+ this.#search = createTitleBarSearch(
4829
+ doc,
4830
+ statics.searchTag,
4831
+ (detail) => emit(this, statics.searchEvent, detail)
4832
+ );
4833
+ this.#searchWrap = el("span", "search");
4834
+ this.#searchWrap.append(this.#search.box);
4835
+ const end = el("div", "end");
4836
+ for (const name of ["collaboration", "account"]) {
4837
+ const slot = doc.createElement("slot");
4838
+ slot.name = name;
4839
+ end.append(slot);
4840
+ }
4841
+ this.#bar = el("div", "bar");
4842
+ this.#bar.setAttribute("part", "bar");
4843
+ this.#full = [
4844
+ this.#mark,
4845
+ this.#autosave,
4846
+ this.#sepAutosave,
4847
+ this.#strip.toolbar,
4848
+ this.#sepStrip,
4849
+ file,
4850
+ this.#searchWrap,
4851
+ end
4852
+ ];
4853
+ this.#bar.append(...this.#full);
4854
+ root.append(this.#bar);
4855
+ }
4856
+ get state() {
4857
+ return this.#state;
4858
+ }
4859
+ set state(value) {
4860
+ this.#state = value ?? EMPTY;
4861
+ this.#paint();
4862
+ }
4863
+ get placement() {
4864
+ return this.getAttribute("placement") === "belowRibbon" ? "belowRibbon" : "titleBar";
4865
+ }
4866
+ set placement(value) {
4867
+ this.setAttribute("placement", value);
4868
+ }
4869
+ /** The search field inside the bar, for hosts that move focus to it (Alt+Q). */
4870
+ get searchField() {
4871
+ return this.#search.input;
4872
+ }
4873
+ connectedCallback() {
4874
+ this.#paint();
4875
+ }
4876
+ attributeChangedCallback() {
4877
+ this.#paint();
4878
+ }
4879
+ /** A Quick Access button was pressed; subclasses may route by id. */
4880
+ activate(id) {
4881
+ emit(this, this.constructor.commandEvent, { command: id });
4882
+ }
4883
+ /** Called after every render; subclasses mirror state onto the host here. */
4884
+ rendered() {
4885
+ }
4886
+ #paint() {
4887
+ const state = this.#state;
4888
+ const below = this.placement === "belowRibbon";
4889
+ if (this.#laidOut !== this.placement) {
4890
+ this.#bar.replaceChildren(...below ? [this.#strip.toolbar] : this.#full);
4891
+ this.#laidOut = this.placement;
4892
+ }
4893
+ const items = state.quickAccess?.items ?? [];
4894
+ this.toggleAttribute("data-empty", below && items.length === 0);
4895
+ this.#strip.render(
4896
+ items,
4897
+ state.quickAccess?.label ?? "",
4898
+ state.quickAccess?.showLabels === true
4899
+ );
4900
+ this.#sepStrip.hidden = below || items.length === 0;
4901
+ this.#mark.hidden = !state.appMark;
4902
+ this.#mark.textContent = state.appMark ?? "";
4903
+ const autosave = state.autosave;
4904
+ this.#autosave.hidden = this.#sepAutosave.hidden = !autosave;
4905
+ if (autosave) {
4906
+ const available = autosave.available !== false;
4907
+ this.#autosaveLabel.textContent = autosave.label;
4908
+ this.#autosaveState.textContent = autosave.stateLabel;
4909
+ this.#switch.disabled = !available;
4910
+ this.#switch.checked = autosave.enabled;
4911
+ this.#switch.setAttribute("aria-label", autosave.toggleLabel);
4912
+ this.#switch.title = autosave.title ?? autosave.toggleLabel;
4913
+ }
4914
+ this.#name.textContent = state.fileName;
4915
+ this.#dot.hidden = this.#status.hidden = !state.status;
4916
+ this.#status.textContent = state.status ?? "";
4917
+ const tone = state.tone ?? "idle";
4918
+ this.#status.classList.toggle("saving", tone === "saving");
4919
+ this.#status.classList.toggle("error", tone === "error");
4920
+ this.#searchWrap.hidden = !state.search;
4921
+ this.#search.render(state.search);
4922
+ this.rendered();
4923
+ }
4924
+ }
4925
+ return OfficeUiTitleBar;
4926
+ });
4927
+
4928
+ // src/zoom-slider.ts
4929
+ var CSS17 = `
4467
4930
  :host { display: inline-flex; align-items: center; gap: ${tok("--office-space-0")}; font-size: ${tok("--office-font-size-xs")};
4468
4931
  color: ${tok("--office-foreground")}; font-family: ${tok("--office-font")}; }
4469
4932
  button { box-sizing: border-box; display: inline-grid; place-items: center; min-width: ${tok("--office-target-size")};
@@ -4499,7 +4962,7 @@ var defineZoomSlider = definer("office-ui-zoom-slider", () => {
4499
4962
  super();
4500
4963
  const doc = this.ownerDocument;
4501
4964
  const root = this.attachShadow({ mode: "open" });
4502
- attachStyles(root, controlCss(CSS16));
4965
+ attachStyles(root, controlCss(CSS17));
4503
4966
  const button = (name, text2) => {
4504
4967
  const element = doc.createElement("button");
4505
4968
  element.type = "button";
@@ -4773,10 +5236,11 @@ var CONTROL_DEFINERS = [
4773
5236
  defineDialogFooter,
4774
5237
  defineToasts,
4775
5238
  defineReadOnlyBanner,
4776
- definePasteOptions
5239
+ definePasteOptions,
5240
+ defineTitleBar
4777
5241
  ];
4778
5242
  function registerControls(registry) {
4779
5243
  for (const define of CONTROL_DEFINERS) define(registry);
4780
5244
  }
4781
5245
 
4782
- 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 };
5246
+ export { CONTROL_DEFINERS, DEFAULT_OFFICE_PROFILE, EMPTY_MENU_STATE, OFFICE_AVATAR_SWATCHES, OFFICE_PROFILE_STORAGE_KEY, OFFICE_TITLE_BAR_SEARCH_LIMIT, OFFICE_TOAST_VISIBLE_LIMIT, attachKeyTips, clampFlyoutPosition, clampOptionNumber, clearOfficeProfile, defineAccount, defineBackstage, defineButton, defineCheckbox, defineCommandSearch, defineContextMenu, defineDialog, defineDialogFooter, defineFindBar, defineMenuButton, defineMenuItem, defineMenuSeparator, defineOptionsDialog, definePasteOptions, definePrintPreview, defineRadio, defineReadOnlyBanner, defineRibbon, defineRibbonGroup, defineRibbonStack, defineRibbonToggle, defineRuler, defineSearchField, defineSelect, defineStatusBar, defineStatusItem, defineSwitch, defineTabStrip, defineTitleBar, defineToasts, defineToolbar, defineZoomSlider, nextEnabledIndex, profileInitials, readOfficeProfile, registerControls, rulerDivisions, sanitizeOfficeProfile, typeAheadIndex, writeOfficeProfile };
@@ -1,4 +1,4 @@
1
- import { definer, attachStyles, controlCss } from './chunk-XPYONXNE.js';
1
+ import { definer, attachStyles, controlCss } from './chunk-UYPH4ESZ.js';
2
2
 
3
3
  // src/icons.ts
4
4
  var registry = /* @__PURE__ */ new Map();
@@ -20,6 +20,7 @@ var BUILT_IN = {
20
20
  reset: "M4 10a6 6 0 1 1 1.8 4.2M4 6v4h4",
21
21
  search: "M3 8.5a5.5 5.5 0 1 0 11 0 5.5 5.5 0 1 0-11 0M13 13l4 4",
22
22
  undo: "M7.5 11.5 3.5 7.5l4-4M3.5 7.5h9a4 4 0 0 1 0 8H10",
23
+ save: "M3.5 3h10.5l2.5 2.5V17h-13ZM6 3v5h7V3M6 17v-5.5h8V17",
23
24
  redo: "m12.5 11.5 4-4-4-4M16.5 7.5h-9a4 4 0 0 0 0 8H10",
24
25
  pointer: "m5 2.5v13.5l3.6-3.6 2.4 5.1 2.1-1-2.4-5H15.5Z",
25
26
  rectangle: "M3 5.5h14v9H3Z",
@@ -1,5 +1,5 @@
1
- import { definer, attachStyles, controlCss, emit } from './chunk-XPYONXNE.js';
2
- import { tok } from './chunk-4MT4OIAJ.js';
1
+ import { definer, attachStyles, controlCss, emit } from './chunk-UYPH4ESZ.js';
2
+ import { tok } from './chunk-A3QNC6VS.js';
3
3
  import { normalizeHexColor } from 'ooxml-core/color';
4
4
 
5
5
  var SVG_NS = "http://www.w3.org/2000/svg";
@@ -1,4 +1,4 @@
1
- import { TOUCH, tok } from './chunk-4MT4OIAJ.js';
1
+ import { TOUCH, tok } from './chunk-A3QNC6VS.js';
2
2
 
3
3
  // src/registry.ts
4
4
  var CONTRACT_REVISION = 1;
@@ -21,14 +21,16 @@ import { defineRibbonGroup, defineRibbonStack, defineToolbar } from './ribbon.js
21
21
  import { defineSelect } from './select.js';
22
22
  import { defineStatusBar, defineStatusItem } from './status-bar.js';
23
23
  import { defineTabStrip } from './tab-strip.js';
24
+ import { defineTitleBar } from './title-bar.js';
24
25
  import { defineZoomSlider } from './zoom-slider.js';
25
- export { defineAccount, defineDialogFooter, definePasteOptions, defineRadio, defineReadOnlyBanner, defineRibbonToggle, defineSearchField, defineToasts, defineBackstage, defineFindBar, definePrintPreview, defineRibbon, defineRuler, defineButton, defineCheckbox, defineCommandSearch, defineContextMenu, defineDialog, defineIcon, defineMenuButton, defineMenuItem, defineMenuSeparator, defineOptionsDialog, defineRibbonGroup, defineRibbonStack, defineSelect, defineStatusBar, defineStatusItem, defineSwitch, defineTabStrip, defineToolbar, defineZoomSlider, };
26
+ export { defineAccount, defineDialogFooter, definePasteOptions, defineRadio, defineReadOnlyBanner, defineRibbonToggle, defineSearchField, defineToasts, defineBackstage, defineFindBar, definePrintPreview, defineRibbon, defineRuler, defineButton, defineCheckbox, defineCommandSearch, defineContextMenu, defineDialog, defineIcon, defineMenuButton, defineMenuItem, defineMenuSeparator, defineOptionsDialog, defineRibbonGroup, defineRibbonStack, defineSelect, defineStatusBar, defineStatusItem, defineSwitch, defineTabStrip, defineTitleBar, defineToolbar, defineZoomSlider, };
26
27
  export type { OfficeCommandEvent } from './button.js';
27
28
  export type { OfficeDialogCloseEvent, OfficeDialogCloseReason } from './dialog.js';
28
29
  export type { OfficeSelectOption } from './select.js';
29
30
  export type { OfficeStatusActivateEvent } from './status-bar.js';
30
31
  export type { OfficeTab, OfficeTabSelectEvent } from './tab-strip.js';
31
32
  export type { OfficeSearchCommand } from './command-search.js';
33
+ export { OFFICE_TITLE_BAR_SEARCH_LIMIT, type OfficeQuickAccessItem, type OfficeTitleBarAutosave, type OfficeTitleBarCommand, type OfficeTitleBarPlacement, type OfficeTitleBarSearch, type OfficeTitleBarSearchDetail, type OfficeTitleBarState, type OfficeTitleBarTone, } from './title-bar.js';
32
34
  export { attachKeyTips, type KeyTipsHandle } from './keytips.js';
33
35
  export type { OfficeBackstageCloseEvent, OfficeBackstageItem, OfficeBackstageSelectEvent, } from './backstage.js';
34
36
  export type { OfficeFindInputEvent, OfficeFindStepEvent } from './find-bar.js';
@@ -41,6 +43,6 @@ export type { OfficePasteOption, OfficePasteOptionsState, OfficeReadOnlyBannerIn
41
43
  export { clearOfficeProfile, DEFAULT_OFFICE_PROFILE, OFFICE_AVATAR_SWATCHES, OFFICE_PROFILE_STORAGE_KEY, profileInitials, readOfficeProfile, sanitizeOfficeProfile, writeOfficeProfile, type OfficeProfile, type OfficeProfileChangeEvent, } from './account.js';
42
44
  export { clampOptionNumber, type OfficeOptionCategory, type OfficeOptionChoice, type OfficeOptionControl, type OfficeOptionSection, type OfficeOptionsChangeEvent, type OfficeOptionValue, type OfficeOptionValues, } from './options.js';
43
45
  /** Every control of this entry. */
44
- export declare const CONTROL_DEFINERS: readonly [import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer];
46
+ export declare const CONTROL_DEFINERS: readonly [import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer, import("./registry.js").Definer];
45
47
  /** Idempotent, SSR-safe (no-op without a DOM). */
46
48
  export declare function registerControls(registry?: CustomElementRegistry): void;
package/dist/controls.js CHANGED
@@ -1,5 +1,5 @@
1
- export { CONTROL_DEFINERS, DEFAULT_OFFICE_PROFILE, EMPTY_MENU_STATE, OFFICE_AVATAR_SWATCHES, OFFICE_PROFILE_STORAGE_KEY, OFFICE_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-IKE3XWDZ.js';
2
- export { defineIcon } from './chunk-YFT6FYOP.js';
3
- import './chunk-YM2DT6QD.js';
4
- import './chunk-XPYONXNE.js';
5
- import './chunk-4MT4OIAJ.js';
1
+ export { CONTROL_DEFINERS, DEFAULT_OFFICE_PROFILE, EMPTY_MENU_STATE, OFFICE_AVATAR_SWATCHES, OFFICE_PROFILE_STORAGE_KEY, OFFICE_TITLE_BAR_SEARCH_LIMIT, OFFICE_TOAST_VISIBLE_LIMIT, attachKeyTips, clampFlyoutPosition, clampOptionNumber, clearOfficeProfile, defineAccount, defineBackstage, defineButton, defineCheckbox, defineCommandSearch, defineContextMenu, defineDialog, defineDialogFooter, defineFindBar, defineMenuButton, defineMenuItem, defineMenuSeparator, defineOptionsDialog, definePasteOptions, definePrintPreview, defineRadio, defineReadOnlyBanner, defineRibbon, defineRibbonGroup, defineRibbonStack, defineRibbonToggle, defineRuler, defineSearchField, defineSelect, defineStatusBar, defineStatusItem, defineSwitch, defineTabStrip, defineTitleBar, defineToasts, defineToolbar, defineZoomSlider, nextEnabledIndex, profileInitials, readOfficeProfile, registerControls, rulerDivisions, sanitizeOfficeProfile, typeAheadIndex, writeOfficeProfile } from './chunk-EIZJR3CC.js';
2
+ export { defineIcon } from './chunk-LI7NB7HR.js';
3
+ import './chunk-DECL6RNI.js';
4
+ import './chunk-UYPH4ESZ.js';
5
+ import './chunk-A3QNC6VS.js';
package/dist/icons.js CHANGED
@@ -1,3 +1,3 @@
1
- export { ICON_CSS, createIconSvg, defineIcon, getIcon, listIcons, paintIcon, registerIcon } from './chunk-YFT6FYOP.js';
2
- import './chunk-XPYONXNE.js';
3
- import './chunk-4MT4OIAJ.js';
1
+ export { ICON_CSS, createIconSvg, defineIcon, getIcon, listIcons, paintIcon, registerIcon } from './chunk-LI7NB7HR.js';
2
+ import './chunk-UYPH4ESZ.js';
3
+ import './chunk-A3QNC6VS.js';
package/dist/index.d.ts CHANGED
@@ -5,7 +5,7 @@ export * from './smartart.js';
5
5
  export * from './theme.js';
6
6
  export { CONTRACT_REVISION, type Definer } from './registry.js';
7
7
  /** Every ooxml-ui tag this package defines, in registration order. */
8
- export declare const OFFICE_UI_TAGS: readonly ["office-ui-icon", "office-ui-button", "office-ui-checkbox", "office-ui-switch", "office-ui-select", "office-ui-ribbon-group", "office-ui-ribbon-stack", "office-ui-menu-item", "office-ui-menu-button", "office-ui-menu-separator", "office-ui-context-menu", "office-ui-command-search", "office-ui-toolbar", "office-ui-dialog", "office-ui-status-bar", "office-ui-status-item", "office-ui-zoom-slider", "office-ui-tab-strip", "office-ui-options-dialog", "office-ui-account", "office-ui-ribbon", "office-ui-find-bar", "office-ui-ruler", "office-ui-backstage", "office-ui-print-preview", "office-ui-radio", "office-ui-search", "office-ui-ribbon-toggle", "office-ui-dialog-footer", "office-ui-toasts", "office-ui-read-only-banner", "office-ui-paste-options", "office-ui-presence", "office-ui-smartart"];
8
+ export declare const OFFICE_UI_TAGS: readonly ["office-ui-icon", "office-ui-button", "office-ui-checkbox", "office-ui-switch", "office-ui-select", "office-ui-ribbon-group", "office-ui-ribbon-stack", "office-ui-menu-item", "office-ui-menu-button", "office-ui-menu-separator", "office-ui-context-menu", "office-ui-command-search", "office-ui-toolbar", "office-ui-dialog", "office-ui-status-bar", "office-ui-status-item", "office-ui-zoom-slider", "office-ui-tab-strip", "office-ui-options-dialog", "office-ui-account", "office-ui-ribbon", "office-ui-find-bar", "office-ui-ruler", "office-ui-backstage", "office-ui-print-preview", "office-ui-radio", "office-ui-search", "office-ui-ribbon-toggle", "office-ui-dialog-footer", "office-ui-toasts", "office-ui-read-only-banner", "office-ui-paste-options", "office-ui-title-bar", "office-ui-presence", "office-ui-smartart"];
9
9
  /**
10
10
  * Install the theme tokens and define every element. Idempotent and safe to call from every
11
11
  * viewer binding; a no-op where there is no DOM (SSR).
package/dist/index.js CHANGED
@@ -1,14 +1,14 @@
1
- import { installOfficeUiTheme } from './chunk-F4TM7U4P.js';
2
- export { THEME_CSS, THEME_STYLE_ID, installOfficeUiTheme } from './chunk-F4TM7U4P.js';
3
- import { registerControls } from './chunk-IKE3XWDZ.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-IKE3XWDZ.js';
5
- export { ICON_CSS, createIconSvg, defineIcon, getIcon, listIcons, paintIcon, registerIcon } from './chunk-YFT6FYOP.js';
6
- import { definePresence } from './chunk-YM2DT6QD.js';
7
- export { definePresence, initialsOf, participantsFromAwareness } from './chunk-YM2DT6QD.js';
8
- import { defineSmartArt } from './chunk-HSM56NH6.js';
9
- export { defineSmartArt, renderDiagramDrawing } from './chunk-HSM56NH6.js';
10
- export { CONTRACT_REVISION } from './chunk-XPYONXNE.js';
11
- export { COMPACT, FOCUS_RING, OFFICE_TOKENS, TOUCH, tok } from './chunk-4MT4OIAJ.js';
1
+ import { installOfficeUiTheme } from './chunk-5L3NYLAW.js';
2
+ export { THEME_CSS, THEME_STYLE_ID, installOfficeUiTheme } from './chunk-5L3NYLAW.js';
3
+ import { registerControls } from './chunk-EIZJR3CC.js';
4
+ export { CONTROL_DEFINERS, DEFAULT_OFFICE_PROFILE, EMPTY_MENU_STATE, OFFICE_AVATAR_SWATCHES, OFFICE_PROFILE_STORAGE_KEY, OFFICE_TITLE_BAR_SEARCH_LIMIT, OFFICE_TOAST_VISIBLE_LIMIT, attachKeyTips, clampFlyoutPosition, clampOptionNumber, clearOfficeProfile, defineAccount, defineBackstage, defineButton, defineCheckbox, defineCommandSearch, defineContextMenu, defineDialog, defineDialogFooter, defineFindBar, defineMenuButton, defineMenuItem, defineMenuSeparator, defineOptionsDialog, definePasteOptions, definePrintPreview, defineRadio, defineReadOnlyBanner, defineRibbon, defineRibbonGroup, defineRibbonStack, defineRibbonToggle, defineRuler, defineSearchField, defineSelect, defineStatusBar, defineStatusItem, defineSwitch, defineTabStrip, defineTitleBar, defineToasts, defineToolbar, defineZoomSlider, nextEnabledIndex, profileInitials, readOfficeProfile, registerControls, rulerDivisions, sanitizeOfficeProfile, typeAheadIndex, writeOfficeProfile } from './chunk-EIZJR3CC.js';
5
+ export { ICON_CSS, createIconSvg, defineIcon, getIcon, listIcons, paintIcon, registerIcon } from './chunk-LI7NB7HR.js';
6
+ import { definePresence } from './chunk-DECL6RNI.js';
7
+ export { definePresence, initialsOf, participantsFromAwareness } from './chunk-DECL6RNI.js';
8
+ import { defineSmartArt } from './chunk-OAGGHX23.js';
9
+ export { defineSmartArt, renderDiagramDrawing } from './chunk-OAGGHX23.js';
10
+ export { CONTRACT_REVISION } from './chunk-UYPH4ESZ.js';
11
+ export { COMPACT, FOCUS_RING, OFFICE_TOKENS, TOUCH, tok } from './chunk-A3QNC6VS.js';
12
12
 
13
13
  // src/index.ts
14
14
  var OFFICE_UI_TAGS = [
@@ -44,6 +44,7 @@ var OFFICE_UI_TAGS = [
44
44
  "office-ui-toasts",
45
45
  "office-ui-read-only-banner",
46
46
  "office-ui-paste-options",
47
+ "office-ui-title-bar",
47
48
  "office-ui-presence",
48
49
  "office-ui-smartart"
49
50
  ];
package/dist/presence.js CHANGED
@@ -1,3 +1,3 @@
1
- export { definePresence, initialsOf, participantsFromAwareness } from './chunk-YM2DT6QD.js';
2
- import './chunk-XPYONXNE.js';
3
- import './chunk-4MT4OIAJ.js';
1
+ export { definePresence, initialsOf, participantsFromAwareness } from './chunk-DECL6RNI.js';
2
+ import './chunk-UYPH4ESZ.js';
3
+ import './chunk-A3QNC6VS.js';
package/dist/smartart.js CHANGED
@@ -1,3 +1,3 @@
1
- export { defineSmartArt, renderDiagramDrawing } from './chunk-HSM56NH6.js';
2
- import './chunk-XPYONXNE.js';
3
- import './chunk-4MT4OIAJ.js';
1
+ export { defineSmartArt, renderDiagramDrawing } from './chunk-OAGGHX23.js';
2
+ import './chunk-UYPH4ESZ.js';
3
+ import './chunk-A3QNC6VS.js';
package/dist/theme.js CHANGED
@@ -1,2 +1,2 @@
1
- export { THEME_CSS, THEME_STYLE_ID, installOfficeUiTheme } from './chunk-F4TM7U4P.js';
2
- export { COMPACT, FOCUS_RING, OFFICE_TOKENS, TOUCH, tok } from './chunk-4MT4OIAJ.js';
1
+ export { THEME_CSS, THEME_STYLE_ID, installOfficeUiTheme } from './chunk-5L3NYLAW.js';
2
+ export { COMPACT, FOCUS_RING, OFFICE_TOKENS, TOUCH, tok } from './chunk-A3QNC6VS.js';
@@ -0,0 +1,43 @@
1
+ /** One command the title-bar search can run. `category` shows on the right of its row. */
2
+ export interface OfficeTitleBarCommand {
3
+ id: string;
4
+ label: string;
5
+ category?: string | undefined;
6
+ }
7
+ /** The centred command search. Every string arrives translated from the host. */
8
+ export interface OfficeTitleBarSearch {
9
+ placeholder: string;
10
+ label: string;
11
+ /** Heading over the matches and the live-region text when there are some. */
12
+ heading: string;
13
+ /** Row and live-region text when nothing matches. */
14
+ empty: string;
15
+ /** Searched by label when `match` is absent. */
16
+ commands?: readonly OfficeTitleBarCommand[] | undefined;
17
+ /** Host ranking (synonyms, keywords); replaces the default label search. */
18
+ match?: ((query: string) => readonly OfficeTitleBarCommand[]) | undefined;
19
+ /** Text of the trailing "search the document" row; absent drops that row. */
20
+ content?: ((query: string) => string) | undefined;
21
+ /** Glyph of the content row; defaults to `search`. */
22
+ contentIcon?: string | undefined;
23
+ }
24
+ /** Detail of the search request: a chosen command, or a document search when `command` is absent. */
25
+ export interface OfficeTitleBarSearchDetail {
26
+ query: string;
27
+ command?: string;
28
+ }
29
+ /** The dropdown shows at most this many commands so it never outgrows its box. */
30
+ export declare const OFFICE_TITLE_BAR_SEARCH_LIMIT = 8;
31
+ export interface TitleBarSearchView {
32
+ box: HTMLElement;
33
+ input: HTMLElement & {
34
+ value: string;
35
+ };
36
+ render(search: OfficeTitleBarSearch | undefined): void;
37
+ close(): void;
38
+ }
39
+ /**
40
+ * A search field plus its result list. The query stays local to the view, so hosts never
41
+ * round-trip keystrokes; they receive one request per commit.
42
+ */
43
+ export declare function createTitleBarSearch(doc: Document, fieldTag: string, request: (detail: OfficeTitleBarSearchDetail) => void): TitleBarSearchView;
@@ -0,0 +1,20 @@
1
+ /** One Quick Access Toolbar button; every string arrives translated from the host. */
2
+ export interface OfficeQuickAccessItem {
3
+ id: string;
4
+ /** Registered glyph name (see `registerIcon`). */
5
+ icon: string;
6
+ /** Accessible name, and the visible text when labels show. */
7
+ label: string;
8
+ /** ScreenTip; absent leaves the button without a `title`. */
9
+ title?: string | undefined;
10
+ disabled?: boolean | undefined;
11
+ }
12
+ export interface QuickAccessStrip {
13
+ toolbar: HTMLElement;
14
+ render(items: readonly OfficeQuickAccessItem[], label: string, showLabels: boolean): void;
15
+ }
16
+ /**
17
+ * The Quick Access Toolbar: one roving tab stop, arrows/Home/End between enabled buttons.
18
+ * Buttons are keyed by id and patched in place, so a focused button survives every update.
19
+ */
20
+ export declare function createQuickAccessStrip(doc: Document, activate: (id: string) => void): QuickAccessStrip;
@@ -0,0 +1,49 @@
1
+ import { type OfficeQuickAccessItem } from './title-bar-strip.js';
2
+ import { type OfficeTitleBarSearch } from './title-bar-search.js';
3
+ export type OfficeTitleBarPlacement = 'titleBar' | 'belowRibbon';
4
+ export type OfficeTitleBarTone = 'idle' | 'saving' | 'error';
5
+ /** The AutoSave switch. The host owns the state; a change is only a request. */
6
+ export interface OfficeTitleBarAutosave {
7
+ enabled: boolean;
8
+ /** Default true. False renders the switch inert. */
9
+ available?: boolean | undefined;
10
+ /** "AutoSave". */
11
+ label: string;
12
+ /** "On" / "Off", shown after the switch. */
13
+ stateLabel: string;
14
+ /** Accessible name of the switch. */
15
+ toggleLabel: string;
16
+ /** ScreenTip of the switch; defaults to `toggleLabel`. */
17
+ title?: string | undefined;
18
+ }
19
+ /** Everything the bar shows, already translated. Absent parts are not rendered. */
20
+ export interface OfficeTitleBarState {
21
+ /** One or two letters in the product-coloured app mark; absent hides the mark. */
22
+ appMark?: string | undefined;
23
+ fileName: string;
24
+ /** Save-location or save-progress text after the name. */
25
+ status?: string | undefined;
26
+ tone?: OfficeTitleBarTone | undefined;
27
+ autosave?: OfficeTitleBarAutosave | undefined;
28
+ quickAccess?: {
29
+ label: string;
30
+ items: readonly OfficeQuickAccessItem[];
31
+ showLabels?: boolean | undefined;
32
+ } | undefined;
33
+ search?: OfficeTitleBarSearch | undefined;
34
+ }
35
+ /**
36
+ * `<office-ui-title-bar>`: Office's title bar above the ribbon (app mark, AutoSave, Quick
37
+ * Access Toolbar, file name and status, centred command search, `collaboration` and `account`
38
+ * slots). Controlled: set `state` (`OfficeTitleBarState`, every string translated); the bar
39
+ * owns no effects. `placement="belowRibbon"` renders only the Quick Access row and hides
40
+ * itself (`data-empty`) while that row is empty. Events (bubbling, composed; static names let a
41
+ * product subclass keep its published ones): `office-autosave-toggle`, `office-command`
42
+ * `{ command }` from a Quick Access button and `office-command-search` `{ query, command? }`.
43
+ * Override `activate(id)` to route Quick Access buttons differently and `rendered()` to mirror
44
+ * state onto the host. Tokens: `--office-title-bar-*`.
45
+ */
46
+ export declare const defineTitleBar: import("./registry.js").Definer;
47
+ export type { OfficeQuickAccessItem } from './title-bar-strip.js';
48
+ export type { OfficeTitleBarCommand, OfficeTitleBarSearch, OfficeTitleBarSearchDetail, } from './title-bar-search.js';
49
+ export { OFFICE_TITLE_BAR_SEARCH_LIMIT } from './title-bar-search.js';
package/dist/tokens.d.ts CHANGED
@@ -202,6 +202,18 @@ export declare const OFFICE_TOKENS: {
202
202
  readonly '--office-avatar-color': "var(--office-muted-foreground, #6b7280)";
203
203
  readonly '--office-toast-width': "360px";
204
204
  readonly '--office-account-field-width': "320px";
205
+ readonly '--office-title-bar-height': "36px";
206
+ readonly '--office-title-bar-below-height': "28px";
207
+ readonly '--office-title-bar-background': "var(--office-surface, #f3f4f6)";
208
+ readonly '--office-title-bar-foreground': "var(--office-foreground, #1f2937)";
209
+ readonly '--office-title-bar-border': "var(--office-border, #d1d5db)";
210
+ readonly '--office-title-bar-mark-size': "20px";
211
+ readonly '--office-title-bar-mark-background': "var(--office-accent, #2563eb)";
212
+ readonly '--office-title-bar-mark-foreground': "var(--office-accent-foreground, #ffffff)";
213
+ readonly '--office-title-bar-name-max-width': "240px";
214
+ readonly '--office-title-bar-name-max-width-narrow': "140px";
215
+ readonly '--office-title-bar-search-max-width': "448px";
216
+ readonly '--office-title-bar-results-max-height': "256px";
205
217
  };
206
218
  export type OfficeToken = keyof typeof OFFICE_TOKENS;
207
219
  /** `var(--office-…, <default>)` for a declared token. The default comes from the table. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ooxml-ui",
3
- "version": "0.16.3",
3
+ "version": "0.17.0",
4
4
  "description": "Shared, format-neutral web components and styles for the Office viewers (Word, PowerPoint, Excel)",
5
5
  "keywords": [
6
6
  "custom-elements",