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,345 @@
1
+ import "../CenterAndHeightResizer.js";
2
+ import { OptionsSection } from "./options-section.js";
3
+ import { urlStateConfig, getNextId, setNextId } from "./urlManager.js";
4
+ import { getSafeFreeOffset } from "../composite-select/namesSource.js";
5
+ const css2 = await fetch("./OptionsSectionManager.css").then((r) => r.text());
6
+ OptionsSection.cssText = css2;
7
+ const reloadLink = document.getElementById("reload-link");
8
+ if (reloadLink) {
9
+ reloadLink.href = window.location.pathname;
10
+ }
11
+ let instanceCounter = 0;
12
+ const updateUrlDisplay = (url = window.location.href) => {
13
+ const el = document.getElementById("url-display");
14
+ if (el)
15
+ el.textContent = url;
16
+ };
17
+ const init = (initialOptions = [], states = {}) => {
18
+ instanceCounter++;
19
+ const id = instanceCounter;
20
+ const resizerLeft = states.left || "50px";
21
+ const resizerCenter = states.center || "350px";
22
+ const resizerHeight = states.height || "";
23
+ const section = document.createElement("div");
24
+ section.className = "demo-section";
25
+ section.innerHTML = `
26
+ <h2>Instance #${id} (No CSS Request)</h2>
27
+ <button class="gcp-css white destroy-btn" data-role="destroy">Destroy</button>
28
+
29
+ <div class="resizer-container">
30
+ <center-and-height-resizer data-role="resizer" left="${resizerLeft}" center="${resizerCenter}" ${resizerHeight ? `height="${resizerHeight}"` : ""}>
31
+ <options-section
32
+ label="${states.label || "Search via attrs..."}"
33
+ value="${states.value || ""}"
34
+ max-height="${states.maxHeight || ""}"
35
+ ${states.loading ? "loading" : ""}
36
+ ${states.disabled ? "disabled" : ""}
37
+ ${states.setShowFooter !== false ? "show-footer" : ""}
38
+ ${states.setShowFilter !== false ? "show-filter" : ""}
39
+ ></options-section>
40
+ </center-and-height-resizer>
41
+ </div>
42
+
43
+ <div class="controls gcp-css" style="margin-bottom: 8px;">
44
+ <div class="controls-label">OptionsSectionManager (No CSS Request)</div>
45
+
46
+ <div style="display: flex; gap: 10px; flex-wrap: wrap;">
47
+ <div class="gcp-css checkbox-wrapper">
48
+ <div class="checkbox-row">
49
+ <input type="checkbox" id="disabled-opt-${id}" data-role="disabled-opt" ${states.disabled ? "checked" : ""}>
50
+ <div class="content-cell"><label for="disabled-opt-${id}">Disabled</label></div>
51
+ </div>
52
+ </div>
53
+
54
+ <div class="gcp-css checkbox-wrapper">
55
+ <div class="checkbox-row">
56
+ <input type="checkbox" id="loading-opt-${id}" data-role="loading-opt" ${states.loading ? "checked" : ""}>
57
+ <div class="content-cell"><label for="loading-opt-${id}">Loading</label></div>
58
+ </div>
59
+ </div>
60
+
61
+ <div class="gcp-css checkbox-wrapper">
62
+ <div class="checkbox-row">
63
+ <input type="checkbox" id="footer-opt-${id}" data-role="footer-opt" ${states.setShowFooter !== false ? "checked" : ""}>
64
+ <div class="content-cell"><label for="footer-opt-${id}">Show Footer</label></div>
65
+ </div>
66
+ </div>
67
+
68
+ <div class="gcp-css checkbox-wrapper">
69
+ <div class="checkbox-row">
70
+ <input type="checkbox" id="filter-opt-${id}" data-role="filter-opt" ${states.setShowFilter !== false ? "checked" : ""}>
71
+ <div class="content-cell"><label for="filter-opt-${id}">Show Filter</label></div>
72
+ </div>
73
+ </div>
74
+
75
+ <div class="gcp-css checkbox-wrapper">
76
+ <div class="checkbox-row">
77
+ <input type="checkbox" id="empty-list-${id}" data-role="empty-list-cb" ${states.emptyList ? "checked" : ""}>
78
+ <div class="content-cell"><label for="empty-list-${id}">Empty list (sim search)</label></div>
79
+ </div>
80
+ </div>
81
+ </div>
82
+
83
+ <div style="display: flex; gap: 10px; flex-wrap: wrap; margin-top: 10px;">
84
+ <div class="gcp-css input-wrapper">
85
+ <input type="text" id="label-input-opt-${id}" data-role="label-input-opt" placeholder="&nbsp;" value="${states.label || ""}">
86
+ <label for="label-input-opt-${id}">Label</label>
87
+ </div>
88
+ <div class="gcp-css input-wrapper">
89
+ <input type="text" id="value-input-opt-${id}" data-role="value-input-opt" placeholder="&nbsp;" value="${states.value || ""}">
90
+ <label for="value-input-opt-${id}">Value</label>
91
+ </div>
92
+ <button class="gcp-css white" data-role="focus-btn">Focus</button>
93
+ <button class="gcp-css white" data-role="add-btn">Add Random</button>
94
+ <button class="gcp-css white" data-role="clear-btn">Clear All</button>
95
+ </div>
96
+
97
+ <div style="display: flex; gap: 5px; align-items: center; width: 100%; margin-top: 10px; flex-wrap: wrap;">
98
+ <span style="min-width: 120px;">📏 <strong>Max Height</strong>:</span>
99
+ <div style="display: flex; gap: 2px;">
100
+ <button class="gcp-css white" data-role="mh-down" style="padding: 0 8px; min-width: auto;">▼</button>
101
+ <div class="gcp-css input-wrapper" style="max-width: 100px; margin-bottom: 0;">
102
+ <input type="text" id="mh-input-${id}" data-role="mh-input" placeholder="&nbsp;" value="${states.maxHeight || ""}">
103
+ <label for="mh-input-${id}">Height</label>
104
+ </div>
105
+ <button class="gcp-css white" data-role="mh-up" style="padding: 0 8px; min-width: auto;">▲</button>
106
+ </div>
107
+ <button class="gcp-css white" data-role="mh-set-btn">Set</button>
108
+ <button class="gcp-css white" data-role="mh-preset" data-value="200px">200px</button>
109
+ <button class="gcp-css white" data-role="mh-preset" data-value="300px">300px</button>
110
+ <button class="gcp-css white" data-role="mh-preset" data-value="400px">400px</button>
111
+ <button class="gcp-css white" data-role="mh-preset" data-value="600px">600px</button>
112
+ <button class="gcp-css white" data-role="mh-preset" data-value="">Reset</button>
113
+ </div>
114
+
115
+ <div style="display: flex; gap: 5px; align-items: center; width: 100%; margin-top: 10px; flex-wrap: wrap;">
116
+ <span style="min-width: 120px;">🎨 <strong>Render</strong>:</span>
117
+ <button class="gcp-css white" data-role="opt-render-btn">Set Custom Render</button>
118
+ <button class="gcp-css white" data-role="opt-string-render-btn">Set String Render</button>
119
+ <button class="gcp-css white" data-role="opt-default-render-btn">Set Default Render</button>
120
+ <button class="gcp-css white" data-role="opt-empty-btn">Set Custom Empty</button>
121
+ <button class="gcp-css white" data-role="opt-default-empty-btn">Set Default Empty</button>
122
+ </div>
123
+
124
+ <div style="width: 100%; margin-top: 10px;">
125
+ (onInputChange triggers: <span data-role="onchange-count" style="font-weight: bold;">0</span>,
126
+ onItemPick: <span data-role="onpick-count" style="font-weight: bold;">0</span>,
127
+ onOk: <span data-role="onok-count" style="font-weight: bold;">0</span>,
128
+ onCancel: <span data-role="oncancel-count" style="font-weight: bold;">0</span>,
129
+ onHighlightChange: <span data-role="onhighlight-count" style="font-weight: bold;">0</span>)
130
+ </div>
131
+ </div>
132
+
133
+ <pre data-role="dump" style="background:#f8f8f8;padding:10px;border:1px solid #eee;border-radius:4px;font-size:12px;margin:0;overflow:auto;"></pre>
134
+ `;
135
+ document.getElementById("instances-area").appendChild(section);
136
+ const wc = section.querySelector("options-section");
137
+ const resizer = section.querySelector('[data-role="resizer"]');
138
+ const destroyBtn = section.querySelector('[data-role="destroy"]');
139
+ const dump = section.querySelector('[data-role="dump"]');
140
+ const disabledOptCb = section.querySelector('[data-role="disabled-opt"]');
141
+ const loadingOptCb = section.querySelector('[data-role="loading-opt"]');
142
+ const footerOptCb = section.querySelector('[data-role="footer-opt"]');
143
+ const filterOptCb = section.querySelector('[data-role="filter-opt"]');
144
+ const emptyListCb = section.querySelector('[data-role="empty-list-cb"]');
145
+ const labelInputOpt = section.querySelector('[data-role="label-input-opt"]');
146
+ const valueInputOpt = section.querySelector('[data-role="value-input-opt"]');
147
+ const focusBtn = section.querySelector('[data-role="focus-btn"]');
148
+ const addBtn = section.querySelector('[data-role="add-btn"]');
149
+ const clearBtn = section.querySelector('[data-role="clear-btn"]');
150
+ const mhInput = section.querySelector('[data-role="mh-input"]');
151
+ const mhSetBtn = section.querySelector('[data-role="mh-set-btn"]');
152
+ const mhUp = section.querySelector('[data-role="mh-up"]');
153
+ const mhDown = section.querySelector('[data-role="mh-down"]');
154
+ const optRenderBtn = section.querySelector('[data-role="opt-render-btn"]');
155
+ const optStringRenderBtn = section.querySelector('[data-role="opt-string-render-btn"]');
156
+ const optDefaultRenderBtn = section.querySelector('[data-role="opt-default-render-btn"]');
157
+ const optEmptyBtn = section.querySelector('[data-role="opt-empty-btn"]');
158
+ const optDefaultEmptyBtn = section.querySelector('[data-role="opt-default-empty-btn"]');
159
+ const inc = (role) => {
160
+ const el = section.querySelector(`[data-role="${role}"]`);
161
+ if (el) {
162
+ el.textContent = String(parseInt(el.textContent || "0", 10) + 1);
163
+ }
164
+ };
165
+ const updateDump = (options) => {
166
+ dump.textContent = JSON.stringify(options.filter((o) => o.selected), null, 2);
167
+ };
168
+ const syncUrl = () => {
169
+ const url = new URL(window.location.href);
170
+ urlStateConfig.toUrl(url, id, {
171
+ options: wc.options,
172
+ left: resizer.getAttribute("left") || "50px",
173
+ center: resizer.getAttribute("center") || "350px",
174
+ height: resizer.getAttribute("height") || "",
175
+ disabled: disabledOptCb.checked,
176
+ loading: loadingOptCb.checked,
177
+ setShowFooter: footerOptCb.checked,
178
+ setShowFilter: filterOptCb.checked,
179
+ emptyList: emptyListCb.checked,
180
+ label: labelInputOpt.value || "",
181
+ value: valueInputOpt.value || "",
182
+ maxHeight: mhInput.value || "",
183
+ highlight: String(wc.highlight || ""),
184
+ });
185
+ window.history.replaceState({}, "", url);
186
+ updateUrlDisplay(url.toString());
187
+ };
188
+ wc.options = initialOptions;
189
+ const mgr = wc.getManager();
190
+ mgr.getSubscriber().bind("onInputChange", (e) => {
191
+ inc("onchange-count");
192
+ valueInputOpt.value = e.target.value;
193
+ syncUrl();
194
+ });
195
+ mgr.getSubscriber().bind("onItemPick", (item) => {
196
+ inc("onpick-count");
197
+ const nextOptions = wc.options.map((o) => {
198
+ if (String(o.id) === String(item.id))
199
+ return { ...o, selected: !o.selected };
200
+ return o;
201
+ });
202
+ wc.options = nextOptions;
203
+ updateDump(nextOptions);
204
+ syncUrl();
205
+ });
206
+ mgr.getSubscriber().bind("onCancel", () => inc("oncancel-count"));
207
+ mgr.getSubscriber().bind("onOk", () => inc("onok-count"));
208
+ mgr.getSubscriber().bind("onHighlightChange", (id) => {
209
+ inc("onhighlight-count");
210
+ syncUrl();
211
+ });
212
+ if (states.highlight) {
213
+ mgr.highlightAndScrollToElementOnTheList(states.highlight);
214
+ }
215
+ updateDump(wc.options);
216
+ disabledOptCb.addEventListener("change", () => {
217
+ wc.setDisabled(disabledOptCb.checked);
218
+ syncUrl();
219
+ });
220
+ loadingOptCb.addEventListener("change", () => {
221
+ wc.setLoading(loadingOptCb.checked);
222
+ syncUrl();
223
+ });
224
+ footerOptCb.addEventListener("change", () => {
225
+ wc.setShowFooter(footerOptCb.checked);
226
+ syncUrl();
227
+ });
228
+ filterOptCb.addEventListener("change", () => {
229
+ wc.setShowFilter(filterOptCb.checked);
230
+ syncUrl();
231
+ });
232
+ emptyListCb.addEventListener("change", () => {
233
+ wc.setValue(wc.value); // Trigger re-search
234
+ syncUrl();
235
+ });
236
+ labelInputOpt.addEventListener("input", () => {
237
+ wc.setLabel(labelInputOpt.value);
238
+ syncUrl();
239
+ });
240
+ valueInputOpt.addEventListener("input", () => {
241
+ wc.setValue(valueInputOpt.value);
242
+ syncUrl();
243
+ });
244
+ focusBtn.addEventListener("click", () => wc.setFocus());
245
+ addBtn.addEventListener("click", () => {
246
+ const id = getNextId();
247
+ setNextId(id + 1);
248
+ const next = [...wc.options, { id, label: `NoCSS Option ${id}` }];
249
+ wc.options = next;
250
+ syncUrl();
251
+ });
252
+ clearBtn.addEventListener("click", () => {
253
+ wc.options = [];
254
+ syncUrl();
255
+ });
256
+ const setMH = (val) => {
257
+ mhInput.value = val;
258
+ wc.maxHeight = val;
259
+ syncUrl();
260
+ };
261
+ mhSetBtn.addEventListener("click", () => setMH(mhInput.value));
262
+ mhUp.addEventListener("click", () => {
263
+ const val = parseInt(mhInput.value) || 200;
264
+ setMH(val + 10 + "px");
265
+ });
266
+ mhDown.addEventListener("click", () => {
267
+ const val = parseInt(mhInput.value) || 200;
268
+ setMH(Math.max(0, val - 10) + "px");
269
+ });
270
+ section.querySelectorAll('[data-role="mh-preset"]').forEach((btn) => {
271
+ btn.addEventListener("click", () => setMH(btn.dataset.value || ""));
272
+ });
273
+ optRenderBtn.addEventListener("click", () => {
274
+ wc.setRenderItem((item) => {
275
+ const el = document.createElement("div");
276
+ el.className = "element";
277
+ el.dataset.id = String(item.id);
278
+ el.style.padding = "8px";
279
+ el.style.borderLeft = item.selected ? "4px solid orange" : "4px solid transparent";
280
+ el.innerHTML = `<strong>NOCSS: ${item.label}</strong> ${item.selected ? "✅" : ""}`;
281
+ return el;
282
+ });
283
+ });
284
+ optStringRenderBtn.addEventListener("click", () => {
285
+ wc.setRenderItem((item) => `<div class="element" data-id="${item.id}" style="color: orange;">STRING NOCSS: ${item.label}</div>`);
286
+ });
287
+ optDefaultRenderBtn.addEventListener("click", () => {
288
+ wc.setRenderItem();
289
+ });
290
+ optEmptyBtn.addEventListener("click", () => {
291
+ wc.setRenderEmpty(() => `<div style="color: orange; padding: 20px;">NOCSS: NOTHING FOUND!</div>`);
292
+ });
293
+ optDefaultEmptyBtn.addEventListener("click", () => {
294
+ wc.setRenderEmpty();
295
+ });
296
+ resizer.addEventListener("onLeft", () => syncUrl());
297
+ resizer.addEventListener("onCenter", () => syncUrl());
298
+ resizer.addEventListener("onHeight", () => syncUrl());
299
+ destroyBtn.addEventListener("click", () => {
300
+ wc.getManager()?.destroy();
301
+ section.remove();
302
+ });
303
+ return wc;
304
+ };
305
+ const initBtn = document.getElementById("init-btn");
306
+ if (initBtn) {
307
+ initBtn.addEventListener("click", () => {
308
+ init([
309
+ { id: 401, label: "NoCSS Item 1" },
310
+ { id: 402, label: "NoCSS Item 2", selected: true },
311
+ ]);
312
+ });
313
+ }
314
+ const loadFromUrl = () => {
315
+ const instancesArea = document.getElementById("instances-area");
316
+ if (!instancesArea)
317
+ return;
318
+ instancesArea.innerHTML = "";
319
+ instanceCounter = 0;
320
+ setNextId(getSafeFreeOffset());
321
+ const urlParams = new URLSearchParams(window.location.search);
322
+ const allIds = urlStateConfig.getAllIds(urlParams);
323
+ if (allIds.length === 0) {
324
+ init([
325
+ { id: 1, label: "Initial NoCSS 1" },
326
+ { id: 2, label: "Initial NoCSS 2" },
327
+ ], {});
328
+ }
329
+ else {
330
+ allIds.forEach((id) => {
331
+ const state = urlStateConfig.fromUrl(urlParams, id);
332
+ if (state.options) {
333
+ state.options.forEach((o) => {
334
+ const numId = typeof o.id === "number" ? o.id : parseInt(String(o.id), 10);
335
+ if (!isNaN(numId) && numId >= getNextId())
336
+ setNextId(numId + 1);
337
+ });
338
+ }
339
+ init(state.options || [], state);
340
+ });
341
+ }
342
+ updateUrlDisplay();
343
+ };
344
+ window.addEventListener("popstate", loadFromUrl);
345
+ loadFromUrl();