@popovandrii/ui-elements 0.1.2 → 0.2.0

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/README.md CHANGED
@@ -1,33 +1,143 @@
1
- # UI elements
2
- Version 0.0.31
1
+ # @popovandrii/ui-elements
3
2
 
4
- TypeScript-based NPM plugin.
5
- The plugin includes interface elements with specific properties.
6
- UI elements that contain a large share of JavaScript.
3
+ Lightweight TypeScript UI component library — **SpinBox**, **Select** (with search),
4
+ **Switch**, **ButtonGroup** (radio), **Button**.
7
5
 
8
- ## add JS
9
- ```js
10
- import { SpinBox, Switch, Select, ButtonGroup } from '@popovandrii/ui-elements';
6
+ - Zero runtime dependencies
7
+ - Vanilla TypeScript — works with any framework or none
8
+ - Accessible (ARIA / A11Y) with full keyboard support
9
+ - Themeable via CSS custom properties — 4 built-in themes
10
+ - SPA-friendly lifecycle: idempotent `scan()`, optional root scoping and `MutationObserver` auto re-scan, teardown-only `destroy()`
11
+ - Custom DOM events + programmatic `setValue`
12
+ - Ripple and flash animations (opt-out per element)
13
+ - Ships as ES, CJS and UMD bundles with type declarations
14
+
15
+ ## Components
16
+
17
+ | Component | Base class | Event | Docs |
18
+ |---|---|---|---|
19
+ | SpinBox | `UIsp` | `ui-spinbox-change` | [SpinBox](docs/spinBox/README.md) |
20
+ | Select | `UIselect` | `ui-select-change` | [Select](docs/select/README.md) |
21
+ | Switch | `UIsw` | `ui-switch-change` | [Switch](docs/switch/README.md) |
22
+ | ButtonGroup | `UIbg` | `ui-button-group-change` | [ButtonGroup (radio)](docs/button-group-radio/README.md) |
23
+ | Button | `UIb` | `ui-button-change` | [Button](docs/button/README.md) |
24
+
25
+ ## Installation
26
+
27
+ ```sh
28
+ npm install @popovandrii/ui-elements@latest
11
29
  ```
12
- Connection with `standard styles` from the package by element name.
30
+
31
+ ## Quick start
32
+
33
+ Import the components you need and the base stylesheet:
34
+
13
35
  ```js
14
- new SpinBox();
15
- new Switch();
36
+ import { SpinBox, Select, Switch, ButtonGroup, Button } from "@popovandrii/ui-elements";
37
+ import "@popovandrii/ui-elements/style.css";
38
+
39
+ // Each constructor scans the DOM for its base class and wires up matching elements.
40
+ new SpinBox();
16
41
  new Select();
42
+ new Switch();
43
+ new ButtonGroup();
44
+ new Button();
45
+ ```
46
+
47
+ Add the matching markup (see each component's docs for full examples):
48
+
49
+ ```html
50
+ <div class="UIsp" data-step="0" data-min="0" data-max="10" role="spinbutton" tabindex="0" aria-label="Numeric input">
51
+ <button class="UIsp__btn" type="button" aria-label="Decrease value">−</button>
52
+ <input class="UIsp__input" id="qty" type="text" value="0" inputmode="decimal">
53
+ <button class="UIsp__btn" type="button" aria-label="Increase value">+</button>
54
+ </div>
55
+ ```
56
+
57
+ ### Debug mode
58
+
59
+ Pass `true` as the second constructor argument to log selector/value warnings:
60
+
61
+ ```js
17
62
  new ButtonGroup({}, true); // debug mode
18
63
  ```
19
- Connection with `custom styles` from a package by element name.
64
+
65
+ ## Themes
66
+
67
+ Theming has two layers:
68
+
69
+ - **`style.css`** — required. Contains the component structure **and the default `light`
70
+ palette at `:root`**, so the components render correctly with just this file and no
71
+ `data-theme` set.
72
+ - **`theme-*.css`** — optional. Each provides one palette scoped under a higher-specificity
73
+ `html[data-theme="..."]` selector, so it overrides the `:root` default whenever the matching
74
+ `data-theme` is set — regardless of CSS import order.
75
+
76
+ Zero-config (light theme, no `data-theme` needed):
77
+
78
+ ```js
79
+ import "@popovandrii/ui-elements/style.css"; // that's it — light theme works
80
+ ```
81
+
82
+ Add theme files only when you need other palettes or runtime switching:
83
+
20
84
  ```js
21
- new SpinBox({
22
- main: "You-costom-class",
23
- btn: "You-costom-class__btn",
24
- input: "You-costom-class__input",
25
- disabledBtn: "You-costom-class__disabled",
26
- });
85
+ import "@popovandrii/ui-elements/style.css"; // required base (also = light default)
86
+
87
+ // import "@popovandrii/ui-elements/theme-dark.css";
88
+ // import "@popovandrii/ui-elements/theme-light-neon.css";
89
+ // import "@popovandrii/ui-elements/theme-dark-neon.css";
90
+ // import "@popovandrii/ui-elements/theme-light.css"; // only to switch *back* to light
91
+ ```
27
92
 
28
- new Switch({
29
- main: "You-costom-class",
30
- label: "You-costom-class-label"
93
+ ### Activate a theme with `data-theme`
94
+
95
+ `light` is the implicit default. To use another theme, load its file and set `data-theme` on a
96
+ parent — usually `<html>`:
97
+
98
+ ```html
99
+ <html data-theme="dark">
100
+ ```
101
+
102
+ Because themes are `html[data-theme="..."]` (higher specificity than `:root`), the explicit
103
+ theme always wins over the default; remove the attribute to fall back to `light`.
104
+
105
+ The `data-theme` values are: `light`, `dark`, `light-neon`, `dark-neon`.
106
+
107
+ ### Switching themes at runtime
108
+
109
+ Because each theme is scoped by its selector, you can import several and switch between them
110
+ by changing a single attribute:
111
+
112
+ ```js
113
+ document.documentElement.dataset.theme = "dark"; // light | dark | light-neon | dark-neon
114
+ ```
115
+
116
+ Themes are driven by CSS custom properties, so you can also override individual variables
117
+ in your own stylesheet instead of shipping a full theme.
118
+
119
+ ### Shared CSS modifier classes
120
+
121
+ Most components share a common set of modifier classes (see each component's docs for the
122
+ exact list it supports):
123
+
124
+ - **Color:** `primary`, `danger`, `info`, `success`, `warning`
125
+ - **Size:** `sm`, `lg` (Switch also has `xsm`)
126
+ - **Border radius:** `r-0`, `r-1` / `r-round`
127
+ - **Gap:** `g-0`, `g-1`
128
+ - **Layout:** `expand`, `between`, `around`, `vertical`, `border`
129
+
130
+ ## Custom class names
131
+
132
+ Every component accepts a partial selector map to match your own markup classes. Defaults
133
+ shown below:
134
+
135
+ ```js
136
+ new SpinBox({
137
+ main: "UIsp",
138
+ btn: "UIsp__btn",
139
+ input: "UIsp__input",
140
+ disabledBtn: "disabled",
31
141
  });
32
142
 
33
143
  new Select({
@@ -38,135 +148,249 @@ new Select({
38
148
  optionsList: "UIselect-options",
39
149
  search: "UIselect-options__search",
40
150
  items: "UIselect-options__items",
41
- excludedItems: ["divider", "test"], // class="costom"
151
+ flash: "UIselect--flash",
152
+ excludedItems: ["divider"], // <li> classes/ids excluded from selection
42
153
  });
43
154
 
44
- new ButtonGroup({
45
- main: "UIbg",
46
- btn: "UIbg-btn",
47
- input: "UIbg-input"
48
- });
155
+ new Switch({ main: "UIsw", label: "UIsw-label" });
156
+
157
+ new ButtonGroup({ main: "UIbg", btn: "UIbg-btn", input: "UIbg-input" });
158
+
159
+ new Button({ main: "UIb" });
49
160
  ```
50
161
 
51
- ## Example for NodeJS + Express (index.umd.js + style.css)
52
- ```sh
53
- npm install @popovandrii/ui-elements@latest
162
+ ## Events
163
+
164
+ Each component dispatches a bubbling `CustomEvent` whose `detail` is `{ id, value }`:
165
+
166
+ ```js
167
+ const el = document.getElementById("mySpinbox");
168
+ el.addEventListener("ui-spinbox-change", (e) => {
169
+ console.log(e.detail); // { id: "mySpinbox", value: "3.1415" }
170
+ });
54
171
  ```
172
+
173
+ | Component | Event name | `detail.value` |
174
+ |---|---|---|
175
+ | SpinBox | `ui-spinbox-change` | current numeric value as string |
176
+ | Select | `ui-select-change` | selected `data-value` |
177
+ | Switch | `ui-switch-change` | `"true"` / `"false"` |
178
+ | ButtonGroup | `ui-button-group-change` | selected `input[value]` |
179
+ | Button | `ui-button-change` | element's `data-value` |
180
+
181
+ ### TypeScript typing
182
+
183
+ ```ts
184
+ type UIChangeDetail = { id: string; value: string };
185
+
186
+ document.addEventListener("ui-select-change", (e) => {
187
+ const { id, value } = (e as CustomEvent<UIChangeDetail>).detail;
188
+ });
189
+ ```
190
+
191
+ ## Programmatic `setValue`
192
+
55
193
  ```js
56
- // app.js
57
- app.use(
58
- '/ui-elements/css',
59
- express.static(path.join(__dirname, 'node_modules/bootstrap/dist/css'))
60
- );
194
+ const sp = new SpinBox();
195
+ sp.setValue(document.getElementById("mySpinbox"), 3.1415);
196
+
197
+ const sl = new Select();
198
+ sl.setValue(document.getElementById("mySelect"), "name"); // matches data-value
199
+
200
+ const sw = new Switch();
201
+ sw.setValue("idSwitchElement", true); // (inputId, boolean)
202
+
203
+ const bg = new ButtonGroup();
204
+ bg.setValue(document.getElementById("myGroup"), "btncheck2"); // matches input[value]
205
+
206
+ const btn = new Button();
207
+ btn.setValue(document.getElementById("myButton"), "/api/users/42", "Edit profile"); // value + optional label
208
+ ```
209
+
210
+ ## Lifecycle (SPA-friendly)
211
+
212
+ Each instance attaches its listeners through a single `AbortController` created once in the
213
+ constructor. The three building blocks:
214
+
215
+ - **`scan()`** — binds every not-yet-bound element. It is **idempotent**: each control gets a
216
+ per-type marker (`data-uib-bound`, `data-uisel-bound`, `data-uisp-bound`, `data-uisw-bound`,
217
+ `data-uibg-bound`) and is skipped on later passes. Call it after rendering new markup — no
218
+ double-binding.
219
+ - **`destroy()`** — teardown only: aborts all listeners, disconnects the observer, clears the
220
+ markers and recreates the `AbortController` so the **same instance can `scan()` again**. It
221
+ does **not** disable elements (behavior change — use `setDisabled()` on Button for that).
222
+ - Markup-disabled elements (`data-disabled`, or `disabled` on the inner input) still render
223
+ disabled on every `scan()`.
224
+
225
+ ```js
226
+ const sl = new Select();
227
+ // ...after rendering new selects into the view:
228
+ sl.scan(); // additive — existing listeners untouched, new ones bound
229
+ // ...on final teardown:
230
+ sl.destroy(); // listeners removed; elements left as-is
231
+ ```
232
+
233
+ ### Scope to a root
234
+
235
+ Pass a third `options` argument to bind only inside a subtree. Useful when several managers of
236
+ the same type live on one page (e.g. a parent view plus a child component):
237
+
238
+ ```js
239
+ const widget = document.getElementById("cart-widget");
240
+ const buttons = new Button({}, false, { root: widget }); // ignores .UIb outside the widget
241
+ ```
242
+
243
+ ### Auto re-scan with `observe`
244
+
245
+ Add `observe: true` to attach a debounced `MutationObserver` on the root; new elements are
246
+ bound automatically, so you can drop manual `scan()` calls:
247
+
248
+ ```js
249
+ new Button({}, false, { root: appEl, observe: true });
250
+ ```
251
+
252
+ ### Singleton factory
253
+
254
+ If you'd rather not hold your own single instance per type, use the lazy factories:
255
+
256
+ ```js
257
+ import {
258
+ getButtonManager,
259
+ getSelectManager,
260
+ getSpinBoxManager,
261
+ getSwitchManager,
262
+ getButtonGroupManager,
263
+ resetManagers,
264
+ } from "@popovandrii/ui-elements";
265
+
266
+ getButtonManager({}, false, { observe: true }).scan(); // first call configures, then reused
267
+ resetManagers(); // drop all cached singletons
268
+ ```
269
+
270
+ The first call configures the manager (its arguments match the constructor); later calls
271
+ return the same instance.
272
+
273
+ ## Animations
274
+
275
+ - **Ripple** — radial wave on click
276
+ - **Flash** — `box-shadow` glow when `setValue` is called
277
+
278
+ Opt out per element or for any ancestor container:
279
+
280
+ ```html
281
+ <div class="UIsp ui-no-ripple ui-no-flash">...</div>
282
+
283
+ <!-- disable globally -->
284
+ <body class="ui-no-ripple ui-no-flash">
285
+ ```
286
+
287
+ ## Usage without a bundler (NodeJS + Express, UMD)
288
+
289
+ Serve the package's `dist` folder as static assets:
290
+
291
+ ```js
292
+ // app.js
61
293
  app.use(
62
- '/ui-elements/js',
63
- express.static(path.join(__dirname, 'node_modules/@popovandrii/ui-elements/dist'))
294
+ "/ui-elements/js",
295
+ express.static(path.join(__dirname, "node_modules/@popovandrii/ui-elements/dist"))
64
296
  );
65
297
  ```
298
+
66
299
  ```html
67
- <!-- you template ...ejs -->
68
- </head>
300
+ <head>
301
+ <link rel="stylesheet" href="/ui-elements/js/style.css" />
302
+ <link rel="stylesheet" href="/ui-elements/js/theme-dark.css" />
303
+ <!-- <link rel="stylesheet" href="/ui-elements/js/theme-light.css" /> -->
304
+ <!-- <link rel="stylesheet" href="/ui-elements/js/theme-light-neon.css" /> -->
305
+ <!-- <link rel="stylesheet" href="/ui-elements/js/theme-dark-neon.css" /> -->
69
306
  <script src="/ui-elements/js/index.umd.js"></script>
70
- <link rel='stylesheet' href="/ui-elements/js/style.css" />
71
- <link rel='stylesheet' href="/ui-elements/js/theme-dark.css" />
72
- <!-- <link rel='stylesheet' href="/ui-elements/js/theme-light.css" /> -->
73
- <!-- <link rel='stylesheet' href="/ui-elements/js/theme-neon-dark.css" /> -->
74
- <!-- <link rel='stylesheet' href="/ui-elements/js/theme-neon-light.css" /> -->
75
307
  </head>
76
308
 
77
- <!-- usually connected with a separate template -->
78
- <div class="UIsp" data-step="<%= step %>" data-min="<%= min %>" data-max="<%= max %>" role="spinbutton" tabindex="0"
79
- aria-label="Numeric input">
80
- <div class="UIsp-label"><%= label %></div>
81
- <button class="UIsp__btn" type="button" aria-label="Decrease value">svg icon</button>
82
- <input class="UIsp__input" id="<%= id %>" type="text" value="<%= min %>" aria-hidden="true" inputmode="decimal">
83
- <button class="UIsp__btn" type="button" aria-label="Increase value">svg icon</button>
84
- </div>
85
-
86
309
  <script>
87
- // the constructor can contain an object with your custom style
310
+ // UMD exposes a global `UiElements`
88
311
  new UiElements.SpinBox();
89
312
  new UiElements.Switch();
90
- new UiElements.Select();;
313
+ new UiElements.Select();
91
314
  </script>
92
315
  ```
93
316
 
94
- ## add Style
95
- ```js
96
- import '@popovandrii/ui-elements/style.css';
97
- // 4 design styles available.
98
- // theme-dark.css theme-neon-dark.css theme-neon-light.css
99
- import '@popovandrii/ui-elements/theme-light.css';
100
- ```
101
-
102
- Abbreviation of the base (main) class of each element:<br>
103
- `UIsp`, UIdd, UIsw ... (`UI + Spin-Box`, UI + Drop-Down, UI + Switch ...)<br>
104
- `<div class="UIsp">...</div>`
317
+ ## Documentation
105
318
 
106
- ### UI Elements
319
+ Each component has detailed docs covering markup, attributes, events, disabled states and
320
+ examples:
107
321
 
322
+ - [SpinBox](docs/spinBox/README.md) — numeric input with +/− buttons, min/max, decimal precision
323
+ - [Select](docs/select/README.md) — dropdown with optional search and keyboard navigation
324
+ - [Switch](docs/switch/README.md) — toggle based on `<input type="checkbox">`
325
+ - [ButtonGroup (radio)](docs/button-group-radio/README.md) — radio group styled as buttons
326
+ - [Button](docs/button/README.md) — styled button / link with event dispatch
108
327
 
109
- ### Button group UI
110
328
  <p align="center">
111
- <img src="https://gitlab.com/AndreyPopov/ui-elements/-/raw/main/docs/images/button-group-UI.png" alt="Switch Preview" width="700">
329
+ <img src="https://gitlab.com/AndreyPopov/ui-elements/-/raw/main/docs/images/button-group-UI.png" alt="ButtonGroup Preview" width="700">
112
330
  </p>
113
-
114
- #### [Button group README (radio)](/docs/button-group-radio/README.md)
115
-
116
- ### Button UI
117
331
  <p align="center">
118
- <img src="https://gitlab.com/AndreyPopov/ui-elements/-/raw/main/docs/images/button-UI.png" alt="Switch Preview" width="700">
332
+ <img src="https://gitlab.com/AndreyPopov/ui-elements/-/raw/main/docs/images/select-UI.png" alt="Select Preview" width="700">
119
333
  </p>
120
334
 
121
- #### [Button README (button)](/docs/button/README.md)
335
+ ## Development
122
336
 
123
- ### Switch UI
124
- <p align="center">
125
- <img src="https://gitlab.com/AndreyPopov/ui-elements/-/raw/main/docs/images/switch-UI.png" alt="Switch Preview" width="700">
126
- </p>
337
+ This project runs inside Docker (`node:24-alpine`); Node/npm are not required on the host.
127
338
 
128
- #### [Switch README (input)](/docs/switch/README.md)
339
+ ```sh
340
+ git clone git@gitlab.com:AndreyPopov/ui-elements.git && cd ui-elements
129
341
 
130
- ### SpinBox UI
131
- <p align="center">
132
- <img src="https://gitlab.com/AndreyPopov/ui-elements/-/raw/main/docs/images/spinBox-UI.png" alt="Switch Preview" width="700">
133
- </p>
342
+ docker compose up -d --build # start the dev container
343
+ docker compose exec vite-dev sh # shell into it
344
+ ```
134
345
 
135
- #### [SpinBox README (button -> input)](/docs/spinBox/README.md)
346
+ Inside the container:
136
347
 
137
- #### Select UI
348
+ ```sh
349
+ npm install
350
+ npm run dev # vite dev playground on port 5173
351
+ npm run build # build to ./dist (node build.js)
352
+ npm run test # vitest
353
+ npm run lint # eslint
354
+ npm run format # prettier
355
+ ```
138
356
 
139
- <p align="center">
140
- <img src="https://gitlab.com/AndreyPopov/ui-elements/-/raw/main/docs/images/select-UI.png" alt="Switch Preview" width="700">
141
- </p>
357
+ The `./playground` folder hosts the browser demo and unit tests.
142
358
 
143
- #### [Select README](/docs/select/README.md)
359
+ ### Publishing
144
360
 
145
- # Information for Developers
146
361
  ```sh
147
- git clone git@gitlab.com:AndreyPopov/ui-elements.git && cd ui-elements
362
+ npm install # refresh package-lock.json
363
+ npm login
364
+ npm publish --access public
365
+ npm info @popovandrii/ui-elements@latest
148
366
  ```
149
367
 
150
- ```sh
151
- docker compose up -d --build
152
- ```
368
+ ### Releasing
369
+
370
+ `dist/` is git-ignored, so always build before packing or publishing. Tags use the
371
+ `vX.Y.Z` scheme and point at the merge commit on `main`.
153
372
 
154
373
  ```sh
155
- docker compose exec vite-dev sh
374
+ # 1. Bump the version on dev (no auto-tag — we tag on main after the merge)
375
+ npm version 0.2.0 --no-git-tag-version
376
+ git commit -am "Version: 0.2.0"
377
+
378
+ # 2. Push dev and open a merge request dev -> main on GitLab, then merge it
379
+ git push origin dev
380
+
381
+ # 3. Tag the merged main (annotated) and push the tag
382
+ git fetch origin
383
+ git tag -a v0.2.0 origin/main -m "Release 0.2.0"
384
+ git push origin v0.2.0
385
+
386
+ # 4. Publish the build to npm (dist is git-ignored — build first)
387
+ npm run build
388
+ npm publish --access public
156
389
  ```
157
390
 
158
- ```sh
159
- $ npm install
160
- $ npm run build # Compile the project into the ./dist folder.
161
- $ npm run dev # Work on the project
162
- $ npm run test # Vtest
163
- $ npm run lint
164
- $ npm run format
165
- $ npm install # before publishing the package (generation of the package-lock.json file)
166
- $ npm login
167
- $ npm publish --access public
168
- $ npm info @popovandrii/ui-elements@0.0.x
169
- $ npm install @popovandrii/ui-elements@latest
170
- ```
171
-
172
- The `./playground` folder for viewing in a browser
391
+ On GitLab, create the release from **Deploy → Releases → New release**, pick the
392
+ `vX.Y.Z` tag and paste the changelog as the release notes.
393
+
394
+ ## License
395
+
396
+ [MIT](LICENSE) © Andrii Popov
package/dist/Button.d.ts CHANGED
@@ -1,19 +1,31 @@
1
1
  interface SelectorMap {
2
2
  main: string;
3
3
  }
4
+ interface InitOptions {
5
+ /** Limit scanning to this subtree instead of the whole document. */
6
+ root?: Document | HTMLElement;
7
+ /** Auto re-scan on DOM changes inside the root (debounced MutationObserver). */
8
+ observe?: boolean;
9
+ }
4
10
  export declare class Button {
5
- #private;
6
11
  private selectors;
7
12
  private buttons;
8
13
  private abortController;
9
14
  private dbug;
10
- constructor(selectors?: Partial<SelectorMap>, dbug?: boolean);
15
+ private root;
16
+ private observer;
17
+ private rescanTimer;
18
+ constructor(selectors?: Partial<SelectorMap>, dbug?: boolean, options?: InitOptions);
19
+ /** Watch the root for added/removed nodes and re-scan (debounced). */
20
+ private observe;
11
21
  setValue(el: HTMLElement, value: string, label?: string): void;
12
22
  destroy(): void;
13
23
  private disableEl;
14
24
  private enableEl;
15
25
  private isDisabled;
16
26
  setDisabled(el: HTMLElement, disabled: boolean): void;
27
+ /** Bind every not-yet-bound `.UIb`. Safe to call repeatedly (SPA re-render). */
28
+ scan(): void;
17
29
  private ripple;
18
30
  private customEvent;
19
31
  }
@@ -3,16 +3,28 @@ interface SelectorMap {
3
3
  btn: string;
4
4
  input: string;
5
5
  }
6
+ interface InitOptions {
7
+ /** Limit scanning to this subtree instead of the whole document. */
8
+ root?: Document | HTMLElement;
9
+ /** Auto re-scan on DOM changes inside the root (debounced MutationObserver). */
10
+ observe?: boolean;
11
+ }
6
12
  export declare class ButtonGroup {
7
13
  #private;
8
14
  private selectors;
9
15
  private main;
10
16
  private abortController;
11
17
  private dbug;
12
- constructor(selectors?: Partial<SelectorMap>, dbug?: boolean);
18
+ private root;
19
+ private observer;
20
+ private rescanTimer;
21
+ constructor(selectors?: Partial<SelectorMap>, dbug?: boolean, options?: InitOptions);
22
+ /** Watch the root for added/removed nodes and re-scan (debounced). */
23
+ private observe;
13
24
  destroy(): void;
14
- private disableEl;
15
25
  setValue(el: HTMLElement, value: string): void;
26
+ /** Bind every not-yet-bound `.UIbg`. Safe to call repeatedly (SPA re-render). */
27
+ scan(): void;
16
28
  private costomEvent;
17
29
  }
18
30
  export {};
package/dist/Select.d.ts CHANGED
@@ -9,14 +9,25 @@ interface SelectorMap {
9
9
  flash: string;
10
10
  excludedItems: Array<string>;
11
11
  }
12
+ interface InitOptions {
13
+ /** Limit scanning to this subtree instead of the whole document. */
14
+ root?: Document | HTMLElement;
15
+ /** Auto re-scan on DOM changes inside the root (debounced MutationObserver). */
16
+ observe?: boolean;
17
+ }
12
18
  export declare class Select {
13
19
  private selectors;
14
20
  private main;
15
21
  private itemArrowInitialized;
16
22
  private abortController;
17
23
  private dbug;
24
+ private root;
25
+ private observer;
26
+ private rescanTimer;
18
27
  private selectMap;
19
- constructor(selectors?: Partial<SelectorMap>, dbug?: boolean);
28
+ constructor(selectors?: Partial<SelectorMap>, dbug?: boolean, options?: InitOptions);
29
+ /** Watch the root for added/removed nodes and re-scan (debounced). */
30
+ private observe;
20
31
  private filterExcluded;
21
32
  private filterSearch;
22
33
  destroy(): void;
@@ -28,7 +39,8 @@ export declare class Select {
28
39
  * @returns
29
40
  */
30
41
  setValue(el: HTMLElement, value: string | number): void;
31
- private event;
42
+ /** Bind every not-yet-bound `.UIselect`. Safe to call repeatedly (SPA re-render). */
43
+ scan(): void;
32
44
  private itemArrow;
33
45
  private itemsPosition;
34
46
  private items;
package/dist/SpinBox.d.ts CHANGED
@@ -4,18 +4,31 @@ interface SelectorMap {
4
4
  input: string;
5
5
  disabledBtn: string;
6
6
  }
7
+ interface InitOptions {
8
+ /** Limit scanning to this subtree instead of the whole document. */
9
+ root?: Document | HTMLElement;
10
+ /** Auto re-scan on DOM changes inside the root (debounced MutationObserver). */
11
+ observe?: boolean;
12
+ }
7
13
  export declare class SpinBox {
8
14
  private selectors;
9
15
  private spinBoxes;
10
16
  private abortController;
11
17
  private dbug;
12
- constructor(selectors?: Partial<SelectorMap>, dbug?: boolean);
18
+ private root;
19
+ private observer;
20
+ private rescanTimer;
21
+ constructor(selectors?: Partial<SelectorMap>, dbug?: boolean, options?: InitOptions);
22
+ /** Watch the root for added/removed nodes and re-scan (debounced). */
23
+ private observe;
13
24
  private state;
14
25
  destroy(): void;
15
26
  private disableEl;
16
27
  setValue(el: HTMLElement, value: string | number): void;
17
28
  getValidDataNumber: (el: HTMLElement, attr: string) => number;
18
- private event;
29
+ /** Bind every not-yet-bound `.UIsp`. Safe to call repeatedly (SPA re-render). */
30
+ scan(): void;
31
+ private ripple;
19
32
  private costomEvent;
20
33
  }
21
34
  export {};
package/dist/Switch.d.ts CHANGED
@@ -2,21 +2,33 @@ interface SelectorMap {
2
2
  main: string;
3
3
  label: string;
4
4
  }
5
+ interface InitOptions {
6
+ /** Limit scanning to this subtree instead of the whole document. */
7
+ root?: Document | HTMLElement;
8
+ /** Auto re-scan on DOM changes inside the root (debounced MutationObserver). */
9
+ observe?: boolean;
10
+ }
5
11
  export declare class Switch {
6
12
  private selectors;
7
13
  private main;
8
14
  private abortController;
9
15
  private dbug;
10
- constructor(selectors?: Partial<SelectorMap>, dbug?: boolean);
16
+ private root;
17
+ private observer;
18
+ private rescanTimer;
19
+ constructor(selectors?: Partial<SelectorMap>, dbug?: boolean, options?: InitOptions);
20
+ /** Watch the root for added/removed nodes and re-scan (debounced). */
21
+ private observe;
11
22
  destroy(): void;
12
- private disableEl;
13
- private event;
23
+ /** Bind every not-yet-bound `.UIsw`. Safe to call repeatedly (SPA re-render). */
24
+ scan(): void;
14
25
  /**
15
26
  * Sets the state of a specific switch by its ID.
16
27
  * @param id ID of the internal input element
17
28
  * @param checked State (true/false)
18
29
  */
19
30
  setValue(id: string, value: boolean): void;
31
+ private ripple;
20
32
  private customEvent;
21
33
  }
22
34
  export {};