@zeyos/zx 4.3.0 → 4.4.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/CHANGELOG.md +266 -1
- package/README.md +7 -3
- package/dist/types/components/activity-item/activity-item.d.ts +351 -0
- package/dist/types/components/activity-list/activity-list.d.ts +195 -0
- package/dist/types/components/app-sidebar/app-sidebar.d.ts +28 -0
- package/dist/types/components/button/button.d.ts +8 -0
- package/dist/types/components/calendar/calendar-model.d.ts +22 -0
- package/dist/types/components/calendar/calendar.d.ts +19 -0
- package/dist/types/components/card/card.d.ts +7 -0
- package/dist/types/components/card-view/card-view.d.ts +12 -4
- package/dist/types/components/card-view/record-card.d.ts +53 -5
- package/dist/types/components/code-editor/code-editor.d.ts +160 -0
- package/dist/types/components/code-editor/field-adapter.d.ts +5 -0
- package/dist/types/components/context-menu/context-menu.d.ts +18 -2
- package/dist/types/components/date-picker/date-picker.d.ts +8 -0
- package/dist/types/components/date-picker/time-picker.d.ts +7 -0
- package/dist/types/components/dialog/dialog.d.ts +29 -0
- package/dist/types/components/entity-ref/entity-ref.d.ts +331 -0
- package/dist/types/components/file-item/file-item.d.ts +234 -0
- package/dist/types/components/file-list/file-list.d.ts +171 -0
- package/dist/types/components/filter/filter.d.ts +91 -36
- package/dist/types/components/filter-panel/filter-panel.d.ts +449 -0
- package/dist/types/components/kanban-view/kanban-card.d.ts +138 -0
- package/dist/types/components/kanban-view/kanban-policy.d.ts +268 -0
- package/dist/types/components/kanban-view/kanban-view.d.ts +837 -26
- package/dist/types/components/launcher/launcher.d.ts +19 -12
- package/dist/types/components/list-toolbar/list-toolbar.d.ts +599 -0
- package/dist/types/components/menu-button/menu-button.d.ts +4 -37
- package/dist/types/components/message/message.d.ts +7 -0
- package/dist/types/components/modal/modal.d.ts +48 -0
- package/dist/types/components/navigation-bar/navigation-bar.d.ts +105 -21
- package/dist/types/components/panel/panel.d.ts +7 -0
- package/dist/types/components/search/search.d.ts +7 -0
- package/dist/types/components/select/select.d.ts +4 -0
- package/dist/types/components/sort-control/sort-control.d.ts +105 -0
- package/dist/types/components/stat-tile/stat-tile.d.ts +277 -0
- package/dist/types/components/tabbox/tabbox.d.ts +7 -0
- package/dist/types/components/table/table.d.ts +144 -0
- package/dist/types/components/table-view/table-view.d.ts +11 -5
- package/dist/types/components/timebox/timebox.d.ts +7 -0
- package/dist/types/components/value-list/value-list.d.ts +8 -0
- package/dist/types/components/view/record-view.d.ts +96 -5
- package/dist/types/core/component.d.ts +6 -1
- package/dist/types/core/icons.d.ts +17 -0
- package/dist/types/index.d.ts +13 -1
- package/dist/types/internal/app-rail.d.ts +10 -0
- package/dist/types/internal/menu-items.d.ts +134 -0
- package/dist/zx-zeyos.esm.js +651 -88
- package/dist/zx-zeyos.esm.min.js +8 -1
- package/dist/zx.css +6266 -3900
- package/dist/zx.esm.js +8487 -1805
- package/dist/zx.esm.min.js +10 -3
- package/dist/zx.global.js +8487 -1805
- package/dist/zx.global.min.js +10 -3
- package/dist/zx.min.css +1 -1
- package/docs/api.json +1811 -247
- package/docs/llms.md +345 -40
- package/docs/llms.txt +11 -7
- package/package.json +1 -2
- package/src/components/activity-item/activity-item.css +137 -0
- package/src/components/activity-item/activity-item.js +599 -0
- package/src/components/activity-list/activity-list.css +64 -0
- package/src/components/activity-list/activity-list.js +375 -0
- package/src/components/app-rail/app-rail.css +227 -19
- package/src/components/app-sidebar/app-sidebar.css +414 -24
- package/src/components/app-sidebar/app-sidebar.js +65 -5
- package/src/components/button/button.css +8 -0
- package/src/components/button/button.js +6 -1
- package/src/components/calendar/calendar-model.js +45 -0
- package/src/components/calendar/calendar.css +30 -10
- package/src/components/calendar/calendar.js +41 -13
- package/src/components/card/card.js +12 -1
- package/src/components/card-view/card-view.css +212 -9
- package/src/components/card-view/card-view.js +32 -16
- package/src/components/card-view/record-card.js +98 -21
- package/src/components/code-editor/code-editor.css +67 -0
- package/src/components/code-editor/code-editor.js +288 -0
- package/src/components/code-editor/field-adapter.js +34 -0
- package/src/components/context-menu/context-menu.css +80 -3
- package/src/components/context-menu/context-menu.js +22 -30
- package/src/components/date-picker/date-picker.js +22 -8
- package/src/components/date-picker/month-picker.js +3 -3
- package/src/components/date-picker/time-picker.js +20 -8
- package/src/components/dialog/dialog.js +88 -66
- package/src/components/dropdown/dropdown.js +2 -2
- package/src/components/entity-ref/entity-ref.css +182 -0
- package/src/components/entity-ref/entity-ref.js +496 -0
- package/src/components/file-item/file-item.css +88 -0
- package/src/components/file-item/file-item.js +371 -0
- package/src/components/file-list/file-list.css +51 -0
- package/src/components/file-list/file-list.js +320 -0
- package/src/components/filter/filter.css +27 -1
- package/src/components/filter/filter.js +199 -45
- package/src/components/filter-panel/filter-panel.css +104 -0
- package/src/components/filter-panel/filter-panel.js +964 -0
- package/src/components/kanban-view/kanban-card.js +239 -0
- package/src/components/kanban-view/kanban-policy.js +412 -0
- package/src/components/kanban-view/kanban-view.css +674 -36
- package/src/components/kanban-view/kanban-view.js +1762 -240
- package/src/components/launcher/launcher.js +59 -27
- package/src/components/list-toolbar/list-toolbar.css +189 -0
- package/src/components/list-toolbar/list-toolbar.js +851 -0
- package/src/components/menu-button/menu-button.css +80 -3
- package/src/components/menu-button/menu-button.js +21 -37
- package/src/components/message/message.css +14 -12
- package/src/components/message/message.js +13 -2
- package/src/components/modal/modal.css +15 -0
- package/src/components/modal/modal.js +141 -0
- package/src/components/navigation-bar/navigation-bar.css +77 -2
- package/src/components/navigation-bar/navigation-bar.js +171 -4
- package/src/components/panel/panel.js +13 -2
- package/src/components/search/search.js +17 -5
- package/src/components/select/field-adapter.js +4 -1
- package/src/components/select/select.js +3 -0
- package/src/components/sort-control/sort-control.css +17 -0
- package/src/components/sort-control/sort-control.js +140 -0
- package/src/components/stat-tile/stat-tile.css +213 -0
- package/src/components/stat-tile/stat-tile.js +590 -0
- package/src/components/tabbox/tabbox.js +12 -1
- package/src/components/table/table.css +51 -2
- package/src/components/table/table.js +298 -19
- package/src/components/table-view/table-view.css +8 -2
- package/src/components/table-view/table-view.js +21 -6
- package/src/components/tag-picker/tag-picker.css +3 -1
- package/src/components/timebox/timebox.js +18 -5
- package/src/components/value-list/value-list.js +22 -6
- package/src/components/view/record-view.css +5 -0
- package/src/components/view/record-view.js +100 -7
- package/src/core/component.js +8 -3
- package/src/core/icons.js +74 -5
- package/src/index.js +33 -3
- package/src/internal/app-rail.js +19 -1
- package/src/internal/menu-items.js +142 -0
- package/styles/print.css +192 -0
- package/styles/zx.css +11 -0
- package/DESIGN-SYSTEM.md +0 -182
package/dist/zx-zeyos.esm.js
CHANGED
|
@@ -870,21 +870,26 @@ var Component = class extends EventTarget {
|
|
|
870
870
|
* Dispatches a component event and a bubbling, composed `zx-*` DOM event.
|
|
871
871
|
* @param {string} type Lowercase event name.
|
|
872
872
|
* @param {Record<string, unknown>} [detail={}] Single event detail object.
|
|
873
|
+
* @param {{honorDomCancellation?:boolean}} [options={}] Mirrored DOM-event behavior. Components
|
|
874
|
+
* with a cancelable mutation boundary may opt into treating `preventDefault()` on the bubbling
|
|
875
|
+
* `zx-*` event exactly like cancellation of the component event.
|
|
873
876
|
* @returns {Event & {detail: Record<string, unknown>}}
|
|
874
877
|
* @fires Component#event
|
|
875
878
|
*/
|
|
876
|
-
emit(type, detail = {}) {
|
|
879
|
+
emit(type, detail = {}, options = {}) {
|
|
877
880
|
if (detail === null || typeof detail !== "object" || Array.isArray(detail)) {
|
|
878
881
|
throw new TypeError("Event detail must be an object");
|
|
879
882
|
}
|
|
880
883
|
const componentEvent = createCustomEvent(type, detail, { cancelable: true });
|
|
881
884
|
this.dispatchEvent(componentEvent);
|
|
882
885
|
if (this.el) {
|
|
883
|
-
|
|
886
|
+
const domEvent = createCustomEvent(`zx-${type}`, detail, {
|
|
884
887
|
bubbles: true,
|
|
885
888
|
composed: true,
|
|
886
889
|
cancelable: true
|
|
887
|
-
})
|
|
890
|
+
});
|
|
891
|
+
this.el.dispatchEvent(domEvent);
|
|
892
|
+
if (options.honorDomCancellation && domEvent.defaultPrevented) componentEvent.preventDefault();
|
|
888
893
|
}
|
|
889
894
|
return componentEvent;
|
|
890
895
|
}
|
|
@@ -1795,6 +1800,271 @@ function registerChecklistFieldAdapter() {
|
|
|
1795
1800
|
});
|
|
1796
1801
|
}
|
|
1797
1802
|
|
|
1803
|
+
// src/components/code-editor/code-editor.js
|
|
1804
|
+
var CodeEditor = class extends Component {
|
|
1805
|
+
static cssName = "code-editor";
|
|
1806
|
+
/** @type {CodeEditorOptions} */
|
|
1807
|
+
static defaults = {
|
|
1808
|
+
value: "",
|
|
1809
|
+
name: "",
|
|
1810
|
+
language: "text",
|
|
1811
|
+
label: "Code editor",
|
|
1812
|
+
placeholder: "",
|
|
1813
|
+
rows: 12,
|
|
1814
|
+
indent: " ",
|
|
1815
|
+
wrap: "off",
|
|
1816
|
+
spellcheck: false,
|
|
1817
|
+
readOnly: false,
|
|
1818
|
+
disabled: false,
|
|
1819
|
+
status: true
|
|
1820
|
+
};
|
|
1821
|
+
/** @returns {HTMLElement} */
|
|
1822
|
+
render() {
|
|
1823
|
+
this._createdRoot = this.el === null;
|
|
1824
|
+
const root = (
|
|
1825
|
+
/** @type {HTMLElement} */
|
|
1826
|
+
this.el ?? h("div")
|
|
1827
|
+
);
|
|
1828
|
+
this.el = root;
|
|
1829
|
+
this._initialChildren = this._createdRoot ? [] : [...root.childNodes];
|
|
1830
|
+
this._initialAttributes = new Map(["data-language", "data-readonly", "data-disabled"].map((name) => [name, root.getAttribute(name)]));
|
|
1831
|
+
this._language = normalizeLanguage(this.options.language);
|
|
1832
|
+
this._languageLabel = h("span", { class: "zx-code-editor__language" }, this._language);
|
|
1833
|
+
this._position = h("span", {
|
|
1834
|
+
class: "zx-code-editor__position",
|
|
1835
|
+
role: "status",
|
|
1836
|
+
ariaLive: "polite"
|
|
1837
|
+
});
|
|
1838
|
+
this._header = h(
|
|
1839
|
+
"div",
|
|
1840
|
+
{ class: "zx-code-editor__header" },
|
|
1841
|
+
this._languageLabel,
|
|
1842
|
+
this.options.status ? this._position : null
|
|
1843
|
+
);
|
|
1844
|
+
this._input = /** @type {HTMLTextAreaElement} */
|
|
1845
|
+
h("textarea", {
|
|
1846
|
+
class: "zx-code-editor__input",
|
|
1847
|
+
name: this.options.name ? String(this.options.name) : void 0,
|
|
1848
|
+
ariaLabel: String(this.options.label ?? "Code editor"),
|
|
1849
|
+
placeholder: String(this.options.placeholder ?? ""),
|
|
1850
|
+
rows: normalizeRows(this.options.rows),
|
|
1851
|
+
wrap: normalizeWrap(this.options.wrap),
|
|
1852
|
+
spellcheck: Boolean(this.options.spellcheck),
|
|
1853
|
+
readOnly: Boolean(this.options.readOnly),
|
|
1854
|
+
disabled: Boolean(this.options.disabled),
|
|
1855
|
+
autocomplete: "off",
|
|
1856
|
+
autocapitalize: "off"
|
|
1857
|
+
});
|
|
1858
|
+
this._input.value = String(this.options.value ?? "");
|
|
1859
|
+
root.dataset.language = this._language;
|
|
1860
|
+
root.dataset.readonly = String(Boolean(this.options.readOnly));
|
|
1861
|
+
root.dataset.disabled = String(Boolean(this.options.disabled));
|
|
1862
|
+
root.replaceChildren(this._header, this._input);
|
|
1863
|
+
this.listen(this._input, "keydown", (event) => this._handleKeydown(event));
|
|
1864
|
+
this.listen(this._input, "input", () => {
|
|
1865
|
+
this._updatePosition();
|
|
1866
|
+
this.emit("input", { value: this.getValue() });
|
|
1867
|
+
});
|
|
1868
|
+
this.listen(this._input, "change", () => this.emit("change", { value: this.getValue() }));
|
|
1869
|
+
for (const type of ["click", "keyup", "select", "focus"]) {
|
|
1870
|
+
this.listen(this._input, type, () => this._updatePosition());
|
|
1871
|
+
}
|
|
1872
|
+
this._updatePosition();
|
|
1873
|
+
return root;
|
|
1874
|
+
}
|
|
1875
|
+
/** @returns {string} */
|
|
1876
|
+
getValue() {
|
|
1877
|
+
return this._input.value;
|
|
1878
|
+
}
|
|
1879
|
+
/**
|
|
1880
|
+
* Replaces the editor text.
|
|
1881
|
+
* @param {unknown} value New value.
|
|
1882
|
+
* @param {{silent?:boolean}} [options={}] Suppress the `change` event.
|
|
1883
|
+
* @returns {this}
|
|
1884
|
+
*/
|
|
1885
|
+
setValue(value, { silent = false } = {}) {
|
|
1886
|
+
const next = String(value ?? "");
|
|
1887
|
+
if (this._input.value === next) return this;
|
|
1888
|
+
this._input.value = next;
|
|
1889
|
+
this._updatePosition();
|
|
1890
|
+
if (!silent) this.emit("change", { value: next });
|
|
1891
|
+
return this;
|
|
1892
|
+
}
|
|
1893
|
+
/** @param {unknown} language New language identifier. @returns {this} */
|
|
1894
|
+
setLanguage(language2) {
|
|
1895
|
+
this._language = normalizeLanguage(language2);
|
|
1896
|
+
this.el.dataset.language = this._language;
|
|
1897
|
+
this._languageLabel.textContent = this._language;
|
|
1898
|
+
return this;
|
|
1899
|
+
}
|
|
1900
|
+
/** @returns {this} */
|
|
1901
|
+
focus() {
|
|
1902
|
+
this._input.focus();
|
|
1903
|
+
return this;
|
|
1904
|
+
}
|
|
1905
|
+
/** @returns {this} */
|
|
1906
|
+
enable() {
|
|
1907
|
+
this._input.disabled = false;
|
|
1908
|
+
this.el.dataset.disabled = "false";
|
|
1909
|
+
return this;
|
|
1910
|
+
}
|
|
1911
|
+
/** @returns {this} */
|
|
1912
|
+
disable() {
|
|
1913
|
+
this._input.disabled = true;
|
|
1914
|
+
this.el.dataset.disabled = "true";
|
|
1915
|
+
return this;
|
|
1916
|
+
}
|
|
1917
|
+
/** @param {boolean} value Read-only state. @returns {this} */
|
|
1918
|
+
setReadOnly(value) {
|
|
1919
|
+
this._input.readOnly = Boolean(value);
|
|
1920
|
+
this.el.dataset.readonly = String(Boolean(value));
|
|
1921
|
+
return this;
|
|
1922
|
+
}
|
|
1923
|
+
/** @param {KeyboardEvent} event @returns {void} */
|
|
1924
|
+
_handleKeydown(event) {
|
|
1925
|
+
if (event.key !== "Tab" || event.altKey || event.ctrlKey || event.metaKey || this._input.readOnly || this._input.disabled) return;
|
|
1926
|
+
const indent = String(this.options.indent ?? " ");
|
|
1927
|
+
if (!indent) return;
|
|
1928
|
+
event.preventDefault();
|
|
1929
|
+
const result = indentSelection(
|
|
1930
|
+
this._input.value,
|
|
1931
|
+
this._input.selectionStart ?? 0,
|
|
1932
|
+
this._input.selectionEnd ?? 0,
|
|
1933
|
+
indent,
|
|
1934
|
+
event.shiftKey
|
|
1935
|
+
);
|
|
1936
|
+
if (result.value === this._input.value) return;
|
|
1937
|
+
this._input.value = result.value;
|
|
1938
|
+
this._input.setSelectionRange(result.start, result.end);
|
|
1939
|
+
this._updatePosition();
|
|
1940
|
+
this.emit("input", { value: this.getValue() });
|
|
1941
|
+
}
|
|
1942
|
+
/** @returns {void} */
|
|
1943
|
+
_updatePosition() {
|
|
1944
|
+
if (!this.options.status) return;
|
|
1945
|
+
const position2 = editorPosition(
|
|
1946
|
+
this._input.value,
|
|
1947
|
+
this._input.selectionStart ?? 0,
|
|
1948
|
+
this._input.selectionEnd ?? 0
|
|
1949
|
+
);
|
|
1950
|
+
this._position.textContent = position2.lines > 1 ? `Ln ${position2.line}, Col ${position2.column} \xB7 ${position2.lines} lines selected` : `Ln ${position2.line}, Col ${position2.column}`;
|
|
1951
|
+
}
|
|
1952
|
+
/** @returns {void} */
|
|
1953
|
+
destroy() {
|
|
1954
|
+
if (!this._createdRoot) {
|
|
1955
|
+
this.el.replaceChildren(...this._initialChildren);
|
|
1956
|
+
for (const [name, value] of this._initialAttributes) {
|
|
1957
|
+
if (value === null) this.el.removeAttribute(name);
|
|
1958
|
+
else this.el.setAttribute(name, value);
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
super.destroy();
|
|
1962
|
+
}
|
|
1963
|
+
};
|
|
1964
|
+
function indentSelection(value, start, end, indent = " ", outdent = false) {
|
|
1965
|
+
const source = String(value ?? "");
|
|
1966
|
+
const unit = String(indent ?? "");
|
|
1967
|
+
const from = clampIndex(start, source.length);
|
|
1968
|
+
const to = clampIndex(end, source.length);
|
|
1969
|
+
if (!unit) return { value: source, start: from, end: to };
|
|
1970
|
+
if (from === to && !outdent) {
|
|
1971
|
+
return {
|
|
1972
|
+
value: source.slice(0, from) + unit + source.slice(to),
|
|
1973
|
+
start: from + unit.length,
|
|
1974
|
+
end: from + unit.length
|
|
1975
|
+
};
|
|
1976
|
+
}
|
|
1977
|
+
const lineStart = source.lastIndexOf("\n", Math.max(0, from - 1)) + 1;
|
|
1978
|
+
let lineEnd = source.indexOf("\n", to);
|
|
1979
|
+
if (lineEnd < 0) lineEnd = source.length;
|
|
1980
|
+
const block = source.slice(lineStart, lineEnd);
|
|
1981
|
+
const lines = block.split("\n");
|
|
1982
|
+
let removedFirst = 0;
|
|
1983
|
+
let delta = 0;
|
|
1984
|
+
const transformed = lines.map((line, index) => {
|
|
1985
|
+
if (!outdent) {
|
|
1986
|
+
delta += unit.length;
|
|
1987
|
+
return unit + line;
|
|
1988
|
+
}
|
|
1989
|
+
const removed = removableIndent(line, unit);
|
|
1990
|
+
if (index === 0) removedFirst = removed;
|
|
1991
|
+
delta -= removed;
|
|
1992
|
+
return line.slice(removed);
|
|
1993
|
+
}).join("\n");
|
|
1994
|
+
const nextStart = outdent ? Math.max(lineStart, from - Math.min(removedFirst, from - lineStart)) : from + unit.length;
|
|
1995
|
+
return {
|
|
1996
|
+
value: source.slice(0, lineStart) + transformed + source.slice(lineEnd),
|
|
1997
|
+
start: nextStart,
|
|
1998
|
+
end: Math.max(nextStart, to + delta)
|
|
1999
|
+
};
|
|
2000
|
+
}
|
|
2001
|
+
function editorPosition(value, start, end = start) {
|
|
2002
|
+
const source = String(value ?? "");
|
|
2003
|
+
const from = clampIndex(start, source.length);
|
|
2004
|
+
const to = clampIndex(end, source.length);
|
|
2005
|
+
const before = source.slice(0, from);
|
|
2006
|
+
return {
|
|
2007
|
+
line: before.split("\n").length,
|
|
2008
|
+
column: from - before.lastIndexOf("\n"),
|
|
2009
|
+
lines: source.slice(from, to).split("\n").length
|
|
2010
|
+
};
|
|
2011
|
+
}
|
|
2012
|
+
function removableIndent(line, indent) {
|
|
2013
|
+
if (line.startsWith(indent)) return indent.length;
|
|
2014
|
+
if (indent === " ") return line.startsWith(" ") ? 1 : Math.min(/^ +/.exec(line)?.[0].length ?? 0, 2);
|
|
2015
|
+
return Math.min(/^\s+/.exec(line)?.[0].length ?? 0, indent.length);
|
|
2016
|
+
}
|
|
2017
|
+
function normalizeLanguage(value) {
|
|
2018
|
+
const language2 = String(value ?? "text").trim().toLowerCase();
|
|
2019
|
+
return /^[a-z0-9][a-z0-9+_.-]*$/.test(language2) ? language2 : "text";
|
|
2020
|
+
}
|
|
2021
|
+
function normalizeRows(value) {
|
|
2022
|
+
const rows = Number(value);
|
|
2023
|
+
return Number.isFinite(rows) ? Math.max(2, Math.min(100, Math.round(rows))) : 12;
|
|
2024
|
+
}
|
|
2025
|
+
function normalizeWrap(value) {
|
|
2026
|
+
return ["off", "soft", "hard"].includes(String(value)) ? (
|
|
2027
|
+
/** @type {'off'|'soft'|'hard'} */
|
|
2028
|
+
value
|
|
2029
|
+
) : "off";
|
|
2030
|
+
}
|
|
2031
|
+
function clampIndex(value, length) {
|
|
2032
|
+
const number = Number(value);
|
|
2033
|
+
return Math.max(0, Math.min(length, Number.isFinite(number) ? Math.round(number) : 0));
|
|
2034
|
+
}
|
|
2035
|
+
|
|
2036
|
+
// src/components/code-editor/field-adapter.js
|
|
2037
|
+
function registerCodeEditorFieldAdapter() {
|
|
2038
|
+
Field.register("code", (field, options) => {
|
|
2039
|
+
const editor = field.own(new CodeEditor(null, {
|
|
2040
|
+
label: options.label ? String(options.label) : "Code editor",
|
|
2041
|
+
placeholder: options.placeholder,
|
|
2042
|
+
readOnly: Boolean(options.props?.readOnly),
|
|
2043
|
+
disabled: Boolean(options.disabled),
|
|
2044
|
+
...options.props ?? {},
|
|
2045
|
+
value: options.value
|
|
2046
|
+
}));
|
|
2047
|
+
let setting = false;
|
|
2048
|
+
editor.on("input", (event) => {
|
|
2049
|
+
if (!setting) field.emit("change", { value: event.detail.value });
|
|
2050
|
+
});
|
|
2051
|
+
return {
|
|
2052
|
+
el: editor.el,
|
|
2053
|
+
get: () => editor.getValue(),
|
|
2054
|
+
set: (value) => {
|
|
2055
|
+
setting = true;
|
|
2056
|
+
try {
|
|
2057
|
+
editor.setValue(value, { silent: true });
|
|
2058
|
+
} finally {
|
|
2059
|
+
setting = false;
|
|
2060
|
+
}
|
|
2061
|
+
},
|
|
2062
|
+
focus: () => editor.focus(),
|
|
2063
|
+
setDisabled: (value) => value ? editor.disable() : editor.enable()
|
|
2064
|
+
};
|
|
2065
|
+
});
|
|
2066
|
+
}
|
|
2067
|
+
|
|
1798
2068
|
// src/core/date.js
|
|
1799
2069
|
var MONTHS = [
|
|
1800
2070
|
"January",
|
|
@@ -2080,6 +2350,8 @@ function loadFontAwesomeKit(kit) {
|
|
|
2080
2350
|
// src/core/icons.js
|
|
2081
2351
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
2082
2352
|
var icons = Object.freeze({
|
|
2353
|
+
"arrow-up-wide-short": ["0 0 576 512", "M151.6 42.4C145.5 35.8 137 32 128 32s-17.5 3.8-23.6 10.4l-88 96c-11.9 13-11.1 33.3 2 45.2s33.3 11.1 45.2-2L96 146.3 96 448c0 17.7 14.3 32 32 32s32-14.3 32-32l0-301.7 32.4 35.4c11.9 13 32.2 13.9 45.2 2s13.9-32.2 2-45.2l-88-96zM320 480l32 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l-32 0c-17.7 0-32 14.3-32 32s14.3 32 32 32zm0-128l96 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l-96 0c-17.7 0-32 14.3-32 32s14.3 32 32 32zm0-128l160 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l-160 0c-17.7 0-32 14.3-32 32s14.3 32 32 32zm0-128l224 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L320 32c-17.7 0-32 14.3-32 32s14.3 32 32 32z"],
|
|
2354
|
+
"arrow-down-wide-short": ["0 0 576 512", "M151.6 469.6C145.5 476.2 137 480 128 480s-17.5-3.8-23.6-10.4l-88-96c-11.9-13-11.1-33.3 2-45.2s33.3-11.1 45.2 2L96 365.7 96 64c0-17.7 14.3-32 32-32s32 14.3 32 32l0 301.7 32.4-35.4c11.9-13 32.2-13.9 45.2-2s13.9 32.2 2 45.2l-88 96zM320 480c-17.7 0-32-14.3-32-32s14.3-32 32-32l32 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-32 0zm0-128c-17.7 0-32-14.3-32-32s14.3-32 32-32l96 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-96 0zm0-128c-17.7 0-32-14.3-32-32s14.3-32 32-32l160 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-160 0zm0-128c-17.7 0-32-14.3-32-32s14.3-32 32-32l224 0c17.7 0 32 14.3 32 32s-14.3 32-32 32L320 96z"],
|
|
2083
2355
|
"chevron-down": ["0 0 512 512", "M233.4 406.6c12.5 12.5 32.8 12.5 45.3 0l192-192c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L256 338.7 86.6 169.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l192 192z"],
|
|
2084
2356
|
"chevron-up": ["0 0 512 512", "M233.4 105.4c12.5-12.5 32.8-12.5 45.3 0l192 192c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L256 173.3 86.6 342.6c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3l192-192z"],
|
|
2085
2357
|
"chevron-left": ["0 0 320 512", "M9.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l192 192c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L109.3 256 246.6 118.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-192 192z"],
|
|
@@ -2175,11 +2447,21 @@ function icon(name, options = {}) {
|
|
|
2175
2447
|
}
|
|
2176
2448
|
function builtinIcon(name, options) {
|
|
2177
2449
|
const entry = extraGlyphs[name] ?? icons[name];
|
|
2178
|
-
if (!entry)
|
|
2450
|
+
if (!entry) {
|
|
2451
|
+
if (options.strict) throw new RangeError(`Unknown icon: ${name}`);
|
|
2452
|
+
warnMissingIcon(name);
|
|
2453
|
+
return missingIcon(name, options);
|
|
2454
|
+
}
|
|
2179
2455
|
const [viewBox, pathData] = entry;
|
|
2456
|
+
const svg = iconSvg(viewBox, options);
|
|
2457
|
+
const path = document.createElementNS(SVG_NS, "path");
|
|
2458
|
+
path.setAttribute("d", pathData);
|
|
2459
|
+
svg.append(path);
|
|
2460
|
+
return svg;
|
|
2461
|
+
}
|
|
2462
|
+
function iconSvg(viewBox, options) {
|
|
2180
2463
|
const { size = 16 } = options;
|
|
2181
2464
|
const svg = document.createElementNS(SVG_NS, "svg");
|
|
2182
|
-
const path = document.createElementNS(SVG_NS, "path");
|
|
2183
2465
|
svg.setAttribute("class", classList("zx-icon", options.class));
|
|
2184
2466
|
svg.setAttribute("viewBox", viewBox);
|
|
2185
2467
|
svg.setAttribute("width", String(size));
|
|
@@ -2187,10 +2469,20 @@ function builtinIcon(name, options) {
|
|
|
2187
2469
|
svg.setAttribute("fill", "currentColor");
|
|
2188
2470
|
svg.setAttribute("focusable", "false");
|
|
2189
2471
|
applyLabel(svg, options.label ?? null);
|
|
2190
|
-
path.setAttribute("d", pathData);
|
|
2191
|
-
svg.append(path);
|
|
2192
2472
|
return svg;
|
|
2193
2473
|
}
|
|
2474
|
+
var PLACEHOLDER_VIEW_BOX = "0 0 512 512";
|
|
2475
|
+
function missingIcon(name, options) {
|
|
2476
|
+
const svg = iconSvg(PLACEHOLDER_VIEW_BOX, options);
|
|
2477
|
+
svg.setAttribute("data-zx-icon-missing", name);
|
|
2478
|
+
return svg;
|
|
2479
|
+
}
|
|
2480
|
+
var warnedMissing = /* @__PURE__ */ new Set();
|
|
2481
|
+
function warnMissingIcon(name) {
|
|
2482
|
+
if (warnedMissing.has(name)) return;
|
|
2483
|
+
warnedMissing.add(name);
|
|
2484
|
+
console.warn(`[zx.icon] Unknown icon "${name}" \u2014 rendered an empty placeholder. Add it with registerIcons(), or render Font Awesome with useFontAwesome().`);
|
|
2485
|
+
}
|
|
2194
2486
|
function faIcon(classes, options) {
|
|
2195
2487
|
const { size = 16 } = options;
|
|
2196
2488
|
const element = document.createElement("i");
|
|
@@ -2234,15 +2526,15 @@ var TimePicker = class extends Component {
|
|
|
2234
2526
|
const content = h("div", {
|
|
2235
2527
|
class: "zx-time-picker__segments",
|
|
2236
2528
|
role: "group",
|
|
2237
|
-
ariaLabel: "Time"
|
|
2529
|
+
ariaLabel: this._message("timePicker.label", "Time")
|
|
2238
2530
|
});
|
|
2239
2531
|
this._content = content;
|
|
2240
|
-
this._addSpin(content, "h", "Hour", 23);
|
|
2532
|
+
this._addSpin(content, "h", this._message("timePicker.hour", "Hour"), 23);
|
|
2241
2533
|
content.append(h("span", { class: "zx-time-picker__separator", ariaHidden: "true" }, ":"));
|
|
2242
|
-
this._addSpin(content, "m", "Minute", 59);
|
|
2534
|
+
this._addSpin(content, "m", this._message("timePicker.minute", "Minute"), 59);
|
|
2243
2535
|
if (this.options.seconds) {
|
|
2244
2536
|
content.append(h("span", { class: "zx-time-picker__separator", ariaHidden: "true" }, ":"));
|
|
2245
|
-
this._addSpin(content, "s", "Second", 59);
|
|
2537
|
+
this._addSpin(content, "s", this._message("timePicker.second", "Second"), 59);
|
|
2246
2538
|
}
|
|
2247
2539
|
root.append(content);
|
|
2248
2540
|
if (this.options.clock) {
|
|
@@ -2251,7 +2543,7 @@ var TimePicker = class extends Component {
|
|
|
2251
2543
|
ref: "clockToggle",
|
|
2252
2544
|
class: "zx-icon-btn zx-time-picker__clock-toggle",
|
|
2253
2545
|
type: "button",
|
|
2254
|
-
ariaLabel: "Pick the time on a clock",
|
|
2546
|
+
ariaLabel: this._message("timePicker.clock", "Pick the time on a clock"),
|
|
2255
2547
|
ariaExpanded: "false",
|
|
2256
2548
|
ariaControls: clockId
|
|
2257
2549
|
}, icon("clock", { size: 15 })));
|
|
@@ -2398,7 +2690,7 @@ var TimePicker = class extends Component {
|
|
|
2398
2690
|
ref: "headHour",
|
|
2399
2691
|
class: "zx-time-picker__clock-unit",
|
|
2400
2692
|
type: "button",
|
|
2401
|
-
ariaLabel: "Select the hour",
|
|
2693
|
+
ariaLabel: this._message("timePicker.selectHour", "Select the hour"),
|
|
2402
2694
|
dataset: { unit: "h" }
|
|
2403
2695
|
}),
|
|
2404
2696
|
h("span", { class: "zx-time-picker__clock-colon", ariaHidden: "true" }, ":"),
|
|
@@ -2406,7 +2698,7 @@ var TimePicker = class extends Component {
|
|
|
2406
2698
|
ref: "headMinute",
|
|
2407
2699
|
class: "zx-time-picker__clock-unit",
|
|
2408
2700
|
type: "button",
|
|
2409
|
-
ariaLabel: "Select the minutes",
|
|
2701
|
+
ariaLabel: this._message("timePicker.selectMinutes", "Select the minutes"),
|
|
2410
2702
|
dataset: { unit: "m" }
|
|
2411
2703
|
})
|
|
2412
2704
|
),
|
|
@@ -2464,7 +2756,7 @@ var TimePicker = class extends Component {
|
|
|
2464
2756
|
this.refs.headMinute.textContent = pad2(this._display.m);
|
|
2465
2757
|
this.refs.headHour.setAttribute("aria-pressed", String(hours));
|
|
2466
2758
|
this.refs.headMinute.setAttribute("aria-pressed", String(!hours));
|
|
2467
|
-
this.refs.dial.setAttribute("aria-label", hours ? "Hour" : "Minutes");
|
|
2759
|
+
this.refs.dial.setAttribute("aria-label", hours ? this._message("timePicker.hour", "Hour") : this._message("timePicker.minutes", "Minutes"));
|
|
2468
2760
|
if (!this._clockOpen) return;
|
|
2469
2761
|
const selected = hours ? this._display.h : this._display.m;
|
|
2470
2762
|
const marks = hours ? hourMarks() : minuteMarks();
|
|
@@ -2499,6 +2791,16 @@ var TimePicker = class extends Component {
|
|
|
2499
2791
|
element.setAttribute("aria-checked", String(checked));
|
|
2500
2792
|
element.tabIndex = checked ? 0 : -1;
|
|
2501
2793
|
}
|
|
2794
|
+
/**
|
|
2795
|
+
* Resolves a message through the host translator, falling back to the built-in English text.
|
|
2796
|
+
* @param {string} key Message key.
|
|
2797
|
+
* @param {string} fallback English default.
|
|
2798
|
+
* @returns {string}
|
|
2799
|
+
*/
|
|
2800
|
+
_message(key, fallback) {
|
|
2801
|
+
const message = this.msg(key);
|
|
2802
|
+
return message === key ? fallback : message;
|
|
2803
|
+
}
|
|
2502
2804
|
};
|
|
2503
2805
|
function hourMarks() {
|
|
2504
2806
|
const marks = [];
|
|
@@ -2585,7 +2887,7 @@ var DatePicker = class extends Component {
|
|
|
2585
2887
|
ref: "previous",
|
|
2586
2888
|
class: "zx-date-picker__nav",
|
|
2587
2889
|
type: "button",
|
|
2588
|
-
ariaLabel: "Previous month"
|
|
2890
|
+
ariaLabel: this._message("datePicker.previousMonth", "Previous month")
|
|
2589
2891
|
}, icon("chevron-left")),
|
|
2590
2892
|
h("button", {
|
|
2591
2893
|
ref: "heading",
|
|
@@ -2598,7 +2900,7 @@ var DatePicker = class extends Component {
|
|
|
2598
2900
|
ref: "next",
|
|
2599
2901
|
class: "zx-date-picker__nav",
|
|
2600
2902
|
type: "button",
|
|
2601
|
-
ariaLabel: "Next month"
|
|
2903
|
+
ariaLabel: this._message("datePicker.nextMonth", "Next month")
|
|
2602
2904
|
}, icon("chevron-right"))
|
|
2603
2905
|
),
|
|
2604
2906
|
h(
|
|
@@ -2615,14 +2917,14 @@ var DatePicker = class extends Component {
|
|
|
2615
2917
|
ref: "quickPrevious",
|
|
2616
2918
|
class: "zx-date-picker__nav",
|
|
2617
2919
|
type: "button",
|
|
2618
|
-
ariaLabel: "Previous year"
|
|
2920
|
+
ariaLabel: this._message("datePicker.previousYear", "Previous year")
|
|
2619
2921
|
}, icon("chevron-left")),
|
|
2620
2922
|
h("span", { ref: "quickYear", class: "zx-date-picker__quick-year", ariaLive: "polite" }),
|
|
2621
2923
|
h("button", {
|
|
2622
2924
|
ref: "quickNext",
|
|
2623
2925
|
class: "zx-date-picker__nav",
|
|
2624
2926
|
type: "button",
|
|
2625
|
-
ariaLabel: "Next year"
|
|
2927
|
+
ariaLabel: this._message("datePicker.nextYear", "Next year")
|
|
2626
2928
|
}, icon("chevron-right"))
|
|
2627
2929
|
),
|
|
2628
2930
|
h("div", { ref: "quickGrid", class: "zx-date-picker__quick-grid", role: "grid" })
|
|
@@ -2633,7 +2935,7 @@ var DatePicker = class extends Component {
|
|
|
2633
2935
|
ref: "grid",
|
|
2634
2936
|
class: "zx-date-picker__grid",
|
|
2635
2937
|
role: "grid",
|
|
2636
|
-
ariaLabel: "Calendar"
|
|
2938
|
+
ariaLabel: this._message("datePicker.calendar", "Calendar")
|
|
2637
2939
|
},
|
|
2638
2940
|
h("thead", { ref: "weekdays" }),
|
|
2639
2941
|
h("tbody", { ref: "days" })
|
|
@@ -2731,7 +3033,7 @@ var DatePicker = class extends Component {
|
|
|
2731
3033
|
row.append(h("th", {
|
|
2732
3034
|
class: "zx-date-picker__week-heading",
|
|
2733
3035
|
scope: "col",
|
|
2734
|
-
ariaLabel: "Week number"
|
|
3036
|
+
ariaLabel: this._message("datePicker.weekNumber", "Week number")
|
|
2735
3037
|
}, "#"));
|
|
2736
3038
|
}
|
|
2737
3039
|
const sunday = new Date(2023, 0, 1);
|
|
@@ -2751,7 +3053,10 @@ var DatePicker = class extends Component {
|
|
|
2751
3053
|
const offset = (first.getDay() - this._weekStart + 7) % 7;
|
|
2752
3054
|
const start = addDays(first, -offset);
|
|
2753
3055
|
this.refs.heading.textContent = formatDate(first, "%B %Y");
|
|
2754
|
-
this.refs.heading.setAttribute(
|
|
3056
|
+
this.refs.heading.setAttribute(
|
|
3057
|
+
"aria-label",
|
|
3058
|
+
this._message("datePicker.chooseMonthYear", "Choose month and year, %1", formatDate(first, "%B %Y"))
|
|
3059
|
+
);
|
|
2755
3060
|
const rows = [];
|
|
2756
3061
|
for (let week = 0; week < 6; week += 1) {
|
|
2757
3062
|
const rowStart = addDays(start, week * 7);
|
|
@@ -2760,7 +3065,7 @@ var DatePicker = class extends Component {
|
|
|
2760
3065
|
row.append(h("th", {
|
|
2761
3066
|
class: "zx-date-picker__week",
|
|
2762
3067
|
scope: "row",
|
|
2763
|
-
ariaLabel:
|
|
3068
|
+
ariaLabel: this._message("datePicker.week", "Week %1", isoWeekNumber(rowStart))
|
|
2764
3069
|
}, String(isoWeekNumber(rowStart))));
|
|
2765
3070
|
}
|
|
2766
3071
|
for (let column = 0; column < 7; column += 1) {
|
|
@@ -2965,6 +3270,17 @@ var DatePicker = class extends Component {
|
|
|
2965
3270
|
_buttonForDate(date) {
|
|
2966
3271
|
return this.refs.days.querySelector(`[data-date="${formatDate(date, "%Y-%m-%d")}"]`);
|
|
2967
3272
|
}
|
|
3273
|
+
/**
|
|
3274
|
+
* Resolves a message through the host translator, falling back to the built-in English text.
|
|
3275
|
+
* @param {string} key Message key.
|
|
3276
|
+
* @param {string} fallback Built-in text, with `%1`-style placeholders.
|
|
3277
|
+
* @param {...unknown} args Interpolation values.
|
|
3278
|
+
* @returns {string}
|
|
3279
|
+
*/
|
|
3280
|
+
_message(key, fallback, ...args) {
|
|
3281
|
+
const message = this.msg(key, ...args);
|
|
3282
|
+
return message === key ? printf(fallback, args) : message;
|
|
3283
|
+
}
|
|
2968
3284
|
};
|
|
2969
3285
|
function validDate(value) {
|
|
2970
3286
|
return value instanceof Date && !Number.isNaN(value.getTime()) ? new Date(value.getTime()) : null;
|
|
@@ -3026,21 +3342,21 @@ var MonthPicker = class extends DatePicker {
|
|
|
3026
3342
|
ref: "previousYear",
|
|
3027
3343
|
class: "zx-month-picker__nav",
|
|
3028
3344
|
type: "button",
|
|
3029
|
-
ariaLabel: "Previous year"
|
|
3345
|
+
ariaLabel: this._message("monthPicker.previousYear", "Previous year")
|
|
3030
3346
|
}, icon("chevron-left")),
|
|
3031
3347
|
h("span", { ref: "year", class: "zx-month-picker__year", ariaLive: "polite" }),
|
|
3032
3348
|
h("button", {
|
|
3033
3349
|
ref: "nextYear",
|
|
3034
3350
|
class: "zx-month-picker__nav",
|
|
3035
3351
|
type: "button",
|
|
3036
|
-
ariaLabel: "Next year"
|
|
3352
|
+
ariaLabel: this._message("monthPicker.nextYear", "Next year")
|
|
3037
3353
|
}, icon("chevron-right"))
|
|
3038
3354
|
),
|
|
3039
3355
|
h("div", {
|
|
3040
3356
|
ref: "grid",
|
|
3041
3357
|
class: "zx-month-picker__grid",
|
|
3042
3358
|
role: "grid",
|
|
3043
|
-
ariaLabel: "Choose month"
|
|
3359
|
+
ariaLabel: this._message("monthPicker.chooseMonth", "Choose month")
|
|
3044
3360
|
})
|
|
3045
3361
|
);
|
|
3046
3362
|
this._content = content;
|
|
@@ -6589,6 +6905,7 @@ var Select = class _Select extends Component {
|
|
|
6589
6905
|
value: null,
|
|
6590
6906
|
disabled: false,
|
|
6591
6907
|
placeholder: "",
|
|
6908
|
+
label: "",
|
|
6592
6909
|
clearable: false,
|
|
6593
6910
|
filter: false,
|
|
6594
6911
|
searchKeys: null,
|
|
@@ -6630,6 +6947,7 @@ var Select = class _Select extends Component {
|
|
|
6630
6947
|
class: "zx-select__input",
|
|
6631
6948
|
type: "text",
|
|
6632
6949
|
role: "combobox",
|
|
6950
|
+
ariaLabel: String(this.options.label || this.options.placeholder || "Select"),
|
|
6633
6951
|
autocomplete: "off",
|
|
6634
6952
|
spellcheck: false,
|
|
6635
6953
|
ariaExpanded: "false",
|
|
@@ -7548,7 +7866,10 @@ function registerSelectFieldAdapter() {
|
|
|
7548
7866
|
Field.register("zxselect", (field, options) => {
|
|
7549
7867
|
const props = options.props ?? {};
|
|
7550
7868
|
const preset = props.preset;
|
|
7551
|
-
const selectOptions = { ...props, value: options.value };
|
|
7869
|
+
const selectOptions = { ...props, value: options.value, label: options.label || props.label, placeholder: props.placeholder ?? options.placeholder };
|
|
7870
|
+
field.listen(field.el, "click", (event) => {
|
|
7871
|
+
if (event.target.closest?.(".zx-field__label")) field.adapter.focus();
|
|
7872
|
+
});
|
|
7552
7873
|
delete selectOptions.preset;
|
|
7553
7874
|
const select = field.own(preset === "priority" ? Select.priority(null, selectOptions) : preset === "status" ? Select.status(null, selectOptions) : new Select(null, selectOptions));
|
|
7554
7875
|
field.listen(select.el, "change", (event) => event.stopImmediatePropagation());
|
|
@@ -8788,7 +9109,7 @@ var Timebox = class extends Component {
|
|
|
8788
9109
|
const content = h("div", {
|
|
8789
9110
|
class: "zx-timebox__content",
|
|
8790
9111
|
role: "group",
|
|
8791
|
-
ariaLabel: this.options.seconds ? "Duration in hours, minutes, and seconds" : "Duration in hours and minutes"
|
|
9112
|
+
ariaLabel: this.options.seconds ? this._message("timebox.durationWithSeconds", "Duration in hours, minutes, and seconds") : this._message("timebox.duration", "Duration in hours and minutes")
|
|
8792
9113
|
});
|
|
8793
9114
|
this._content = content;
|
|
8794
9115
|
if (this.options.signed) {
|
|
@@ -8796,7 +9117,7 @@ var Timebox = class extends Component {
|
|
|
8796
9117
|
ref: "sign",
|
|
8797
9118
|
class: "zx-timebox__sign",
|
|
8798
9119
|
type: "button",
|
|
8799
|
-
ariaLabel: "Toggle duration sign",
|
|
9120
|
+
ariaLabel: this._message("timebox.toggleSign", "Toggle duration sign"),
|
|
8800
9121
|
ariaPressed: "false"
|
|
8801
9122
|
}, "+"));
|
|
8802
9123
|
this.listen(this.refs.sign, "click", () => {
|
|
@@ -8806,12 +9127,12 @@ var Timebox = class extends Component {
|
|
|
8806
9127
|
this._emitChange();
|
|
8807
9128
|
});
|
|
8808
9129
|
}
|
|
8809
|
-
this._addSegment(content, "hours", "Hours", false);
|
|
9130
|
+
this._addSegment(content, "hours", this._message("timebox.hours", "Hours"), false);
|
|
8810
9131
|
content.append(h("span", { class: "zx-timebox__separator", ariaHidden: "true" }, ":"));
|
|
8811
|
-
this._addSegment(content, "minutes", "Minutes", true);
|
|
9132
|
+
this._addSegment(content, "minutes", this._message("timebox.minutes", "Minutes"), true);
|
|
8812
9133
|
if (this.options.seconds) {
|
|
8813
9134
|
content.append(h("span", { class: "zx-timebox__separator", ariaHidden: "true" }, ":"));
|
|
8814
|
-
this._addSegment(content, "seconds", "Seconds", true);
|
|
9135
|
+
this._addSegment(content, "seconds", this._message("timebox.seconds", "Seconds"), true);
|
|
8815
9136
|
}
|
|
8816
9137
|
root.append(content);
|
|
8817
9138
|
this.set(this.options.value, this.options.unit, { silent: true });
|
|
@@ -8937,6 +9258,16 @@ var Timebox = class extends Component {
|
|
|
8937
9258
|
_emitChange() {
|
|
8938
9259
|
this.emit("change", { value: this.get(this.options.unit) });
|
|
8939
9260
|
}
|
|
9261
|
+
/**
|
|
9262
|
+
* Resolves a message through the host translator, falling back to the built-in English text.
|
|
9263
|
+
* @param {string} key Message key.
|
|
9264
|
+
* @param {string} fallback English default.
|
|
9265
|
+
* @returns {string}
|
|
9266
|
+
*/
|
|
9267
|
+
_message(key, fallback) {
|
|
9268
|
+
const message = this.msg(key);
|
|
9269
|
+
return message === key ? fallback : message;
|
|
9270
|
+
}
|
|
8940
9271
|
};
|
|
8941
9272
|
function finiteNumber2(value) {
|
|
8942
9273
|
const number = Number(value);
|
|
@@ -9149,14 +9480,14 @@ var ValueList = class extends Component {
|
|
|
9149
9480
|
this._list = h("ul", {
|
|
9150
9481
|
class: "zx-value-list__list",
|
|
9151
9482
|
role: "listbox",
|
|
9152
|
-
ariaLabel: "Values",
|
|
9483
|
+
ariaLabel: this._message("valueList.values", "Values"),
|
|
9153
9484
|
ariaOrientation: "horizontal"
|
|
9154
9485
|
});
|
|
9155
9486
|
this._input = h("input", {
|
|
9156
9487
|
class: "zx-value-list__input",
|
|
9157
9488
|
type: "text",
|
|
9158
9489
|
placeholder: String(this.options.placeholder ?? ""),
|
|
9159
|
-
ariaLabel: "Add value",
|
|
9490
|
+
ariaLabel: this._message("valueList.add", "Add value"),
|
|
9160
9491
|
ariaDescribedby: instructionsId
|
|
9161
9492
|
});
|
|
9162
9493
|
this._status = h("div", {
|
|
@@ -9167,7 +9498,10 @@ var ValueList = class extends Component {
|
|
|
9167
9498
|
this._instructions = h("span", {
|
|
9168
9499
|
class: "zx-value-list__instructions",
|
|
9169
9500
|
id: instructionsId
|
|
9170
|
-
},
|
|
9501
|
+
}, this._message(
|
|
9502
|
+
"valueList.instructions",
|
|
9503
|
+
"Press Enter to add. Focus a value and press Ctrl plus Left or Right to reorder."
|
|
9504
|
+
));
|
|
9171
9505
|
this._ownedNodes.push(this._list, this._input, this._status, this._instructions);
|
|
9172
9506
|
root.append(this._list, this._input, this._status, this._instructions);
|
|
9173
9507
|
this.listen(this._input, "keydown", (event) => this._handleInputKeydown(event));
|
|
@@ -9216,13 +9550,13 @@ var ValueList = class extends Component {
|
|
|
9216
9550
|
const normalized = String(value ?? "").trim();
|
|
9217
9551
|
if (!normalized) return false;
|
|
9218
9552
|
if (this.options.unique && this._values.includes(normalized)) {
|
|
9219
|
-
this._showError("This value already exists.");
|
|
9553
|
+
this._showError(this._message("valueList.duplicate", "This value already exists."));
|
|
9220
9554
|
return false;
|
|
9221
9555
|
}
|
|
9222
9556
|
if (typeof this.options.validate === "function") {
|
|
9223
9557
|
const result = this.options.validate(normalized);
|
|
9224
9558
|
if (result !== true) {
|
|
9225
|
-
this._showError(typeof result === "string" ? result : "This value is not valid.");
|
|
9559
|
+
this._showError(typeof result === "string" ? result : this._message("valueList.invalid", "This value is not valid."));
|
|
9226
9560
|
return false;
|
|
9227
9561
|
}
|
|
9228
9562
|
}
|
|
@@ -9287,7 +9621,7 @@ var ValueList = class extends Component {
|
|
|
9287
9621
|
draggable: Boolean(this.options.sortable) && !this._disabled,
|
|
9288
9622
|
ariaSelected: "false",
|
|
9289
9623
|
ariaDisabled: String(this._disabled),
|
|
9290
|
-
ariaLabel: this.options.deletable ?
|
|
9624
|
+
ariaLabel: this.options.deletable ? this._message("valueList.removable", "%1. Press Delete to remove.", value) : value,
|
|
9291
9625
|
dataset: { index }
|
|
9292
9626
|
}, h("span", { class: "zx-value-list__value" }, value), this.options.deletable ? h("span", {
|
|
9293
9627
|
class: "zx-value-list__remove",
|
|
@@ -9383,6 +9717,17 @@ var ValueList = class extends Component {
|
|
|
9383
9717
|
this._status.textContent = message;
|
|
9384
9718
|
this._input.setAttribute("aria-invalid", "true");
|
|
9385
9719
|
}
|
|
9720
|
+
/**
|
|
9721
|
+
* Resolves a message through the host translator, falling back to the built-in English text.
|
|
9722
|
+
* @param {string} key Message key.
|
|
9723
|
+
* @param {string} fallback Built-in text, with `%1`-style placeholders.
|
|
9724
|
+
* @param {...unknown} args Interpolation values.
|
|
9725
|
+
* @returns {string}
|
|
9726
|
+
*/
|
|
9727
|
+
_message(key, fallback, ...args) {
|
|
9728
|
+
const message = this.msg(key, ...args);
|
|
9729
|
+
return message === key ? printf(fallback, args) : message;
|
|
9730
|
+
}
|
|
9386
9731
|
/** @returns {void} */
|
|
9387
9732
|
destroy() {
|
|
9388
9733
|
for (const node of this._ownedNodes ?? []) node.remove();
|
|
@@ -9626,6 +9971,8 @@ var Table = class extends Component {
|
|
|
9626
9971
|
height: null,
|
|
9627
9972
|
emptyText: null,
|
|
9628
9973
|
rowClass: null,
|
|
9974
|
+
rowKind: null,
|
|
9975
|
+
rowKinds: null,
|
|
9629
9976
|
zebra: true,
|
|
9630
9977
|
editMode: false,
|
|
9631
9978
|
editTrigger: "double",
|
|
@@ -9655,6 +10002,10 @@ var Table = class extends Component {
|
|
|
9655
10002
|
this._original = created ? null : snapshotTarget(root);
|
|
9656
10003
|
this._columns = normalizeTableColumns(this.options.columns);
|
|
9657
10004
|
this._data = Array.isArray(this.options.data) ? [...this.options.data] : [];
|
|
10005
|
+
this._rowKind = normalizeRowKind(this.options.rowKind);
|
|
10006
|
+
this._rowKinds = normalizeRowKinds(this.options.rowKinds);
|
|
10007
|
+
this._spanning = this._hasSpanningRow();
|
|
10008
|
+
this._sortWarned = false;
|
|
9658
10009
|
this._selected = /* @__PURE__ */ new Set();
|
|
9659
10010
|
this._selectionAnchorId = null;
|
|
9660
10011
|
this._sort = normalizeSort(this.options.sort, this._columns);
|
|
@@ -10030,6 +10381,7 @@ var Table = class extends Component {
|
|
|
10030
10381
|
const row = this.getRow(id);
|
|
10031
10382
|
const target = this.getRow(targetId);
|
|
10032
10383
|
if (!row || !target || Object.is(id, targetId)) return this;
|
|
10384
|
+
if (this._isSpanningRow(row)) return this;
|
|
10033
10385
|
const next = reorderTableRows(this._data, this.options.rowId, id, targetId, position2, this._hierarchy?.parentId);
|
|
10034
10386
|
if (!next) return this;
|
|
10035
10387
|
const event = this.emit("rowmove", { row, id, target, targetId, position: position2 });
|
|
@@ -10066,6 +10418,10 @@ var Table = class extends Component {
|
|
|
10066
10418
|
/**
|
|
10067
10419
|
* Activates a column sort. Local mode stably reorders data; server mode only updates the
|
|
10068
10420
|
* header state and emits the request event.
|
|
10421
|
+
*
|
|
10422
|
+
* Inert while the data holds a spanning row: a sort would scatter the positions out of the
|
|
10423
|
+
* sections that group them, in either sort mode. The header withholds its controls for the same
|
|
10424
|
+
* reason, so nothing on screen invites the call.
|
|
10069
10425
|
* @param {string} id Column id.
|
|
10070
10426
|
* @param {TableSortDirection} [dir] Direction; omitted toggles the current column.
|
|
10071
10427
|
* @param {{silent?: boolean}} [options={}] Event options.
|
|
@@ -10074,6 +10430,13 @@ var Table = class extends Component {
|
|
|
10074
10430
|
* @fires Table#editcancel
|
|
10075
10431
|
*/
|
|
10076
10432
|
setSort(id, dir, options = {}) {
|
|
10433
|
+
if (this._spanning) {
|
|
10434
|
+
if (!this._sortWarned) {
|
|
10435
|
+
this._sortWarned = true;
|
|
10436
|
+
console.warn("[zx.Table] setSort() is inert while the data contains spanning rowKinds rows: sorting would scatter the rows out of the sections that group them.");
|
|
10437
|
+
}
|
|
10438
|
+
return this;
|
|
10439
|
+
}
|
|
10077
10440
|
this._abortEdit({ focus: false });
|
|
10078
10441
|
const column = this._columns.find((candidate) => candidate.id === id);
|
|
10079
10442
|
if (!column) throw new RangeError(`Unknown table column: ${id}`);
|
|
@@ -10125,7 +10488,7 @@ var Table = class extends Component {
|
|
|
10125
10488
|
*/
|
|
10126
10489
|
setSelection(ids) {
|
|
10127
10490
|
if (!Array.isArray(ids)) throw new TypeError("Table selection must be an array of row ids");
|
|
10128
|
-
const valid =
|
|
10491
|
+
const valid = this._selectableIds();
|
|
10129
10492
|
const next = /* @__PURE__ */ new Set();
|
|
10130
10493
|
if (this.options.selectable !== false) {
|
|
10131
10494
|
for (const id of ids) {
|
|
@@ -10237,6 +10600,7 @@ var Table = class extends Component {
|
|
|
10237
10600
|
if (!requested) return this;
|
|
10238
10601
|
const current = this._data.find((candidate) => Object.is(this._idFor(candidate), rowId));
|
|
10239
10602
|
if (current === void 0) return this;
|
|
10603
|
+
if (this._isSpanningRow(current)) return this;
|
|
10240
10604
|
const column = this._editMode === "row" && this._hiddenColumns.has(requested.id) ? this._visibleColumns().find((candidate) => resolveEditable(candidate, current) !== false) ?? null : requested;
|
|
10241
10605
|
if (!column || resolveEditable(column, current) === false) return this;
|
|
10242
10606
|
const activeColumnId = column.id;
|
|
@@ -10525,6 +10889,41 @@ var Table = class extends Component {
|
|
|
10525
10889
|
_visibleColumns() {
|
|
10526
10890
|
return this._columns.filter((column) => !this._hiddenColumns.has(column.id));
|
|
10527
10891
|
}
|
|
10892
|
+
/**
|
|
10893
|
+
* Whether a row draws as one cell across the table instead of as a record.
|
|
10894
|
+
* @param {TableRow} row Row to classify.
|
|
10895
|
+
* @returns {boolean}
|
|
10896
|
+
*/
|
|
10897
|
+
_isSpanningRow(row) {
|
|
10898
|
+
if (this._rowKind === null || this._rowKinds === null) return false;
|
|
10899
|
+
return isSpanningRow(row, this._rowKind, this._rowKinds);
|
|
10900
|
+
}
|
|
10901
|
+
/**
|
|
10902
|
+
* Whether any row in the current data — not only the rendered prefix — spans. This is what
|
|
10903
|
+
* withholds the sort controls, and the reader must not be offered a control that the next
|
|
10904
|
+
* `growBy()` would have to take away again.
|
|
10905
|
+
* @returns {boolean}
|
|
10906
|
+
*/
|
|
10907
|
+
_hasSpanningRow() {
|
|
10908
|
+
return hasSpanningRow(this._data, this._rowKind, this._rowKinds);
|
|
10909
|
+
}
|
|
10910
|
+
/**
|
|
10911
|
+
* How many cells one row occupies: every visible column plus the structural columns the table
|
|
10912
|
+
* renders beside them. Shared by the spanning cell and the empty-state cell so the two can never
|
|
10913
|
+
* disagree about the table's width.
|
|
10914
|
+
* @returns {number}
|
|
10915
|
+
*/
|
|
10916
|
+
_spanColspan() {
|
|
10917
|
+
return tableSpanColspan(this._visibleColumns().length, {
|
|
10918
|
+
selectable: this.options.selectable,
|
|
10919
|
+
rowReorder: this.options.rowReorder
|
|
10920
|
+
});
|
|
10921
|
+
}
|
|
10922
|
+
/** @returns {TableRow[]} Rendered rows that can carry a selection; spanning rows cannot. */
|
|
10923
|
+
_selectableData() {
|
|
10924
|
+
const visible = this._visibleData();
|
|
10925
|
+
return this._rowKind === null ? visible : visible.filter((row) => !this._isSpanningRow(row));
|
|
10926
|
+
}
|
|
10528
10927
|
/** @returns {HTMLElement} */
|
|
10529
10928
|
_createColumnControls() {
|
|
10530
10929
|
const list = h("div", { class: "zx-table__column-list" });
|
|
@@ -10537,7 +10936,12 @@ var Table = class extends Component {
|
|
|
10537
10936
|
const details = h(
|
|
10538
10937
|
"details",
|
|
10539
10938
|
{ class: "zx-table__column-controls" },
|
|
10540
|
-
h(
|
|
10939
|
+
h(
|
|
10940
|
+
"summary",
|
|
10941
|
+
{ class: "zx-button zx-button--sm" },
|
|
10942
|
+
icon("fields", { size: 13 }),
|
|
10943
|
+
this._message("table.columns", "Columns", [])
|
|
10944
|
+
),
|
|
10541
10945
|
list
|
|
10542
10946
|
);
|
|
10543
10947
|
this._renderColumnControls();
|
|
@@ -10572,7 +10976,7 @@ var Table = class extends Component {
|
|
|
10572
10976
|
{
|
|
10573
10977
|
class: "zx-table__column-order",
|
|
10574
10978
|
role: "group",
|
|
10575
|
-
ariaLabel:
|
|
10979
|
+
ariaLabel: this._message("table.moveColumn", "Move %1", [column.label])
|
|
10576
10980
|
},
|
|
10577
10981
|
h("button", {
|
|
10578
10982
|
class: "zx-table__column-move",
|
|
@@ -10845,9 +11249,9 @@ var Table = class extends Component {
|
|
|
10845
11249
|
row.append(selectionHeader);
|
|
10846
11250
|
this.listen(this._selectAll, "click", () => {
|
|
10847
11251
|
if (this._selectAll.checked) {
|
|
10848
|
-
for (const dataRow of this.
|
|
11252
|
+
for (const dataRow of this._selectableData()) this._selected.add(this._idFor(dataRow));
|
|
10849
11253
|
} else {
|
|
10850
|
-
for (const dataRow of this.
|
|
11254
|
+
for (const dataRow of this._selectableData()) this._selected.delete(this._idFor(dataRow));
|
|
10851
11255
|
}
|
|
10852
11256
|
this._selectionAnchorId = null;
|
|
10853
11257
|
this._syncSelection();
|
|
@@ -10857,12 +11261,13 @@ var Table = class extends Component {
|
|
|
10857
11261
|
this._selectAll = null;
|
|
10858
11262
|
}
|
|
10859
11263
|
this._headers = /* @__PURE__ */ new Map();
|
|
11264
|
+
this._headerSpanning = this._spanning;
|
|
10860
11265
|
for (const column of this._visibleColumns()) {
|
|
10861
11266
|
const th = h("th", { scope: "col" });
|
|
10862
11267
|
const align = column.align ?? (isNumericColumn(column) ? "end" : null);
|
|
10863
11268
|
if (align) th.dataset.align = align;
|
|
10864
11269
|
if (column.headerTitle) th.title = column.headerTitle;
|
|
10865
|
-
if (column.sortable) {
|
|
11270
|
+
if (column.sortable && !this._spanning) {
|
|
10866
11271
|
const button = h("button", {
|
|
10867
11272
|
class: "zx-table__sort-button",
|
|
10868
11273
|
type: "button"
|
|
@@ -10884,6 +11289,8 @@ var Table = class extends Component {
|
|
|
10884
11289
|
/** @returns {void} @fires Table#editcancel */
|
|
10885
11290
|
_renderBody() {
|
|
10886
11291
|
this._abortEdit({ focus: false });
|
|
11292
|
+
this._spanning = this._hasSpanningRow();
|
|
11293
|
+
if (this._headers && this._spanning !== this._headerSpanning) this._renderHeader();
|
|
10887
11294
|
const fragment2 = document.createDocumentFragment();
|
|
10888
11295
|
this._rowMeta = /* @__PURE__ */ new WeakMap();
|
|
10889
11296
|
this._rowElements = /* @__PURE__ */ new Map();
|
|
@@ -10895,10 +11302,7 @@ var Table = class extends Component {
|
|
|
10895
11302
|
fragment2.append(h(
|
|
10896
11303
|
"tr",
|
|
10897
11304
|
{ class: "zx-table__empty-row" },
|
|
10898
|
-
h("td", {
|
|
10899
|
-
class: "zx-table__empty",
|
|
10900
|
-
colspan: this._visibleColumns().length + (this.options.selectable === "multi" ? 1 : 0) + (this.options.rowReorder ? 1 : 0)
|
|
10901
|
-
}, this._emptyContent())
|
|
11305
|
+
h("td", { class: "zx-table__empty", colspan: this._spanColspan() }, this._emptyContent())
|
|
10902
11306
|
));
|
|
10903
11307
|
} else {
|
|
10904
11308
|
this._visibleEntries().forEach((entry, visibleIndex) => {
|
|
@@ -10941,7 +11345,14 @@ var Table = class extends Component {
|
|
|
10941
11345
|
if (this._growStep) tr.setAttribute("aria-rowindex", String(tree.visibleIndex + 2));
|
|
10942
11346
|
const rowClass = typeof this.options.rowClass === "function" ? this.options.rowClass(row) : "";
|
|
10943
11347
|
if (rowClass) tr.classList.add(...String(rowClass).split(/\s+/).filter(Boolean));
|
|
10944
|
-
|
|
11348
|
+
const kind = this._rowKind === null ? null : resolveRowKind(row, this._rowKind);
|
|
11349
|
+
const kindSpec = kind === null ? null : resolveRowKindSpec(this._rowKinds, kind);
|
|
11350
|
+
const spanning = Boolean(kindSpec?.span);
|
|
11351
|
+
if (kind !== null) tr.dataset.rowKind = kind;
|
|
11352
|
+
if (kindSpec?.class) tr.classList.add(...String(kindSpec.class).split(/\s+/).filter(Boolean));
|
|
11353
|
+
if (this.options.selectable !== false && !spanning) {
|
|
11354
|
+
tr.setAttribute("aria-selected", String(this._selected.has(id)));
|
|
11355
|
+
}
|
|
10945
11356
|
if (this._hierarchy) {
|
|
10946
11357
|
tr.setAttribute("aria-level", String(tree.depth + 1));
|
|
10947
11358
|
if (tree.hasChildren) tr.setAttribute("aria-expanded", String(this._expanded.has(id)));
|
|
@@ -10950,6 +11361,23 @@ var Table = class extends Component {
|
|
|
10950
11361
|
const elements = this._rowElements.get(id) ?? [];
|
|
10951
11362
|
elements.push(tr);
|
|
10952
11363
|
this._rowElements.set(id, elements);
|
|
11364
|
+
if (spanning) {
|
|
11365
|
+
tr.dataset.span = "true";
|
|
11366
|
+
const cell = (
|
|
11367
|
+
/** @type {HTMLTableCellElement} */
|
|
11368
|
+
h("th", {
|
|
11369
|
+
class: "zx-table__section-cell",
|
|
11370
|
+
scope: "colgroup",
|
|
11371
|
+
colspan: this._spanColspan()
|
|
11372
|
+
})
|
|
11373
|
+
);
|
|
11374
|
+
const content = spanRowContent(row, kindSpec, this._visibleColumns(), index);
|
|
11375
|
+
if (content && typeof content === "object" && typeof content.nodeType === "number") {
|
|
11376
|
+
cell.append(content);
|
|
11377
|
+
} else if (content != null) cell.append(document.createTextNode(String(content)));
|
|
11378
|
+
tr.append(cell);
|
|
11379
|
+
return tr;
|
|
11380
|
+
}
|
|
10953
11381
|
if (this.options.rowReorder) {
|
|
10954
11382
|
const handle = h("button", {
|
|
10955
11383
|
class: "zx-table__row-handle",
|
|
@@ -11068,7 +11496,7 @@ var Table = class extends Component {
|
|
|
11068
11496
|
}
|
|
11069
11497
|
}
|
|
11070
11498
|
this.emit("rowclick", { ...meta, event });
|
|
11071
|
-
if (this.options.selectable === "single" && !this._selected.has(meta.id)) {
|
|
11499
|
+
if (this.options.selectable === "single" && !this._selected.has(meta.id) && !this._isSpanningRow(meta.row)) {
|
|
11072
11500
|
this._selected = /* @__PURE__ */ new Set([meta.id]);
|
|
11073
11501
|
this._selectionAnchorId = meta.id;
|
|
11074
11502
|
this._syncSelection();
|
|
@@ -11411,6 +11839,7 @@ var Table = class extends Component {
|
|
|
11411
11839
|
if (row < 0 || row >= visible.length) return null;
|
|
11412
11840
|
const candidateRow = visible[row];
|
|
11413
11841
|
const candidateColumn = columns[column];
|
|
11842
|
+
if (this._isSpanningRow(candidateRow)) continue;
|
|
11414
11843
|
if (resolveEditable(candidateColumn, candidateRow) !== false) {
|
|
11415
11844
|
return {
|
|
11416
11845
|
id: this._idFor(candidateRow),
|
|
@@ -11492,6 +11921,7 @@ var Table = class extends Component {
|
|
|
11492
11921
|
const start = Math.min(anchorIndex, currentIndex);
|
|
11493
11922
|
const end = Math.max(anchorIndex, currentIndex);
|
|
11494
11923
|
for (let index = start; index <= end; index += 1) {
|
|
11924
|
+
if (this._isSpanningRow(visible[index])) continue;
|
|
11495
11925
|
const id = this._idFor(visible[index]);
|
|
11496
11926
|
if (checked) this._selected.add(id);
|
|
11497
11927
|
else this._selected.delete(id);
|
|
@@ -11510,6 +11940,7 @@ var Table = class extends Component {
|
|
|
11510
11940
|
for (const [id, rows] of this._rowElements) {
|
|
11511
11941
|
const selected = this._selected.has(id);
|
|
11512
11942
|
for (const row of rows) {
|
|
11943
|
+
if (row.hasAttribute("data-span")) continue;
|
|
11513
11944
|
row.setAttribute("aria-selected", String(selected));
|
|
11514
11945
|
const checkbox = row.querySelector(".zx-table__row-checkbox");
|
|
11515
11946
|
if (checkbox) checkbox.checked = selected;
|
|
@@ -11520,7 +11951,7 @@ var Table = class extends Component {
|
|
|
11520
11951
|
/** @returns {void} */
|
|
11521
11952
|
_syncSelectAll() {
|
|
11522
11953
|
if (!this._selectAll) return;
|
|
11523
|
-
const visible = this.
|
|
11954
|
+
const visible = this._selectableData();
|
|
11524
11955
|
const selectedRows = visible.reduce(
|
|
11525
11956
|
(count, row) => count + Number(this._selected.has(this._idFor(row))),
|
|
11526
11957
|
0
|
|
@@ -11533,13 +11964,15 @@ var Table = class extends Component {
|
|
|
11533
11964
|
_syncSortHeader() {
|
|
11534
11965
|
if (!this._headers) return;
|
|
11535
11966
|
for (const [id, header] of this._headers) {
|
|
11536
|
-
if (this._sort?.id === id)
|
|
11537
|
-
|
|
11967
|
+
if (!this._spanning && this._sort?.id === id) {
|
|
11968
|
+
header.setAttribute("aria-sort", this._sort.dir === "asc" ? "ascending" : "descending");
|
|
11969
|
+
} else header.removeAttribute("aria-sort");
|
|
11538
11970
|
}
|
|
11539
11971
|
}
|
|
11540
11972
|
/** @returns {void} */
|
|
11541
11973
|
_sortData() {
|
|
11542
|
-
|
|
11974
|
+
this._spanning = this._hasSpanningRow();
|
|
11975
|
+
if (!this._sort || this._spanning) return;
|
|
11543
11976
|
const column = this._columns.find((candidate) => candidate.id === this._sort.id);
|
|
11544
11977
|
if (!column) return;
|
|
11545
11978
|
const getValue = typeof column.sortValue === "function" ? column.sortValue : (row) => row?.[column.id];
|
|
@@ -11572,9 +12005,17 @@ var Table = class extends Component {
|
|
|
11572
12005
|
const valid = new Set(branches);
|
|
11573
12006
|
for (const id of this._expanded) if (!valid.has(id)) this._expanded.delete(id);
|
|
11574
12007
|
}
|
|
12008
|
+
/** @returns {Set<unknown>} Ids of every row in the data that may hold a selection. */
|
|
12009
|
+
_selectableIds() {
|
|
12010
|
+
const ids = /* @__PURE__ */ new Set();
|
|
12011
|
+
for (const row of this._data) {
|
|
12012
|
+
if (!this._isSpanningRow(row)) ids.add(this._idFor(row));
|
|
12013
|
+
}
|
|
12014
|
+
return ids;
|
|
12015
|
+
}
|
|
11575
12016
|
/** @returns {boolean} Whether selection changed. */
|
|
11576
12017
|
_pruneSelection() {
|
|
11577
|
-
const valid =
|
|
12018
|
+
const valid = this._selectableIds();
|
|
11578
12019
|
const previousSize = this._selected.size;
|
|
11579
12020
|
for (const id of this._selected) if (!valid.has(id)) this._selected.delete(id);
|
|
11580
12021
|
if (!valid.has(this._selectionAnchorId)) this._selectionAnchorId = null;
|
|
@@ -11594,6 +12035,34 @@ var Table = class extends Component {
|
|
|
11594
12035
|
this.emit("datachange", { rows: this.getData() });
|
|
11595
12036
|
}
|
|
11596
12037
|
};
|
|
12038
|
+
function resolveRowKind(row, rowKind) {
|
|
12039
|
+
if (rowKind == null || rowKind === "") return null;
|
|
12040
|
+
const raw2 = typeof rowKind === "function" ? rowKind(row) : row?.[rowKind];
|
|
12041
|
+
return raw2 == null ? null : String(raw2);
|
|
12042
|
+
}
|
|
12043
|
+
function resolveRowKindSpec(rowKinds, kind) {
|
|
12044
|
+
if (kind === null || rowKinds == null || typeof rowKinds !== "object") return null;
|
|
12045
|
+
if (!Object.prototype.hasOwnProperty.call(rowKinds, kind)) return null;
|
|
12046
|
+
const spec = rowKinds[kind];
|
|
12047
|
+
return spec && typeof spec === "object" ? spec : null;
|
|
12048
|
+
}
|
|
12049
|
+
function isSpanningRow(row, rowKind, rowKinds) {
|
|
12050
|
+
return Boolean(resolveRowKindSpec(rowKinds, resolveRowKind(row, rowKind))?.span);
|
|
12051
|
+
}
|
|
12052
|
+
function hasSpanningRow(rows, rowKind, rowKinds) {
|
|
12053
|
+
if (!Array.isArray(rows) || rowKind == null || rowKinds == null) return false;
|
|
12054
|
+
return rows.some((row) => isSpanningRow(row, rowKind, rowKinds));
|
|
12055
|
+
}
|
|
12056
|
+
function tableSpanColspan(columnCount, structure = {}) {
|
|
12057
|
+
const columns = Number.isFinite(Number(columnCount)) ? Math.max(0, Math.trunc(Number(columnCount))) : 0;
|
|
12058
|
+
const extras = (structure.selectable === "multi" ? 1 : 0) + (structure.rowReorder ? 1 : 0);
|
|
12059
|
+
return Math.max(1, columns + extras);
|
|
12060
|
+
}
|
|
12061
|
+
function spanRowContent(row, spec, visibleColumns, index = 0) {
|
|
12062
|
+
if (typeof spec?.render === "function") return spec.render(row, index);
|
|
12063
|
+
const first = visibleColumns?.[0];
|
|
12064
|
+
return first ? row?.[first.id] : null;
|
|
12065
|
+
}
|
|
11597
12066
|
function formatTableCell(column, row, index = 0) {
|
|
11598
12067
|
if (typeof column?.render === "function") return column.render(row, index);
|
|
11599
12068
|
const value = row?.[column?.id];
|
|
@@ -11822,6 +12291,20 @@ function normalizeHierarchy(option, columns) {
|
|
|
11822
12291
|
if (!column) return null;
|
|
11823
12292
|
return { ...option, parentId, column };
|
|
11824
12293
|
}
|
|
12294
|
+
function normalizeRowKind(option) {
|
|
12295
|
+
if (typeof option === "function") return (
|
|
12296
|
+
/** @type {(row: TableRow) => unknown} */
|
|
12297
|
+
option
|
|
12298
|
+
);
|
|
12299
|
+
return typeof option === "string" && option !== "" ? option : null;
|
|
12300
|
+
}
|
|
12301
|
+
function normalizeRowKinds(option) {
|
|
12302
|
+
if (!option || typeof option !== "object" || Array.isArray(option)) return null;
|
|
12303
|
+
return (
|
|
12304
|
+
/** @type {Record<string, TableRowKind>} */
|
|
12305
|
+
option
|
|
12306
|
+
);
|
|
12307
|
+
}
|
|
11825
12308
|
function initialExpanded(option) {
|
|
11826
12309
|
return new Set(Array.isArray(option) ? option : []);
|
|
11827
12310
|
}
|
|
@@ -12058,14 +12541,20 @@ var Launcher = class extends Component {
|
|
|
12058
12541
|
debounce: 250,
|
|
12059
12542
|
minQuery: 0,
|
|
12060
12543
|
maxResults: 100,
|
|
12061
|
-
|
|
12062
|
-
|
|
12063
|
-
|
|
12064
|
-
|
|
12065
|
-
|
|
12066
|
-
|
|
12544
|
+
/*
|
|
12545
|
+
* The six labels default to null rather than to their English text so that an application
|
|
12546
|
+
* which installs a translator and passes no labels still gets a translated launcher. The
|
|
12547
|
+
* documented default is what `_message()` falls back to, so an untranslated application
|
|
12548
|
+
* renders exactly the same words as before.
|
|
12549
|
+
*/
|
|
12550
|
+
placeholder: null,
|
|
12551
|
+
label: null,
|
|
12552
|
+
closeLabel: null,
|
|
12553
|
+
resultsLabel: null,
|
|
12554
|
+
emptyText: null,
|
|
12555
|
+
loadingText: null,
|
|
12067
12556
|
shortcut: "mod+k",
|
|
12068
|
-
hints:
|
|
12557
|
+
hints: null,
|
|
12069
12558
|
scope: null
|
|
12070
12559
|
};
|
|
12071
12560
|
/**
|
|
@@ -12104,6 +12593,7 @@ var Launcher = class extends Component {
|
|
|
12104
12593
|
this._busy = false;
|
|
12105
12594
|
this._destroyed = false;
|
|
12106
12595
|
const listId = uid("zx-launcher-results");
|
|
12596
|
+
const label = String(this.options.label ?? this._message("launcher.label", "Launcher"));
|
|
12107
12597
|
const input = h("input", {
|
|
12108
12598
|
ref: "input",
|
|
12109
12599
|
class: "zx-launcher__input",
|
|
@@ -12114,15 +12604,15 @@ var Launcher = class extends Component {
|
|
|
12114
12604
|
ariaAutocomplete: "list",
|
|
12115
12605
|
ariaControls: listId,
|
|
12116
12606
|
ariaExpanded: "false",
|
|
12117
|
-
ariaLabel:
|
|
12118
|
-
placeholder: this.options.placeholder,
|
|
12607
|
+
ariaLabel: label,
|
|
12608
|
+
placeholder: this.options.placeholder ?? this._message("launcher.placeholder", "Search applications and records"),
|
|
12119
12609
|
value: this._query
|
|
12120
12610
|
});
|
|
12121
12611
|
const close = h("button", {
|
|
12122
12612
|
ref: "close",
|
|
12123
12613
|
class: "zx-icon-btn zx-launcher__close",
|
|
12124
12614
|
type: "button",
|
|
12125
|
-
ariaLabel: this.options.closeLabel
|
|
12615
|
+
ariaLabel: this.options.closeLabel ?? this._message("launcher.close", "Close launcher")
|
|
12126
12616
|
}, icon("x"));
|
|
12127
12617
|
const status = h("div", {
|
|
12128
12618
|
ref: "status",
|
|
@@ -12135,14 +12625,18 @@ var Launcher = class extends Component {
|
|
|
12135
12625
|
class: "zx-launcher__results",
|
|
12136
12626
|
id: listId,
|
|
12137
12627
|
role: "listbox",
|
|
12138
|
-
ariaLabel: this.options.resultsLabel
|
|
12628
|
+
ariaLabel: this.options.resultsLabel ?? this._message("launcher.results", "Launcher results")
|
|
12139
12629
|
});
|
|
12140
12630
|
const shortcut = this.options.shortcut === "mod+k" ? h("kbd", {
|
|
12141
12631
|
class: "zx-launcher__shortcut",
|
|
12142
12632
|
ariaHidden: "true"
|
|
12143
12633
|
}, launcherShortcutLabel()) : null;
|
|
12144
|
-
const footer = launcherHints(this.options.hints
|
|
12145
|
-
|
|
12634
|
+
const footer = launcherHints(this.options.hints, {
|
|
12635
|
+
move: this._message("launcher.hintMove", "Move"),
|
|
12636
|
+
open: this._message("launcher.hintOpen", "Open"),
|
|
12637
|
+
close: this._message("launcher.hintClose", "Close")
|
|
12638
|
+
});
|
|
12639
|
+
dialog.setAttribute("aria-label", label);
|
|
12146
12640
|
dialog.replaceChildren(
|
|
12147
12641
|
h(
|
|
12148
12642
|
"div",
|
|
@@ -12434,9 +12928,13 @@ var Launcher = class extends Component {
|
|
|
12434
12928
|
}
|
|
12435
12929
|
/** @returns {void} */
|
|
12436
12930
|
_renderStatus() {
|
|
12437
|
-
if (this._busy)
|
|
12438
|
-
|
|
12439
|
-
else this.
|
|
12931
|
+
if (this._busy) {
|
|
12932
|
+
this.refs.status.textContent = String(this.options.loadingText ?? this._message("launcher.loading", "Searching\u2026"));
|
|
12933
|
+
} else if (this._results.length === 0) {
|
|
12934
|
+
this.refs.status.textContent = String(this.options.emptyText ?? this._message("launcher.empty", "No results"));
|
|
12935
|
+
} else {
|
|
12936
|
+
this.refs.status.textContent = "";
|
|
12937
|
+
}
|
|
12440
12938
|
this.refs.status.hidden = !this.refs.status.textContent;
|
|
12441
12939
|
}
|
|
12442
12940
|
/** @returns {void} */
|
|
@@ -12529,6 +13027,16 @@ var Launcher = class extends Component {
|
|
|
12529
13027
|
event.preventDefault();
|
|
12530
13028
|
this.open();
|
|
12531
13029
|
}
|
|
13030
|
+
/**
|
|
13031
|
+
* Resolves a message through the host translator, falling back to the built-in English text.
|
|
13032
|
+
* @param {string} key Message key.
|
|
13033
|
+
* @param {string} fallback English default.
|
|
13034
|
+
* @returns {string}
|
|
13035
|
+
*/
|
|
13036
|
+
_message(key, fallback) {
|
|
13037
|
+
const message = this.msg(key);
|
|
13038
|
+
return message === key ? fallback : message;
|
|
13039
|
+
}
|
|
12532
13040
|
};
|
|
12533
13041
|
function launcherShortcutLabel() {
|
|
12534
13042
|
const platform = String(
|
|
@@ -12537,15 +13045,15 @@ function launcherShortcutLabel() {
|
|
|
12537
13045
|
);
|
|
12538
13046
|
return /mac|iphone|ipad/i.test(platform) ? "\u2318 K" : "Ctrl K";
|
|
12539
13047
|
}
|
|
12540
|
-
function launcherHints(hints) {
|
|
13048
|
+
function launcherHints(hints, defaults) {
|
|
12541
13049
|
if (hints === false) return null;
|
|
12542
13050
|
const labels = hints && typeof hints === "object" ? hints : {};
|
|
12543
13051
|
return h(
|
|
12544
13052
|
"footer",
|
|
12545
13053
|
{ class: "zx-launcher__hints", ariaHidden: "true" },
|
|
12546
|
-
h("span", {}, h("kbd", {}, "\u2191\u2193\u2190\u2192"), labels.move ??
|
|
12547
|
-
h("span", {}, h("kbd", {}, "\u21B5"), labels.open ??
|
|
12548
|
-
h("span", {}, h("kbd", {}, "Esc"), labels.close ??
|
|
13054
|
+
h("span", {}, h("kbd", {}, "\u2191\u2193\u2190\u2192"), labels.move ?? defaults.move),
|
|
13055
|
+
h("span", {}, h("kbd", {}, "\u21B5"), labels.open ?? defaults.open),
|
|
13056
|
+
h("span", {}, h("kbd", {}, "Esc"), labels.close ?? defaults.close)
|
|
12549
13057
|
);
|
|
12550
13058
|
}
|
|
12551
13059
|
function launcherItemIcon(item) {
|
|
@@ -12965,8 +13473,8 @@ var Message = class _Message extends Component {
|
|
|
12965
13473
|
const close = h("button", {
|
|
12966
13474
|
class: "zx-icon-btn zx-message__close",
|
|
12967
13475
|
type: "button",
|
|
12968
|
-
ariaLabel: "Close message",
|
|
12969
|
-
title: "Close"
|
|
13476
|
+
ariaLabel: this._message("message.close", "Close message"),
|
|
13477
|
+
title: this._message("message.closeTitle", "Close")
|
|
12970
13478
|
}, icon("x", { size: 14 }));
|
|
12971
13479
|
node.append(close);
|
|
12972
13480
|
this.listen(close, "click", () => this._close(entry));
|
|
@@ -13034,6 +13542,16 @@ var Message = class _Message extends Component {
|
|
|
13034
13542
|
this._entries.delete(entry);
|
|
13035
13543
|
this._queue.remove(entry);
|
|
13036
13544
|
}
|
|
13545
|
+
/**
|
|
13546
|
+
* Resolves a message through the host translator, falling back to the built-in English text.
|
|
13547
|
+
* @param {string} key Message key.
|
|
13548
|
+
* @param {string} fallback English default.
|
|
13549
|
+
* @returns {string}
|
|
13550
|
+
*/
|
|
13551
|
+
_message(key, fallback) {
|
|
13552
|
+
const message = this.msg(key);
|
|
13553
|
+
return message === key ? fallback : message;
|
|
13554
|
+
}
|
|
13037
13555
|
/** @param {Element|string|null|undefined} scope @returns {Message} */
|
|
13038
13556
|
static #floatingRegion(scope2) {
|
|
13039
13557
|
const host = overlayHost(scope2 ?? null);
|
|
@@ -13132,6 +13650,29 @@ function calendarRange(view, anchor, options = {}) {
|
|
|
13132
13650
|
}
|
|
13133
13651
|
return { start, end };
|
|
13134
13652
|
}
|
|
13653
|
+
function calendarPageDate(view, anchor, direction, options = {}) {
|
|
13654
|
+
const date = validDate5(anchor, "Calendar date");
|
|
13655
|
+
const step = integer(direction, "direction");
|
|
13656
|
+
if (view === "day") date.setDate(date.getDate() + step);
|
|
13657
|
+
else if (view === "agenda") {
|
|
13658
|
+
date.setDate(date.getDate() + step * positiveInteger(options.agendaDays ?? 14, "agendaDays"));
|
|
13659
|
+
} else if (view === "week") date.setDate(date.getDate() + step * 7);
|
|
13660
|
+
else if (view === "month") return addCalendarMonths(date, step);
|
|
13661
|
+
else if (view === "year") return addCalendarMonths(date, step * 12);
|
|
13662
|
+
else throw new RangeError(`Unknown calendar view: ${view}`);
|
|
13663
|
+
return date;
|
|
13664
|
+
}
|
|
13665
|
+
function addCalendarMonths(value, months) {
|
|
13666
|
+
const date = validDate5(value, "Calendar date");
|
|
13667
|
+
const day = date.getDate();
|
|
13668
|
+
date.setDate(1);
|
|
13669
|
+
date.setMonth(date.getMonth() + integer(months, "month amount"));
|
|
13670
|
+
date.setDate(Math.min(day, daysInCalendarMonth(date.getFullYear(), date.getMonth())));
|
|
13671
|
+
return date;
|
|
13672
|
+
}
|
|
13673
|
+
function daysInCalendarMonth(year, month) {
|
|
13674
|
+
return new Date(year, month + 1, 0).getDate();
|
|
13675
|
+
}
|
|
13135
13676
|
function normalizeCalendarEvents(records, options = {}) {
|
|
13136
13677
|
if (!Array.isArray(records)) throw new TypeError("Calendar events must be an array");
|
|
13137
13678
|
const readers = {
|
|
@@ -13478,7 +14019,7 @@ var Calendar = class extends Component {
|
|
|
13478
14019
|
ref: "views",
|
|
13479
14020
|
class: "zx-calendar__views",
|
|
13480
14021
|
role: "group",
|
|
13481
|
-
ariaLabel: "Calendar view"
|
|
14022
|
+
ariaLabel: this._message("calendar.viewSwitch", "Calendar view")
|
|
13482
14023
|
}, this._views.map((view) => h("button", {
|
|
13483
14024
|
type: "button",
|
|
13484
14025
|
class: "zx-calendar__view-button",
|
|
@@ -13575,7 +14116,7 @@ var Calendar = class extends Component {
|
|
|
13575
14116
|
durationEditable: Object.prototype.hasOwnProperty.call(changes, "durationEditable") ? changes.durationEditable : current.durationEditable,
|
|
13576
14117
|
data: changes.data ?? current.data
|
|
13577
14118
|
};
|
|
13578
|
-
const [next] = normalizeCalendarEvents([source]);
|
|
14119
|
+
const [next] = normalizeCalendarEvents([source], { dateUnit: this.options.dateUnit });
|
|
13579
14120
|
next.data = source.data;
|
|
13580
14121
|
this._events = this._events.map((event, eventIndex) => eventIndex === index ? next : event);
|
|
13581
14122
|
this._mutationVersions.delete(String(id));
|
|
@@ -13926,7 +14467,7 @@ var Calendar = class extends Component {
|
|
|
13926
14467
|
eventCount: String(count)
|
|
13927
14468
|
},
|
|
13928
14469
|
ariaCurrent: sameCalendarDay(day, this._now()) ? "date" : null,
|
|
13929
|
-
ariaLabel:
|
|
14470
|
+
ariaLabel: this._dayCountLabel(day, count),
|
|
13930
14471
|
disabled: this.options.disabled
|
|
13931
14472
|
}, this._format(day, { day: "numeric" })));
|
|
13932
14473
|
}
|
|
@@ -13996,7 +14537,7 @@ var Calendar = class extends Component {
|
|
|
13996
14537
|
activity: String(Math.min(3, count))
|
|
13997
14538
|
},
|
|
13998
14539
|
ariaCurrent: sameCalendarDay(day, this._now()) ? "date" : null,
|
|
13999
|
-
ariaLabel:
|
|
14540
|
+
ariaLabel: this._dayCountLabel(day, count),
|
|
14000
14541
|
disabled: this.options.disabled
|
|
14001
14542
|
}, String(day.getDate())));
|
|
14002
14543
|
}
|
|
@@ -14601,13 +15142,9 @@ var Calendar = class extends Component {
|
|
|
14601
15142
|
}
|
|
14602
15143
|
/** @param {number} direction @returns {this} */
|
|
14603
15144
|
_page(direction) {
|
|
14604
|
-
|
|
14605
|
-
|
|
14606
|
-
|
|
14607
|
-
else if (this._view === "week") date.setDate(date.getDate() + direction * 7);
|
|
14608
|
-
else if (this._view === "month") date.setMonth(date.getMonth() + direction);
|
|
14609
|
-
else date.setFullYear(date.getFullYear() + direction);
|
|
14610
|
-
return this.setDate(date);
|
|
15145
|
+
return this.setDate(calendarPageDate(this._view, this._date, direction, {
|
|
15146
|
+
agendaDays: this.options.agendaDays
|
|
15147
|
+
}));
|
|
14611
15148
|
}
|
|
14612
15149
|
/** @param {{start: Date, end: Date}} range @returns {string} */
|
|
14613
15150
|
_rangeTitle(range) {
|
|
@@ -14731,6 +15268,31 @@ var Calendar = class extends Component {
|
|
|
14731
15268
|
if (!this._destroyed) this.refs.status.textContent = message;
|
|
14732
15269
|
});
|
|
14733
15270
|
}
|
|
15271
|
+
/**
|
|
15272
|
+
* Names a month or year cell by its date and how many events it holds. Singular and plural are
|
|
15273
|
+
* separate keys because a language that inflects the noun cannot reach it from one template.
|
|
15274
|
+
* @param {Date} day Day the cell stands for.
|
|
15275
|
+
* @param {number} count Events on that day.
|
|
15276
|
+
* @returns {string}
|
|
15277
|
+
*/
|
|
15278
|
+
_dayCountLabel(day, count) {
|
|
15279
|
+
const date = this._format(day, { dateStyle: "full" });
|
|
15280
|
+
return count === 1 ? this._message("calendar.dayEvent", "%1, %2 event", date, count) : this._message("calendar.dayEvents", "%1, %2 events", date, count);
|
|
15281
|
+
}
|
|
15282
|
+
/**
|
|
15283
|
+
* Resolves a message through the host translator, falling back to the built-in English text.
|
|
15284
|
+
*
|
|
15285
|
+
* Distinct from `msg()`: the built-in `msg` option answers the calendar's own vocabulary, so a
|
|
15286
|
+
* dotted key falls past it to the host translator, which is what these strings never had.
|
|
15287
|
+
* @param {string} key Message key.
|
|
15288
|
+
* @param {string} fallback Built-in text, with `%1`-style placeholders.
|
|
15289
|
+
* @param {...unknown} args Interpolation values.
|
|
15290
|
+
* @returns {string}
|
|
15291
|
+
*/
|
|
15292
|
+
_message(key, fallback, ...args) {
|
|
15293
|
+
const message = this.msg(key, ...args);
|
|
15294
|
+
return message === key ? printf(fallback, args) : message;
|
|
15295
|
+
}
|
|
14734
15296
|
};
|
|
14735
15297
|
function normalizeViews(value) {
|
|
14736
15298
|
if (!Array.isArray(value) || value.length === 0) throw new TypeError("Calendar views must be a non-empty array");
|
|
@@ -15349,6 +15911,7 @@ function isEmpty(value) {
|
|
|
15349
15911
|
function registerFieldAdapters() {
|
|
15350
15912
|
registerSelectFieldAdapter();
|
|
15351
15913
|
registerChecklistFieldAdapter();
|
|
15914
|
+
registerCodeEditorFieldAdapter();
|
|
15352
15915
|
registerDateboxFieldAdapters();
|
|
15353
15916
|
registerDatePickerFieldAdapters();
|
|
15354
15917
|
registerDateRangeFieldAdapter();
|