@pure-ds/core 0.6.10 → 0.6.11
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/custom-elements.json +803 -16
- package/dist/types/pds.d.ts +1 -0
- package/dist/types/public/assets/js/pds-manager.d.ts +98 -1
- package/dist/types/public/assets/js/pds-manager.d.ts.map +1 -1
- package/dist/types/public/assets/js/pds.d.ts.map +1 -1
- package/dist/types/public/assets/pds/components/pds-live-converter.d.ts +8 -0
- package/dist/types/public/assets/pds/components/pds-live-converter.d.ts.map +1 -0
- package/dist/types/public/assets/pds/components/pds-live-importer.d.ts +2 -0
- package/dist/types/public/assets/pds/components/pds-live-importer.d.ts.map +1 -0
- package/dist/types/public/assets/pds/components/pds-live-template-canvas.d.ts +2 -0
- package/dist/types/public/assets/pds/components/pds-live-template-canvas.d.ts.map +1 -0
- package/dist/types/public/assets/pds/components/pds-omnibox.d.ts.map +1 -1
- package/dist/types/public/assets/pds/components/pds-scrollrow.d.ts +20 -0
- package/dist/types/public/assets/pds/components/pds-scrollrow.d.ts.map +1 -1
- package/dist/types/public/assets/pds/components/pds-toaster.d.ts +1 -1
- package/dist/types/public/assets/pds/components/pds-toaster.d.ts.map +1 -1
- package/dist/types/public/assets/pds/components/pds-treeview.d.ts +37 -0
- package/dist/types/public/assets/pds/components/pds-treeview.d.ts.map +1 -0
- package/dist/types/src/js/common/toast.d.ts +8 -0
- package/dist/types/src/js/common/toast.d.ts.map +1 -1
- package/dist/types/src/js/pds-core/pds-enhancers.d.ts.map +1 -1
- package/dist/types/src/js/pds-core/pds-generator.d.ts.map +1 -1
- package/dist/types/src/js/pds-core/pds-live.d.ts +2 -1
- package/dist/types/src/js/pds-core/pds-live.d.ts.map +1 -1
- package/dist/types/src/js/pds-live-manager/conversion-service.d.ts +66 -0
- package/dist/types/src/js/pds-live-manager/conversion-service.d.ts.map +1 -0
- package/dist/types/src/js/pds-live-manager/import-contract.d.ts +15 -0
- package/dist/types/src/js/pds-live-manager/import-contract.d.ts.map +1 -0
- package/dist/types/src/js/pds-live-manager/import-history-service.d.ts +32 -0
- package/dist/types/src/js/pds-live-manager/import-history-service.d.ts.map +1 -0
- package/dist/types/src/js/pds-live-manager/import-service.d.ts +21 -0
- package/dist/types/src/js/pds-live-manager/import-service.d.ts.map +1 -0
- package/dist/types/src/js/pds-live-manager/template-service.d.ts +17 -0
- package/dist/types/src/js/pds-live-manager/template-service.d.ts.map +1 -0
- package/dist/types/src/js/pds-manager.d.ts +4 -0
- package/dist/types/src/js/pds.d.ts.map +1 -1
- package/package.json +6 -2
- package/packages/pds-cli/README.md +51 -0
- package/packages/pds-cli/bin/pds-import.js +176 -0
- package/packages/pds-cli/bin/pds-static.js +15 -0
- package/packages/pds-cli/bin/postinstall.mjs +17 -8
- package/public/assets/js/app.js +15 -139
- package/public/assets/js/pds-manager.js +358 -255
- package/public/assets/js/pds.js +7 -7
- package/public/assets/pds/components/pds-live-converter.js +47 -0
- package/public/assets/pds/components/pds-live-edit.js +760 -43
- package/public/assets/pds/components/pds-live-importer.js +772 -0
- package/public/assets/pds/components/pds-live-template-canvas.js +171 -0
- package/public/assets/pds/components/pds-omnibox.js +136 -2
- package/public/assets/pds/components/pds-scrollrow.js +56 -1
- package/public/assets/pds/components/pds-toaster.js +50 -5
- package/public/assets/pds/components/pds-treeview.js +972 -0
- package/public/assets/pds/custom-elements.json +803 -16
- package/public/assets/pds/pds-css-complete.json +7 -2
- package/public/assets/pds/templates/commerce-scroll-explorer.html +115 -0
- package/public/assets/pds/templates/content-brand-showcase.html +110 -0
- package/public/assets/pds/templates/feedback-ops-dashboard.html +91 -0
- package/public/assets/pds/templates/release-readiness-radar.html +69 -0
- package/public/assets/pds/templates/support-command-center.html +92 -0
- package/public/assets/pds/templates/templates.json +53 -0
- package/public/assets/pds/templates/workspace-settings-lab.html +131 -0
- package/public/assets/pds/vscode-custom-data.json +54 -4
- package/readme.md +34 -0
- package/src/js/pds-core/pds-config.js +9 -9
- package/src/js/pds-core/pds-enhancers.js +146 -0
- package/src/js/pds-core/pds-generator.js +170 -29
- package/src/js/pds-core/pds-live.js +453 -13
- package/src/js/pds-live-manager/conversion-service.js +3136 -0
- package/src/js/pds-live-manager/import-contract.js +57 -0
- package/src/js/pds-live-manager/import-history-service.js +145 -0
- package/src/js/pds-live-manager/import-service.js +255 -0
- package/src/js/pds-live-manager/tailwind-conversion-rules.json +383 -0
- package/src/js/pds-live-manager/template-service.js +170 -0
- package/src/js/pds.d.ts +1 -0
- package/src/js/pds.js +35 -0
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
const COMPONENT_TAG = "pds-live-template-canvas";
|
|
2
|
+
const PDS = globalThis.PDS;
|
|
3
|
+
|
|
4
|
+
let managerPromise = null;
|
|
5
|
+
|
|
6
|
+
async function getManagerModule() {
|
|
7
|
+
if (managerPromise) return managerPromise;
|
|
8
|
+
managerPromise = (async () => {
|
|
9
|
+
const candidates = [
|
|
10
|
+
PDS?.currentConfig?.managerURL,
|
|
11
|
+
"../core/pds-manager.js",
|
|
12
|
+
"/assets/pds/core/pds-manager.js",
|
|
13
|
+
].filter(Boolean);
|
|
14
|
+
|
|
15
|
+
const attempted = new Set();
|
|
16
|
+
for (const candidate of candidates) {
|
|
17
|
+
try {
|
|
18
|
+
const resolved = new URL(candidate, import.meta.url).href;
|
|
19
|
+
if (attempted.has(resolved)) continue;
|
|
20
|
+
attempted.add(resolved);
|
|
21
|
+
const mod = await import(resolved);
|
|
22
|
+
if (mod && typeof mod === "object") return mod;
|
|
23
|
+
} catch (e) {}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return null;
|
|
27
|
+
})();
|
|
28
|
+
|
|
29
|
+
return managerPromise;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
class PdsLiveTemplateCanvas extends HTMLElement {
|
|
33
|
+
constructor() {
|
|
34
|
+
super();
|
|
35
|
+
this._templates = [];
|
|
36
|
+
this._selectedTemplateId = "";
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
connectedCallback() {
|
|
40
|
+
this._renderShell();
|
|
41
|
+
this._loadTemplates();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
_renderShell() {
|
|
45
|
+
this.className = "stack-sm";
|
|
46
|
+
this.innerHTML = `
|
|
47
|
+
<label class="stack-xs">
|
|
48
|
+
<span>Template</span>
|
|
49
|
+
<div class="pds-live-template-omnibox"></div>
|
|
50
|
+
</label>
|
|
51
|
+
<p class="text-muted pds-live-template-description"></p>
|
|
52
|
+
`;
|
|
53
|
+
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async _loadTemplates() {
|
|
57
|
+
const manager = await getManagerModule();
|
|
58
|
+
if (typeof manager?.listLiveTemplates !== "function") return;
|
|
59
|
+
|
|
60
|
+
this._templates = (await manager.listLiveTemplates()) || [];
|
|
61
|
+
this._selectedTemplateId = "";
|
|
62
|
+
|
|
63
|
+
const host = this.querySelector(".pds-live-template-omnibox");
|
|
64
|
+
if (!host) return;
|
|
65
|
+
|
|
66
|
+
host.replaceChildren();
|
|
67
|
+
try {
|
|
68
|
+
const omnibox = document.createElement("pds-omnibox");
|
|
69
|
+
omnibox.setAttribute("item-grid", "45px 1fr 0");
|
|
70
|
+
omnibox.setAttribute("placeholder", "Search canvas templates...");
|
|
71
|
+
omnibox.value = "";
|
|
72
|
+
|
|
73
|
+
const templates = this._templates;
|
|
74
|
+
omnibox.settings = {
|
|
75
|
+
hideCategory: true,
|
|
76
|
+
itemGrid: "45px 1fr 0",
|
|
77
|
+
categories: {
|
|
78
|
+
Templates: {
|
|
79
|
+
trigger: () => true,
|
|
80
|
+
getItems: (context = {}) => {
|
|
81
|
+
const query = String(context?.search || "").toLowerCase().trim();
|
|
82
|
+
return templates
|
|
83
|
+
.filter((item) => {
|
|
84
|
+
if (!query) return true;
|
|
85
|
+
const haystack = [item.name, item.description, ...(item.tags || [])]
|
|
86
|
+
.join(" ")
|
|
87
|
+
.toLowerCase();
|
|
88
|
+
return haystack.includes(query);
|
|
89
|
+
})
|
|
90
|
+
.map((item) => ({
|
|
91
|
+
id: item.id,
|
|
92
|
+
text: item.name,
|
|
93
|
+
description: item.description,
|
|
94
|
+
icon: item.icon || "grid-four",
|
|
95
|
+
}));
|
|
96
|
+
},
|
|
97
|
+
action: (selection) => {
|
|
98
|
+
this._selectedTemplateId = selection?.id || "";
|
|
99
|
+
this._updateDescription();
|
|
100
|
+
this._applyTemplate();
|
|
101
|
+
return selection?.id || "";
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
omnibox.addEventListener("result-selected", (event) => {
|
|
108
|
+
const selectedId =
|
|
109
|
+
event?.detail?.id ||
|
|
110
|
+
this._templates.find((item) => item.name === event?.detail?.text)?.id ||
|
|
111
|
+
this._selectedTemplateId;
|
|
112
|
+
if (selectedId) {
|
|
113
|
+
this._selectedTemplateId = selectedId;
|
|
114
|
+
}
|
|
115
|
+
const selected = this._templates.find((item) => item.id === this._selectedTemplateId);
|
|
116
|
+
if (selected?.name) {
|
|
117
|
+
omnibox.value = selected.name;
|
|
118
|
+
}
|
|
119
|
+
this._updateDescription();
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
host.appendChild(omnibox);
|
|
123
|
+
} catch (error) {
|
|
124
|
+
const fallback = document.createElement("select");
|
|
125
|
+
fallback.className = "pds-live-template-select";
|
|
126
|
+
this._templates.forEach((template) => {
|
|
127
|
+
const option = document.createElement("option");
|
|
128
|
+
option.value = template.id;
|
|
129
|
+
option.textContent = template.name;
|
|
130
|
+
fallback.appendChild(option);
|
|
131
|
+
});
|
|
132
|
+
fallback.addEventListener("change", () => {
|
|
133
|
+
this._selectedTemplateId = fallback.value;
|
|
134
|
+
this._updateDescription();
|
|
135
|
+
this._applyTemplate();
|
|
136
|
+
});
|
|
137
|
+
host.appendChild(fallback);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
this._updateDescription();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
_updateDescription() {
|
|
144
|
+
const description = this.querySelector(".pds-live-template-description");
|
|
145
|
+
if (!description) return;
|
|
146
|
+
const selected = this._templates.find((item) => item.id === this._selectedTemplateId);
|
|
147
|
+
description.textContent = selected?.description || "";
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
async _applyTemplate() {
|
|
151
|
+
if (!this._selectedTemplateId) return;
|
|
152
|
+
|
|
153
|
+
const manager = await getManagerModule();
|
|
154
|
+
if (typeof manager?.runLiveImport !== "function") return;
|
|
155
|
+
|
|
156
|
+
const result = await manager.runLiveImport({
|
|
157
|
+
sourceType: "template",
|
|
158
|
+
templateId: this._selectedTemplateId,
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
this.dispatchEvent(
|
|
162
|
+
new CustomEvent("pds:live-template:inject", {
|
|
163
|
+
bubbles: true,
|
|
164
|
+
composed: true,
|
|
165
|
+
detail: { result, templateId: this._selectedTemplateId },
|
|
166
|
+
})
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
customElements.define(COMPONENT_TAG, PdsLiveTemplateCanvas);
|
|
@@ -648,6 +648,8 @@ export class PdsOmnibox extends HTMLElement {
|
|
|
648
648
|
if (!suggestion) return;
|
|
649
649
|
this.#suggestionsObserver = new MutationObserver(() => {
|
|
650
650
|
if (!suggestion.classList.contains("ac-active")) {
|
|
651
|
+
this.removeAttribute("data-suggestions-open");
|
|
652
|
+
this.#clearSuggestionOverlayStyles(suggestion);
|
|
651
653
|
this.#resetIconToDefault();
|
|
652
654
|
}
|
|
653
655
|
});
|
|
@@ -682,6 +684,106 @@ export class PdsOmnibox extends HTMLElement {
|
|
|
682
684
|
this.#autoCompleteViewportHandler = null;
|
|
683
685
|
}
|
|
684
686
|
|
|
687
|
+
#clearSuggestionOverlayStyles(suggestion) {
|
|
688
|
+
if (!suggestion || !suggestion.style) return;
|
|
689
|
+
suggestion.style.removeProperty("position");
|
|
690
|
+
suggestion.style.removeProperty("left");
|
|
691
|
+
suggestion.style.removeProperty("right");
|
|
692
|
+
suggestion.style.removeProperty("top");
|
|
693
|
+
suggestion.style.removeProperty("bottom");
|
|
694
|
+
suggestion.style.removeProperty("width");
|
|
695
|
+
suggestion.style.removeProperty("max-width");
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
#getComposedParent(node) {
|
|
699
|
+
if (!node) return null;
|
|
700
|
+
if (node.parentElement) return node.parentElement;
|
|
701
|
+
const root = node.getRootNode?.();
|
|
702
|
+
if (root && root.host) return root.host;
|
|
703
|
+
return null;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
#hasTransformedAncestor(startNode) {
|
|
707
|
+
let current = startNode;
|
|
708
|
+
let safety = 0;
|
|
709
|
+
while (current && safety < 80) {
|
|
710
|
+
if (current instanceof Element) {
|
|
711
|
+
const style = getComputedStyle(current);
|
|
712
|
+
if (
|
|
713
|
+
style.transform !== "none" ||
|
|
714
|
+
style.perspective !== "none" ||
|
|
715
|
+
style.filter !== "none" ||
|
|
716
|
+
style.backdropFilter !== "none"
|
|
717
|
+
) {
|
|
718
|
+
return true;
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
current = this.#getComposedParent(current);
|
|
722
|
+
safety += 1;
|
|
723
|
+
}
|
|
724
|
+
return false;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
#shouldUseFixedSuggestionOverlay(container) {
|
|
728
|
+
if (!container) return false;
|
|
729
|
+
if (this.closest("pds-drawer, dialog")) return false;
|
|
730
|
+
return !this.#hasTransformedAncestor(this);
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
#positionSuggestionInline({ container, suggestion, rect, direction, offset, maxHeight }) {
|
|
734
|
+
if (!container || !suggestion) return;
|
|
735
|
+
this.#clearSuggestionOverlayStyles(suggestion);
|
|
736
|
+
if (direction === "up") {
|
|
737
|
+
suggestion.style.top = "auto";
|
|
738
|
+
suggestion.style.bottom = `${Math.round(rect.height + offset)}px`;
|
|
739
|
+
} else {
|
|
740
|
+
suggestion.style.bottom = "auto";
|
|
741
|
+
suggestion.style.top = `${Math.round(rect.height + offset)}px`;
|
|
742
|
+
}
|
|
743
|
+
container.setAttribute("data-direction", direction);
|
|
744
|
+
suggestion.setAttribute("data-direction", direction);
|
|
745
|
+
container.style.setProperty("--ac-max-height", `${maxHeight}px`);
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
#positionSuggestionOverlay({
|
|
749
|
+
container,
|
|
750
|
+
suggestion,
|
|
751
|
+
rect,
|
|
752
|
+
viewportHeight,
|
|
753
|
+
viewportWidth,
|
|
754
|
+
direction,
|
|
755
|
+
maxHeight,
|
|
756
|
+
gap,
|
|
757
|
+
offset,
|
|
758
|
+
}) {
|
|
759
|
+
if (!container || !suggestion || !suggestion.style) return;
|
|
760
|
+
if (suggestion.classList.contains("full-mobile")) {
|
|
761
|
+
this.#clearSuggestionOverlayStyles(suggestion);
|
|
762
|
+
return;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
const clampedLeft = Math.max(gap, Math.min(rect.left, viewportWidth - rect.width - gap));
|
|
766
|
+
const clampedWidth = Math.max(0, Math.min(rect.width, viewportWidth - gap * 2));
|
|
767
|
+
|
|
768
|
+
suggestion.style.position = "fixed";
|
|
769
|
+
suggestion.style.left = `${Math.round(clampedLeft)}px`;
|
|
770
|
+
suggestion.style.width = `${Math.round(clampedWidth)}px`;
|
|
771
|
+
suggestion.style.maxWidth = `${Math.round(Math.max(0, viewportWidth - gap * 2))}px`;
|
|
772
|
+
suggestion.style.right = "auto";
|
|
773
|
+
|
|
774
|
+
if (direction === "up") {
|
|
775
|
+
suggestion.style.top = "auto";
|
|
776
|
+
suggestion.style.bottom = `${Math.round(viewportHeight - rect.top + offset)}px`;
|
|
777
|
+
} else {
|
|
778
|
+
suggestion.style.bottom = "auto";
|
|
779
|
+
suggestion.style.top = `${Math.round(rect.bottom + offset)}px`;
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
container.setAttribute("data-direction", direction);
|
|
783
|
+
suggestion.setAttribute("data-direction", direction);
|
|
784
|
+
container.style.setProperty("--ac-max-height", `${maxHeight}px`);
|
|
785
|
+
}
|
|
786
|
+
|
|
685
787
|
#updateSuggestionMaxHeight() {
|
|
686
788
|
if (!this.#input) return;
|
|
687
789
|
const container = this.#input.parentElement;
|
|
@@ -696,6 +798,7 @@ export class PdsOmnibox extends HTMLElement {
|
|
|
696
798
|
suggestion?.getAttribute("data-direction") ||
|
|
697
799
|
container.getAttribute("data-direction") ||
|
|
698
800
|
"down";
|
|
801
|
+
const offset = this.#readSpacingToken(container, "--ac-suggest-offset") || 0;
|
|
699
802
|
|
|
700
803
|
const availableDown = viewportHeight - rect.bottom - gap;
|
|
701
804
|
const availableUp = rect.top - gap;
|
|
@@ -705,8 +808,6 @@ export class PdsOmnibox extends HTMLElement {
|
|
|
705
808
|
container.setAttribute("data-direction", direction);
|
|
706
809
|
if (suggestion) suggestion.setAttribute("data-direction", direction);
|
|
707
810
|
if (suggestion) {
|
|
708
|
-
const offset =
|
|
709
|
-
this.#readSpacingToken(container, "--ac-suggest-offset") || 0;
|
|
710
811
|
if (direction === "up") {
|
|
711
812
|
suggestion.style.top = "auto";
|
|
712
813
|
suggestion.style.bottom = `${rect.height + offset}px`;
|
|
@@ -726,6 +827,39 @@ export class PdsOmnibox extends HTMLElement {
|
|
|
726
827
|
Math.floor(Math.min(available, configuredMaxHeight)),
|
|
727
828
|
);
|
|
728
829
|
container.style.setProperty("--ac-max-height", `${maxHeight}px`);
|
|
830
|
+
|
|
831
|
+
const isSuggestionActive = suggestion?.classList?.contains("ac-active");
|
|
832
|
+
this.toggleAttribute("data-suggestions-open", Boolean(isSuggestionActive));
|
|
833
|
+
|
|
834
|
+
if (!suggestion || !isSuggestionActive || suggestion.classList.contains("full-mobile")) {
|
|
835
|
+
this.#clearSuggestionOverlayStyles(suggestion);
|
|
836
|
+
return;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
if (!this.#shouldUseFixedSuggestionOverlay(container)) {
|
|
840
|
+
this.#positionSuggestionInline({
|
|
841
|
+
container,
|
|
842
|
+
suggestion,
|
|
843
|
+
rect,
|
|
844
|
+
direction,
|
|
845
|
+
offset,
|
|
846
|
+
maxHeight,
|
|
847
|
+
});
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
const viewportWidth = window.visualViewport?.width || window.innerWidth;
|
|
852
|
+
this.#positionSuggestionOverlay({
|
|
853
|
+
container,
|
|
854
|
+
suggestion,
|
|
855
|
+
rect,
|
|
856
|
+
viewportHeight,
|
|
857
|
+
viewportWidth,
|
|
858
|
+
direction,
|
|
859
|
+
maxHeight,
|
|
860
|
+
gap,
|
|
861
|
+
offset,
|
|
862
|
+
});
|
|
729
863
|
}
|
|
730
864
|
|
|
731
865
|
#resolveSuggestionDirection(container) {
|
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
*
|
|
12
12
|
* @attr {string} label - Accessible label for the scroll region; also used as fallback heading copy
|
|
13
13
|
* @attr {"start"|"center"} snap - Snap alignment for tiles when scrolling (default: start)
|
|
14
|
+
* @attr {string} tile-min - Minimum tile width (CSS length, e.g. "250px")
|
|
15
|
+
* @attr {string} tile-max - Maximum tile width (CSS length, e.g. "360px")
|
|
14
16
|
*/
|
|
15
17
|
class PdsScrollrow extends HTMLElement {
|
|
16
18
|
#viewport;
|
|
@@ -19,7 +21,7 @@ class PdsScrollrow extends HTMLElement {
|
|
|
19
21
|
#adopted = false;
|
|
20
22
|
|
|
21
23
|
static get observedAttributes() {
|
|
22
|
-
return ["label", "snap"];
|
|
24
|
+
return ["label", "snap", "tile-min", "tile-max"];
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
constructor() {
|
|
@@ -128,6 +130,36 @@ class PdsScrollrow extends HTMLElement {
|
|
|
128
130
|
else this.setAttribute("snap", String(val));
|
|
129
131
|
}
|
|
130
132
|
|
|
133
|
+
/**
|
|
134
|
+
* Minimum tile size applied to slotted content.
|
|
135
|
+
* @returns {string|null}
|
|
136
|
+
*/
|
|
137
|
+
get tileMin() {
|
|
138
|
+
return this.getAttribute("tile-min");
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* @param {string|null} val
|
|
142
|
+
*/
|
|
143
|
+
set tileMin(val) {
|
|
144
|
+
if (val == null) this.removeAttribute("tile-min");
|
|
145
|
+
else this.setAttribute("tile-min", String(val));
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Maximum tile size applied to slotted content.
|
|
150
|
+
* @returns {string|null}
|
|
151
|
+
*/
|
|
152
|
+
get tileMax() {
|
|
153
|
+
return this.getAttribute("tile-max");
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* @param {string|null} val
|
|
157
|
+
*/
|
|
158
|
+
set tileMax(val) {
|
|
159
|
+
if (val == null) this.removeAttribute("tile-max");
|
|
160
|
+
else this.setAttribute("tile-max", String(val));
|
|
161
|
+
}
|
|
162
|
+
|
|
131
163
|
/**
|
|
132
164
|
* Lifecycle hook called when the element is inserted into the document.
|
|
133
165
|
*/
|
|
@@ -189,6 +221,11 @@ class PdsScrollrow extends HTMLElement {
|
|
|
189
221
|
this.#applySnap();
|
|
190
222
|
break;
|
|
191
223
|
}
|
|
224
|
+
case "tile-min":
|
|
225
|
+
case "tile-max": {
|
|
226
|
+
this.#applyTileSizing();
|
|
227
|
+
break;
|
|
228
|
+
}
|
|
192
229
|
}
|
|
193
230
|
}
|
|
194
231
|
|
|
@@ -256,6 +293,7 @@ class PdsScrollrow extends HTMLElement {
|
|
|
256
293
|
|
|
257
294
|
// Apply initial snap alignment
|
|
258
295
|
this.#applySnap();
|
|
296
|
+
this.#applyTileSizing();
|
|
259
297
|
|
|
260
298
|
// Observe size changes to refresh controls
|
|
261
299
|
this.#ro = new ResizeObserver(() => this.#updateControls());
|
|
@@ -274,6 +312,23 @@ class PdsScrollrow extends HTMLElement {
|
|
|
274
312
|
}
|
|
275
313
|
}
|
|
276
314
|
|
|
315
|
+
#applyTileSizing() {
|
|
316
|
+
const tileMin = this.tileMin;
|
|
317
|
+
const tileMax = this.tileMax;
|
|
318
|
+
|
|
319
|
+
if (tileMin && String(tileMin).trim()) {
|
|
320
|
+
this.style.setProperty("--tile-min", String(tileMin).trim());
|
|
321
|
+
} else {
|
|
322
|
+
this.style.removeProperty("--tile-min");
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (tileMax && String(tileMax).trim()) {
|
|
326
|
+
this.style.setProperty("--tile-max", String(tileMax).trim());
|
|
327
|
+
} else {
|
|
328
|
+
this.style.removeProperty("--tile-max");
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
277
332
|
/**
|
|
278
333
|
* Scroll the viewport by roughly one page in the indicated direction.
|
|
279
334
|
* @param {Event} e
|
|
@@ -124,6 +124,14 @@ export class AppToaster extends HTMLElement {
|
|
|
124
124
|
white-space: pre-line;
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
+
aside.toast .toast-content {
|
|
128
|
+
width: 100%;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
aside.toast .toast-action {
|
|
132
|
+
margin-top: var(--spacing-2);
|
|
133
|
+
}
|
|
134
|
+
|
|
127
135
|
/* Mobile responsive toast positioning */
|
|
128
136
|
@_media (max-width: 640px) {
|
|
129
137
|
:host {
|
|
@@ -182,19 +190,23 @@ export class AppToaster extends HTMLElement {
|
|
|
182
190
|
duration: null, // auto-calculated based on reading time
|
|
183
191
|
closable: true,
|
|
184
192
|
persistent: false, // if true, doesn't auto-dismiss
|
|
193
|
+
html: false,
|
|
194
|
+
action: null,
|
|
185
195
|
};
|
|
186
196
|
|
|
187
197
|
const config = { ...defaults, ...options };
|
|
188
198
|
|
|
189
199
|
// Calculate reading time (average 200 words per minute)
|
|
190
|
-
const
|
|
200
|
+
const messageText = String(message || "");
|
|
201
|
+
const readingText = config.html ? messageText.replace(/<[^>]*>/g, " ") : messageText;
|
|
202
|
+
const wordCount = readingText.split(/\s+/).filter(Boolean).length;
|
|
191
203
|
const baseReadingTime = Math.max(2000, (wordCount / 200) * 60 * 1000); // minimum 2 seconds
|
|
192
204
|
|
|
193
205
|
// Extend time for errors (people need more time to process error messages)
|
|
194
206
|
const multiplier = config.type === "error" ? 1.5 : 1;
|
|
195
207
|
const duration = config.duration || baseReadingTime * multiplier;
|
|
196
208
|
|
|
197
|
-
return this.#showToast(
|
|
209
|
+
return this.#showToast(messageText, config, duration);
|
|
198
210
|
}
|
|
199
211
|
|
|
200
212
|
/*
|
|
@@ -213,7 +225,9 @@ export class AppToaster extends HTMLElement {
|
|
|
213
225
|
config.type,
|
|
214
226
|
config.closable,
|
|
215
227
|
duration,
|
|
216
|
-
config.persistent
|
|
228
|
+
config.persistent,
|
|
229
|
+
config.html,
|
|
230
|
+
config.action
|
|
217
231
|
);
|
|
218
232
|
|
|
219
233
|
// Add to DOM
|
|
@@ -247,7 +261,7 @@ export class AppToaster extends HTMLElement {
|
|
|
247
261
|
* @param {boolean} persistent
|
|
248
262
|
* @returns {HTMLElement}
|
|
249
263
|
*/
|
|
250
|
-
createToastElement(id, message, type, closable, duration, persistent) {
|
|
264
|
+
createToastElement(id, message, type, closable, duration, persistent, html = false, action = null) {
|
|
251
265
|
const toast = document.createElement("aside");
|
|
252
266
|
toast.className = `toast callout ${this.#getAlertClass(type)}`;
|
|
253
267
|
toast.setAttribute("data-toast-id", id);
|
|
@@ -260,6 +274,7 @@ export class AppToaster extends HTMLElement {
|
|
|
260
274
|
icon.setAttribute("size", "lg");
|
|
261
275
|
|
|
262
276
|
const content = document.createElement("div");
|
|
277
|
+
content.className = "toast-content";
|
|
263
278
|
|
|
264
279
|
const title = document.createElement("div");
|
|
265
280
|
title.className = "callout-title";
|
|
@@ -267,11 +282,41 @@ export class AppToaster extends HTMLElement {
|
|
|
267
282
|
|
|
268
283
|
const text = document.createElement("p");
|
|
269
284
|
text.style.margin = "0";
|
|
270
|
-
|
|
285
|
+
if (html) {
|
|
286
|
+
text.innerHTML = String(message || "");
|
|
287
|
+
} else {
|
|
288
|
+
text.textContent = String(message || "");
|
|
289
|
+
}
|
|
271
290
|
|
|
272
291
|
content.appendChild(title);
|
|
273
292
|
content.appendChild(text);
|
|
274
293
|
|
|
294
|
+
if (action && typeof action === "object" && action.label) {
|
|
295
|
+
const actionButton = document.createElement("button");
|
|
296
|
+
actionButton.className = "btn-outline btn-sm toast-action";
|
|
297
|
+
actionButton.type = "button";
|
|
298
|
+
const actionLabel = document.createElement("span");
|
|
299
|
+
actionLabel.textContent = String(action.label);
|
|
300
|
+
|
|
301
|
+
if (action.icon) {
|
|
302
|
+
const icon = document.createElement("pds-icon");
|
|
303
|
+
icon.setAttribute("icon", String(action.icon));
|
|
304
|
+
icon.setAttribute("size", "sm");
|
|
305
|
+
actionButton.appendChild(icon);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
actionButton.appendChild(actionLabel);
|
|
309
|
+
actionButton.addEventListener("click", () => {
|
|
310
|
+
if (typeof action.onClick === "function") {
|
|
311
|
+
action.onClick();
|
|
312
|
+
}
|
|
313
|
+
if (action.dismissOnClick !== false) {
|
|
314
|
+
this.dismissToast(id);
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
content.appendChild(actionButton);
|
|
318
|
+
}
|
|
319
|
+
|
|
275
320
|
toast.appendChild(icon);
|
|
276
321
|
toast.appendChild(content);
|
|
277
322
|
|