composite-select 1.0.8 → 1.0.10

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.
Files changed (43) hide show
  1. package/dist/cjs/CenterAndHeightResizer.cjs +268 -0
  2. package/dist/cjs/CenterResizer.cjs +195 -0
  3. package/dist/cjs/composite-select/ContainerManager.html.cjs +650 -0
  4. package/dist/cjs/composite-select/composite-select.html.cjs +651 -0
  5. package/dist/cjs/options-section/OptionsSectionManager.html.cjs +362 -0
  6. package/dist/cjs/options-section/OptionsSectionManagerWebComponent.attributes.html.cjs +346 -0
  7. package/dist/cjs/options-section/OptionsSectionManagerWebComponent.html.cjs +354 -0
  8. package/dist/cjs/options-section/OptionsSectionManagerWebComponent.nocssrequest.html.cjs +345 -0
  9. package/dist/cjs/selected-section/SelectedSectionManager.html.cjs +336 -0
  10. package/dist/cjs/selected-section/SelectedSectionManager.templates.html.cjs +353 -0
  11. package/dist/cjs/selected-section/SelectedSectionManagerWebComponent.attributes.html.cjs +353 -0
  12. package/dist/cjs/selected-section/SelectedSectionManagerWebComponent.html.cjs +335 -0
  13. package/dist/cjs/selected-section/SelectedSectionManagerWebComponent.nocssrequest.html.cjs +341 -0
  14. package/dist/esm/CenterAndHeightResizer.js +268 -0
  15. package/dist/esm/CenterResizer.js +195 -0
  16. package/dist/types/CenterAndHeightResizer.d.ts +18 -0
  17. package/dist/types/CenterResizer.d.ts +16 -0
  18. package/dist/types/composite-select/ContainerManager.html.d.ts +1 -1
  19. package/dist/types/composite-select/composite-select.html.d.ts +1 -1
  20. package/dist/types/options-section/OptionsSectionManager.html.d.ts +1 -1
  21. package/dist/types/options-section/OptionsSectionManagerWebComponent.attributes.html.d.ts +1 -1
  22. package/dist/types/options-section/OptionsSectionManagerWebComponent.html.d.ts +1 -1
  23. package/dist/types/options-section/OptionsSectionManagerWebComponent.nocssrequest.html.d.ts +1 -1
  24. package/dist/types/selected-section/SelectedSectionManager.html.d.ts +1 -1
  25. package/dist/types/selected-section/SelectedSectionManager.templates.html.d.ts +1 -1
  26. package/dist/types/selected-section/SelectedSectionManagerWebComponent.attributes.html.d.ts +1 -1
  27. package/dist/types/selected-section/SelectedSectionManagerWebComponent.html.d.ts +1 -1
  28. package/package.json +1 -1
  29. package/js/CenterAndHeightResizer.js +0 -263
  30. package/js/CenterResizer.js +0 -190
  31. /package/dist/cjs/composite-select/{CompositeManager.js → CompositeManager.cjs} +0 -0
  32. /package/dist/cjs/composite-select/{composite-select.js → composite-select.cjs} +0 -0
  33. /package/dist/cjs/composite-select/{debounce.js → debounce.cjs} +0 -0
  34. /package/dist/cjs/composite-select/{helpers.js → helpers.cjs} +0 -0
  35. /package/dist/cjs/composite-select/{react.js → react.cjs} +0 -0
  36. /package/dist/cjs/container/{ContainerManager.js → ContainerManager.cjs} +0 -0
  37. /package/dist/cjs/options-section/{OptionsSectionManager.js → OptionsSectionManager.cjs} +0 -0
  38. /package/dist/cjs/options-section/{options-section.js → options-section.cjs} +0 -0
  39. /package/dist/cjs/options-section/{react.js → react.cjs} +0 -0
  40. /package/dist/cjs/selected-section/{SelectedSectionManager.js → SelectedSectionManager.cjs} +0 -0
  41. /package/dist/cjs/selected-section/{react.js → react.cjs} +0 -0
  42. /package/dist/cjs/selected-section/{selected-section.js → selected-section.cjs} +0 -0
  43. /package/dist/cjs/unbind/{clickOutside.js → clickOutside.cjs} +0 -0
@@ -0,0 +1,353 @@
1
+ import "../CenterResizer.js";
2
+ import { SelectedSectionManager } from "./SelectedSectionManager.js";
3
+ import { urlStateConfig, getNextId, setNextId } from "./urlManager.js";
4
+ import { getSafeFreeOffset } from "../composite-select/namesSource.js";
5
+ const reloadLink = document.getElementById("reload-link");
6
+ if (reloadLink) {
7
+ reloadLink.href = window.location.pathname;
8
+ }
9
+ let instanceCounter = 0;
10
+ const imgData = await fetch("../img/img.json").then((r) => r.json());
11
+ const updateUrlDisplay = (url = window.location.href) => {
12
+ const el = document.getElementById("url-display");
13
+ if (el)
14
+ el.textContent = url;
15
+ };
16
+ const init = (initialSelected = [], states = {}) => {
17
+ instanceCounter++;
18
+ const id = instanceCounter;
19
+ const resizerLeft = states.left || "50px";
20
+ const resizerCenter = states.center || "350px";
21
+ const section = document.createElement("div");
22
+ section.className = "demo-section";
23
+ let templateButtonsHtml = "";
24
+ for (const [color, images] of Object.entries(imgData)) {
25
+ images.forEach((img) => {
26
+ templateButtonsHtml += `<button class="gcp-css white" data-role="template-btn" data-color="${color}" data-img="${img}" style="color: ${color}; padding: 2px 8px; font-size: 11px;">${img}</button>`;
27
+ });
28
+ }
29
+ section.innerHTML = `
30
+ <h2>Instance #${id} (Templates)</h2>
31
+ <button class="gcp-css white destroy-btn" data-role="destroy">Destroy</button>
32
+
33
+ <div class="resizer-container">
34
+ <center-resizer data-role="resizer" left="${resizerLeft}" center="${resizerCenter}" style="padding: 12px;">
35
+ <div data-role="container"></div>
36
+ </center-resizer>
37
+ </div>
38
+
39
+ <div class="controls gcp-css" style="margin-bottom: 8px;">
40
+ <div class="controls-label">SelectedSectionManager (Templates)</div>
41
+
42
+ <div style="display: flex; gap: 10px; flex-wrap: wrap;">
43
+ <div class="gcp-css checkbox-wrapper">
44
+ <div class="checkbox-row">
45
+ <input type="checkbox" id="disabled-sel-${id}" data-role="disabled-sel" ${states.disabled ? "checked" : ""}>
46
+ <div class="content-cell"><label for="disabled-sel-${id}">Disabled</label></div>
47
+ </div>
48
+ </div>
49
+
50
+ <div class="gcp-css checkbox-wrapper">
51
+ <div class="checkbox-row">
52
+ <input type="checkbox" id="loading-sel-${id}" data-role="loading-sel" ${states.loading ? "checked" : ""}>
53
+ <div class="content-cell"><label for="loading-sel-${id}">Loading</label></div>
54
+ </div>
55
+ </div>
56
+
57
+ <div class="gcp-css checkbox-wrapper">
58
+ <div class="checkbox-row">
59
+ <input type="checkbox" id="error-sel-${id}" data-role="error-sel" ${states.error ? "checked" : ""}>
60
+ <div class="content-cell"><label for="error-sel-${id}">Error</label></div>
61
+ </div>
62
+ </div>
63
+
64
+ <div class="gcp-css checkbox-wrapper">
65
+ <div class="checkbox-row">
66
+ <input type="checkbox" id="show-input-sel-${id}" data-role="show-input-sel" ${states.showInput !== false ? "checked" : ""}>
67
+ <div class="content-cell"><label for="show-input-sel-${id}">Show Input</label></div>
68
+ </div>
69
+ </div>
70
+ </div>
71
+
72
+ <div style="display: flex; gap: 10px; flex-wrap: wrap; margin-top: 10px;">
73
+ <div class="gcp-css input-wrapper">
74
+ <input type="text" id="label-input-sel-${id}" data-role="label-input-opt" placeholder="&nbsp;" value="${states.label || ""}">
75
+ <label for="label-input-sel-${id}">Label</label>
76
+ </div>
77
+ <div class="gcp-css input-wrapper">
78
+ <input type="text" id="value-input-sel-${id}" data-role="value-input-opt" placeholder="&nbsp;" value="${states.value || ""}">
79
+ <label for="value-input-sel-${id}">Value</label>
80
+ </div>
81
+ <button class="gcp-css white" data-role="focus-btn">Focus</button>
82
+ <button class="gcp-css white" data-role="add-btn">Add Random</button>
83
+ <button class="gcp-css white" data-role="clear-btn">Clear All</button>
84
+ </div>
85
+
86
+ <div style="display: flex; gap: 5px; align-items: center; width: 100%; margin-top: 10px; flex-wrap: wrap;">
87
+ <span style="min-width: 120px;">🖼️ <strong>Templates</strong>:</span>
88
+ ${templateButtonsHtml}
89
+ </div>
90
+
91
+ <div style="display: flex; gap: 5px; align-items: center; width: 100%; margin-top: 10px; flex-wrap: wrap;">
92
+ <span style="min-width: 120px;">🎨 <strong>Render</strong>:</span>
93
+ <button class="gcp-css white" data-role="opt-render-btn">Set Custom Render</button>
94
+ <button class="gcp-css white" data-role="opt-list-render-btn">Set Custom List Render</button>
95
+ <button class="gcp-css white" data-role="opt-default-render-btn">Reset Renderers</button>
96
+ </div>
97
+
98
+ <div style="width: 100%; margin-top: 10px;">
99
+ (onInputChange triggers: <span data-role="onchange-count" style="font-weight: bold;">0</span>,
100
+ onDelete triggers: <span data-role="ondelete-count" style="font-weight: bold;">0</span>,
101
+ onClear triggers: <span data-role="onclear-count" style="font-weight: bold;">0</span>,
102
+ onChange triggers: <span data-role="onitemchange-count" style="font-weight: bold;">0</span>,
103
+ onFocus triggers: <span data-role="onfocus-count" style="font-weight: bold;">0</span>)
104
+ </div>
105
+ </div>
106
+
107
+ <pre data-role="dump" style="background:#f8f8f8;padding:10px;border:1px solid #eee;border-radius:4px;font-size:12px;margin:0;overflow:auto;"></pre>
108
+ `;
109
+ document.getElementById("instances-area").appendChild(section);
110
+ const container = section.querySelector('[data-role="container"]');
111
+ const resizer = section.querySelector('[data-role="resizer"]');
112
+ const destroyBtn = section.querySelector('[data-role="destroy"]');
113
+ const dump = section.querySelector('[data-role="dump"]');
114
+ const disabledSelCb = section.querySelector('[data-role="disabled-sel"]');
115
+ const loadingSelCb = section.querySelector('[data-role="loading-sel"]');
116
+ const errorSelCb = section.querySelector('[data-role="error-sel"]');
117
+ const showInputSelCb = section.querySelector('[data-role="show-input-sel"]');
118
+ const labelInputSel = section.querySelector('[data-role="label-input-opt"]');
119
+ const valueInputSel = section.querySelector('[data-role="value-input-opt"]');
120
+ const focusBtn = section.querySelector('[data-role="focus-btn"]');
121
+ const addBtn = section.querySelector('[data-role="add-btn"]');
122
+ const clearBtn = section.querySelector('[data-role="clear-btn"]');
123
+ const optRenderBtn = section.querySelector('[data-role="opt-render-btn"]');
124
+ const optListRenderBtn = section.querySelector('[data-role="opt-list-render-btn"]');
125
+ const optDefaultRenderBtn = section.querySelector('[data-role="opt-default-render-btn"]');
126
+ const inc = (role) => {
127
+ const el = section.querySelector(`[data-role="${role}"]`);
128
+ if (el) {
129
+ el.textContent = String(parseInt(el.textContent || "0", 10) + 1);
130
+ }
131
+ };
132
+ const updateDump = (list) => {
133
+ dump.textContent = JSON.stringify(list, null, 2);
134
+ };
135
+ let mgr;
136
+ const syncUrl = () => {
137
+ const url = new URL(window.location.href);
138
+ urlStateConfig.toUrl(url, id, {
139
+ selected: mgr.getSelected(),
140
+ left: resizer.getAttribute("left") || "50px",
141
+ center: resizer.getAttribute("center") || "350px",
142
+ disabled: disabledSelCb.checked,
143
+ loading: loadingSelCb.checked,
144
+ label: labelInputSel.value || "",
145
+ value: valueInputSel.value || "",
146
+ error: errorSelCb.checked,
147
+ showInput: showInputSelCb.checked,
148
+ });
149
+ window.history.replaceState({}, "", url);
150
+ updateUrlDisplay(url.toString());
151
+ };
152
+ mgr = new SelectedSectionManager(container, {
153
+ selected: initialSelected,
154
+ label: states.label || "Select options",
155
+ disabled: !!states.disabled,
156
+ loading: !!states.loading,
157
+ error: !!states.error,
158
+ showInput: states.showInput !== false,
159
+ value: states.value || "",
160
+ onFocus: () => {
161
+ inc("onfocus-count");
162
+ },
163
+ onInputChange: (e) => {
164
+ inc("onchange-count");
165
+ valueInputSel.value = e.target.value;
166
+ if (e.key === "Enter") {
167
+ const val = e.target.value.trim();
168
+ if (val) {
169
+ const id = getNextId();
170
+ setNextId(id + 1);
171
+ mgr.setSelected([...mgr.getSelected(), { id, label: val }]);
172
+ mgr.setValue("");
173
+ }
174
+ }
175
+ if (e.key === "Backspace" && e.target.value === "" && mgr.getSelected().length > 0) {
176
+ const selected = [...mgr.getSelected()];
177
+ selected.pop();
178
+ mgr.setSelected(selected);
179
+ }
180
+ syncUrl();
181
+ },
182
+ onDelete: (id) => {
183
+ inc("ondelete-count");
184
+ mgr.setSelected(mgr.getSelected().filter((i) => String(i.id) !== String(id)));
185
+ syncUrl();
186
+ },
187
+ onClear: () => {
188
+ inc("onclear-count");
189
+ mgr.setSelected([]);
190
+ syncUrl();
191
+ },
192
+ onChange: (items) => {
193
+ inc("onitemchange-count");
194
+ updateDump(items);
195
+ },
196
+ onComponentChange: (opt) => {
197
+ disabledSelCb.checked = !!opt.disabled;
198
+ loadingSelCb.checked = !!opt.loading;
199
+ errorSelCb.checked = !!opt.error;
200
+ showInputSelCb.checked = opt.showInput !== false;
201
+ labelInputSel.value = opt.label || "";
202
+ valueInputSel.value = opt.value || "";
203
+ },
204
+ });
205
+ updateDump(mgr.getSelected());
206
+ disabledSelCb.addEventListener("change", () => {
207
+ mgr.setDisabled(disabledSelCb.checked);
208
+ syncUrl();
209
+ });
210
+ loadingSelCb.addEventListener("change", () => {
211
+ mgr.setLoading(loadingSelCb.checked);
212
+ syncUrl();
213
+ });
214
+ errorSelCb.addEventListener("change", () => {
215
+ mgr.setError(errorSelCb.checked);
216
+ syncUrl();
217
+ });
218
+ showInputSelCb.addEventListener("change", () => {
219
+ mgr.setShowInput(showInputSelCb.checked);
220
+ syncUrl();
221
+ });
222
+ labelInputSel.addEventListener("input", () => {
223
+ mgr.setLabel(labelInputSel.value);
224
+ syncUrl();
225
+ });
226
+ valueInputSel.addEventListener("input", () => {
227
+ mgr.setValue(valueInputSel.value);
228
+ syncUrl();
229
+ });
230
+ focusBtn.addEventListener("click", () => mgr.setFocus());
231
+ addBtn.addEventListener("click", () => {
232
+ const id = getNextId();
233
+ setNextId(id + 1);
234
+ mgr.setSelected([...mgr.getSelected(), { id, label: `Item ${id}` }]);
235
+ syncUrl();
236
+ });
237
+ clearBtn.addEventListener("click", () => {
238
+ mgr.clearSearch(true);
239
+ syncUrl();
240
+ });
241
+ section.querySelectorAll('[data-role="template-btn"]').forEach((btn) => {
242
+ btn.addEventListener("click", () => {
243
+ const b = btn;
244
+ const id = getNextId();
245
+ setNextId(id + 1);
246
+ mgr.setSelected([
247
+ ...mgr.getSelected(),
248
+ {
249
+ id,
250
+ label: b.dataset.img ? b.dataset.img.split(".")[0] : `Template ${id}`,
251
+ color: b.dataset.color,
252
+ img: b.dataset.img,
253
+ },
254
+ ]);
255
+ syncUrl();
256
+ });
257
+ });
258
+ optRenderBtn.addEventListener("click", () => {
259
+ mgr.setRenderItem((item) => {
260
+ const el = document.createElement("div");
261
+ el.className = "element";
262
+ el.dataset.id = String(item.id);
263
+ el.style.border = `2px solid ${item.color || "#ccc"}`;
264
+ el.style.display = "flex";
265
+ el.style.alignItems = "center";
266
+ el.style.gap = "5px";
267
+ el.style.padding = "4px 8px";
268
+ el.style.borderRadius = "12px";
269
+ el.style.background = "#fff";
270
+ if (item.img) {
271
+ const img = document.createElement("img");
272
+ img.src = `../img/${item.img}`;
273
+ img.style.width = "16px";
274
+ img.style.height = "16px";
275
+ img.style.objectFit = "contain";
276
+ el.appendChild(img);
277
+ }
278
+ const label = document.createElement("label");
279
+ label.textContent = item.label;
280
+ el.appendChild(label);
281
+ const del = document.createElement("div");
282
+ del.dataset.remove = String(item.id);
283
+ el.appendChild(del);
284
+ return el;
285
+ });
286
+ });
287
+ optListRenderBtn.addEventListener("click", () => {
288
+ mgr.setRenderList((selected, defaultRenderList) => {
289
+ const elements = defaultRenderList(selected);
290
+ const groups = [];
291
+ for (let i = 0; i < elements.length; i += 3) {
292
+ const groupDiv = document.createElement("div");
293
+ groupDiv.style.border = "1px dashed #aaa";
294
+ groupDiv.style.padding = "4px";
295
+ groupDiv.style.margin = "2px";
296
+ groupDiv.style.display = "flex";
297
+ groupDiv.style.gap = "5px";
298
+ groupDiv.style.borderRadius = "4px";
299
+ const chunk = elements.slice(i, i + 3);
300
+ chunk.forEach((el) => groupDiv.appendChild(el));
301
+ groups.push(groupDiv);
302
+ }
303
+ return groups;
304
+ });
305
+ });
306
+ optDefaultRenderBtn.addEventListener("click", () => {
307
+ mgr.setRenderItem();
308
+ mgr.setRenderList();
309
+ });
310
+ resizer.addEventListener("onLeft", () => syncUrl());
311
+ resizer.addEventListener("onCenter", () => syncUrl());
312
+ destroyBtn.addEventListener("click", () => {
313
+ mgr.destroy();
314
+ section.remove();
315
+ });
316
+ return mgr;
317
+ };
318
+ const initBtn = document.getElementById("init-btn");
319
+ if (initBtn) {
320
+ initBtn.addEventListener("click", () => init());
321
+ }
322
+ const loadFromUrl = () => {
323
+ const instancesArea = document.getElementById("instances-area");
324
+ if (!instancesArea)
325
+ return;
326
+ instancesArea.innerHTML = "";
327
+ instanceCounter = 0;
328
+ setNextId(getSafeFreeOffset());
329
+ const urlParams = new URLSearchParams(window.location.search);
330
+ const allIds = urlStateConfig.getAllIds(urlParams);
331
+ if (allIds.length === 0) {
332
+ init([
333
+ { id: 1, label: "Initial 1" },
334
+ { id: 2, label: "Initial 2" },
335
+ ], {});
336
+ }
337
+ else {
338
+ allIds.forEach((id) => {
339
+ const state = urlStateConfig.fromUrl(urlParams, id);
340
+ if (state.selected) {
341
+ state.selected.forEach((item) => {
342
+ const numId = typeof item.id === "number" ? item.id : parseInt(String(item.id), 10);
343
+ if (!isNaN(numId) && numId >= getNextId())
344
+ setNextId(numId + 1);
345
+ });
346
+ }
347
+ init(state.selected || [], state);
348
+ });
349
+ }
350
+ updateUrlDisplay();
351
+ };
352
+ window.addEventListener("popstate", loadFromUrl);
353
+ loadFromUrl();