@ixfx/components 0.5.1 → 0.5.3
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/bundle/index.d.ts +153 -6
- package/bundle/index.d.ts.map +1 -1
- package/bundle/index.js +495 -23
- package/bundle/index.js.map +1 -1
- package/bundle/style.css +80 -0
- package/dist/index.d.ts +148 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +473 -1
- package/dist/index.js.map +1 -1
- package/dist/style.css +80 -0
- package/docs-user/README.md +1 -0
- package/docs-user/form.md +108 -0
- package/docs-user/tabs.md +105 -2
- package/package.json +1 -1
package/bundle/index.js
CHANGED
|
@@ -9724,6 +9724,132 @@ __decorate([property({
|
|
|
9724
9724
|
__decorate([property({ type: Number })], EditableNumber.prototype, "precision", void 0);
|
|
9725
9725
|
EditableNumber = __decorate([safeCustomElement(`ixfx-editable-number`)], EditableNumber);
|
|
9726
9726
|
//#endregion
|
|
9727
|
+
//#region src/form/form-group.ts
|
|
9728
|
+
let FormGroupElement = class FormGroupElement extends i {
|
|
9729
|
+
constructor(..._args) {
|
|
9730
|
+
super(..._args);
|
|
9731
|
+
this.label = ``;
|
|
9732
|
+
}
|
|
9733
|
+
createRenderRoot() {
|
|
9734
|
+
return this;
|
|
9735
|
+
}
|
|
9736
|
+
connectedCallback() {
|
|
9737
|
+
super.connectedCallback();
|
|
9738
|
+
this._observer = new MutationObserver(() => this._moveChildren());
|
|
9739
|
+
}
|
|
9740
|
+
firstUpdated() {
|
|
9741
|
+
this._fieldset = this.querySelector(`fieldset`) ?? void 0;
|
|
9742
|
+
if (this._fieldset) {
|
|
9743
|
+
this._observer?.observe(this, { childList: true });
|
|
9744
|
+
this._moveChildren();
|
|
9745
|
+
}
|
|
9746
|
+
}
|
|
9747
|
+
disconnectedCallback() {
|
|
9748
|
+
super.disconnectedCallback();
|
|
9749
|
+
this._observer?.disconnect();
|
|
9750
|
+
}
|
|
9751
|
+
_moveChildren() {
|
|
9752
|
+
if (!this._fieldset) return;
|
|
9753
|
+
Array.from(this.children).filter((el) => el.tagName !== `FIELDSET`).forEach((el) => {
|
|
9754
|
+
this._fieldset.appendChild(el);
|
|
9755
|
+
});
|
|
9756
|
+
}
|
|
9757
|
+
render() {
|
|
9758
|
+
return b`<fieldset><legend>${this.label}</legend></fieldset>`;
|
|
9759
|
+
}
|
|
9760
|
+
};
|
|
9761
|
+
__decorate([property({ type: String })], FormGroupElement.prototype, "label", void 0);
|
|
9762
|
+
FormGroupElement = __decorate([safeCustomElement(`ixfx-form-group`)], FormGroupElement);
|
|
9763
|
+
//#endregion
|
|
9764
|
+
//#region src/form/form-part.ts
|
|
9765
|
+
let idCounter = 0;
|
|
9766
|
+
let FormPartElement = class FormPartElement extends i {
|
|
9767
|
+
constructor(..._args) {
|
|
9768
|
+
super(..._args);
|
|
9769
|
+
this.label = ``;
|
|
9770
|
+
}
|
|
9771
|
+
createRenderRoot() {
|
|
9772
|
+
return this;
|
|
9773
|
+
}
|
|
9774
|
+
connectedCallback() {
|
|
9775
|
+
super.connectedCallback();
|
|
9776
|
+
this._ensureId();
|
|
9777
|
+
}
|
|
9778
|
+
_ensureId() {
|
|
9779
|
+
const control = this.querySelector(`input, select, textarea, [name]`);
|
|
9780
|
+
if (!control) return;
|
|
9781
|
+
if (!control.id) {
|
|
9782
|
+
this._id = `ixfx-form-part-${++idCounter}`;
|
|
9783
|
+
control.id = this._id;
|
|
9784
|
+
} else this._id = control.id;
|
|
9785
|
+
}
|
|
9786
|
+
render() {
|
|
9787
|
+
if (!this._id) this._ensureId();
|
|
9788
|
+
return b`<label for=${this._id ?? ``}>${this.label}</label>`;
|
|
9789
|
+
}
|
|
9790
|
+
};
|
|
9791
|
+
__decorate([property({ type: String })], FormPartElement.prototype, "label", void 0);
|
|
9792
|
+
FormPartElement = __decorate([safeCustomElement(`ixfx-form-part`)], FormPartElement);
|
|
9793
|
+
//#endregion
|
|
9794
|
+
//#region src/form/form-values.ts
|
|
9795
|
+
function collectFormValues(root) {
|
|
9796
|
+
const values = {};
|
|
9797
|
+
root.querySelectorAll(`[name]`).forEach((el) => {
|
|
9798
|
+
const name = el.getAttribute(`name`);
|
|
9799
|
+
if (!name) return;
|
|
9800
|
+
if (el instanceof HTMLInputElement) {
|
|
9801
|
+
if (el.type === `radio`) {
|
|
9802
|
+
if (el.checked) values[name] = el.value;
|
|
9803
|
+
} else if (el.type === `checkbox`) values[name] = el.checked;
|
|
9804
|
+
else values[name] = el.value;
|
|
9805
|
+
} else if (el instanceof HTMLSelectElement) {
|
|
9806
|
+
if (el.multiple) values[name] = Array.from(el.selectedOptions).map((opt) => opt.value);
|
|
9807
|
+
else values[name] = el.value;
|
|
9808
|
+
} else if (el instanceof HTMLTextAreaElement) values[name] = el.value;
|
|
9809
|
+
else if (`value` in el) values[name] = el.value;
|
|
9810
|
+
});
|
|
9811
|
+
return values;
|
|
9812
|
+
}
|
|
9813
|
+
function applyFormValues(root, data) {
|
|
9814
|
+
root.querySelectorAll(`[name]`).forEach((el) => {
|
|
9815
|
+
const name = el.getAttribute(`name`);
|
|
9816
|
+
if (!name || !(name in data)) return;
|
|
9817
|
+
const value = data[name];
|
|
9818
|
+
if (el instanceof HTMLInputElement) {
|
|
9819
|
+
if (el.type === `radio`) el.checked = el.value === value;
|
|
9820
|
+
else if (el.type === `checkbox`) el.checked = Boolean(value);
|
|
9821
|
+
else el.value = String(value ?? ``);
|
|
9822
|
+
el.dispatchEvent(new Event(`input`, { bubbles: true }));
|
|
9823
|
+
el.dispatchEvent(new Event(`change`, { bubbles: true }));
|
|
9824
|
+
} else if (el instanceof HTMLSelectElement) {
|
|
9825
|
+
if (el.multiple && Array.isArray(value)) Array.from(el.options).forEach((opt) => {
|
|
9826
|
+
opt.selected = value.includes(opt.value);
|
|
9827
|
+
});
|
|
9828
|
+
else el.value = String(value ?? ``);
|
|
9829
|
+
el.dispatchEvent(new Event(`input`, { bubbles: true }));
|
|
9830
|
+
el.dispatchEvent(new Event(`change`, { bubbles: true }));
|
|
9831
|
+
} else if (el instanceof HTMLTextAreaElement) {
|
|
9832
|
+
el.value = String(value ?? ``);
|
|
9833
|
+
el.dispatchEvent(new Event(`input`, { bubbles: true }));
|
|
9834
|
+
el.dispatchEvent(new Event(`change`, { bubbles: true }));
|
|
9835
|
+
} else if (`value` in el) el.value = value;
|
|
9836
|
+
});
|
|
9837
|
+
}
|
|
9838
|
+
//#endregion
|
|
9839
|
+
//#region src/form/form.ts
|
|
9840
|
+
let FormElement = class FormElement extends i {
|
|
9841
|
+
createRenderRoot() {
|
|
9842
|
+
return this;
|
|
9843
|
+
}
|
|
9844
|
+
getValues() {
|
|
9845
|
+
return collectFormValues(this);
|
|
9846
|
+
}
|
|
9847
|
+
setValues(data) {
|
|
9848
|
+
applyFormValues(this, data);
|
|
9849
|
+
}
|
|
9850
|
+
};
|
|
9851
|
+
FormElement = __decorate([safeCustomElement(`ixfx-form`)], FormElement);
|
|
9852
|
+
//#endregion
|
|
9727
9853
|
//#region src/panel/panel.ts
|
|
9728
9854
|
let PanelElement = class PanelElement extends i {
|
|
9729
9855
|
constructor(..._args) {
|
|
@@ -23799,6 +23925,331 @@ __decorate([property({ attribute: false })], TabListItemElement.prototype, "regi
|
|
|
23799
23925
|
__decorate([state()], TabListItemElement.prototype, "_compact", void 0);
|
|
23800
23926
|
TabListItemElement = __decorate([safeCustomElement(`ixfx-tab-list-item`)], TabListItemElement);
|
|
23801
23927
|
//#endregion
|
|
23928
|
+
//#region src/tabs/tab-panel.ts
|
|
23929
|
+
let TabPanelElement = class TabPanelElement extends i {
|
|
23930
|
+
render() {
|
|
23931
|
+
return b`<slot></slot>`;
|
|
23932
|
+
}
|
|
23933
|
+
static {
|
|
23934
|
+
this.styles = [themeFallbacks, i$3`
|
|
23935
|
+
:host {
|
|
23936
|
+
display:none;
|
|
23937
|
+
height:100%;
|
|
23938
|
+
width:100%;
|
|
23939
|
+
}
|
|
23940
|
+
|
|
23941
|
+
:host([selected]) {
|
|
23942
|
+
background: var(--surface-3);
|
|
23943
|
+
display:block;
|
|
23944
|
+
}
|
|
23945
|
+
`];
|
|
23946
|
+
}
|
|
23947
|
+
};
|
|
23948
|
+
TabPanelElement = __decorate([safeCustomElement(`ixfx-tab-panel`)], TabPanelElement);
|
|
23949
|
+
//#endregion
|
|
23950
|
+
//#region src/tabs/tab-controller.ts
|
|
23951
|
+
/**
|
|
23952
|
+
* Connects an `ixfx-tab-list` to an `ixfx-tab-panels` container, handling the
|
|
23953
|
+
* wiring between them (header clicks show the matching panel, closing a tab
|
|
23954
|
+
* removes its panel, etc.) and offering an API to select, add, remove, rename
|
|
23955
|
+
* and reorder tabs.
|
|
23956
|
+
*
|
|
23957
|
+
* @example
|
|
23958
|
+
* ```ts
|
|
23959
|
+
* const ctrl = new TabController(
|
|
23960
|
+
* document.querySelector('ixfx-tab-list'),
|
|
23961
|
+
* document.querySelector('ixfx-tab-panels'),
|
|
23962
|
+
* );
|
|
23963
|
+
* ctrl.connect();
|
|
23964
|
+
*
|
|
23965
|
+
* ctrl.addTab({ label: 'Console', content: 'Console panel' });
|
|
23966
|
+
* ctrl.selectTab('Console');
|
|
23967
|
+
* ```
|
|
23968
|
+
*/
|
|
23969
|
+
var TabController = class {
|
|
23970
|
+
#list;
|
|
23971
|
+
#panels;
|
|
23972
|
+
#opts;
|
|
23973
|
+
#tabs = [];
|
|
23974
|
+
#signal;
|
|
23975
|
+
#observer;
|
|
23976
|
+
#commands;
|
|
23977
|
+
#registeredCommands = /* @__PURE__ */ new Set();
|
|
23978
|
+
constructor(list, panels, options = {}) {
|
|
23979
|
+
this.#list = list;
|
|
23980
|
+
this.#panels = panels;
|
|
23981
|
+
this.#opts = options;
|
|
23982
|
+
this.#commands = options.commands;
|
|
23983
|
+
}
|
|
23984
|
+
connect() {
|
|
23985
|
+
this.disconnect();
|
|
23986
|
+
this.#signal = new AbortController();
|
|
23987
|
+
const { signal } = this.#signal;
|
|
23988
|
+
this.#list.addEventListener(`change`, this.#onChange, { signal });
|
|
23989
|
+
this.#list.addEventListener(`reorder`, this.#onReorder, { signal });
|
|
23990
|
+
this.#list.addEventListener(`close`, this.#onClose, { signal });
|
|
23991
|
+
this.#observer = new MutationObserver(() => this.#rebuild());
|
|
23992
|
+
this.#observer.observe(this.#list, { childList: true });
|
|
23993
|
+
this.#observer.observe(this.#panels, { childList: true });
|
|
23994
|
+
this.#rebuild();
|
|
23995
|
+
this.#panels.syncWithList(this.#list);
|
|
23996
|
+
for (const tab of this.#tabs) this.#registerCommand(tab);
|
|
23997
|
+
}
|
|
23998
|
+
disconnect() {
|
|
23999
|
+
this.#signal?.abort();
|
|
24000
|
+
this.#signal = void 0;
|
|
24001
|
+
this.#observer?.disconnect();
|
|
24002
|
+
this.#observer = void 0;
|
|
24003
|
+
for (const tab of this.#tabs) this.#unregisterCommand(tab);
|
|
24004
|
+
this.#registeredCommands.clear();
|
|
24005
|
+
this.#tabs = [];
|
|
24006
|
+
}
|
|
24007
|
+
/**
|
|
24008
|
+
* Select a tab as if it was clicked — activates the header (deactivating the
|
|
24009
|
+
* others) and shows its panel.
|
|
24010
|
+
*
|
|
24011
|
+
* `sel` may be a tab id, the panel id its `for` points at, its label text
|
|
24012
|
+
* (case-insensitive), or the tab item element itself.
|
|
24013
|
+
*
|
|
24014
|
+
* Returns true if a tab was found.
|
|
24015
|
+
*/
|
|
24016
|
+
selectTab(sel) {
|
|
24017
|
+
const tab = this.#resolveTab(sel);
|
|
24018
|
+
if (!tab) return false;
|
|
24019
|
+
const previous = this.getSelected();
|
|
24020
|
+
if (previous?.id === tab.id) {
|
|
24021
|
+
this.#panels.selectPanel(tab.forId);
|
|
24022
|
+
return true;
|
|
24023
|
+
}
|
|
24024
|
+
this.#list.selectElement(tab.item);
|
|
24025
|
+
this.#panels.selectPanel(tab.forId);
|
|
24026
|
+
this.#opts.onSelect?.(tab, previous);
|
|
24027
|
+
return true;
|
|
24028
|
+
}
|
|
24029
|
+
selectNext() {
|
|
24030
|
+
return this.#selectOffset(1);
|
|
24031
|
+
}
|
|
24032
|
+
selectPrevious() {
|
|
24033
|
+
return this.#selectOffset(-1);
|
|
24034
|
+
}
|
|
24035
|
+
getSelected() {
|
|
24036
|
+
return this.#tabs.find((t) => t.item.hasAttribute(`selected`));
|
|
24037
|
+
}
|
|
24038
|
+
getTabs() {
|
|
24039
|
+
return [...this.#tabs];
|
|
24040
|
+
}
|
|
24041
|
+
getTab(id) {
|
|
24042
|
+
return this.#tabs.find((t) => t.id === id);
|
|
24043
|
+
}
|
|
24044
|
+
addTab(opts) {
|
|
24045
|
+
const { id, forId } = this.#idsFor(opts);
|
|
24046
|
+
const item = document.createElement(`ixfx-tab-list-item`);
|
|
24047
|
+
item.id = id;
|
|
24048
|
+
item.setAttribute(`for`, forId);
|
|
24049
|
+
item.closeable = opts.closeable ?? true;
|
|
24050
|
+
item.append(opts.label);
|
|
24051
|
+
if (opts.iconName) item.iconName = opts.iconName;
|
|
24052
|
+
if (opts.description) item.description = opts.description;
|
|
24053
|
+
for (const el of opts.toolbar ?? []) {
|
|
24054
|
+
el.slot = `toolbar`;
|
|
24055
|
+
item.append(el);
|
|
24056
|
+
}
|
|
24057
|
+
const panel = document.createElement(`ixfx-tab-panel`);
|
|
24058
|
+
panel.id = forId;
|
|
24059
|
+
if (opts.content !== void 0) this.#fillContent(panel, opts.content);
|
|
24060
|
+
const index = Math.max(0, Math.min(opts.index ?? this.#tabs.length, this.#tabs.length));
|
|
24061
|
+
this.#insertElement(this.#list, item, index);
|
|
24062
|
+
this.#insertElement(this.#panels, panel, index);
|
|
24063
|
+
const tab = {
|
|
24064
|
+
id,
|
|
24065
|
+
forId,
|
|
24066
|
+
item,
|
|
24067
|
+
panel,
|
|
24068
|
+
label: opts.label,
|
|
24069
|
+
iconName: opts.iconName
|
|
24070
|
+
};
|
|
24071
|
+
this.#tabs.splice(index, 0, tab);
|
|
24072
|
+
this.#registerCommand(tab);
|
|
24073
|
+
this.#opts.onAdd?.(tab);
|
|
24074
|
+
if (opts.select ?? true) this.selectTab(id);
|
|
24075
|
+
return tab;
|
|
24076
|
+
}
|
|
24077
|
+
removeTab(sel) {
|
|
24078
|
+
const tab = this.#resolveTab(sel);
|
|
24079
|
+
if (!tab) return false;
|
|
24080
|
+
const index = this.#tabs.indexOf(tab);
|
|
24081
|
+
const adjacent = tab.item.hasAttribute(`selected`) ? this.#adjacentTab(index) : void 0;
|
|
24082
|
+
tab.item.remove();
|
|
24083
|
+
tab.panel.remove();
|
|
24084
|
+
this.#removeFromIndex(tab);
|
|
24085
|
+
this.#unregisterCommand(tab);
|
|
24086
|
+
this.#opts.onRemove?.(tab);
|
|
24087
|
+
if (adjacent) this.selectTab(adjacent.id);
|
|
24088
|
+
return true;
|
|
24089
|
+
}
|
|
24090
|
+
renameTab(sel, label) {
|
|
24091
|
+
const tab = this.#resolveTab(sel);
|
|
24092
|
+
if (!tab) return false;
|
|
24093
|
+
for (const child of [...tab.item.childNodes]) {
|
|
24094
|
+
if (child.nodeType === Node.ELEMENT_NODE && child.slot === `toolbar`) continue;
|
|
24095
|
+
tab.item.removeChild(child);
|
|
24096
|
+
}
|
|
24097
|
+
tab.item.prepend(label);
|
|
24098
|
+
tab.label = label;
|
|
24099
|
+
this.#reregisterCommand(tab);
|
|
24100
|
+
return true;
|
|
24101
|
+
}
|
|
24102
|
+
setTabIcon(sel, iconName) {
|
|
24103
|
+
const tab = this.#resolveTab(sel);
|
|
24104
|
+
if (!tab) return false;
|
|
24105
|
+
if (iconName) {
|
|
24106
|
+
tab.item.iconName = iconName;
|
|
24107
|
+
tab.iconName = iconName;
|
|
24108
|
+
} else {
|
|
24109
|
+
tab.item.iconName = void 0;
|
|
24110
|
+
tab.item.removeAttribute(`icon-name`);
|
|
24111
|
+
tab.iconName = void 0;
|
|
24112
|
+
}
|
|
24113
|
+
return true;
|
|
24114
|
+
}
|
|
24115
|
+
#onChange = (event) => {
|
|
24116
|
+
const detail = event.detail;
|
|
24117
|
+
this.#panels.selectPanel(detail.for);
|
|
24118
|
+
const tab = this.#tabs.find((t) => t.forId === detail.for);
|
|
24119
|
+
if (!tab) return;
|
|
24120
|
+
const previous = detail.previous ? this.#tabs.find((t) => t.id === detail.previous) : void 0;
|
|
24121
|
+
this.#opts.onSelect?.(tab, previous);
|
|
24122
|
+
};
|
|
24123
|
+
#onReorder = () => {
|
|
24124
|
+
this.#rebuild();
|
|
24125
|
+
this.#opts.onReorder?.(this.#tabs);
|
|
24126
|
+
};
|
|
24127
|
+
#onClose = (event) => {
|
|
24128
|
+
const item = event.target?.closest(`ixfx-tab-list-item`);
|
|
24129
|
+
const tab = item ? this.#tabByItem(item) : void 0;
|
|
24130
|
+
if (!tab) return;
|
|
24131
|
+
const index = this.#tabs.indexOf(tab);
|
|
24132
|
+
const adjacent = tab.item.hasAttribute(`selected`) ? this.#adjacentTab(index) : void 0;
|
|
24133
|
+
tab.panel.remove();
|
|
24134
|
+
this.#removeFromIndex(tab);
|
|
24135
|
+
this.#unregisterCommand(tab);
|
|
24136
|
+
this.#opts.onRemove?.(tab);
|
|
24137
|
+
if (adjacent) this.selectTab(adjacent.id);
|
|
24138
|
+
};
|
|
24139
|
+
#selectOffset(offset) {
|
|
24140
|
+
const tabs = this.#tabs;
|
|
24141
|
+
if (tabs.length === 0) return false;
|
|
24142
|
+
const current = this.getSelected();
|
|
24143
|
+
const next = ((current ? tabs.indexOf(current) : offset === 1 ? -1 : 0) + offset + tabs.length) % tabs.length;
|
|
24144
|
+
return this.selectTab(tabs[next].id);
|
|
24145
|
+
}
|
|
24146
|
+
#resolveTab(sel) {
|
|
24147
|
+
if (typeof sel !== `string`) return this.#tabs.find((t) => t.item === sel);
|
|
24148
|
+
const label = sel.trim().toLowerCase();
|
|
24149
|
+
return this.#tabs.find((t) => t.id === sel) ?? this.#tabs.find((t) => t.forId === sel) ?? this.#tabs.find((t) => t.label.toLowerCase() === label);
|
|
24150
|
+
}
|
|
24151
|
+
#tabByItem(item) {
|
|
24152
|
+
return this.#tabs.find((t) => t.item === item);
|
|
24153
|
+
}
|
|
24154
|
+
#adjacentTab(index) {
|
|
24155
|
+
const tabs = this.#tabs;
|
|
24156
|
+
if (tabs.length <= 1) return void 0;
|
|
24157
|
+
return tabs[index + 1] ?? tabs[index - 1];
|
|
24158
|
+
}
|
|
24159
|
+
#removeFromIndex(tab) {
|
|
24160
|
+
const index = this.#tabs.indexOf(tab);
|
|
24161
|
+
if (index >= 0) this.#tabs.splice(index, 1);
|
|
24162
|
+
}
|
|
24163
|
+
#idsFor(opts) {
|
|
24164
|
+
const base = this.#slug(opts.label) || `tab`;
|
|
24165
|
+
return {
|
|
24166
|
+
id: opts.id ?? this.#uniqueId(`tab-${base}`),
|
|
24167
|
+
forId: opts.forId ?? this.#uniqueId(`panel-${base}`)
|
|
24168
|
+
};
|
|
24169
|
+
}
|
|
24170
|
+
#slug(value) {
|
|
24171
|
+
return value.toLowerCase().replace(/[^a-z0-9]+/g, `-`).replace(/^-+|-+$/g, ``);
|
|
24172
|
+
}
|
|
24173
|
+
#uniqueId(base) {
|
|
24174
|
+
let candidate = base;
|
|
24175
|
+
let n = 2;
|
|
24176
|
+
while (document.getElementById(candidate)) candidate = `${base}-${n++}`;
|
|
24177
|
+
return candidate;
|
|
24178
|
+
}
|
|
24179
|
+
#fillContent(panel, content) {
|
|
24180
|
+
if (typeof content === `function`) {
|
|
24181
|
+
content(panel);
|
|
24182
|
+
return;
|
|
24183
|
+
}
|
|
24184
|
+
if (typeof content === `string`) {
|
|
24185
|
+
panel.append(document.createTextNode(content));
|
|
24186
|
+
return;
|
|
24187
|
+
}
|
|
24188
|
+
panel.append(content);
|
|
24189
|
+
}
|
|
24190
|
+
#insertElement(container, el, index) {
|
|
24191
|
+
const children = Array.from(container.children);
|
|
24192
|
+
container.insertBefore(el, children[index] ?? null);
|
|
24193
|
+
}
|
|
24194
|
+
#rebuild() {
|
|
24195
|
+
const panels = /* @__PURE__ */ new Map();
|
|
24196
|
+
for (const el of this.#panels.querySelectorAll(`ixfx-tab-panel`)) panels.set(el.id, el);
|
|
24197
|
+
const tabs = [];
|
|
24198
|
+
for (const item of this.#list.querySelectorAll(`ixfx-tab-list-item`)) {
|
|
24199
|
+
const forId = item.getAttribute(`for`) ?? ``;
|
|
24200
|
+
const panel = panels.get(forId);
|
|
24201
|
+
if (!panel) continue;
|
|
24202
|
+
tabs.push({
|
|
24203
|
+
id: item.id || forId,
|
|
24204
|
+
forId,
|
|
24205
|
+
item,
|
|
24206
|
+
panel,
|
|
24207
|
+
label: this.#labelOf(item),
|
|
24208
|
+
iconName: item.iconName
|
|
24209
|
+
});
|
|
24210
|
+
}
|
|
24211
|
+
this.#tabs = tabs;
|
|
24212
|
+
}
|
|
24213
|
+
/** The tab's visible label text, excluding any `slot="toolbar"` content. */
|
|
24214
|
+
#labelOf(item) {
|
|
24215
|
+
const clone = item.cloneNode(true);
|
|
24216
|
+
clone.querySelectorAll(`[slot="toolbar"]`).forEach((el) => el.remove());
|
|
24217
|
+
return (clone.textContent ?? ``).trim();
|
|
24218
|
+
}
|
|
24219
|
+
#registerCommand(tab) {
|
|
24220
|
+
if (!this.#commands) return;
|
|
24221
|
+
if (tab.item.commandActive) return;
|
|
24222
|
+
if (this.#commands.has(tab.id)) return;
|
|
24223
|
+
this.#commands.register({
|
|
24224
|
+
id: tab.id,
|
|
24225
|
+
label: tab.label,
|
|
24226
|
+
description: tab.item.description ?? tab.label,
|
|
24227
|
+
icon: tab.iconName,
|
|
24228
|
+
execute: () => {
|
|
24229
|
+
this.selectTab(tab.id);
|
|
24230
|
+
}
|
|
24231
|
+
});
|
|
24232
|
+
this.#registeredCommands.add(tab.id);
|
|
24233
|
+
}
|
|
24234
|
+
#unregisterCommand(tab) {
|
|
24235
|
+
if (!this.#commands) return;
|
|
24236
|
+
if (this.#registeredCommands.has(tab.id)) {
|
|
24237
|
+
this.#commands.unregister(tab.id);
|
|
24238
|
+
this.#registeredCommands.delete(tab.id);
|
|
24239
|
+
}
|
|
24240
|
+
}
|
|
24241
|
+
#reregisterCommand(tab) {
|
|
24242
|
+
if (!this.#commands || !this.#registeredCommands.has(tab.id)) return;
|
|
24243
|
+
const existing = this.#commands.get(tab.id);
|
|
24244
|
+
if (!existing) return;
|
|
24245
|
+
this.#commands.unregister(tab.id);
|
|
24246
|
+
this.#commands.register({
|
|
24247
|
+
...existing,
|
|
24248
|
+
label: tab.label
|
|
24249
|
+
});
|
|
24250
|
+
}
|
|
24251
|
+
};
|
|
24252
|
+
//#endregion
|
|
23802
24253
|
//#region src/util/drag-ghost.ts
|
|
23803
24254
|
/**
|
|
23804
24255
|
* Theme-aware floating element helper.
|
|
@@ -24389,30 +24840,13 @@ __decorate([property({
|
|
|
24389
24840
|
})], TabListElement.prototype, "dragMode", void 0);
|
|
24390
24841
|
TabListElement = __decorate([safeCustomElement(`ixfx-tab-list`)], TabListElement);
|
|
24391
24842
|
//#endregion
|
|
24392
|
-
//#region src/tabs/tab-panel.ts
|
|
24393
|
-
let TabPanelElement = class TabPanelElement extends i {
|
|
24394
|
-
render() {
|
|
24395
|
-
return b`<slot></slot>`;
|
|
24396
|
-
}
|
|
24397
|
-
static {
|
|
24398
|
-
this.styles = [themeFallbacks, i$3`
|
|
24399
|
-
:host {
|
|
24400
|
-
display:none;
|
|
24401
|
-
height:100%;
|
|
24402
|
-
width:100%;
|
|
24403
|
-
}
|
|
24404
|
-
|
|
24405
|
-
:host([selected]) {
|
|
24406
|
-
background: var(--surface-3);
|
|
24407
|
-
display:block;
|
|
24408
|
-
}
|
|
24409
|
-
`];
|
|
24410
|
-
}
|
|
24411
|
-
};
|
|
24412
|
-
TabPanelElement = __decorate([safeCustomElement(`ixfx-tab-panel`)], TabPanelElement);
|
|
24413
|
-
//#endregion
|
|
24414
24843
|
//#region src/tabs/tab-panels.ts
|
|
24415
24844
|
let TabPanelsElement = class TabPanelsElement extends i {
|
|
24845
|
+
/**
|
|
24846
|
+
* The `ixfx-tab-list` this panels element is associated with, established by
|
|
24847
|
+
* `syncWithList()`. Used by `selectTab()` to activate the matching header.
|
|
24848
|
+
*/
|
|
24849
|
+
#list;
|
|
24416
24850
|
render() {
|
|
24417
24851
|
return b`<slot></slot>`;
|
|
24418
24852
|
}
|
|
@@ -24432,6 +24866,7 @@ let TabPanelsElement = class TabPanelsElement extends i {
|
|
|
24432
24866
|
if (this.onSelectedPanel) this.onSelectedPanel(el.id, el);
|
|
24433
24867
|
}
|
|
24434
24868
|
syncWithList(el) {
|
|
24869
|
+
this.#list = el;
|
|
24435
24870
|
const doSync = () => {
|
|
24436
24871
|
const t = el.getSelectedElement();
|
|
24437
24872
|
if (!t) return;
|
|
@@ -24453,6 +24888,43 @@ let TabPanelsElement = class TabPanelsElement extends i {
|
|
|
24453
24888
|
}
|
|
24454
24889
|
return found;
|
|
24455
24890
|
}
|
|
24891
|
+
/**
|
|
24892
|
+
* Select a tab as if the user clicked it — activates the matching header in
|
|
24893
|
+
* the associated `ixfx-tab-list` (deactivating the others) and shows its
|
|
24894
|
+
* panel.
|
|
24895
|
+
*
|
|
24896
|
+
* `nameOrTitle` may be the label text of a tab (e.g. `'Home'`, matched
|
|
24897
|
+
* case-insensitively) or the panel id its `for` attribute points at
|
|
24898
|
+
* (e.g. `'panel-home'`). If no tab matches, `nameOrTitle` is tried directly
|
|
24899
|
+
* as a panel id.
|
|
24900
|
+
*
|
|
24901
|
+
* The tab list must first be associated via `syncWithList()` for the header
|
|
24902
|
+
* to be activated; panel selection works regardless.
|
|
24903
|
+
*
|
|
24904
|
+
* Returns true if a panel was found and selected.
|
|
24905
|
+
*/
|
|
24906
|
+
selectTab(nameOrTitle) {
|
|
24907
|
+
const item = this.#findTabItem(nameOrTitle);
|
|
24908
|
+
if (item) {
|
|
24909
|
+
this.#list?.selectElement(item);
|
|
24910
|
+
return this.selectPanel(item.getAttribute(`for`) ?? ``) === true;
|
|
24911
|
+
}
|
|
24912
|
+
return this.selectPanel(nameOrTitle) === true;
|
|
24913
|
+
}
|
|
24914
|
+
#findTabItem(nameOrTitle) {
|
|
24915
|
+
const list = this.#list;
|
|
24916
|
+
if (!list) return void 0;
|
|
24917
|
+
const items = Array.from(list.querySelectorAll(`ixfx-tab-list-item`));
|
|
24918
|
+
for (const item of items) if (item.getAttribute(`for`) === nameOrTitle) return item;
|
|
24919
|
+
const label = nameOrTitle.trim().toLowerCase();
|
|
24920
|
+
for (const item of items) if (this.#labelOf(item).toLowerCase() === label) return item;
|
|
24921
|
+
}
|
|
24922
|
+
/** The tab's visible label text, excluding any `slot="toolbar"` content. */
|
|
24923
|
+
#labelOf(item) {
|
|
24924
|
+
const clone = item.cloneNode(true);
|
|
24925
|
+
clone.querySelectorAll(`[slot="toolbar"]`).forEach((el) => el.remove());
|
|
24926
|
+
return (clone.textContent ?? ``).trim();
|
|
24927
|
+
}
|
|
24456
24928
|
static {
|
|
24457
24929
|
this.styles = i$3`
|
|
24458
24930
|
:host {
|
|
@@ -27069,6 +27541,6 @@ function init() {
|
|
|
27069
27541
|
console.log(`Init`);
|
|
27070
27542
|
}
|
|
27071
27543
|
//#endregion
|
|
27072
|
-
export { AcTextElement, AcTokenElement, ButtonElement, Checkbox, ColourPicker, ColourPickerPopup, CrumbNavigationElement, CrumbPathController, CrumbPathElement, DataController, DataDisplayComponent, EditableLabel, EditableNumber, GroupedItemListerElement, ICON_CARET_RIGHT, ICON_CHECK, ICON_CHEVRON_DOWN, ICON_CLOSE, IncrSearchTreeController as IncrSearchMillerController, IncrSearchTreeController, IxfxHexEditorElement, IxfxIconElement, IxfxTimelineElement, LabelledRadialInput, LabelledRangeInput, LedElement, menu_exports as Menu, MillerBaseElement, MillerListElement, MillerTreeController, NarrowedTextElement, NotificationManager, NotificationPillElement, PanelElement, PanelGroupElement, PlotDataSeries, PlotHistogram, PlotMultiAxis, PlotSingleAxis, PlotXyAxis, PolarPad, RadialInputElement, RadioGroup, RangeElement, RangeInput, RangeMultiElement, SelectHorizontalElement, SliderInputElement, SnapContainer, SplitButton, SplitLayoutElement, SwipeElement, TabListElement, TabListItemElement, TabPanelElement, TabPanelsElement, TimelineController, TimelineTrackTabElement, TooltipElement, TransitoryLabelElement, TreeBaseElement, TreeController, TreeDataModel, TreeListElement, VerticalListElement, XyPad, applyAgeModification, applyHighlights, attachTimelineInteractions, buildHighlightTargets, clearHighlights, collectDataResult, computeColour, createAcCompletionProvider, createElementIncrSearch, createFuzzySearch, createIncrSearch, createPillRenderer, createTreeListAdapter, createVerticalListAdapter, getIcon, hasIcon, iconBus, init, monitorIndeterminate, parseColourScaleAttr, readBaseColour, registerIcon, resolveCssVars, resolveGrid, svgToDataUri, timelineStyles };
|
|
27544
|
+
export { AcTextElement, AcTokenElement, ButtonElement, Checkbox, ColourPicker, ColourPickerPopup, CrumbNavigationElement, CrumbPathController, CrumbPathElement, DataController, DataDisplayComponent, EditableLabel, EditableNumber, FormElement, FormGroupElement, FormPartElement, GroupedItemListerElement, ICON_CARET_RIGHT, ICON_CHECK, ICON_CHEVRON_DOWN, ICON_CLOSE, IncrSearchTreeController as IncrSearchMillerController, IncrSearchTreeController, IxfxHexEditorElement, IxfxIconElement, IxfxTimelineElement, LabelledRadialInput, LabelledRangeInput, LedElement, menu_exports as Menu, MillerBaseElement, MillerListElement, MillerTreeController, NarrowedTextElement, NotificationManager, NotificationPillElement, PanelElement, PanelGroupElement, PlotDataSeries, PlotHistogram, PlotMultiAxis, PlotSingleAxis, PlotXyAxis, PolarPad, RadialInputElement, RadioGroup, RangeElement, RangeInput, RangeMultiElement, SelectHorizontalElement, SliderInputElement, SnapContainer, SplitButton, SplitLayoutElement, SwipeElement, TabController, TabListElement, TabListItemElement, TabPanelElement, TabPanelsElement, TimelineController, TimelineTrackTabElement, TooltipElement, TransitoryLabelElement, TreeBaseElement, TreeController, TreeDataModel, TreeListElement, VerticalListElement, XyPad, applyAgeModification, applyHighlights, attachTimelineInteractions, buildHighlightTargets, clearHighlights, collectDataResult, computeColour, createAcCompletionProvider, createElementIncrSearch, createFuzzySearch, createIncrSearch, createPillRenderer, createTreeListAdapter, createVerticalListAdapter, getIcon, hasIcon, iconBus, init, monitorIndeterminate, parseColourScaleAttr, readBaseColour, registerIcon, resolveCssVars, resolveGrid, svgToDataUri, timelineStyles };
|
|
27073
27545
|
|
|
27074
27546
|
//# sourceMappingURL=index.js.map
|