@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/dist/index.js
CHANGED
|
@@ -2863,6 +2863,132 @@ __decorate([property({
|
|
|
2863
2863
|
__decorate([property({ type: Number })], EditableNumber.prototype, "precision", void 0);
|
|
2864
2864
|
EditableNumber = __decorate([safeCustomElement(`ixfx-editable-number`)], EditableNumber);
|
|
2865
2865
|
//#endregion
|
|
2866
|
+
//#region src/form/form-group.ts
|
|
2867
|
+
let FormGroupElement = class FormGroupElement extends LitElement {
|
|
2868
|
+
constructor(..._args) {
|
|
2869
|
+
super(..._args);
|
|
2870
|
+
this.label = ``;
|
|
2871
|
+
}
|
|
2872
|
+
createRenderRoot() {
|
|
2873
|
+
return this;
|
|
2874
|
+
}
|
|
2875
|
+
connectedCallback() {
|
|
2876
|
+
super.connectedCallback();
|
|
2877
|
+
this._observer = new MutationObserver(() => this._moveChildren());
|
|
2878
|
+
}
|
|
2879
|
+
firstUpdated() {
|
|
2880
|
+
this._fieldset = this.querySelector(`fieldset`) ?? void 0;
|
|
2881
|
+
if (this._fieldset) {
|
|
2882
|
+
this._observer?.observe(this, { childList: true });
|
|
2883
|
+
this._moveChildren();
|
|
2884
|
+
}
|
|
2885
|
+
}
|
|
2886
|
+
disconnectedCallback() {
|
|
2887
|
+
super.disconnectedCallback();
|
|
2888
|
+
this._observer?.disconnect();
|
|
2889
|
+
}
|
|
2890
|
+
_moveChildren() {
|
|
2891
|
+
if (!this._fieldset) return;
|
|
2892
|
+
Array.from(this.children).filter((el) => el.tagName !== `FIELDSET`).forEach((el) => {
|
|
2893
|
+
this._fieldset.appendChild(el);
|
|
2894
|
+
});
|
|
2895
|
+
}
|
|
2896
|
+
render() {
|
|
2897
|
+
return html`<fieldset><legend>${this.label}</legend></fieldset>`;
|
|
2898
|
+
}
|
|
2899
|
+
};
|
|
2900
|
+
__decorate([property({ type: String })], FormGroupElement.prototype, "label", void 0);
|
|
2901
|
+
FormGroupElement = __decorate([safeCustomElement(`ixfx-form-group`)], FormGroupElement);
|
|
2902
|
+
//#endregion
|
|
2903
|
+
//#region src/form/form-part.ts
|
|
2904
|
+
let idCounter = 0;
|
|
2905
|
+
let FormPartElement = class FormPartElement extends LitElement {
|
|
2906
|
+
constructor(..._args) {
|
|
2907
|
+
super(..._args);
|
|
2908
|
+
this.label = ``;
|
|
2909
|
+
}
|
|
2910
|
+
createRenderRoot() {
|
|
2911
|
+
return this;
|
|
2912
|
+
}
|
|
2913
|
+
connectedCallback() {
|
|
2914
|
+
super.connectedCallback();
|
|
2915
|
+
this._ensureId();
|
|
2916
|
+
}
|
|
2917
|
+
_ensureId() {
|
|
2918
|
+
const control = this.querySelector(`input, select, textarea, [name]`);
|
|
2919
|
+
if (!control) return;
|
|
2920
|
+
if (!control.id) {
|
|
2921
|
+
this._id = `ixfx-form-part-${++idCounter}`;
|
|
2922
|
+
control.id = this._id;
|
|
2923
|
+
} else this._id = control.id;
|
|
2924
|
+
}
|
|
2925
|
+
render() {
|
|
2926
|
+
if (!this._id) this._ensureId();
|
|
2927
|
+
return html`<label for=${this._id ?? ``}>${this.label}</label>`;
|
|
2928
|
+
}
|
|
2929
|
+
};
|
|
2930
|
+
__decorate([property({ type: String })], FormPartElement.prototype, "label", void 0);
|
|
2931
|
+
FormPartElement = __decorate([safeCustomElement(`ixfx-form-part`)], FormPartElement);
|
|
2932
|
+
//#endregion
|
|
2933
|
+
//#region src/form/form-values.ts
|
|
2934
|
+
function collectFormValues(root) {
|
|
2935
|
+
const values = {};
|
|
2936
|
+
root.querySelectorAll(`[name]`).forEach((el) => {
|
|
2937
|
+
const name = el.getAttribute(`name`);
|
|
2938
|
+
if (!name) return;
|
|
2939
|
+
if (el instanceof HTMLInputElement) {
|
|
2940
|
+
if (el.type === `radio`) {
|
|
2941
|
+
if (el.checked) values[name] = el.value;
|
|
2942
|
+
} else if (el.type === `checkbox`) values[name] = el.checked;
|
|
2943
|
+
else values[name] = el.value;
|
|
2944
|
+
} else if (el instanceof HTMLSelectElement) {
|
|
2945
|
+
if (el.multiple) values[name] = Array.from(el.selectedOptions).map((opt) => opt.value);
|
|
2946
|
+
else values[name] = el.value;
|
|
2947
|
+
} else if (el instanceof HTMLTextAreaElement) values[name] = el.value;
|
|
2948
|
+
else if (`value` in el) values[name] = el.value;
|
|
2949
|
+
});
|
|
2950
|
+
return values;
|
|
2951
|
+
}
|
|
2952
|
+
function applyFormValues(root, data) {
|
|
2953
|
+
root.querySelectorAll(`[name]`).forEach((el) => {
|
|
2954
|
+
const name = el.getAttribute(`name`);
|
|
2955
|
+
if (!name || !(name in data)) return;
|
|
2956
|
+
const value = data[name];
|
|
2957
|
+
if (el instanceof HTMLInputElement) {
|
|
2958
|
+
if (el.type === `radio`) el.checked = el.value === value;
|
|
2959
|
+
else if (el.type === `checkbox`) el.checked = Boolean(value);
|
|
2960
|
+
else el.value = String(value ?? ``);
|
|
2961
|
+
el.dispatchEvent(new Event(`input`, { bubbles: true }));
|
|
2962
|
+
el.dispatchEvent(new Event(`change`, { bubbles: true }));
|
|
2963
|
+
} else if (el instanceof HTMLSelectElement) {
|
|
2964
|
+
if (el.multiple && Array.isArray(value)) Array.from(el.options).forEach((opt) => {
|
|
2965
|
+
opt.selected = value.includes(opt.value);
|
|
2966
|
+
});
|
|
2967
|
+
else el.value = String(value ?? ``);
|
|
2968
|
+
el.dispatchEvent(new Event(`input`, { bubbles: true }));
|
|
2969
|
+
el.dispatchEvent(new Event(`change`, { bubbles: true }));
|
|
2970
|
+
} else if (el instanceof HTMLTextAreaElement) {
|
|
2971
|
+
el.value = String(value ?? ``);
|
|
2972
|
+
el.dispatchEvent(new Event(`input`, { bubbles: true }));
|
|
2973
|
+
el.dispatchEvent(new Event(`change`, { bubbles: true }));
|
|
2974
|
+
} else if (`value` in el) el.value = value;
|
|
2975
|
+
});
|
|
2976
|
+
}
|
|
2977
|
+
//#endregion
|
|
2978
|
+
//#region src/form/form.ts
|
|
2979
|
+
let FormElement = class FormElement extends LitElement {
|
|
2980
|
+
createRenderRoot() {
|
|
2981
|
+
return this;
|
|
2982
|
+
}
|
|
2983
|
+
getValues() {
|
|
2984
|
+
return collectFormValues(this);
|
|
2985
|
+
}
|
|
2986
|
+
setValues(data) {
|
|
2987
|
+
applyFormValues(this, data);
|
|
2988
|
+
}
|
|
2989
|
+
};
|
|
2990
|
+
FormElement = __decorate([safeCustomElement(`ixfx-form`)], FormElement);
|
|
2991
|
+
//#endregion
|
|
2866
2992
|
//#region src/grouped-item-lister/grouped-item-lister.ts
|
|
2867
2993
|
const UNGROUPED_KEY = `__ungrouped__`;
|
|
2868
2994
|
let GroupedItemListerElement = class GroupedItemListerElement extends LitElement {
|
|
@@ -5272,8 +5398,316 @@ let TabPanelElement = class TabPanelElement extends LitElement {
|
|
|
5272
5398
|
};
|
|
5273
5399
|
TabPanelElement = __decorate([safeCustomElement(`ixfx-tab-panel`)], TabPanelElement);
|
|
5274
5400
|
//#endregion
|
|
5401
|
+
//#region src/tabs/tab-controller.ts
|
|
5402
|
+
/**
|
|
5403
|
+
* Connects an `ixfx-tab-list` to an `ixfx-tab-panels` container, handling the
|
|
5404
|
+
* wiring between them (header clicks show the matching panel, closing a tab
|
|
5405
|
+
* removes its panel, etc.) and offering an API to select, add, remove, rename
|
|
5406
|
+
* and reorder tabs.
|
|
5407
|
+
*
|
|
5408
|
+
* @example
|
|
5409
|
+
* ```ts
|
|
5410
|
+
* const ctrl = new TabController(
|
|
5411
|
+
* document.querySelector('ixfx-tab-list'),
|
|
5412
|
+
* document.querySelector('ixfx-tab-panels'),
|
|
5413
|
+
* );
|
|
5414
|
+
* ctrl.connect();
|
|
5415
|
+
*
|
|
5416
|
+
* ctrl.addTab({ label: 'Console', content: 'Console panel' });
|
|
5417
|
+
* ctrl.selectTab('Console');
|
|
5418
|
+
* ```
|
|
5419
|
+
*/
|
|
5420
|
+
var TabController = class {
|
|
5421
|
+
#list;
|
|
5422
|
+
#panels;
|
|
5423
|
+
#opts;
|
|
5424
|
+
#tabs = [];
|
|
5425
|
+
#signal;
|
|
5426
|
+
#observer;
|
|
5427
|
+
#commands;
|
|
5428
|
+
#registeredCommands = /* @__PURE__ */ new Set();
|
|
5429
|
+
constructor(list, panels, options = {}) {
|
|
5430
|
+
this.#list = list;
|
|
5431
|
+
this.#panels = panels;
|
|
5432
|
+
this.#opts = options;
|
|
5433
|
+
this.#commands = options.commands;
|
|
5434
|
+
}
|
|
5435
|
+
connect() {
|
|
5436
|
+
this.disconnect();
|
|
5437
|
+
this.#signal = new AbortController();
|
|
5438
|
+
const { signal } = this.#signal;
|
|
5439
|
+
this.#list.addEventListener(`change`, this.#onChange, { signal });
|
|
5440
|
+
this.#list.addEventListener(`reorder`, this.#onReorder, { signal });
|
|
5441
|
+
this.#list.addEventListener(`close`, this.#onClose, { signal });
|
|
5442
|
+
this.#observer = new MutationObserver(() => this.#rebuild());
|
|
5443
|
+
this.#observer.observe(this.#list, { childList: true });
|
|
5444
|
+
this.#observer.observe(this.#panels, { childList: true });
|
|
5445
|
+
this.#rebuild();
|
|
5446
|
+
this.#panels.syncWithList(this.#list);
|
|
5447
|
+
for (const tab of this.#tabs) this.#registerCommand(tab);
|
|
5448
|
+
}
|
|
5449
|
+
disconnect() {
|
|
5450
|
+
this.#signal?.abort();
|
|
5451
|
+
this.#signal = void 0;
|
|
5452
|
+
this.#observer?.disconnect();
|
|
5453
|
+
this.#observer = void 0;
|
|
5454
|
+
for (const tab of this.#tabs) this.#unregisterCommand(tab);
|
|
5455
|
+
this.#registeredCommands.clear();
|
|
5456
|
+
this.#tabs = [];
|
|
5457
|
+
}
|
|
5458
|
+
/**
|
|
5459
|
+
* Select a tab as if it was clicked — activates the header (deactivating the
|
|
5460
|
+
* others) and shows its panel.
|
|
5461
|
+
*
|
|
5462
|
+
* `sel` may be a tab id, the panel id its `for` points at, its label text
|
|
5463
|
+
* (case-insensitive), or the tab item element itself.
|
|
5464
|
+
*
|
|
5465
|
+
* Returns true if a tab was found.
|
|
5466
|
+
*/
|
|
5467
|
+
selectTab(sel) {
|
|
5468
|
+
const tab = this.#resolveTab(sel);
|
|
5469
|
+
if (!tab) return false;
|
|
5470
|
+
const previous = this.getSelected();
|
|
5471
|
+
if (previous?.id === tab.id) {
|
|
5472
|
+
this.#panels.selectPanel(tab.forId);
|
|
5473
|
+
return true;
|
|
5474
|
+
}
|
|
5475
|
+
this.#list.selectElement(tab.item);
|
|
5476
|
+
this.#panels.selectPanel(tab.forId);
|
|
5477
|
+
this.#opts.onSelect?.(tab, previous);
|
|
5478
|
+
return true;
|
|
5479
|
+
}
|
|
5480
|
+
selectNext() {
|
|
5481
|
+
return this.#selectOffset(1);
|
|
5482
|
+
}
|
|
5483
|
+
selectPrevious() {
|
|
5484
|
+
return this.#selectOffset(-1);
|
|
5485
|
+
}
|
|
5486
|
+
getSelected() {
|
|
5487
|
+
return this.#tabs.find((t) => t.item.hasAttribute(`selected`));
|
|
5488
|
+
}
|
|
5489
|
+
getTabs() {
|
|
5490
|
+
return [...this.#tabs];
|
|
5491
|
+
}
|
|
5492
|
+
getTab(id) {
|
|
5493
|
+
return this.#tabs.find((t) => t.id === id);
|
|
5494
|
+
}
|
|
5495
|
+
addTab(opts) {
|
|
5496
|
+
const { id, forId } = this.#idsFor(opts);
|
|
5497
|
+
const item = document.createElement(`ixfx-tab-list-item`);
|
|
5498
|
+
item.id = id;
|
|
5499
|
+
item.setAttribute(`for`, forId);
|
|
5500
|
+
item.closeable = opts.closeable ?? true;
|
|
5501
|
+
item.append(opts.label);
|
|
5502
|
+
if (opts.iconName) item.iconName = opts.iconName;
|
|
5503
|
+
if (opts.description) item.description = opts.description;
|
|
5504
|
+
for (const el of opts.toolbar ?? []) {
|
|
5505
|
+
el.slot = `toolbar`;
|
|
5506
|
+
item.append(el);
|
|
5507
|
+
}
|
|
5508
|
+
const panel = document.createElement(`ixfx-tab-panel`);
|
|
5509
|
+
panel.id = forId;
|
|
5510
|
+
if (opts.content !== void 0) this.#fillContent(panel, opts.content);
|
|
5511
|
+
const index = Math.max(0, Math.min(opts.index ?? this.#tabs.length, this.#tabs.length));
|
|
5512
|
+
this.#insertElement(this.#list, item, index);
|
|
5513
|
+
this.#insertElement(this.#panels, panel, index);
|
|
5514
|
+
const tab = {
|
|
5515
|
+
id,
|
|
5516
|
+
forId,
|
|
5517
|
+
item,
|
|
5518
|
+
panel,
|
|
5519
|
+
label: opts.label,
|
|
5520
|
+
iconName: opts.iconName
|
|
5521
|
+
};
|
|
5522
|
+
this.#tabs.splice(index, 0, tab);
|
|
5523
|
+
this.#registerCommand(tab);
|
|
5524
|
+
this.#opts.onAdd?.(tab);
|
|
5525
|
+
if (opts.select ?? true) this.selectTab(id);
|
|
5526
|
+
return tab;
|
|
5527
|
+
}
|
|
5528
|
+
removeTab(sel) {
|
|
5529
|
+
const tab = this.#resolveTab(sel);
|
|
5530
|
+
if (!tab) return false;
|
|
5531
|
+
const index = this.#tabs.indexOf(tab);
|
|
5532
|
+
const adjacent = tab.item.hasAttribute(`selected`) ? this.#adjacentTab(index) : void 0;
|
|
5533
|
+
tab.item.remove();
|
|
5534
|
+
tab.panel.remove();
|
|
5535
|
+
this.#removeFromIndex(tab);
|
|
5536
|
+
this.#unregisterCommand(tab);
|
|
5537
|
+
this.#opts.onRemove?.(tab);
|
|
5538
|
+
if (adjacent) this.selectTab(adjacent.id);
|
|
5539
|
+
return true;
|
|
5540
|
+
}
|
|
5541
|
+
renameTab(sel, label) {
|
|
5542
|
+
const tab = this.#resolveTab(sel);
|
|
5543
|
+
if (!tab) return false;
|
|
5544
|
+
for (const child of [...tab.item.childNodes]) {
|
|
5545
|
+
if (child.nodeType === Node.ELEMENT_NODE && child.slot === `toolbar`) continue;
|
|
5546
|
+
tab.item.removeChild(child);
|
|
5547
|
+
}
|
|
5548
|
+
tab.item.prepend(label);
|
|
5549
|
+
tab.label = label;
|
|
5550
|
+
this.#reregisterCommand(tab);
|
|
5551
|
+
return true;
|
|
5552
|
+
}
|
|
5553
|
+
setTabIcon(sel, iconName) {
|
|
5554
|
+
const tab = this.#resolveTab(sel);
|
|
5555
|
+
if (!tab) return false;
|
|
5556
|
+
if (iconName) {
|
|
5557
|
+
tab.item.iconName = iconName;
|
|
5558
|
+
tab.iconName = iconName;
|
|
5559
|
+
} else {
|
|
5560
|
+
tab.item.iconName = void 0;
|
|
5561
|
+
tab.item.removeAttribute(`icon-name`);
|
|
5562
|
+
tab.iconName = void 0;
|
|
5563
|
+
}
|
|
5564
|
+
return true;
|
|
5565
|
+
}
|
|
5566
|
+
#onChange = (event) => {
|
|
5567
|
+
const detail = event.detail;
|
|
5568
|
+
this.#panels.selectPanel(detail.for);
|
|
5569
|
+
const tab = this.#tabs.find((t) => t.forId === detail.for);
|
|
5570
|
+
if (!tab) return;
|
|
5571
|
+
const previous = detail.previous ? this.#tabs.find((t) => t.id === detail.previous) : void 0;
|
|
5572
|
+
this.#opts.onSelect?.(tab, previous);
|
|
5573
|
+
};
|
|
5574
|
+
#onReorder = () => {
|
|
5575
|
+
this.#rebuild();
|
|
5576
|
+
this.#opts.onReorder?.(this.#tabs);
|
|
5577
|
+
};
|
|
5578
|
+
#onClose = (event) => {
|
|
5579
|
+
const item = event.target?.closest(`ixfx-tab-list-item`);
|
|
5580
|
+
const tab = item ? this.#tabByItem(item) : void 0;
|
|
5581
|
+
if (!tab) return;
|
|
5582
|
+
const index = this.#tabs.indexOf(tab);
|
|
5583
|
+
const adjacent = tab.item.hasAttribute(`selected`) ? this.#adjacentTab(index) : void 0;
|
|
5584
|
+
tab.panel.remove();
|
|
5585
|
+
this.#removeFromIndex(tab);
|
|
5586
|
+
this.#unregisterCommand(tab);
|
|
5587
|
+
this.#opts.onRemove?.(tab);
|
|
5588
|
+
if (adjacent) this.selectTab(adjacent.id);
|
|
5589
|
+
};
|
|
5590
|
+
#selectOffset(offset) {
|
|
5591
|
+
const tabs = this.#tabs;
|
|
5592
|
+
if (tabs.length === 0) return false;
|
|
5593
|
+
const current = this.getSelected();
|
|
5594
|
+
const next = ((current ? tabs.indexOf(current) : offset === 1 ? -1 : 0) + offset + tabs.length) % tabs.length;
|
|
5595
|
+
return this.selectTab(tabs[next].id);
|
|
5596
|
+
}
|
|
5597
|
+
#resolveTab(sel) {
|
|
5598
|
+
if (typeof sel !== `string`) return this.#tabs.find((t) => t.item === sel);
|
|
5599
|
+
const label = sel.trim().toLowerCase();
|
|
5600
|
+
return this.#tabs.find((t) => t.id === sel) ?? this.#tabs.find((t) => t.forId === sel) ?? this.#tabs.find((t) => t.label.toLowerCase() === label);
|
|
5601
|
+
}
|
|
5602
|
+
#tabByItem(item) {
|
|
5603
|
+
return this.#tabs.find((t) => t.item === item);
|
|
5604
|
+
}
|
|
5605
|
+
#adjacentTab(index) {
|
|
5606
|
+
const tabs = this.#tabs;
|
|
5607
|
+
if (tabs.length <= 1) return void 0;
|
|
5608
|
+
return tabs[index + 1] ?? tabs[index - 1];
|
|
5609
|
+
}
|
|
5610
|
+
#removeFromIndex(tab) {
|
|
5611
|
+
const index = this.#tabs.indexOf(tab);
|
|
5612
|
+
if (index >= 0) this.#tabs.splice(index, 1);
|
|
5613
|
+
}
|
|
5614
|
+
#idsFor(opts) {
|
|
5615
|
+
const base = this.#slug(opts.label) || `tab`;
|
|
5616
|
+
return {
|
|
5617
|
+
id: opts.id ?? this.#uniqueId(`tab-${base}`),
|
|
5618
|
+
forId: opts.forId ?? this.#uniqueId(`panel-${base}`)
|
|
5619
|
+
};
|
|
5620
|
+
}
|
|
5621
|
+
#slug(value) {
|
|
5622
|
+
return value.toLowerCase().replace(/[^a-z0-9]+/g, `-`).replace(/^-+|-+$/g, ``);
|
|
5623
|
+
}
|
|
5624
|
+
#uniqueId(base) {
|
|
5625
|
+
let candidate = base;
|
|
5626
|
+
let n = 2;
|
|
5627
|
+
while (document.getElementById(candidate)) candidate = `${base}-${n++}`;
|
|
5628
|
+
return candidate;
|
|
5629
|
+
}
|
|
5630
|
+
#fillContent(panel, content) {
|
|
5631
|
+
if (typeof content === `function`) {
|
|
5632
|
+
content(panel);
|
|
5633
|
+
return;
|
|
5634
|
+
}
|
|
5635
|
+
if (typeof content === `string`) {
|
|
5636
|
+
panel.append(document.createTextNode(content));
|
|
5637
|
+
return;
|
|
5638
|
+
}
|
|
5639
|
+
panel.append(content);
|
|
5640
|
+
}
|
|
5641
|
+
#insertElement(container, el, index) {
|
|
5642
|
+
const children = Array.from(container.children);
|
|
5643
|
+
container.insertBefore(el, children[index] ?? null);
|
|
5644
|
+
}
|
|
5645
|
+
#rebuild() {
|
|
5646
|
+
const panels = /* @__PURE__ */ new Map();
|
|
5647
|
+
for (const el of this.#panels.querySelectorAll(`ixfx-tab-panel`)) panels.set(el.id, el);
|
|
5648
|
+
const tabs = [];
|
|
5649
|
+
for (const item of this.#list.querySelectorAll(`ixfx-tab-list-item`)) {
|
|
5650
|
+
const forId = item.getAttribute(`for`) ?? ``;
|
|
5651
|
+
const panel = panels.get(forId);
|
|
5652
|
+
if (!panel) continue;
|
|
5653
|
+
tabs.push({
|
|
5654
|
+
id: item.id || forId,
|
|
5655
|
+
forId,
|
|
5656
|
+
item,
|
|
5657
|
+
panel,
|
|
5658
|
+
label: this.#labelOf(item),
|
|
5659
|
+
iconName: item.iconName
|
|
5660
|
+
});
|
|
5661
|
+
}
|
|
5662
|
+
this.#tabs = tabs;
|
|
5663
|
+
}
|
|
5664
|
+
/** The tab's visible label text, excluding any `slot="toolbar"` content. */
|
|
5665
|
+
#labelOf(item) {
|
|
5666
|
+
const clone = item.cloneNode(true);
|
|
5667
|
+
clone.querySelectorAll(`[slot="toolbar"]`).forEach((el) => el.remove());
|
|
5668
|
+
return (clone.textContent ?? ``).trim();
|
|
5669
|
+
}
|
|
5670
|
+
#registerCommand(tab) {
|
|
5671
|
+
if (!this.#commands) return;
|
|
5672
|
+
if (tab.item.commandActive) return;
|
|
5673
|
+
if (this.#commands.has(tab.id)) return;
|
|
5674
|
+
this.#commands.register({
|
|
5675
|
+
id: tab.id,
|
|
5676
|
+
label: tab.label,
|
|
5677
|
+
description: tab.item.description ?? tab.label,
|
|
5678
|
+
icon: tab.iconName,
|
|
5679
|
+
execute: () => {
|
|
5680
|
+
this.selectTab(tab.id);
|
|
5681
|
+
}
|
|
5682
|
+
});
|
|
5683
|
+
this.#registeredCommands.add(tab.id);
|
|
5684
|
+
}
|
|
5685
|
+
#unregisterCommand(tab) {
|
|
5686
|
+
if (!this.#commands) return;
|
|
5687
|
+
if (this.#registeredCommands.has(tab.id)) {
|
|
5688
|
+
this.#commands.unregister(tab.id);
|
|
5689
|
+
this.#registeredCommands.delete(tab.id);
|
|
5690
|
+
}
|
|
5691
|
+
}
|
|
5692
|
+
#reregisterCommand(tab) {
|
|
5693
|
+
if (!this.#commands || !this.#registeredCommands.has(tab.id)) return;
|
|
5694
|
+
const existing = this.#commands.get(tab.id);
|
|
5695
|
+
if (!existing) return;
|
|
5696
|
+
this.#commands.unregister(tab.id);
|
|
5697
|
+
this.#commands.register({
|
|
5698
|
+
...existing,
|
|
5699
|
+
label: tab.label
|
|
5700
|
+
});
|
|
5701
|
+
}
|
|
5702
|
+
};
|
|
5703
|
+
//#endregion
|
|
5275
5704
|
//#region src/tabs/tab-panels.ts
|
|
5276
5705
|
let TabPanelsElement = class TabPanelsElement extends LitElement {
|
|
5706
|
+
/**
|
|
5707
|
+
* The `ixfx-tab-list` this panels element is associated with, established by
|
|
5708
|
+
* `syncWithList()`. Used by `selectTab()` to activate the matching header.
|
|
5709
|
+
*/
|
|
5710
|
+
#list;
|
|
5277
5711
|
render() {
|
|
5278
5712
|
return html`<slot></slot>`;
|
|
5279
5713
|
}
|
|
@@ -5293,6 +5727,7 @@ let TabPanelsElement = class TabPanelsElement extends LitElement {
|
|
|
5293
5727
|
if (this.onSelectedPanel) this.onSelectedPanel(el.id, el);
|
|
5294
5728
|
}
|
|
5295
5729
|
syncWithList(el) {
|
|
5730
|
+
this.#list = el;
|
|
5296
5731
|
const doSync = () => {
|
|
5297
5732
|
const t = el.getSelectedElement();
|
|
5298
5733
|
if (!t) return;
|
|
@@ -5314,6 +5749,43 @@ let TabPanelsElement = class TabPanelsElement extends LitElement {
|
|
|
5314
5749
|
}
|
|
5315
5750
|
return found;
|
|
5316
5751
|
}
|
|
5752
|
+
/**
|
|
5753
|
+
* Select a tab as if the user clicked it — activates the matching header in
|
|
5754
|
+
* the associated `ixfx-tab-list` (deactivating the others) and shows its
|
|
5755
|
+
* panel.
|
|
5756
|
+
*
|
|
5757
|
+
* `nameOrTitle` may be the label text of a tab (e.g. `'Home'`, matched
|
|
5758
|
+
* case-insensitively) or the panel id its `for` attribute points at
|
|
5759
|
+
* (e.g. `'panel-home'`). If no tab matches, `nameOrTitle` is tried directly
|
|
5760
|
+
* as a panel id.
|
|
5761
|
+
*
|
|
5762
|
+
* The tab list must first be associated via `syncWithList()` for the header
|
|
5763
|
+
* to be activated; panel selection works regardless.
|
|
5764
|
+
*
|
|
5765
|
+
* Returns true if a panel was found and selected.
|
|
5766
|
+
*/
|
|
5767
|
+
selectTab(nameOrTitle) {
|
|
5768
|
+
const item = this.#findTabItem(nameOrTitle);
|
|
5769
|
+
if (item) {
|
|
5770
|
+
this.#list?.selectElement(item);
|
|
5771
|
+
return this.selectPanel(item.getAttribute(`for`) ?? ``) === true;
|
|
5772
|
+
}
|
|
5773
|
+
return this.selectPanel(nameOrTitle) === true;
|
|
5774
|
+
}
|
|
5775
|
+
#findTabItem(nameOrTitle) {
|
|
5776
|
+
const list = this.#list;
|
|
5777
|
+
if (!list) return void 0;
|
|
5778
|
+
const items = Array.from(list.querySelectorAll(`ixfx-tab-list-item`));
|
|
5779
|
+
for (const item of items) if (item.getAttribute(`for`) === nameOrTitle) return item;
|
|
5780
|
+
const label = nameOrTitle.trim().toLowerCase();
|
|
5781
|
+
for (const item of items) if (this.#labelOf(item).toLowerCase() === label) return item;
|
|
5782
|
+
}
|
|
5783
|
+
/** The tab's visible label text, excluding any `slot="toolbar"` content. */
|
|
5784
|
+
#labelOf(item) {
|
|
5785
|
+
const clone = item.cloneNode(true);
|
|
5786
|
+
clone.querySelectorAll(`[slot="toolbar"]`).forEach((el) => el.remove());
|
|
5787
|
+
return (clone.textContent ?? ``).trim();
|
|
5788
|
+
}
|
|
5317
5789
|
static {
|
|
5318
5790
|
this.styles = css`
|
|
5319
5791
|
:host {
|
|
@@ -5625,6 +6097,6 @@ function init() {
|
|
|
5625
6097
|
console.log(`Init`);
|
|
5626
6098
|
}
|
|
5627
6099
|
//#endregion
|
|
5628
|
-
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 };
|
|
6100
|
+
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 };
|
|
5629
6101
|
|
|
5630
6102
|
//# sourceMappingURL=index.js.map
|