ooxml-ui 0.17.0 → 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) |
@@ -1,4 +1,4 @@
1
- import { createIconSvg, paintIcon, defineIcon } from './chunk-LI7NB7HR.js';
1
+ import { createIconSvg, paintIcon, defineIcon } from './chunk-HRWP3FWD.js';
2
2
  import { initialsOf } from './chunk-DECL6RNI.js';
3
3
  import { definer, attachStyles, controlCss, present, emit } from './chunk-UYPH4ESZ.js';
4
4
  import { tok, FOCUS_RING, COMPACT, OFFICE_TOKENS } from './chunk-A3QNC6VS.js';
@@ -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");
@@ -18,6 +18,8 @@ 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",
23
25
  save: "M3.5 3h10.5l2.5 2.5V17h-13ZM6 3v5h7V3M6 17v-5.5h8V17",
@@ -27,7 +27,7 @@ export { defineAccount, defineDialogFooter, definePasteOptions, defineRadio, def
27
27
  export type { OfficeCommandEvent } from './button.js';
28
28
  export type { OfficeDialogCloseEvent, OfficeDialogCloseReason } from './dialog.js';
29
29
  export type { OfficeSelectOption } from './select.js';
30
- export type { OfficeStatusActivateEvent } from './status-bar.js';
30
+ export type { OfficeStatusActivateEvent, OfficeStatusBarState, OfficeStatusButton, OfficeStatusText, } from './status-bar.js';
31
31
  export type { OfficeTab, OfficeTabSelectEvent } from './tab-strip.js';
32
32
  export type { OfficeSearchCommand } from './command-search.js';
33
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';
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_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';
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
3
  import './chunk-DECL6RNI.js';
4
4
  import './chunk-UYPH4ESZ.js';
5
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-LI7NB7HR.js';
1
+ export { ICON_CSS, createIconSvg, defineIcon, getIcon, listIcons, paintIcon, registerIcon } from './chunk-HRWP3FWD.js';
2
2
  import './chunk-UYPH4ESZ.js';
3
3
  import './chunk-A3QNC6VS.js';
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { installOfficeUiTheme } from './chunk-5L3NYLAW.js';
2
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';
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
6
  import { definePresence } from './chunk-DECL6RNI.js';
7
7
  export { definePresence, initialsOf, participantsFromAwareness } from './chunk-DECL6RNI.js';
8
8
  import { defineSmartArt } from './chunk-OAGGHX23.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ooxml-ui",
3
- "version": "0.17.0",
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",