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