ooxml-ui 0.1.12 → 0.2.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 +22 -20
- package/dist/button.d.ts +2 -1
- package/dist/{chunk-5UKGBJXE.js → chunk-Q2FH3CZQ.js} +307 -5
- package/dist/{chunk-7MCSBDSU.js → chunk-Y4YIYNUZ.js} +11 -1
- package/dist/controls.d.ts +5 -2
- package/dist/controls.js +2 -2
- package/dist/icons.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +5 -3
- package/dist/status-bar.d.ts +4 -1
- package/dist/tab-strip.d.ts +18 -0
- package/dist/zoom-slider.d.ts +9 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -43,14 +43,14 @@ document.body.append(button);
|
|
|
43
43
|
|
|
44
44
|
## API: entries (ESM only)
|
|
45
45
|
|
|
46
|
-
| Entry | Contents
|
|
47
|
-
| ------------------- |
|
|
48
|
-
| `ooxml-ui` | everything below plus `registerOfficeUi()` and `OFFICE_UI_TAGS`
|
|
49
|
-
| `ooxml-ui/theme` | `THEME_CSS`, `installOfficeUiTheme()` (tokens, dark mode, forced-colors, touch targets)
|
|
50
|
-
| `ooxml-ui/icons` | icon registry (`registerIcon`, `getIcon`, `listIcons`) and `<office-ui-icon>`
|
|
51
|
-
| `ooxml-ui/controls` | button, checkbox, switch, select, ribbon group, toolbar, dialog, status bar and item
|
|
52
|
-
| `ooxml-ui/presence` | `<office-ui-presence>` avatar stack for collaboration awareness
|
|
53
|
-
| `ooxml-ui/smartart` | `<office-ui-smartart>`: draws a core `DiagramDrawing` as SVG
|
|
46
|
+
| Entry | Contents |
|
|
47
|
+
| ------------------- | ------------------------------------------------------------------------------------------------------------ |
|
|
48
|
+
| `ooxml-ui` | everything below plus `registerOfficeUi()` and `OFFICE_UI_TAGS` |
|
|
49
|
+
| `ooxml-ui/theme` | `THEME_CSS`, `installOfficeUiTheme()` (tokens, dark mode, forced-colors, touch targets) |
|
|
50
|
+
| `ooxml-ui/icons` | icon registry (`registerIcon`, `getIcon`, `listIcons`) and `<office-ui-icon>` |
|
|
51
|
+
| `ooxml-ui/controls` | button, checkbox, switch, select, ribbon group, toolbar, dialog, status bar and item, zoom slider, tab strip |
|
|
52
|
+
| `ooxml-ui/presence` | `<office-ui-presence>` avatar stack for collaboration awareness |
|
|
53
|
+
| `ooxml-ui/smartart` | `<office-ui-smartart>`: draws a core `DiagramDrawing` as SVG |
|
|
54
54
|
|
|
55
55
|
Importing an entry never touches the DOM (SSR-safe). Elements are defined by the `define*` /
|
|
56
56
|
`register*` functions, which are idempotent, no-ops without a `window`, and refuse to coexist
|
|
@@ -58,18 +58,20 @@ with an incompatible build of this package.
|
|
|
58
58
|
|
|
59
59
|
## Features: elements
|
|
60
60
|
|
|
61
|
-
| Tag | Attributes / properties
|
|
62
|
-
| ---------------------------------------- |
|
|
63
|
-
| `office-ui-button` | `label`, `icon`, `command`, `disabled`, `pressed`, `expanded`, `icon-only`, `variant="stacked"` | `office-command` `{ command }`
|
|
64
|
-
| `office-ui-checkbox`, `office-ui-switch` | `checked`, `disabled`, `value`, `aria-label`; form-associated
|
|
65
|
-
| `office-ui-select` | `options` `[{ value, label, disabled? }]`, `value`, `selectedIndex`, `disabled`
|
|
66
|
-
| `office-ui-ribbon-group` | `label`; default slot
|
|
67
|
-
| `office-ui-toolbar` | `aria-label`, `aria-orientation`; arrow-key focus movement
|
|
68
|
-
| `office-ui-dialog` | `open`, `heading`, `dismissible="false"`, `show()`, `close()`; slots default, `footer`
|
|
69
|
-
| `office-ui-status-bar` / `-status-item` | `label`, `value`, `interactive`, `id`
|
|
70
|
-
| `office-ui-
|
|
71
|
-
| `office-ui-
|
|
72
|
-
| `office-ui-
|
|
61
|
+
| Tag | Attributes / properties | Events (all bubble, composed) |
|
|
62
|
+
| ---------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
|
|
63
|
+
| `office-ui-button` | `label`, `icon`, `command`, `disabled`, `pressed`, `expanded`, `icon-only`, `variant="stacked"`, `keyshortcuts` | `office-command` `{ command }` |
|
|
64
|
+
| `office-ui-checkbox`, `office-ui-switch` | `checked`, `disabled`, `value`, `aria-label`; form-associated | `input`, `change` |
|
|
65
|
+
| `office-ui-select` | `options` `[{ value, label, disabled? }]`, `value`, `selectedIndex`, `disabled` | `input`, `change` |
|
|
66
|
+
| `office-ui-ribbon-group` | `label`; default slot | none |
|
|
67
|
+
| `office-ui-toolbar` | `aria-label`, `aria-orientation`; arrow-key focus movement | none |
|
|
68
|
+
| `office-ui-dialog` | `open`, `heading`, `dismissible="false"`, `show()`, `close()`; slots default, `footer` | `office-dialog-close` `{ reason }` (cancelable) |
|
|
69
|
+
| `office-ui-status-bar` / `-status-item` | `label`, `value`, `interactive`, `id` | `office-status-activate` `{ id }` |
|
|
70
|
+
| `office-ui-zoom-slider` | `value` (percent), `min`, `max`, `step`, `disabled`, `fit` (fit button name), `label` | `input`, `change`; fit: `office-command` `{ command: 'zoom-fit' }` |
|
|
71
|
+
| `office-ui-tab-strip` | `tabs` `[{ id, label, title? }]`, `selected`, `label`, `disabled` | `office-tab-select` `{ id }` (cancelable) |
|
|
72
|
+
| `office-ui-presence` | `participants`, `max`, `label` | `office-presence-select` `{ id }` |
|
|
73
|
+
| `office-ui-smartart` | `drawing` (core `DiagramDrawing`), `schemeColors`, `label` | `office-smartart-render` (render report) |
|
|
74
|
+
| `office-ui-icon` | `name`, `label` | none |
|
|
73
75
|
|
|
74
76
|
Setting a property never emits an event; only user activation does. Controls honour
|
|
75
77
|
`prefers-color-scheme`, `forced-colors: active` (system colours and a visible focus ring) and
|
package/dist/button.d.ts
CHANGED
|
@@ -3,7 +3,8 @@ export type OfficeCommandEvent = CustomEvent<{
|
|
|
3
3
|
}>;
|
|
4
4
|
/**
|
|
5
5
|
* Command button. Attributes: `label`, `icon`, `command`, `disabled`, `pressed` (aria-pressed),
|
|
6
|
-
* `expanded` (aria-expanded), `icon-only`, `variant="stacked"`, `title
|
|
6
|
+
* `expanded` (aria-expanded), `icon-only`, `variant="stacked"`, `title`, `keyshortcuts`
|
|
7
|
+
* (forwarded as aria-keyshortcuts, e.g. `Control+Z`).
|
|
7
8
|
* Activation (pointer, Enter, Space) emits one bubbling, composed `office-command`
|
|
8
9
|
* event with `{ command }`; the host decides what it does. Nothing happens when disabled.
|
|
9
10
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createIconSvg, paintIcon, defineIcon } from './chunk-
|
|
1
|
+
import { createIconSvg, paintIcon, defineIcon } from './chunk-Y4YIYNUZ.js';
|
|
2
2
|
import { definer, attachStyles, controlCss, emit } from './chunk-EY266IK3.js';
|
|
3
3
|
|
|
4
4
|
// src/button.ts
|
|
@@ -34,7 +34,8 @@ var defineButton = definer("office-ui-button", () => {
|
|
|
34
34
|
"pressed",
|
|
35
35
|
"expanded",
|
|
36
36
|
"icon-only",
|
|
37
|
-
"title"
|
|
37
|
+
"title",
|
|
38
|
+
"keyshortcuts"
|
|
38
39
|
];
|
|
39
40
|
button;
|
|
40
41
|
svg;
|
|
@@ -84,6 +85,9 @@ var defineButton = definer("office-ui-button", () => {
|
|
|
84
85
|
else this.button.removeAttribute("aria-label");
|
|
85
86
|
this.button.title = this.getAttribute("title") ?? (iconOnly ? label : "");
|
|
86
87
|
this.button.disabled = this.disabled;
|
|
88
|
+
const shortcuts = this.getAttribute("keyshortcuts");
|
|
89
|
+
if (shortcuts) this.button.setAttribute("aria-keyshortcuts", shortcuts);
|
|
90
|
+
else this.button.removeAttribute("aria-keyshortcuts");
|
|
87
91
|
if (paintIcon(this.svg, this.getAttribute("icon"))) this.svg.setAttribute("data-painted", "");
|
|
88
92
|
else this.svg.removeAttribute("data-painted");
|
|
89
93
|
for (const attr of ["pressed", "expanded"]) {
|
|
@@ -648,7 +652,9 @@ var defineStatusBar = definer("office-ui-status-bar", () => {
|
|
|
648
652
|
super();
|
|
649
653
|
const root = this.attachShadow({ mode: "open" });
|
|
650
654
|
attachStyles(root, controlCss(BAR_CSS));
|
|
651
|
-
|
|
655
|
+
const end = this.ownerDocument.createElement("slot");
|
|
656
|
+
end.name = "end";
|
|
657
|
+
root.append(this.ownerDocument.createElement("slot"), end);
|
|
652
658
|
}
|
|
653
659
|
connectedCallback() {
|
|
654
660
|
this.setAttribute("role", "group");
|
|
@@ -725,6 +731,300 @@ var defineStatusItem = definer("office-ui-status-item", () => {
|
|
|
725
731
|
return OfficeUiStatusItem;
|
|
726
732
|
});
|
|
727
733
|
|
|
734
|
+
// src/tab-strip.ts
|
|
735
|
+
var CSS4 = `
|
|
736
|
+
:host { display: flex; align-items: stretch; min-width: 0; min-height: 28px; gap: 2px; padding: 0 6px;
|
|
737
|
+
background: var(--office-surface, #f3f4f6); color: var(--office-muted-foreground, #6b7280);
|
|
738
|
+
border-top: 1px solid var(--office-border, #d1d5db); font-size: 12px;
|
|
739
|
+
font-family: var(--office-font, system-ui, sans-serif); }
|
|
740
|
+
.step { flex: none; display: inline-grid; place-items: center; width: var(--office-target-size, 26px);
|
|
741
|
+
min-height: var(--office-target-size, 26px);
|
|
742
|
+
padding: 0; border: 0; background: transparent; color: inherit; cursor: pointer; }
|
|
743
|
+
.step:disabled { opacity: .4; cursor: default; }
|
|
744
|
+
.list { display: flex; align-items: stretch; min-width: 0; overflow-x: auto; scrollbar-width: thin; }
|
|
745
|
+
.tab { flex: none; max-width: 220px; min-height: var(--office-target-size, 26px); margin-top: -1px;
|
|
746
|
+
padding: 2px 14px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
|
|
747
|
+
border: 1px solid transparent; border-top: 0; border-radius: 0 0 var(--office-radius, 4px) var(--office-radius, 4px);
|
|
748
|
+
background: transparent; color: inherit; font: inherit; cursor: pointer; }
|
|
749
|
+
.tab:hover { color: var(--office-foreground, #1f2937); }
|
|
750
|
+
.tab[aria-selected="true"] { border-color: var(--office-border, #d1d5db); background: var(--office-background, #fff);
|
|
751
|
+
color: var(--office-accent, #2563eb); font-weight: 600; box-shadow: inset 0 2px 0 var(--office-accent, #2563eb); }
|
|
752
|
+
button:focus-visible { outline: 2px solid var(--office-ring, #2563eb); outline-offset: -2px; }
|
|
753
|
+
svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.5;
|
|
754
|
+
stroke-linecap: round; stroke-linejoin: round; }
|
|
755
|
+
@media (forced-colors: active) {
|
|
756
|
+
:host { border-top-color: CanvasText; }
|
|
757
|
+
.tab[aria-selected="true"] { background: Highlight; color: HighlightText; forced-color-adjust: none; }
|
|
758
|
+
}
|
|
759
|
+
`;
|
|
760
|
+
var defineTabStrip = definer("office-ui-tab-strip", () => {
|
|
761
|
+
class OfficeUiTabStrip extends HTMLElement {
|
|
762
|
+
static observedAttributes = ["label", "disabled", "selected", "previous-label", "next-label"];
|
|
763
|
+
items = [];
|
|
764
|
+
list;
|
|
765
|
+
previous;
|
|
766
|
+
next;
|
|
767
|
+
constructor() {
|
|
768
|
+
super();
|
|
769
|
+
const doc = this.ownerDocument;
|
|
770
|
+
const root = this.attachShadow({ mode: "open" });
|
|
771
|
+
attachStyles(root, controlCss(CSS4));
|
|
772
|
+
const step = (name, icon) => {
|
|
773
|
+
const button = doc.createElement("button");
|
|
774
|
+
button.type = "button";
|
|
775
|
+
button.className = "step";
|
|
776
|
+
button.setAttribute("aria-label", name);
|
|
777
|
+
button.title = name;
|
|
778
|
+
const svg = createIconSvg(doc);
|
|
779
|
+
paintIcon(svg, icon);
|
|
780
|
+
button.append(svg);
|
|
781
|
+
return button;
|
|
782
|
+
};
|
|
783
|
+
this.previous = step("Previous", "chevronLeft");
|
|
784
|
+
this.next = step("Next", "chevronRight");
|
|
785
|
+
this.list = doc.createElement("div");
|
|
786
|
+
this.list.className = "list";
|
|
787
|
+
this.list.setAttribute("role", "tablist");
|
|
788
|
+
root.append(this.previous, this.next, this.list);
|
|
789
|
+
this.previous.addEventListener("click", () => this.move(-1, false));
|
|
790
|
+
this.next.addEventListener("click", () => this.move(1, false));
|
|
791
|
+
this.list.addEventListener("click", (event) => {
|
|
792
|
+
const tab = event.target.closest(".tab");
|
|
793
|
+
if (tab?.dataset.id !== void 0) this.choose(tab.dataset.id, false);
|
|
794
|
+
});
|
|
795
|
+
this.list.addEventListener("keydown", (event) => this.onKey(event));
|
|
796
|
+
}
|
|
797
|
+
connectedCallback() {
|
|
798
|
+
this.render();
|
|
799
|
+
}
|
|
800
|
+
attributeChangedCallback(name) {
|
|
801
|
+
if (name === "selected") this.sync();
|
|
802
|
+
else this.render();
|
|
803
|
+
}
|
|
804
|
+
get tabs() {
|
|
805
|
+
return this.items.map((tab) => ({ ...tab }));
|
|
806
|
+
}
|
|
807
|
+
set tabs(value) {
|
|
808
|
+
this.items = (Array.isArray(value) ? value : []).filter((tab) => tab && typeof tab.id === "string").map((tab) => ({
|
|
809
|
+
id: tab.id,
|
|
810
|
+
label: String(tab.label ?? ""),
|
|
811
|
+
...tab.title === void 0 ? {} : { title: String(tab.title) }
|
|
812
|
+
}));
|
|
813
|
+
this.render();
|
|
814
|
+
}
|
|
815
|
+
get selected() {
|
|
816
|
+
return this.getAttribute("selected") ?? "";
|
|
817
|
+
}
|
|
818
|
+
set selected(id) {
|
|
819
|
+
this.setAttribute("selected", String(id));
|
|
820
|
+
}
|
|
821
|
+
index() {
|
|
822
|
+
return this.items.findIndex((tab) => tab.id === this.selected);
|
|
823
|
+
}
|
|
824
|
+
move(delta, focus) {
|
|
825
|
+
const index = this.index();
|
|
826
|
+
const target = this.items[Math.max(0, Math.min(this.items.length - 1, index + delta))];
|
|
827
|
+
if (target) this.choose(target.id, focus);
|
|
828
|
+
}
|
|
829
|
+
choose(id, focus) {
|
|
830
|
+
if (this.hasAttribute("disabled")) return;
|
|
831
|
+
if (id !== this.selected && emit(this, "office-tab-select", { id }, true)) this.selected = id;
|
|
832
|
+
if (focus) this.tabButton(this.selected)?.focus();
|
|
833
|
+
}
|
|
834
|
+
tabButton(id) {
|
|
835
|
+
return [...this.list.querySelectorAll(".tab")].find(
|
|
836
|
+
(tab) => tab.dataset.id === id
|
|
837
|
+
);
|
|
838
|
+
}
|
|
839
|
+
onKey(event) {
|
|
840
|
+
const keys = {
|
|
841
|
+
ArrowLeft: -1,
|
|
842
|
+
ArrowRight: 1,
|
|
843
|
+
ArrowUp: -1,
|
|
844
|
+
ArrowDown: 1
|
|
845
|
+
};
|
|
846
|
+
if (event.key === "Home" || event.key === "End") {
|
|
847
|
+
event.preventDefault();
|
|
848
|
+
const target = event.key === "Home" ? this.items[0] : this.items[this.items.length - 1];
|
|
849
|
+
if (target) this.choose(target.id, true);
|
|
850
|
+
} else if (keys[event.key] !== void 0) {
|
|
851
|
+
event.preventDefault();
|
|
852
|
+
this.move(keys[event.key], true);
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
render() {
|
|
856
|
+
const doc = this.ownerDocument;
|
|
857
|
+
this.list.setAttribute("aria-label", this.getAttribute("label") ?? "Tabs");
|
|
858
|
+
for (const [button, name, fallback] of [
|
|
859
|
+
[this.previous, "previous-label", "Previous"],
|
|
860
|
+
[this.next, "next-label", "Next"]
|
|
861
|
+
]) {
|
|
862
|
+
const label = this.getAttribute(name) || fallback;
|
|
863
|
+
button.setAttribute("aria-label", label);
|
|
864
|
+
button.title = label;
|
|
865
|
+
}
|
|
866
|
+
this.list.replaceChildren(
|
|
867
|
+
...this.items.map((item) => {
|
|
868
|
+
const tab = doc.createElement("button");
|
|
869
|
+
tab.type = "button";
|
|
870
|
+
tab.className = "tab";
|
|
871
|
+
tab.setAttribute("role", "tab");
|
|
872
|
+
tab.dataset.id = item.id;
|
|
873
|
+
tab.textContent = item.label;
|
|
874
|
+
tab.title = item.title ?? item.label;
|
|
875
|
+
return tab;
|
|
876
|
+
})
|
|
877
|
+
);
|
|
878
|
+
this.sync();
|
|
879
|
+
}
|
|
880
|
+
sync() {
|
|
881
|
+
const disabled = this.hasAttribute("disabled");
|
|
882
|
+
const index = this.index();
|
|
883
|
+
for (const tab of this.list.querySelectorAll(".tab")) {
|
|
884
|
+
const selected = tab.dataset.id === this.selected;
|
|
885
|
+
tab.setAttribute("aria-selected", String(selected));
|
|
886
|
+
tab.tabIndex = selected || index < 0 && tab === this.list.firstElementChild ? 0 : -1;
|
|
887
|
+
tab.disabled = disabled;
|
|
888
|
+
if (selected) tab.scrollIntoView?.({ block: "nearest", inline: "nearest" });
|
|
889
|
+
}
|
|
890
|
+
this.previous.disabled = disabled || index <= 0;
|
|
891
|
+
this.next.disabled = disabled || index < 0 || index >= this.items.length - 1;
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
return OfficeUiTabStrip;
|
|
895
|
+
});
|
|
896
|
+
|
|
897
|
+
// src/zoom-slider.ts
|
|
898
|
+
var CSS5 = `
|
|
899
|
+
:host { display: inline-flex; align-items: center; gap: 2px; font-size: 11px;
|
|
900
|
+
color: var(--office-foreground, #1f2937); font-family: var(--office-font, system-ui, sans-serif); }
|
|
901
|
+
button { box-sizing: border-box; display: inline-grid; place-items: center; min-width: var(--office-target-size, 24px);
|
|
902
|
+
min-height: var(--office-target-size, 24px); padding: 0; border: 1px solid transparent;
|
|
903
|
+
border-radius: var(--office-radius, 4px); background: transparent; color: inherit; font: inherit;
|
|
904
|
+
font-size: 15px; line-height: 1; cursor: pointer; }
|
|
905
|
+
button:hover:not(:disabled) { background: var(--office-background, #fff); }
|
|
906
|
+
button:focus-visible, input:focus-visible { outline: 2px solid var(--office-ring, #2563eb); outline-offset: 1px; }
|
|
907
|
+
button:disabled, input:disabled { opacity: .5; cursor: not-allowed; }
|
|
908
|
+
input { width: var(--office-zoom-slider-width, 110px); min-width: 48px; margin: 0 2px;
|
|
909
|
+
accent-color: var(--office-accent, #2563eb); }
|
|
910
|
+
output { min-width: 40px; text-align: center; font-variant-numeric: tabular-nums; }
|
|
911
|
+
svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.5;
|
|
912
|
+
stroke-linecap: round; stroke-linejoin: round; }
|
|
913
|
+
:host(:not([fit])) .fit { display: none; }
|
|
914
|
+
@media (pointer: coarse), (max-width: 767px) { input { flex: 1; } }
|
|
915
|
+
@media (forced-colors: active) { button { color: ButtonText; } button:disabled { color: GrayText; } }
|
|
916
|
+
`;
|
|
917
|
+
var clampTo = (value, min, max) => Math.min(max, Math.max(min, Math.round(value)));
|
|
918
|
+
var number = (value, fallback) => {
|
|
919
|
+
const parsed = Number(value);
|
|
920
|
+
return value !== null && Number.isFinite(parsed) ? parsed : fallback;
|
|
921
|
+
};
|
|
922
|
+
var defineZoomSlider = definer("office-ui-zoom-slider", () => {
|
|
923
|
+
class OfficeUiZoomSlider extends HTMLElement {
|
|
924
|
+
static observedAttributes = ["value", "min", "max", "disabled", "fit", "label"];
|
|
925
|
+
out;
|
|
926
|
+
in;
|
|
927
|
+
range;
|
|
928
|
+
output;
|
|
929
|
+
fit;
|
|
930
|
+
constructor() {
|
|
931
|
+
super();
|
|
932
|
+
const doc = this.ownerDocument;
|
|
933
|
+
const root = this.attachShadow({ mode: "open" });
|
|
934
|
+
attachStyles(root, controlCss(CSS5));
|
|
935
|
+
const button = (name, text) => {
|
|
936
|
+
const element = doc.createElement("button");
|
|
937
|
+
element.type = "button";
|
|
938
|
+
element.setAttribute("aria-label", name);
|
|
939
|
+
element.title = name;
|
|
940
|
+
element.textContent = text;
|
|
941
|
+
return element;
|
|
942
|
+
};
|
|
943
|
+
this.out = button("Zoom out", "\u2212");
|
|
944
|
+
this.in = button("Zoom in", "+");
|
|
945
|
+
this.range = doc.createElement("input");
|
|
946
|
+
this.range.type = "range";
|
|
947
|
+
this.range.setAttribute("aria-label", "Zoom");
|
|
948
|
+
this.output = doc.createElement("output");
|
|
949
|
+
this.fit = button("Fit", "");
|
|
950
|
+
this.fit.className = "fit";
|
|
951
|
+
const svg = createIconSvg(doc);
|
|
952
|
+
paintIcon(svg, "fitPage");
|
|
953
|
+
this.fit.append(svg);
|
|
954
|
+
root.append(this.out, this.range, this.in, this.output, this.fit);
|
|
955
|
+
this.out.addEventListener("click", () => this.stepBy(-1));
|
|
956
|
+
this.in.addEventListener("click", () => this.stepBy(1));
|
|
957
|
+
this.range.addEventListener("input", () => this.commit(this.range.valueAsNumber, "input"));
|
|
958
|
+
this.range.addEventListener(
|
|
959
|
+
"change",
|
|
960
|
+
() => this.dispatchEvent(new Event("change", { bubbles: true, composed: true }))
|
|
961
|
+
);
|
|
962
|
+
this.fit.addEventListener(
|
|
963
|
+
"click",
|
|
964
|
+
() => emit(this, "office-command", { command: "zoom-fit" })
|
|
965
|
+
);
|
|
966
|
+
}
|
|
967
|
+
connectedCallback() {
|
|
968
|
+
this.setAttribute("role", "group");
|
|
969
|
+
this.sync();
|
|
970
|
+
}
|
|
971
|
+
attributeChangedCallback() {
|
|
972
|
+
this.sync();
|
|
973
|
+
}
|
|
974
|
+
get min() {
|
|
975
|
+
return number(this.getAttribute("min"), 10);
|
|
976
|
+
}
|
|
977
|
+
get max() {
|
|
978
|
+
return Math.max(this.min, number(this.getAttribute("max"), 400));
|
|
979
|
+
}
|
|
980
|
+
get value() {
|
|
981
|
+
return clampTo(number(this.getAttribute("value"), 100), this.min, this.max);
|
|
982
|
+
}
|
|
983
|
+
set value(next) {
|
|
984
|
+
this.setAttribute("value", String(clampTo(Number(next) || 0, this.min, this.max)));
|
|
985
|
+
}
|
|
986
|
+
get disabled() {
|
|
987
|
+
return this.hasAttribute("disabled");
|
|
988
|
+
}
|
|
989
|
+
set disabled(value) {
|
|
990
|
+
this.toggleAttribute("disabled", Boolean(value));
|
|
991
|
+
}
|
|
992
|
+
/** Office buttons snap to the next multiple of `step`, so 67% steps to 70%, not 77%. */
|
|
993
|
+
stepBy(direction) {
|
|
994
|
+
const step = Math.max(1, number(this.getAttribute("step"), 10));
|
|
995
|
+
const current = this.value;
|
|
996
|
+
const next = direction > 0 ? Math.floor(current / step) * step + step : Math.ceil(current / step) * step - step;
|
|
997
|
+
this.commit(next, "change");
|
|
998
|
+
}
|
|
999
|
+
commit(next, type) {
|
|
1000
|
+
if (this.disabled) return;
|
|
1001
|
+
const value = clampTo(next, this.min, this.max);
|
|
1002
|
+
if (value === this.value && type === "change") return;
|
|
1003
|
+
this.value = value;
|
|
1004
|
+
this.dispatchEvent(new Event("input", { bubbles: true, composed: true }));
|
|
1005
|
+
if (type === "change")
|
|
1006
|
+
this.dispatchEvent(new Event("change", { bubbles: true, composed: true }));
|
|
1007
|
+
}
|
|
1008
|
+
sync() {
|
|
1009
|
+
const { min, max, value, disabled } = this;
|
|
1010
|
+
this.setAttribute("aria-label", this.getAttribute("label") ?? "Zoom");
|
|
1011
|
+
this.range.min = String(min);
|
|
1012
|
+
this.range.max = String(max);
|
|
1013
|
+
this.range.value = String(value);
|
|
1014
|
+
this.range.setAttribute("aria-valuetext", `${value}%`);
|
|
1015
|
+
this.output.value = `${value}%`;
|
|
1016
|
+
this.out.disabled = disabled || value <= min;
|
|
1017
|
+
this.in.disabled = disabled || value >= max;
|
|
1018
|
+
this.range.disabled = disabled;
|
|
1019
|
+
const fit = this.getAttribute("fit");
|
|
1020
|
+
this.fit.disabled = disabled;
|
|
1021
|
+
this.fit.setAttribute("aria-label", fit || "Fit");
|
|
1022
|
+
this.fit.title = fit || "Fit";
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
return OfficeUiZoomSlider;
|
|
1026
|
+
});
|
|
1027
|
+
|
|
728
1028
|
// src/controls.ts
|
|
729
1029
|
var CONTROL_DEFINERS = [
|
|
730
1030
|
defineIcon,
|
|
@@ -736,10 +1036,12 @@ var CONTROL_DEFINERS = [
|
|
|
736
1036
|
defineToolbar,
|
|
737
1037
|
defineDialog,
|
|
738
1038
|
defineStatusBar,
|
|
739
|
-
defineStatusItem
|
|
1039
|
+
defineStatusItem,
|
|
1040
|
+
defineZoomSlider,
|
|
1041
|
+
defineTabStrip
|
|
740
1042
|
];
|
|
741
1043
|
function registerControls(registry) {
|
|
742
1044
|
for (const define of CONTROL_DEFINERS) define(registry);
|
|
743
1045
|
}
|
|
744
1046
|
|
|
745
|
-
export { CONTROL_DEFINERS, defineButton, defineCheckbox, defineDialog, defineRibbonGroup, defineSelect, defineStatusBar, defineStatusItem, defineSwitch, defineToolbar, registerControls };
|
|
1047
|
+
export { CONTROL_DEFINERS, defineButton, defineCheckbox, defineDialog, defineRibbonGroup, defineSelect, defineStatusBar, defineStatusItem, defineSwitch, defineTabStrip, defineToolbar, defineZoomSlider, registerControls };
|
|
@@ -18,7 +18,17 @@ 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
|
-
search: "M3 8.5a5.5 5.5 0 1 0 11 0 5.5 5.5 0 1 0-11 0M13 13l4 4"
|
|
21
|
+
search: "M3 8.5a5.5 5.5 0 1 0 11 0 5.5 5.5 0 1 0-11 0M13 13l4 4",
|
|
22
|
+
undo: "M7.5 11.5 3.5 7.5l4-4M3.5 7.5h9a4 4 0 0 1 0 8H10",
|
|
23
|
+
redo: "m12.5 11.5 4-4-4-4M16.5 7.5h-9a4 4 0 0 0 0 8H10",
|
|
24
|
+
pointer: "m5 2.5v13.5l3.6-3.6 2.4 5.1 2.1-1-2.4-5H15.5Z",
|
|
25
|
+
rectangle: "M3 5.5h14v9H3Z",
|
|
26
|
+
fullscreen: "M3 7.5V3h4.5M12.5 3H17v4.5M17 12.5V17h-4.5M7.5 17H3v-4.5",
|
|
27
|
+
grid: "M3 3h14v14H3ZM7.7 3v14M12.3 3v14M3 7.7h14M3 12.3h14",
|
|
28
|
+
fitPage: "M6.5 6.5h7v7h-7ZM2.5 6V2.5H6M14 2.5h3.5V6M17.5 14v3.5H14M6 17.5H2.5V14",
|
|
29
|
+
pageWidth: "M5.5 3.5h9v13h-9ZM1.5 10h17M4 8l-2.5 2L4 12M16 8l2.5 2-2.5 2",
|
|
30
|
+
zoomIn: "M3 8.5a5.5 5.5 0 1 0 11 0 5.5 5.5 0 1 0-11 0M13 13l4 4M6 8.5h5M8.5 6v5",
|
|
31
|
+
zoomOut: "M3 8.5a5.5 5.5 0 1 0 11 0 5.5 5.5 0 1 0-11 0M13 13l4 4M6 8.5h5"
|
|
22
32
|
};
|
|
23
33
|
for (const [name, d] of Object.entries(BUILT_IN)) registry.set(name, { d });
|
|
24
34
|
function registerIcon(name, icon) {
|
package/dist/controls.d.ts
CHANGED
|
@@ -5,12 +5,15 @@ import { defineIcon } from './icons.js';
|
|
|
5
5
|
import { defineRibbonGroup, defineToolbar } from './ribbon.js';
|
|
6
6
|
import { defineSelect } from './select.js';
|
|
7
7
|
import { defineStatusBar, defineStatusItem } from './status-bar.js';
|
|
8
|
-
|
|
8
|
+
import { defineTabStrip } from './tab-strip.js';
|
|
9
|
+
import { defineZoomSlider } from './zoom-slider.js';
|
|
10
|
+
export { defineButton, defineCheckbox, defineDialog, defineIcon, defineRibbonGroup, defineSelect, defineStatusBar, defineStatusItem, defineSwitch, defineTabStrip, defineToolbar, defineZoomSlider, };
|
|
9
11
|
export type { OfficeCommandEvent } from './button.js';
|
|
10
12
|
export type { OfficeDialogCloseEvent, OfficeDialogCloseReason } from './dialog.js';
|
|
11
13
|
export type { OfficeSelectOption } from './select.js';
|
|
12
14
|
export type { OfficeStatusActivateEvent } from './status-bar.js';
|
|
15
|
+
export type { OfficeTab, OfficeTabSelectEvent } from './tab-strip.js';
|
|
13
16
|
/** Every control of this entry. */
|
|
14
|
-
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];
|
|
17
|
+
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];
|
|
15
18
|
/** Idempotent, SSR-safe (no-op without a DOM). */
|
|
16
19
|
export declare function registerControls(registry?: CustomElementRegistry): void;
|
package/dist/controls.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { CONTROL_DEFINERS, defineButton, defineCheckbox, defineDialog, defineRibbonGroup, defineSelect, defineStatusBar, defineStatusItem, defineSwitch, defineToolbar, registerControls } from './chunk-
|
|
2
|
-
export { defineIcon } from './chunk-
|
|
1
|
+
export { CONTROL_DEFINERS, defineButton, defineCheckbox, defineDialog, defineRibbonGroup, defineSelect, defineStatusBar, defineStatusItem, defineSwitch, defineTabStrip, defineToolbar, defineZoomSlider, registerControls } from './chunk-Q2FH3CZQ.js';
|
|
2
|
+
export { defineIcon } from './chunk-Y4YIYNUZ.js';
|
|
3
3
|
import './chunk-EY266IK3.js';
|
package/dist/icons.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { ICON_CSS, createIconSvg, defineIcon, getIcon, listIcons, paintIcon, registerIcon } from './chunk-
|
|
1
|
+
export { ICON_CSS, createIconSvg, defineIcon, getIcon, listIcons, paintIcon, registerIcon } from './chunk-Y4YIYNUZ.js';
|
|
2
2
|
import './chunk-EY266IK3.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-toolbar", "office-ui-dialog", "office-ui-status-bar", "office-ui-status-item", "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-toolbar", "office-ui-dialog", "office-ui-status-bar", "office-ui-status-item", "office-ui-zoom-slider", "office-ui-tab-strip", "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,8 +1,8 @@
|
|
|
1
1
|
import { installOfficeUiTheme } from './chunk-H4KFVIGT.js';
|
|
2
2
|
export { THEME_CSS, THEME_STYLE_ID, installOfficeUiTheme } from './chunk-H4KFVIGT.js';
|
|
3
|
-
import { registerControls } from './chunk-
|
|
4
|
-
export { CONTROL_DEFINERS, defineButton, defineCheckbox, defineDialog, defineRibbonGroup, defineSelect, defineStatusBar, defineStatusItem, defineSwitch, defineToolbar, registerControls } from './chunk-
|
|
5
|
-
export { ICON_CSS, createIconSvg, defineIcon, getIcon, listIcons, paintIcon, registerIcon } from './chunk-
|
|
3
|
+
import { registerControls } from './chunk-Q2FH3CZQ.js';
|
|
4
|
+
export { CONTROL_DEFINERS, defineButton, defineCheckbox, defineDialog, defineRibbonGroup, defineSelect, defineStatusBar, defineStatusItem, defineSwitch, defineTabStrip, defineToolbar, defineZoomSlider, registerControls } from './chunk-Q2FH3CZQ.js';
|
|
5
|
+
export { ICON_CSS, createIconSvg, defineIcon, getIcon, listIcons, paintIcon, registerIcon } from './chunk-Y4YIYNUZ.js';
|
|
6
6
|
import { definePresence } from './chunk-RLPL7Q6J.js';
|
|
7
7
|
export { definePresence, initialsOf, participantsFromAwareness } from './chunk-RLPL7Q6J.js';
|
|
8
8
|
import { defineSmartArt } from './chunk-KJV76AB7.js';
|
|
@@ -21,6 +21,8 @@ var OFFICE_UI_TAGS = [
|
|
|
21
21
|
"office-ui-dialog",
|
|
22
22
|
"office-ui-status-bar",
|
|
23
23
|
"office-ui-status-item",
|
|
24
|
+
"office-ui-zoom-slider",
|
|
25
|
+
"office-ui-tab-strip",
|
|
24
26
|
"office-ui-presence",
|
|
25
27
|
"office-ui-smartart"
|
|
26
28
|
];
|
package/dist/status-bar.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
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).
|
|
7
|
+
*/
|
|
5
8
|
export declare const defineStatusBar: import("./registry.js").Definer;
|
|
6
9
|
/**
|
|
7
10
|
* One status entry: `label` and `value` attributes (textual, so assistive tech reads both).
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface OfficeTab {
|
|
2
|
+
id: string;
|
|
3
|
+
label: string;
|
|
4
|
+
/** Tooltip; defaults to the label. */
|
|
5
|
+
title?: string;
|
|
6
|
+
}
|
|
7
|
+
export type OfficeTabSelectEvent = CustomEvent<{
|
|
8
|
+
id: string;
|
|
9
|
+
}>;
|
|
10
|
+
/**
|
|
11
|
+
* Bottom document tabs (Visio pages, Excel sheets). Set `tabs` (`OfficeTab[]`) and `selected`
|
|
12
|
+
* (a tab id). Labels are inserted as text. The previous/next buttons and arrow, Home and End
|
|
13
|
+
* keys move the selection; the tab list uses a roving tabindex. User selection emits
|
|
14
|
+
* `office-tab-select` `{ id }` (cancelable); setting properties never emits.
|
|
15
|
+
* Attributes: `label` (tab list name, default "Tabs"), `previous-label` and `next-label`
|
|
16
|
+
* (step button names, default "Previous" and "Next"), `disabled`.
|
|
17
|
+
*/
|
|
18
|
+
export declare const defineTabStrip: import("./registry.js").Definer;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Office status-bar zoom: zoom out, slider, zoom in, percentage and an optional fit button.
|
|
3
|
+
* Attributes: `value` (percent, default 100), `min` (10), `max` (400), `step` (10, for the
|
|
4
|
+
* buttons), `disabled`, `fit` (shows the fit button; its value is the button's name, e.g.
|
|
5
|
+
* "Fit page to current window"), `label` (group name, default "Zoom").
|
|
6
|
+
* User changes emit native `input` (slider drag) and `change` events with `value` updated;
|
|
7
|
+
* the fit button emits `office-command` `{ command: 'zoom-fit' }`. Setting `value` never emits.
|
|
8
|
+
*/
|
|
9
|
+
export declare const defineZoomSlider: import("./registry.js").Definer;
|