ooxml-ui 0.16.3 → 0.18.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
@@ -70,7 +70,7 @@ with an incompatible build of this package.
70
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
71
  | `office-ui-toolbar` | `aria-label`, `aria-orientation`; arrow-key focus movement | none |
72
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 }` |
73
+ | `office-ui-status-bar` / `-status-item` | `label`, `value`, `interactive`, `id`; controlled bar: `state` `{ items?, toggles?, views?, zoom? }` with `collaboration` and `end` slots | `office-status-activate` `{ id }` |
74
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
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
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) |
@@ -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,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-HRWP3FWD.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")};
@@ -4183,23 +4183,234 @@ var defineSelect = definer("office-ui-select", () => {
4183
4183
  return OfficeUiSelect;
4184
4184
  });
4185
4185
 
4186
+ // src/status-bar-view.ts
4187
+ function createStatusBarView(doc, activate2) {
4188
+ const el = (tag, className) => {
4189
+ const node = doc.createElement(tag);
4190
+ node.className = className;
4191
+ return node;
4192
+ };
4193
+ const sep = (className) => {
4194
+ const node = el("i", className);
4195
+ node.setAttribute("aria-hidden", "true");
4196
+ return node;
4197
+ };
4198
+ const slot = (name2) => {
4199
+ const node = doc.createElement("slot");
4200
+ if (name2) node.name = name2;
4201
+ return node;
4202
+ };
4203
+ const button = (id, className) => {
4204
+ const node = el("button", className);
4205
+ node.type = "button";
4206
+ node.dataset.id = id;
4207
+ node.addEventListener("click", () => activate2(id));
4208
+ node.addEventListener("keydown", (event) => {
4209
+ const { key, ctrlKey, metaKey, altKey } = event;
4210
+ if ((key === " " || key === "Enter") && !ctrlKey && !metaKey && !altKey)
4211
+ event.stopPropagation();
4212
+ });
4213
+ return node;
4214
+ };
4215
+ const paint = (node, spec) => {
4216
+ let svg = node.querySelector("svg");
4217
+ if (!svg) svg = node.insertBefore(createIconSvg(doc), node.firstChild);
4218
+ paintIcon(svg, spec.icon);
4219
+ node.title = spec.label;
4220
+ node.setAttribute("aria-label", spec.label);
4221
+ if (spec.pressed !== void 0) node.setAttribute("aria-pressed", String(spec.pressed));
4222
+ else node.removeAttribute("aria-pressed");
4223
+ node.hidden = spec.hidden === true;
4224
+ let text2 = node.querySelector(".label");
4225
+ if (spec.text) {
4226
+ text2 ??= node.appendChild(el("span", "label"));
4227
+ text2.textContent = spec.text;
4228
+ } else {
4229
+ text2?.remove();
4230
+ }
4231
+ };
4232
+ const keyed = (parent, make, patch) => {
4233
+ const nodes = /* @__PURE__ */ new Map();
4234
+ return (specs) => {
4235
+ for (const [id, node] of nodes)
4236
+ if (!specs.some((spec) => spec.id === id)) {
4237
+ node.remove();
4238
+ nodes.delete(id);
4239
+ }
4240
+ for (const spec of specs) {
4241
+ let node = nodes.get(spec.id);
4242
+ if (!node) {
4243
+ node = make(spec);
4244
+ nodes.set(spec.id, node);
4245
+ }
4246
+ patch(node, spec);
4247
+ }
4248
+ const current = [...parent.children];
4249
+ if (specs.some((spec, index) => current[index] !== nodes.get(spec.id)))
4250
+ parent.append(...specs.map((spec) => nodes.get(spec.id)));
4251
+ };
4252
+ };
4253
+ const items = el("span", "items");
4254
+ const renderItems = keyed(
4255
+ items,
4256
+ (spec) => {
4257
+ const node = el("span", "item");
4258
+ node.dataset.item = spec.id;
4259
+ return node;
4260
+ },
4261
+ (node, spec) => {
4262
+ node.textContent = spec.text;
4263
+ if (spec.title) node.title = spec.title;
4264
+ else node.removeAttribute("title");
4265
+ node.classList.toggle("saving", spec.tone === "saving");
4266
+ node.classList.toggle("error", spec.tone === "error");
4267
+ node.classList.toggle("narrow-hide", spec.narrowHide === true);
4268
+ if (spec.live) node.setAttribute("aria-live", "polite");
4269
+ else node.removeAttribute("aria-live");
4270
+ }
4271
+ );
4272
+ const spacer = el("span", "spacer");
4273
+ const toggles = el("span", "toggles");
4274
+ const renderToggles = keyed(
4275
+ toggles,
4276
+ (spec) => button(spec.id, "toggle"),
4277
+ (node, spec) => paint(node, spec)
4278
+ );
4279
+ const viewSep = sep("sep tight");
4280
+ const views = el("div", "group views");
4281
+ const renderViews = keyed(
4282
+ views,
4283
+ (spec) => button(spec.id, "view"),
4284
+ (node, spec) => paint(node, spec)
4285
+ );
4286
+ const collaboration = slot("collaboration");
4287
+ const collabSep = sep("sep tight");
4288
+ collabSep.hidden = true;
4289
+ collaboration.addEventListener("slotchange", () => {
4290
+ collabSep.hidden = collaboration.assignedNodes().length === 0;
4291
+ });
4292
+ const zoomSep = sep("sep tight");
4293
+ const zoom = el("div", "group zoom");
4294
+ const zoomOut = button("zoomOut", "zoom-step");
4295
+ zoomOut.append(createIconSvg(doc));
4296
+ const zoomFit = button("zoomFit", "zoom-fit");
4297
+ const zoomIn = button("zoomIn", "zoom-step");
4298
+ zoomIn.append(createIconSvg(doc));
4299
+ zoom.append(zoomOut, zoomFit, zoomIn);
4300
+ const bar = el("div", "bar");
4301
+ bar.setAttribute("part", "bar");
4302
+ bar.append(
4303
+ items,
4304
+ slot(""),
4305
+ spacer,
4306
+ toggles,
4307
+ viewSep,
4308
+ views,
4309
+ collabSep,
4310
+ collaboration,
4311
+ slot("end"),
4312
+ zoomSep,
4313
+ zoom
4314
+ );
4315
+ const name = (node, label) => {
4316
+ node.title = label;
4317
+ node.setAttribute("aria-label", label);
4318
+ };
4319
+ return {
4320
+ bar,
4321
+ render(state) {
4322
+ const itemSpecs = state?.items ?? [];
4323
+ renderItems(itemSpecs);
4324
+ items.hidden = itemSpecs.length === 0;
4325
+ const toggleSpecs = state?.toggles ?? [];
4326
+ renderToggles(toggleSpecs);
4327
+ toggles.hidden = toggleSpecs.length === 0;
4328
+ const viewSpecs = state?.views || [];
4329
+ renderViews(viewSpecs);
4330
+ views.hidden = viewSpecs.length === 0;
4331
+ viewSep.hidden = views.hidden || toggles.hidden;
4332
+ spacer.hidden = !state;
4333
+ const z = state?.zoom;
4334
+ zoomSep.hidden = zoom.hidden = !z;
4335
+ if (z) {
4336
+ name(zoomOut, z.outLabel);
4337
+ name(zoomFit, z.fitLabel);
4338
+ name(zoomIn, z.inLabel);
4339
+ paintIcon(zoomOut.querySelector("svg"), z.outIcon ?? "minus");
4340
+ paintIcon(zoomIn.querySelector("svg"), z.inIcon ?? "plus");
4341
+ zoomFit.textContent = `${Math.round(z.percent)}%`;
4342
+ }
4343
+ }
4344
+ };
4345
+ }
4346
+
4186
4347
  // src/status-bar.ts
4187
4348
  var BAR_CSS = `
4188
4349
  :host { display: flex; align-items: center; gap: ${tok("--office-space-3")}; min-height: ${tok("--office-status-bar-height")}; padding: 0 ${tok("--office-space-2")}; font-size: ${tok("--office-font-size-xs")};
4189
4350
  background: ${tok("--office-surface")}; color: ${tok("--office-foreground")};
4190
4351
  border-top: ${tok("--office-border-width")} solid ${tok("--office-border")}; font-family: ${tok("--office-font")}; }
4191
4352
  ::slotted([slot="end"]) { margin-inline-start: auto; }
4192
- @media (forced-colors: active) { :host { background: Canvas; color: CanvasText; border-top-color: CanvasText; } }
4353
+ .bar { display: contents; }
4354
+ [hidden] { display: none !important; }
4355
+ :host([data-controlled]) { display: block; flex: none; padding: 0; gap: 0; }
4356
+ :host([data-controlled]) .bar { box-sizing: border-box; display: flex; align-items: center; gap: ${tok("--office-space-1")}; width: 100%;
4357
+ min-height: ${tok("--office-status-bar-height")}; padding: ${tok("--office-space-0")} ${tok("--office-space-2")}; color: ${tok("--office-muted-foreground")}; }
4358
+ :host([data-controlled]) ::slotted([slot="end"]) { margin-inline-start: 0; }
4359
+ .items { display: flex; align-items: center; min-width: 0; }
4360
+ .item { flex: none; white-space: nowrap; }
4361
+ .item + .item::before { content: ""; display: inline-block; width: ${tok("--office-border-width")}; height: ${tok("--office-space-3")};
4362
+ margin: 0 ${tok("--office-space-2")}; vertical-align: middle; background: ${tok("--office-border")}; }
4363
+ .item.saving { color: ${tok("--office-warning")}; }
4364
+ .item.error { color: ${tok("--office-danger")}; }
4365
+ .spacer { flex: 1; }
4366
+ .toggles, .group { display: flex; align-items: center; gap: ${tok("--office-space-0")}; }
4367
+ .sep { flex: none; width: ${tok("--office-border-width")}; height: ${tok("--office-space-3")}; margin: 0 ${tok("--office-space-0")}; background: ${tok("--office-border")}; }
4368
+ .bar button { box-sizing: border-box; display: inline-flex; align-items: center; justify-content: center; gap: ${tok("--office-space-1")};
4369
+ min-width: ${tok("--office-control-height-xs")}; min-height: ${tok("--office-control-height-xs")}; padding: ${tok("--office-space-1")}; border: 0; border-radius: ${tok("--office-radius-sm")};
4370
+ background: transparent; color: inherit; font: inherit; cursor: pointer; touch-action: manipulation; }
4371
+ .bar button:hover { background: ${tok("--office-selected")}; color: ${tok("--office-foreground")}; }
4372
+ .bar button[aria-pressed="true"] { color: ${tok("--office-accent")}; }
4373
+ .bar button:active { opacity: .8; }
4374
+ .bar button:focus-visible { outline: ${tok("--office-focus-width")} solid ${tok("--office-ring")}; outline-offset: ${tok("--office-focus-offset")}; }
4375
+ .bar svg { flex: none; width: ${tok("--office-icon-size")}; height: ${tok("--office-icon-size")}; fill: none; stroke: currentColor;
4376
+ stroke-width: ${tok("--office-icon-stroke")}; stroke-linecap: round; stroke-linejoin: round; }
4377
+ .toggle svg, .zoom-step svg { width: ${tok("--office-icon-size-sm")}; height: ${tok("--office-icon-size-sm")}; }
4378
+ .zoom-fit { min-width: ${tok("--office-zoom-value-width")}; font-variant-numeric: tabular-nums; }
4379
+ @media ${COMPACT} { .narrow-hide, .toggle .label { display: none !important; } }
4380
+ @media (pointer: coarse) { .bar button { min-width: ${tok("--office-target-size-touch")}; min-height: ${tok("--office-target-size-touch")}; } }
4381
+ @media (forced-colors: active) {
4382
+ :host { background: Canvas; color: CanvasText; border-top-color: CanvasText; }
4383
+ .bar button { color: ButtonText; } .bar button:hover { background: Highlight; color: HighlightText; }
4384
+ .bar button[aria-pressed="true"] { border: ${tok("--office-border-width")} solid Highlight; }
4385
+ .bar button:focus-visible { outline-color: Highlight; }
4386
+ .sep, .item + .item::before { background: CanvasText; }
4387
+ }
4193
4388
  `;
4194
4389
  var defineStatusBar = definer("office-ui-status-bar", () => {
4195
4390
  class OfficeUiStatusBar extends HTMLElement {
4391
+ static activateEvent = "office-status-activate";
4392
+ #state;
4393
+ #view;
4196
4394
  constructor() {
4197
4395
  super();
4198
4396
  const root = this.attachShadow({ mode: "open" });
4199
4397
  attachStyles(root, controlCss(BAR_CSS));
4200
- const end = this.ownerDocument.createElement("slot");
4201
- end.name = "end";
4202
- root.append(this.ownerDocument.createElement("slot"), end);
4398
+ this.#view = createStatusBarView(
4399
+ this.ownerDocument,
4400
+ (id) => emit(this, this.constructor.activateEvent, {
4401
+ id
4402
+ })
4403
+ );
4404
+ root.append(this.#view.bar);
4405
+ this.#view.render(void 0);
4406
+ }
4407
+ get state() {
4408
+ return this.#state;
4409
+ }
4410
+ set state(value) {
4411
+ this.#state = value ?? void 0;
4412
+ this.toggleAttribute("data-controlled", this.#state !== void 0);
4413
+ this.#view.render(this.#state);
4203
4414
  }
4204
4415
  connectedCallback() {
4205
4416
  this.setAttribute("role", "group");
@@ -4462,8 +4673,471 @@ var defineTabStrip = definer("office-ui-tab-strip", () => {
4462
4673
  return OfficeUiTabStrip;
4463
4674
  });
4464
4675
 
4465
- // src/zoom-slider.ts
4676
+ // src/title-bar-strip.ts
4677
+ function createQuickAccessStrip(doc, activate2) {
4678
+ const toolbar = doc.createElement("div");
4679
+ toolbar.className = "qat";
4680
+ toolbar.setAttribute("role", "toolbar");
4681
+ toolbar.setAttribute("part", "quick-access");
4682
+ const buttons = /* @__PURE__ */ new Map();
4683
+ let stop = "";
4684
+ const enabled = () => [...toolbar.querySelectorAll("button:not(:disabled)")];
4685
+ const syncRoving = () => {
4686
+ const list = enabled();
4687
+ const current = list.find((b) => b.dataset.command === stop) ?? list[0];
4688
+ for (const button of buttons.values()) button.tabIndex = button === current ? 0 : -1;
4689
+ };
4690
+ toolbar.addEventListener("focusin", (event) => {
4691
+ const target = event.target.closest("button");
4692
+ if (target?.dataset.command) {
4693
+ stop = target.dataset.command;
4694
+ syncRoving();
4695
+ }
4696
+ });
4697
+ toolbar.addEventListener("keydown", (event) => {
4698
+ if (event.ctrlKey || event.metaKey || event.altKey) return;
4699
+ const list = enabled();
4700
+ const index = list.findIndex((b) => b === event.target.closest("button"));
4701
+ const last = list.length - 1;
4702
+ const moves = {
4703
+ ArrowRight: (index + 1) % list.length,
4704
+ ArrowLeft: (index + last) % list.length,
4705
+ Home: 0,
4706
+ End: last
4707
+ };
4708
+ const next = moves[event.key] ?? -1;
4709
+ if (next >= 0 && index >= 0) {
4710
+ event.preventDefault();
4711
+ list[next]?.focus();
4712
+ }
4713
+ if (next >= 0 || event.key === " " || event.key === "Enter") event.stopPropagation();
4714
+ });
4715
+ const create = (id) => {
4716
+ const button = doc.createElement("button");
4717
+ button.type = "button";
4718
+ button.dataset.command = id;
4719
+ button.append(createIconSvg(doc));
4720
+ button.addEventListener("click", () => activate2(id));
4721
+ return button;
4722
+ };
4723
+ return {
4724
+ toolbar,
4725
+ render(items, label, showLabels) {
4726
+ toolbar.hidden = items.length === 0;
4727
+ toolbar.setAttribute("aria-label", label);
4728
+ for (const id of [...buttons.keys()]) {
4729
+ if (!items.some((item) => item.id === id)) {
4730
+ buttons.get(id)?.remove();
4731
+ buttons.delete(id);
4732
+ }
4733
+ }
4734
+ for (const item of items) {
4735
+ let button = buttons.get(item.id);
4736
+ if (!button) {
4737
+ button = create(item.id);
4738
+ buttons.set(item.id, button);
4739
+ }
4740
+ paintIcon(button.querySelector("svg"), item.icon);
4741
+ button.setAttribute("aria-label", item.label);
4742
+ if (item.title === void 0) button.removeAttribute("title");
4743
+ else button.title = item.title;
4744
+ button.disabled = item.disabled === true;
4745
+ let text2 = button.querySelector("small");
4746
+ if (showLabels) {
4747
+ text2 ??= button.appendChild(doc.createElement("small"));
4748
+ text2.textContent = item.label;
4749
+ } else {
4750
+ text2?.remove();
4751
+ }
4752
+ }
4753
+ const current = [...toolbar.children];
4754
+ if (items.some((item, index) => current[index] !== buttons.get(item.id)))
4755
+ toolbar.append(...items.map((item) => buttons.get(item.id)));
4756
+ syncRoving();
4757
+ }
4758
+ };
4759
+ }
4760
+
4761
+ // src/title-bar-search.ts
4762
+ var OFFICE_TITLE_BAR_SEARCH_LIMIT = 8;
4763
+ function labelMatches(search, query) {
4764
+ const needle = query.trim().toLowerCase();
4765
+ return (search.commands ?? []).filter((entry) => entry.label.toLowerCase().includes(needle));
4766
+ }
4767
+ function createTitleBarSearch(doc, fieldTag, request) {
4768
+ let model;
4769
+ const box = doc.createElement("div");
4770
+ box.className = "box";
4771
+ const input = doc.createElement(fieldTag);
4772
+ input.setAttribute("variant", "titlebar");
4773
+ input.setAttribute("part", "search");
4774
+ const results = doc.createElement("div");
4775
+ results.className = "results";
4776
+ results.setAttribute("role", "listbox");
4777
+ results.hidden = true;
4778
+ const live = doc.createElement("div");
4779
+ live.className = "sr";
4780
+ live.setAttribute("role", "status");
4781
+ box.append(input, results, live);
4782
+ let matches = [];
4783
+ let active = 0;
4784
+ const close = () => {
4785
+ results.hidden = true;
4786
+ results.replaceChildren();
4787
+ live.textContent = "";
4788
+ matches = [];
4789
+ };
4790
+ const commit = (entry) => {
4791
+ const query = input.value;
4792
+ input.value = "";
4793
+ close();
4794
+ request(entry ? { query, command: entry.id } : { query });
4795
+ };
4796
+ const row = (className, text2) => {
4797
+ const node = doc.createElement("div");
4798
+ node.className = className;
4799
+ node.textContent = text2;
4800
+ return node;
4801
+ };
4802
+ const option = (className, onPick) => {
4803
+ const button = doc.createElement("button");
4804
+ button.type = "button";
4805
+ button.tabIndex = -1;
4806
+ button.className = className;
4807
+ button.addEventListener("mousedown", (event) => {
4808
+ event.preventDefault();
4809
+ onPick();
4810
+ });
4811
+ return button;
4812
+ };
4813
+ const paint = () => {
4814
+ [...results.querySelectorAll('[role="option"]')].forEach(
4815
+ (node, index) => node.setAttribute("aria-selected", String(index === active))
4816
+ );
4817
+ };
4818
+ const open = () => {
4819
+ const query = input.value;
4820
+ if (!model || !query.trim()) {
4821
+ close();
4822
+ return;
4823
+ }
4824
+ const found = model.match ? [...model.match(query)] : labelMatches(model, query);
4825
+ matches = found.slice(0, OFFICE_TITLE_BAR_SEARCH_LIMIT);
4826
+ active = Math.min(active, Math.max(matches.length - 1, 0));
4827
+ results.replaceChildren();
4828
+ if (matches.length > 0) {
4829
+ results.append(row("heading", model.heading));
4830
+ matches.forEach((entry, index) => {
4831
+ const button = option("", () => commit(entry));
4832
+ button.setAttribute("role", "option");
4833
+ const label = doc.createElement("span");
4834
+ label.textContent = entry.label;
4835
+ const category = doc.createElement("span");
4836
+ category.className = "cat";
4837
+ category.textContent = entry.category ?? "";
4838
+ button.append(label, category);
4839
+ button.addEventListener("mouseenter", () => {
4840
+ active = index;
4841
+ paint();
4842
+ });
4843
+ results.append(button);
4844
+ });
4845
+ } else {
4846
+ results.append(row("empty", model.empty));
4847
+ }
4848
+ if (model.content) {
4849
+ const content = option("content", () => commit());
4850
+ const svg = createIconSvg(doc);
4851
+ paintIcon(svg, model.contentIcon ?? "search");
4852
+ const text2 = doc.createElement("span");
4853
+ text2.textContent = model.content(query);
4854
+ content.append(svg, text2);
4855
+ results.append(content);
4856
+ }
4857
+ results.hidden = false;
4858
+ live.textContent = matches.length > 0 ? model.heading : model.empty;
4859
+ paint();
4860
+ };
4861
+ input.addEventListener("input", () => {
4862
+ active = 0;
4863
+ open();
4864
+ });
4865
+ input.addEventListener("focusin", open);
4866
+ box.addEventListener("focusout", (event) => {
4867
+ const next = event.relatedTarget;
4868
+ if (!next || !box.contains(next)) close();
4869
+ });
4870
+ input.addEventListener("keydown", (event) => {
4871
+ const { key, ctrlKey, metaKey } = event;
4872
+ if (key === "Enter" && input.value.trim()) {
4873
+ commit(matches[active]);
4874
+ } else if (key === "Escape" && input.value) {
4875
+ input.value = "";
4876
+ close();
4877
+ } else if ((key === "ArrowDown" || key === "ArrowUp") && matches.length > 0) {
4878
+ event.preventDefault();
4879
+ active = (active + (key === "ArrowDown" ? 1 : matches.length - 1)) % matches.length;
4880
+ paint();
4881
+ }
4882
+ if (!ctrlKey && !metaKey) event.stopPropagation();
4883
+ });
4884
+ return {
4885
+ box,
4886
+ input,
4887
+ render(search) {
4888
+ model = search;
4889
+ box.hidden = !search;
4890
+ if (!search) {
4891
+ close();
4892
+ return;
4893
+ }
4894
+ input.setAttribute("placeholder", search.placeholder);
4895
+ input.setAttribute("aria-label", search.label);
4896
+ if (!results.hidden) open();
4897
+ },
4898
+ close
4899
+ };
4900
+ }
4901
+
4902
+ // src/title-bar.ts
4466
4903
  var CSS16 = `
4904
+ :host { display: block; flex: none; }
4905
+ :host([data-empty]) { display: none !important; }
4906
+ [hidden] { display: none !important; }
4907
+ .bar { box-sizing: border-box; display: flex; align-items: center; gap: ${tok("--office-space-1")}; width: 100%;
4908
+ height: ${tok("--office-title-bar-height")}; padding: 0 ${tok("--office-space-2")};
4909
+ border-bottom: ${tok("--office-border-width")} solid ${tok("--office-title-bar-border")};
4910
+ background: ${tok("--office-title-bar-background")}; color: ${tok("--office-title-bar-foreground")};
4911
+ font: ${tok("--office-font-size-xs")}/${tok("--office-line-height-tight")} ${tok("--office-font")}; user-select: none; }
4912
+ :host([placement="belowRibbon"]) .bar { height: auto; min-height: ${tok("--office-title-bar-below-height")}; padding-block: ${tok("--office-space-0")}; }
4913
+ .mark { flex: none; display: flex; align-items: center; justify-content: center;
4914
+ width: ${tok("--office-title-bar-mark-size")}; height: ${tok("--office-title-bar-mark-size")}; border-radius: ${tok("--office-radius-sm")};
4915
+ background: ${tok("--office-title-bar-mark-background")}; color: ${tok("--office-title-bar-mark-foreground")};
4916
+ font-size: ${tok("--office-font-size-2xs")}; font-weight: ${tok("--office-font-weight-bold")}; }
4917
+ .autosave { flex: none; display: flex; align-items: center; gap: ${tok("--office-space-1-5")};
4918
+ padding: 0 ${tok("--office-space-0")} 0 ${tok("--office-space-1-5")}; white-space: nowrap; }
4919
+ .label, .dot, .status { color: ${tok("--office-muted-foreground")}; white-space: nowrap; }
4920
+ .sep { flex: none; width: ${tok("--office-border-width")}; height: ${tok("--office-space-4")}; margin: 0 ${tok("--office-space-1")};
4921
+ background: ${tok("--office-title-bar-border")}; }
4922
+ .qat { display: flex; align-items: center; gap: ${tok("--office-space-0")}; min-width: 0; }
4923
+ .qat button, .results button { box-sizing: border-box; display: inline-flex; align-items: center; justify-content: center;
4924
+ gap: ${tok("--office-space-1")}; min-width: ${tok("--office-control-height-md")}; min-height: ${tok("--office-control-height-md")};
4925
+ padding: ${tok("--office-space-1")}; border: 0; border-radius: ${tok("--office-radius-sm")}; background: transparent;
4926
+ color: ${tok("--office-muted-foreground")}; font: inherit; cursor: pointer; touch-action: manipulation; }
4927
+ .qat button:hover:not(:disabled) { background: ${tok("--office-selected")}; }
4928
+ .qat button:active:not(:disabled) { opacity: .7; }
4929
+ .qat button:disabled { opacity: .4; cursor: not-allowed; }
4930
+ .qat small { font-size: ${tok("--office-font-size-xs")}; white-space: nowrap; }
4931
+ svg { flex: none; width: ${tok("--office-icon-size")}; height: ${tok("--office-icon-size")}; fill: none; stroke: currentColor;
4932
+ stroke-width: ${tok("--office-icon-stroke")}; stroke-linecap: round; stroke-linejoin: round; }
4933
+ .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; }
4934
+ .name { max-width: ${tok("--office-title-bar-name-max-width")}; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
4935
+ color: ${tok("--office-title-bar-foreground")}; font-size: ${tok("--office-font-size-sm")}; font-weight: ${tok("--office-font-weight-medium")}; }
4936
+ .status.saving { color: ${tok("--office-warning")}; }
4937
+ .status.error { color: ${tok("--office-danger")}; }
4938
+ .search { position: relative; flex: 1; display: flex; justify-content: center; min-width: 0; padding: 0 ${tok("--office-space-2")}; }
4939
+ .box { position: relative; width: 100%; max-width: ${tok("--office-title-bar-search-max-width")}; min-width: 0; }
4940
+ .box > [part="search"] { width: 100%; }
4941
+ .results { position: absolute; z-index: ${tok("--office-z-popover")}; top: calc(100% + ${tok("--office-space-1")}); right: 0; left: 0;
4942
+ max-height: ${tok("--office-title-bar-results-max-height")}; overflow-y: auto;
4943
+ border: ${tok("--office-border-width")} solid ${tok("--office-border")}; border-radius: ${tok("--office-radius-lg")};
4944
+ background: ${tok("--office-popover")}; color: ${tok("--office-popover-foreground")}; box-shadow: ${tok("--office-shadow-lg")}; }
4945
+ .heading { padding: ${tok("--office-space-1-5")} ${tok("--office-space-3")}; color: ${tok("--office-muted-foreground")};
4946
+ font-size: ${tok("--office-font-size-2xs")}; font-weight: ${tok("--office-font-weight-bold")}; letter-spacing: .05em; text-transform: uppercase; }
4947
+ .empty { padding: ${tok("--office-space-2")} ${tok("--office-space-3")}; color: ${tok("--office-muted-foreground")}; }
4948
+ .results button { display: flex; width: 100%; justify-content: flex-start; gap: ${tok("--office-space-2")};
4949
+ padding: ${tok("--office-space-1-5")} ${tok("--office-space-3")}; border-radius: 0; color: inherit; text-align: start; }
4950
+ .results button:hover, .results button[aria-selected="true"] { background: ${tok("--office-selected")}; }
4951
+ .results .cat { margin-inline-start: auto; color: ${tok("--office-muted-foreground")}; font-size: ${tok("--office-font-size-2xs")}; text-transform: capitalize; }
4952
+ .results .content { border-top: ${tok("--office-border-width")} solid ${tok("--office-border")}; }
4953
+ .end { flex: none; display: flex; align-items: center; justify-content: flex-end; gap: ${tok("--office-space-1")}; }
4954
+ .sr { position: absolute; width: ${tok("--office-space-px")}; height: ${tok("--office-space-px")}; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
4955
+ button:focus-visible { outline: ${tok("--office-focus-width")} solid ${tok("--office-ring")}; outline-offset: ${tok("--office-focus-offset")}; }
4956
+ @media ${COMPACT}, (max-width: 1023px) and (max-height: 520px) { :host(:not([placement="belowRibbon"])) { display: none !important; } }
4957
+ @media (max-width: 1100px) { .qat small { display: none; } .name { max-width: ${tok("--office-title-bar-name-max-width-narrow")}; } }
4958
+ @media (pointer: coarse) {
4959
+ .qat button, .results button { min-width: ${tok("--office-target-size-touch")}; min-height: ${tok("--office-target-size-touch")}; }
4960
+ .bar { height: auto; min-height: ${tok("--office-target-size-touch")}; }
4961
+ }
4962
+ @media (forced-colors: active) {
4963
+ .bar { border-bottom-color: CanvasText; background: Canvas; color: CanvasText; }
4964
+ .mark { border: ${tok("--office-border-width")} solid CanvasText; background: Canvas; color: CanvasText; }
4965
+ .label, .dot, .status, .name, .qat button, .results button { color: CanvasText; }
4966
+ .sep { background: CanvasText; }
4967
+ .qat button:hover:not(:disabled), .results button:hover, .results button[aria-selected="true"] { background: Highlight; color: HighlightText; }
4968
+ .qat button:disabled { color: GrayText; opacity: 1; }
4969
+ .results { border-color: CanvasText; background: Canvas; }
4970
+ button:focus-visible { outline-color: Highlight; }
4971
+ }
4972
+ `;
4973
+ var EMPTY = { fileName: "" };
4974
+ var defineTitleBar = definer("office-ui-title-bar", () => {
4975
+ class OfficeUiTitleBar extends HTMLElement {
4976
+ static autosaveEvent = "office-autosave-toggle";
4977
+ static commandEvent = "office-command";
4978
+ static searchEvent = "office-command-search";
4979
+ /** Inner controls; a product subclass may use its own aliased tags. */
4980
+ static switchTag = "office-ui-switch";
4981
+ static searchTag = "office-ui-search";
4982
+ static observedAttributes = ["placement"];
4983
+ #state = EMPTY;
4984
+ #bar;
4985
+ #full;
4986
+ #mark;
4987
+ #autosave;
4988
+ #autosaveLabel;
4989
+ #autosaveState;
4990
+ #switch;
4991
+ #sepAutosave;
4992
+ #sepStrip;
4993
+ #name;
4994
+ #dot;
4995
+ #status;
4996
+ #searchWrap;
4997
+ #strip;
4998
+ #search;
4999
+ #laidOut = "titleBar";
5000
+ constructor() {
5001
+ super();
5002
+ const doc = this.ownerDocument;
5003
+ const statics = this.constructor;
5004
+ const root = this.attachShadow({ mode: "open" });
5005
+ attachStyles(root, controlCss(CSS16));
5006
+ const el = (tag, className) => {
5007
+ const node = doc.createElement(tag);
5008
+ node.className = className;
5009
+ return node;
5010
+ };
5011
+ const sep = () => {
5012
+ const node = el("i", "sep");
5013
+ node.setAttribute("aria-hidden", "true");
5014
+ return node;
5015
+ };
5016
+ this.#mark = el("span", "mark");
5017
+ this.#mark.setAttribute("aria-hidden", "true");
5018
+ this.#autosaveLabel = el("span", "label");
5019
+ this.#switch = el(statics.switchTag, "switch");
5020
+ this.#switch.setAttribute("part", "autosave-switch");
5021
+ this.#switch.addEventListener("change", () => {
5022
+ emit(this, statics.autosaveEvent, null);
5023
+ this.#switch.checked = this.#state.autosave?.enabled === true;
5024
+ });
5025
+ this.#autosaveState = el("span", "label");
5026
+ this.#autosave = el("span", "autosave");
5027
+ this.#autosave.append(this.#autosaveLabel, this.#switch, this.#autosaveState);
5028
+ this.#sepAutosave = sep();
5029
+ this.#strip = createQuickAccessStrip(doc, (id) => this.activate(id));
5030
+ this.#sepStrip = sep();
5031
+ this.#name = el("span", "name");
5032
+ this.#name.setAttribute("part", "file-name");
5033
+ this.#dot = el("span", "dot");
5034
+ this.#dot.textContent = "\u2022";
5035
+ this.#dot.setAttribute("aria-hidden", "true");
5036
+ this.#status = el("span", "status");
5037
+ const file = el("span", "file");
5038
+ file.append(this.#name, this.#dot, this.#status);
5039
+ this.#search = createTitleBarSearch(
5040
+ doc,
5041
+ statics.searchTag,
5042
+ (detail) => emit(this, statics.searchEvent, detail)
5043
+ );
5044
+ this.#searchWrap = el("span", "search");
5045
+ this.#searchWrap.append(this.#search.box);
5046
+ const end = el("div", "end");
5047
+ for (const name of ["collaboration", "account"]) {
5048
+ const slot = doc.createElement("slot");
5049
+ slot.name = name;
5050
+ end.append(slot);
5051
+ }
5052
+ this.#bar = el("div", "bar");
5053
+ this.#bar.setAttribute("part", "bar");
5054
+ this.#full = [
5055
+ this.#mark,
5056
+ this.#autosave,
5057
+ this.#sepAutosave,
5058
+ this.#strip.toolbar,
5059
+ this.#sepStrip,
5060
+ file,
5061
+ this.#searchWrap,
5062
+ end
5063
+ ];
5064
+ this.#bar.append(...this.#full);
5065
+ root.append(this.#bar);
5066
+ }
5067
+ get state() {
5068
+ return this.#state;
5069
+ }
5070
+ set state(value) {
5071
+ this.#state = value ?? EMPTY;
5072
+ this.#paint();
5073
+ }
5074
+ get placement() {
5075
+ return this.getAttribute("placement") === "belowRibbon" ? "belowRibbon" : "titleBar";
5076
+ }
5077
+ set placement(value) {
5078
+ this.setAttribute("placement", value);
5079
+ }
5080
+ /** The search field inside the bar, for hosts that move focus to it (Alt+Q). */
5081
+ get searchField() {
5082
+ return this.#search.input;
5083
+ }
5084
+ connectedCallback() {
5085
+ this.#paint();
5086
+ }
5087
+ attributeChangedCallback() {
5088
+ this.#paint();
5089
+ }
5090
+ /** A Quick Access button was pressed; subclasses may route by id. */
5091
+ activate(id) {
5092
+ emit(this, this.constructor.commandEvent, { command: id });
5093
+ }
5094
+ /** Called after every render; subclasses mirror state onto the host here. */
5095
+ rendered() {
5096
+ }
5097
+ #paint() {
5098
+ const state = this.#state;
5099
+ const below = this.placement === "belowRibbon";
5100
+ if (this.#laidOut !== this.placement) {
5101
+ this.#bar.replaceChildren(...below ? [this.#strip.toolbar] : this.#full);
5102
+ this.#laidOut = this.placement;
5103
+ }
5104
+ const items = state.quickAccess?.items ?? [];
5105
+ this.toggleAttribute("data-empty", below && items.length === 0);
5106
+ this.#strip.render(
5107
+ items,
5108
+ state.quickAccess?.label ?? "",
5109
+ state.quickAccess?.showLabels === true
5110
+ );
5111
+ this.#sepStrip.hidden = below || items.length === 0;
5112
+ this.#mark.hidden = !state.appMark;
5113
+ this.#mark.textContent = state.appMark ?? "";
5114
+ const autosave = state.autosave;
5115
+ this.#autosave.hidden = this.#sepAutosave.hidden = !autosave;
5116
+ if (autosave) {
5117
+ const available = autosave.available !== false;
5118
+ this.#autosaveLabel.textContent = autosave.label;
5119
+ this.#autosaveState.textContent = autosave.stateLabel;
5120
+ this.#switch.disabled = !available;
5121
+ this.#switch.checked = autosave.enabled;
5122
+ this.#switch.setAttribute("aria-label", autosave.toggleLabel);
5123
+ this.#switch.title = autosave.title ?? autosave.toggleLabel;
5124
+ }
5125
+ this.#name.textContent = state.fileName;
5126
+ this.#dot.hidden = this.#status.hidden = !state.status;
5127
+ this.#status.textContent = state.status ?? "";
5128
+ const tone = state.tone ?? "idle";
5129
+ this.#status.classList.toggle("saving", tone === "saving");
5130
+ this.#status.classList.toggle("error", tone === "error");
5131
+ this.#searchWrap.hidden = !state.search;
5132
+ this.#search.render(state.search);
5133
+ this.rendered();
5134
+ }
5135
+ }
5136
+ return OfficeUiTitleBar;
5137
+ });
5138
+
5139
+ // src/zoom-slider.ts
5140
+ var CSS17 = `
4467
5141
  :host { display: inline-flex; align-items: center; gap: ${tok("--office-space-0")}; font-size: ${tok("--office-font-size-xs")};
4468
5142
  color: ${tok("--office-foreground")}; font-family: ${tok("--office-font")}; }
4469
5143
  button { box-sizing: border-box; display: inline-grid; place-items: center; min-width: ${tok("--office-target-size")};
@@ -4499,7 +5173,7 @@ var defineZoomSlider = definer("office-ui-zoom-slider", () => {
4499
5173
  super();
4500
5174
  const doc = this.ownerDocument;
4501
5175
  const root = this.attachShadow({ mode: "open" });
4502
- attachStyles(root, controlCss(CSS16));
5176
+ attachStyles(root, controlCss(CSS17));
4503
5177
  const button = (name, text2) => {
4504
5178
  const element = doc.createElement("button");
4505
5179
  element.type = "button";
@@ -4773,10 +5447,11 @@ var CONTROL_DEFINERS = [
4773
5447
  defineDialogFooter,
4774
5448
  defineToasts,
4775
5449
  defineReadOnlyBanner,
4776
- definePasteOptions
5450
+ definePasteOptions,
5451
+ defineTitleBar
4777
5452
  ];
4778
5453
  function registerControls(registry) {
4779
5454
  for (const define of CONTROL_DEFINERS) define(registry);
4780
5455
  }
4781
5456
 
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 };
5457
+ 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,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,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();
@@ -18,8 +18,11 @@ var BUILT_IN = {
18
18
  settings: "M3 5h14M6 10h8M8 15h4M6 3v4M12 8v4M10 13v4",
19
19
  clock: "M3 10a7 7 0 1 0 14 0 7 7 0 1 0-14 0M10 6v4l3 2",
20
20
  reset: "M4 10a6 6 0 1 1 1.8 4.2M4 6v4h4",
21
+ plus: "M10 4v12M4 10h12",
22
+ minus: "M4 10h12",
21
23
  search: "M3 8.5a5.5 5.5 0 1 0 11 0 5.5 5.5 0 1 0-11 0M13 13l4 4",
22
24
  undo: "M7.5 11.5 3.5 7.5l4-4M3.5 7.5h9a4 4 0 0 1 0 8H10",
25
+ save: "M3.5 3h10.5l2.5 2.5V17h-13ZM6 3v5h7V3M6 17v-5.5h8V17",
23
26
  redo: "m12.5 11.5 4-4-4-4M16.5 7.5h-9a4 4 0 0 0 0 8H10",
24
27
  pointer: "m5 2.5v13.5l3.6-3.6 2.4 5.1 2.1-1-2.4-5H15.5Z",
25
28
  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
- export type { OfficeStatusActivateEvent } from './status-bar.js';
30
+ export type { OfficeStatusActivateEvent, OfficeStatusBarState, OfficeStatusButton, OfficeStatusText, } 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-BN5K27RN.js';
2
+ export { defineIcon } from './chunk-HRWP3FWD.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-HRWP3FWD.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-BN5K27RN.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-BN5K27RN.js';
5
+ export { ICON_CSS, createIconSvg, defineIcon, getIcon, listIcons, paintIcon, registerIcon } from './chunk-HRWP3FWD.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';
@@ -0,0 +1,48 @@
1
+ /** A text segment at the start of the bar (page count, words, language, save state). */
2
+ export interface OfficeStatusText {
3
+ id: string;
4
+ text: string;
5
+ title?: string | undefined;
6
+ tone?: 'idle' | 'saving' | 'error' | undefined;
7
+ /** Announce changes politely (a page counter). */
8
+ live?: boolean | undefined;
9
+ /** Hide on phone widths. */
10
+ narrowHide?: boolean | undefined;
11
+ }
12
+ /** A status-bar button (Notes, Comments, a view switch). `label` is its name and ScreenTip. */
13
+ export interface OfficeStatusButton {
14
+ id: string;
15
+ icon: string;
16
+ label: string;
17
+ /** Visible text after the glyph; hidden on phone widths. */
18
+ text?: string | undefined;
19
+ pressed?: boolean | undefined;
20
+ hidden?: boolean | undefined;
21
+ }
22
+ /** Everything the controlled bar shows, already translated. Absent parts are not rendered. */
23
+ export interface OfficeStatusBarState {
24
+ items?: readonly OfficeStatusText[] | undefined;
25
+ toggles?: readonly OfficeStatusButton[] | undefined;
26
+ /** The view switches (Normal, Sorter, Reading); hidden while empty or `false`. */
27
+ views?: readonly OfficeStatusButton[] | false | undefined;
28
+ /** Zoom out, percentage (zoom to fit) and zoom in; emits `zoomOut`, `zoomFit`, `zoomIn`. */
29
+ zoom?: {
30
+ percent: number;
31
+ outLabel: string;
32
+ fitLabel: string;
33
+ inLabel: string;
34
+ /** Glyphs; default `minus` and `plus`. */
35
+ outIcon?: string | undefined;
36
+ inIcon?: string | undefined;
37
+ } | undefined;
38
+ }
39
+ export interface StatusBarView {
40
+ bar: HTMLElement;
41
+ render(state: OfficeStatusBarState | undefined): void;
42
+ }
43
+ /**
44
+ * The controlled status bar: built once, then patched in place so a focused button survives
45
+ * updates. Slots stay in the row: the default slot after the texts, `collaboration` between the
46
+ * views and the zoom, and `end` before the zoom.
47
+ */
48
+ export declare function createStatusBarView(doc: Document, activate: (id: string) => void): StatusBarView;
@@ -2,8 +2,12 @@ export type OfficeStatusActivateEvent = CustomEvent<{
2
2
  id: string;
3
3
  }>;
4
4
  /**
5
- * Status bar container: `role="group"` named by its `label` attribute (default "Status").
6
- * Children with `slot="end"` are pushed to the trailing edge (zoom, view switches).
5
+ * Status bar: `role="group"` named by its `label` attribute (default "Status"). Two ways to fill
6
+ * it. Composed: children, with `slot="end"` pushed to the trailing edge (zoom, view switches).
7
+ * Controlled: set `state` (`OfficeStatusBarState`: start texts, toggles, view switches and a zoom
8
+ * cluster, all translated); every button emits `office-status-activate` `{ id }` (static
9
+ * `activateEvent` lets a product subclass keep its published name). Slots stay available in
10
+ * controlled mode: the default after the texts, `collaboration` and `end` before the zoom.
7
11
  */
8
12
  export declare const defineStatusBar: import("./registry.js").Definer;
9
13
  /**
@@ -12,3 +16,4 @@ export declare const defineStatusBar: import("./registry.js").Definer;
12
16
  * `{ id }` (`id` attribute) on click, Enter or Space; zoom or language pickers are examples.
13
17
  */
14
18
  export declare const defineStatusItem: import("./registry.js").Definer;
19
+ export type { OfficeStatusBarState, OfficeStatusButton, OfficeStatusText, } from './status-bar-view.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.18.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",