@ixfx/components 0.4.4 → 0.5.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.
Files changed (78) hide show
  1. package/bundle/index.d.ts +136 -8
  2. package/bundle/index.d.ts.map +1 -1
  3. package/bundle/index.js +569 -23
  4. package/bundle/index.js.map +1 -1
  5. package/bundle/style.css +1 -1
  6. package/dist/ac-text.d.ts +1 -1
  7. package/dist/{button-DxYee1ZH.js → button-CTE8crYn.js} +3 -1
  8. package/dist/button-CTE8crYn.js.map +1 -0
  9. package/dist/button.d.ts +1 -1
  10. package/dist/button.d.ts.map +1 -1
  11. package/dist/button.js +1 -1
  12. package/dist/{colour-picker-BacNRabo.js → colour-picker-C3Ag4uh-.js} +2 -2
  13. package/dist/{colour-picker-BacNRabo.js.map → colour-picker-C3Ag4uh-.js.map} +1 -1
  14. package/dist/colour-picker.d.ts +1 -1
  15. package/dist/colour-picker.js +1 -1
  16. package/dist/crumbs.d.ts +1 -1
  17. package/dist/{defaults-C3b9OWJD.js → defaults-DcE8RQJc.js} +19 -1
  18. package/dist/defaults-DcE8RQJc.js.map +1 -0
  19. package/dist/{icon-DpA9x2Ve.d.ts → icon-BUwP1CZ1.d.ts} +2 -2
  20. package/dist/icon-BUwP1CZ1.d.ts.map +1 -0
  21. package/dist/icons.d.ts +2 -2
  22. package/dist/icons.js +1 -1
  23. package/dist/{index-DfEkTGvT.d.ts → index-B1UKcA7l.d.ts} +3 -3
  24. package/dist/{index-DfEkTGvT.d.ts.map → index-B1UKcA7l.d.ts.map} +1 -1
  25. package/dist/{index-D_ftz_IT.d.ts → index-BKAlRgbq.d.ts} +2 -2
  26. package/dist/{index-D_ftz_IT.d.ts.map → index-BKAlRgbq.d.ts.map} +1 -1
  27. package/dist/{index-CoqtMSd9.d.ts → index-BUB5SICW.d.ts} +2 -2
  28. package/dist/{index-CoqtMSd9.d.ts.map → index-BUB5SICW.d.ts.map} +1 -1
  29. package/dist/{index-BtGFYfaK.d.ts → index-RqMh1i-O.d.ts} +2 -2
  30. package/dist/{index-BtGFYfaK.d.ts.map → index-RqMh1i-O.d.ts.map} +1 -1
  31. package/dist/index.d.ts +140 -12
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +548 -27
  34. package/dist/index.js.map +1 -1
  35. package/dist/{labelled-input-base-DiTme1JO.d.ts → labelled-input-base-Dp_9KP0G.d.ts} +2 -2
  36. package/dist/{labelled-input-base-DiTme1JO.d.ts.map → labelled-input-base-Dp_9KP0G.d.ts.map} +1 -1
  37. package/dist/labelled-radial-input.d.ts +3 -3
  38. package/dist/labelled-radial-input.d.ts.map +1 -1
  39. package/dist/labelled-range-input.d.ts +1 -1
  40. package/dist/{menu-item-DSyf9f_L.d.ts → menu-item-CQ4Qg731.d.ts} +2 -2
  41. package/dist/{menu-item-DSyf9f_L.d.ts.map → menu-item-CQ4Qg731.d.ts.map} +1 -1
  42. package/dist/menu.d.ts +2 -2
  43. package/dist/panel.d.ts +1 -1
  44. package/dist/polar-pad.d.ts +1 -1
  45. package/dist/{radial-input-DXMN55Nz.d.ts → radial-input-BhZeyyP-.d.ts} +2 -2
  46. package/dist/{radial-input-DXMN55Nz.d.ts.map → radial-input-BhZeyyP-.d.ts.map} +1 -1
  47. package/dist/radial-input.d.ts +1 -1
  48. package/dist/range-input.d.ts +1 -1
  49. package/dist/range.d.ts +1 -1
  50. package/dist/{slider-input-XppH3vcy.d.ts → slider-input-TidGhvXt.d.ts} +2 -2
  51. package/dist/{slider-input-XppH3vcy.d.ts.map → slider-input-TidGhvXt.d.ts.map} +1 -1
  52. package/dist/slider-input.d.ts +1 -1
  53. package/dist/style.css +1 -1
  54. package/dist/swipe.d.ts +1 -1
  55. package/dist/{tab-list-DzknpdSo.js → tab-list-DhkVhRQc.js} +7 -2
  56. package/dist/{tab-list-DzknpdSo.js.map → tab-list-DhkVhRQc.js.map} +1 -1
  57. package/dist/{tab-list-BohmbvqF.d.ts → tab-list-VtWT-_FG.d.ts} +2 -2
  58. package/dist/{tab-list-BohmbvqF.d.ts.map → tab-list-VtWT-_FG.d.ts.map} +1 -1
  59. package/dist/tabs.d.ts +1 -1
  60. package/dist/tabs.js +1 -1
  61. package/dist/wheel-nudge-BlSCe_hD.js.map +1 -1
  62. package/dist/{wheel-nudge-DGrNzWuE.d.ts → wheel-nudge-DgMTRYlh.d.ts} +3 -3
  63. package/dist/wheel-nudge-DgMTRYlh.d.ts.map +1 -0
  64. package/dist/xy-pad.d.ts +1 -1
  65. package/docs-user/README.md +2 -0
  66. package/docs-user/button.md +50 -0
  67. package/docs-user/narrowed-text.md +33 -1
  68. package/docs-user/notifier.md +131 -0
  69. package/docs-user/plots.md +61 -1
  70. package/docs-user/slider-input.md +673 -0
  71. package/docs-user/tabs.md +52 -14
  72. package/docs-user/user-catalog.md +69 -4
  73. package/docs-user/vertical-list.md +102 -7
  74. package/package.json +3 -1
  75. package/dist/button-DxYee1ZH.js.map +0 -1
  76. package/dist/defaults-C3b9OWJD.js.map +0 -1
  77. package/dist/icon-DpA9x2Ve.d.ts.map +0 -1
  78. package/dist/wheel-nudge-DGrNzWuE.d.ts.map +0 -1
@@ -28,6 +28,7 @@ A filtered text selection component with inline search. Shows slotted items filt
28
28
  | `height` | `string \| undefined` | `undefined` | Container height |
29
29
  | `preserveFilter` | `boolean` | `false` | Keep filter query after selection |
30
30
  | `value` | `string` | `''` | Selected value(s) as string |
31
+ | `registry` | `CommandRegistry<unknown> \| undefined` | — | Read-only. Exposes the element's `@clinth/ui-commands` registry. See *Commands*. |
31
32
 
32
33
  ### CSS parts
33
34
 
@@ -42,7 +43,7 @@ A filtered text selection component with inline search. Shows slotted items filt
42
43
 
43
44
  | Event | Detail | Description |
44
45
  |----------|-------------------------------------------------|----------------------------|
45
- | `change` | `{ item, query, selected }` | Fired when selection changes |
46
+ | `change` | `{ item, query, selected }` | Fired when selection changes. `item` is `undefined` for bulk operations (`selectAll` / `deselectAll`). |
46
47
 
47
48
  ```js
48
49
  const nt = document.querySelector('ixfx-narrowed-text');
@@ -51,6 +52,37 @@ nt.addEventListener('change', e => {
51
52
  });
52
53
  ```
53
54
 
55
+ ### Commands
56
+
57
+ The element exposes two commands via the `@clinth/ui-commands` API, accessible through the `registry` property:
58
+
59
+ | Command id | Behaviour |
60
+ |------------------|----------------------------------------------------------------------------|
61
+ | `select-all` | Multi mode: select every currently-filtered item. Single mode: select the first filtered item. No-op if the filter is empty. |
62
+ | `deselect-all` | Clear all selection. No-op if `requiredSelection` is set and only one item remains. |
63
+
64
+ The element does not bind any keyboard shortcuts on its own. Wire up a key of your choice (e.g. CMD+A) using `@clinth/ui-commands`:
65
+
66
+ ```ts
67
+ import { loadKeyBindings, KeyboardManager } from '@clinth/ui-commands';
68
+
69
+ const keyboard = new KeyboardManager();
70
+ loadKeyBindings(keyboard, [
71
+ { key: 'a', modifiers: ['meta'], command: 'select-all', description: 'Select all' },
72
+ { key: 'a', modifiers: ['ctrl'], command: 'select-all', description: 'Select all',
73
+ nonExclusive: true },
74
+ ]);
75
+ keyboard.onKeyEvent(id => el.registry?.invoke(id));
76
+ keyboard.attach(document.body);
77
+ ```
78
+
79
+ ### Methods
80
+
81
+ ```ts
82
+ el.selectAll(); // invokes the 'select-all' command
83
+ el.deselectAll(); // invokes the 'deselect-all' command
84
+ ```
85
+
54
86
  ### Properties of slotted items
55
87
 
56
88
  Items should have `data-value` attribute. Optional attributes:
@@ -0,0 +1,131 @@
1
+ # Notifier
2
+
3
+ A "lookless" app-wide notification system. `NotificationManager` is a singleton that owns notification state, queueing, and timing — it doesn't know how to draw anything. A `NotificationRenderer` (the built-in "pill" renderer, or your own) is responsible for showing/hiding notifications on screen.
4
+
5
+ ```typescript
6
+ import { NotificationManager } from '../src/index.js';
7
+
8
+ NotificationManager.notify({ type: 'info', message: 'Saved.' });
9
+ ```
10
+
11
+ No setup required — the first `notify()` call lazily creates a default pill renderer (`top-right`, list display).
12
+
13
+ ---
14
+
15
+ ## `NotificationManager`
16
+
17
+ ### `notify(content): string`
18
+
19
+ ```typescript
20
+ const id = NotificationManager.notify({
21
+ type: 'error', // 'info' | 'warning' | 'error'
22
+ message: 'Upload failed',
23
+ icon: 'error', // optional; errors default to 'error' if omitted
24
+ onTap: (id) => { /* per-notification tap handler */ },
25
+ });
26
+ ```
27
+
28
+ Returns the notification's `id`, which can be used to `update()` or `dismiss()` it later.
29
+
30
+ ### `update(id, content): void`
31
+
32
+ ```typescript
33
+ NotificationManager.update(id, { message: 'Still uploading…' });
34
+ ```
35
+
36
+ Merges the given fields into the existing notification and, if it's currently the front (displayed) message, resets its dismissal timer.
37
+
38
+ ### `dismiss(id): void` / `dismissAll(): void`
39
+
40
+ Programmatically hide one notification, or clear everything.
41
+
42
+ ### `configure(options): void`
43
+
44
+ Merges into the current configuration. Can be called any time, including after notifications are already showing.
45
+
46
+ ```typescript
47
+ NotificationManager.configure({
48
+ timeout: 4000,
49
+ timeoutError: 8000,
50
+ queue: true,
51
+ queueSize: 3,
52
+ tapBehaviour: 'dismiss',
53
+ tapHandlerDefault: (notification) => console.log(notification.message),
54
+ renderer: createPillRenderer({ position: 'bottom-right' }),
55
+ });
56
+ ```
57
+
58
+ | Option | Type | Default | Description |
59
+ |---|---|---|---|
60
+ | `renderer` | `NotificationRenderer` | built-in pill renderer | Swap the display implementation. See [Custom renderers](#custom-renderers). |
61
+ | `timeout` | `number` (ms) | `4000` | Default display time for `info`/`warning` messages. |
62
+ | `timeoutError` | `number` (ms) | `8000` | Display time for `error` messages. |
63
+ | `queue` | `boolean` | `true` | `true`: up to `queueSize` messages can be waiting at once (see below). `false`: each new message immediately replaces whatever is showing. |
64
+ | `queueSize` | `number` | `3` | Max number of messages held at once when `queue` is `true`. Shrinking it evicts overflow immediately. |
65
+ | `tapBehaviour` | `'none' \| 'dismiss'` | `'dismiss'` | Whether tapping a notification also dismisses it (after any tap handler runs). |
66
+ | `tapHandlerDefault` | `(notification) => void` | — | Called on tap when the notification has no `onTap` of its own. |
67
+
68
+ ---
69
+
70
+ ## Queueing model
71
+
72
+ - **`queue: false`** — a message is always shown alone, for the full `timeout`/`timeoutError`. A new `notify()` call immediately replaces whatever is showing.
73
+ - **`queue: true`** — up to `queueSize` messages are visible at once. When a new message arrives and the queue is already full, **the oldest message is evicted immediately** to make room — nothing waits in an unbounded backlog.
74
+ - Only the **front** message (the oldest, next to be dismissed) has a running timer. A message that arrived while others were already queued gets `1/queueSize` of the normal timeout once it becomes front; a message that was alone in the queue when it arrived gets the full timeout. This means a burst of messages cycles through quickly, while a single message gets the full, unhurried display time.
75
+ - `update()` only resets the timer if the updated notification is currently front (i.e. actually has a timer running).
76
+
77
+ ---
78
+
79
+ ## Pill renderer
80
+
81
+ The built-in renderer, `createPillRenderer(options)`, renders notifications as rounded pills fixed to a corner or edge of the viewport, using theme CSS variables for styling.
82
+
83
+ ```typescript
84
+ import { createPillRenderer, NotificationManager } from '../src/index.js';
85
+
86
+ NotificationManager.configure({
87
+ renderer: createPillRenderer({
88
+ position: 'top-right',
89
+ queueDisplay: 'list',
90
+ safeArea: { top: 60 }, // e.g. clear a fixed header
91
+ }),
92
+ });
93
+ ```
94
+
95
+ | Option | Type | Default | Description |
96
+ |---|---|---|---|
97
+ | `position` | `'top-left' \| 'top-middle' \| 'top-right' \| 'bottom-left' \| 'bottom-middle' \| 'bottom-right'` | `'top-right'` | Which corner/edge pills anchor to, and the direction they slide in/out from. |
98
+ | `queueDisplay` | `'list' \| 'stack'` | `'list'` | How queued (non-front) messages are shown — see below. |
99
+ | `safeArea` | `{ top?, right?, bottom?, left? }` (px) | `{}` | Extra margin added on top of the default spacing, e.g. to avoid a fixed header/footer/notch. |
100
+
101
+ ### `queueDisplay: 'list'`
102
+
103
+ Each message gets its own row. The oldest message sits nearest the anchor edge; newer messages extend away from it (for `top-*` positions, newest is lowest on screen; for `bottom-*`, newest is highest). When the front message is dismissed, the rest animate into the vacated slot.
104
+
105
+ ### `queueDisplay: 'stack'`
106
+
107
+ Only the front message is fully shown. Queued messages peek out from behind it, offset by a few pixels and increasingly faded/desaturated, giving a visual hint that more are waiting. They aren't interactive (no tap, no pointer events) until promoted to front.
108
+
109
+ The offset direction follows the anchor position: corner positions (e.g. `top-left`) offset diagonally, away from both edges (`top-left` → down-right); `-middle` positions offset only vertically, away from the anchor edge (`bottom-middle` → straight up).
110
+
111
+ When the front message is dismissed, the next one animates into the front slot at full opacity.
112
+
113
+ ---
114
+
115
+ ## Custom renderers
116
+
117
+ Anything implementing `NotificationRenderer` can be passed to `configure({ renderer })`:
118
+
119
+ ```typescript
120
+ export interface NotificationRenderer {
121
+ attach: (hooks: NotificationRendererHooks) => void;
122
+ detach?: () => void;
123
+ setNotifications: (notifications: Notification[], queueSize: number) => void;
124
+ }
125
+ ```
126
+
127
+ - `attach(hooks)` is called once when the renderer becomes active. Call `hooks.onTap(id)` whenever the user interacts with a shown notification — the manager decides what tapping means (per-notification `onTap`, `tapHandlerDefault`, `tapBehaviour`).
128
+ - `detach?()` is called if the renderer is swapped out at runtime, so it can tear down its DOM.
129
+ - `setNotifications(notifications, queueSize)` is called any time the visible set changes (new message, dismissal, eviction, reorder, content update). `notifications` is the manager's full, rank-ordered view — index `0` is the front/oldest message — and is never longer than `queueSize`, since the manager itself evicts overflow. A renderer just needs to reconcile this list against whatever it's currently showing (create new, update existing, remove missing) — see `pill-renderer.ts` for a full example.
130
+
131
+ `NotificationContent.onTap` is per-notification and takes the notification's `id`; `tapHandlerDefault` (manager-wide) takes the full `Notification`.
@@ -99,6 +99,8 @@ Renders a 1D data series as a time-series / ordered-sequence plot.
99
99
  | `tooltips` | `boolean` | `true` | Show tooltip on hover |
100
100
  | `precise` | `boolean` | `false` | Show latest value in corner |
101
101
  | `persistentScale` | `boolean` | `true` | Keep same scale; if `false`, scale adjusts to visible data |
102
+ | `rangeMin` | `number` | `NaN` | Fixed minimum value for Y-axis (when set, disables auto-scaling) |
103
+ | `rangeMax` | `number` | `NaN` | Fixed maximum value for Y-axis (when set, disables auto-scaling) |
102
104
  | `clickPauses` | `boolean` | `false` | Toggle pause on click |
103
105
  | `shaded` | `boolean` | `false` | Shaded area under line |
104
106
  | `areaColor` | `string` | `""` | Custom shade colour |
@@ -106,6 +108,16 @@ Renders a 1D data series as a time-series / ordered-sequence plot.
106
108
  | `colorEasing` | `string` | `""` | Easing for colour mapping |
107
109
  | `colorScale` | `string` | `""` | Colour palette for `scale` mode |
108
110
 
111
+ ### Fixed Range
112
+
113
+ Set `range-min` and `range-max` attributes to fix the Y-axis scale:
114
+
115
+ ```html
116
+ <ixfx-plot-single-axis range-min="0" range-max="100"></ixfx-plot-single-axis>
117
+ ```
118
+
119
+ When both are set, the plot uses a fixed range instead of auto-scaling to the data.
120
+
109
121
  ### Draw Styles
110
122
 
111
123
  | Style | Description |
@@ -151,6 +163,24 @@ Use `color-easing` for easing functions or `color-scale` for custom palettes:
151
163
  ### Events
152
164
 
153
165
  - **`plot-datapoint-click`** — `{ value: number, index: number }`
166
+ - **`plot-pointer-move`** — `{ clientX: number, clientY: number, index: number }`
167
+ - **`plot-pointer-leave`** — Fired when pointer leaves the plot
168
+
169
+ ### Value Formatting
170
+
171
+ Override `valueFormat` to customize the tooltip and precise value display:
172
+
173
+ ```typescript
174
+ plot.valueFormat = v => v ? `${v.toFixed(1)}°C` : '';
175
+ ```
176
+
177
+ ### Properties
178
+
179
+ | Property | Type | Description |
180
+ |----------|------|-------------|
181
+ | `values` | `readonly number[]` | Get all values in the series |
182
+ | `dataLength` | `number` | Number of data points |
183
+ | `series` | `PlotDataSeries` | Internal data series instance |
154
184
 
155
185
  ### Example
156
186
 
@@ -228,8 +258,13 @@ Unlike the other plot components, multi-axis manages multiple independent data s
228
258
 
229
259
  ```typescript
230
260
  plot.addData({ temperature: 22, humidity: 60, pressure: 1013 });
261
+ plot.addObject({ temperature: 22, humidity: 60 }); // Add to existing series
262
+ plot.setData('temperature', [1, 2, 3]); // Replace series data
263
+ plot.setObjects({ a: [1,2,3], b: [4,5,6] }); // Replace multiple series
231
264
  plot.styleSeries('temperature', { 'plot-color': '#ff6b6b' });
232
- plot.clear();
265
+ plot.clear(); // Clear all series
266
+ plot.clearSeries('temperature'); // Clear single series
267
+ plot.series; // Get series names array
233
268
  ```
234
269
 
235
270
  ### Layouts
@@ -282,6 +317,19 @@ Renders a histogram of value distributions. Unlike `ixfx-plot-single-axis` (wher
282
317
 
283
318
  **Tag:** `<ixfx-plot-histogram>`
284
319
 
320
+ ### Properties
321
+
322
+ | Property | Type | Default | Description |
323
+ |----------|------|---------|-------------|
324
+ | `orientation` | `PlotHistogramOrientation` | `horizontal` | `horizontal` or `vertical` |
325
+ | `resolution` | `number` | `0.10` | Fraction of range per bucket |
326
+ | `min` / `max` | `number` | auto | Fixed value range (disables auto-scaling) |
327
+ | `capacity` | `number` | `100` | Max values retained |
328
+ | `valueTooltips` | `PlotHistogramValueTooltips` | `hover` | `hover` (bubble), `inline` (overlay-text), or `none` |
329
+ | `tooltipDelay` | `number` | `400` | Hover delay (ms) before the `hover` bubble appears/disappears |
330
+ | `valueUpdateInterval` | `number` | `500` | Max rate (ms) at which a shown value refreshes against live-changing data |
331
+ | `paused` | `boolean` | `false` | Pause rendering updates |
332
+
285
333
  ### Orientation
286
334
 
287
335
  | Value | Description |
@@ -338,6 +386,18 @@ rect.bar {
338
386
 
339
387
  - **`plot-bucket-click`** — `{ bucketIndex: number, valueMin: number, valueMax: number, relativeValue: number }`
340
388
 
389
+ ### Tooltips
390
+
391
+ `valueTooltips` selects how hovering a bucket is shown, sharing the same overridable `valueFormat(valueMin, valueMax, frequency)` (default: `"<min> - <max>: <frequency>"`):
392
+
393
+ - `"hover"` (default) — a floating `ixfx-tooltip` bubble, positioned by the component itself: centred on the hovered bar along the bucket axis, offset from the cursor on the other axis. Debounced by `tooltipDelay` ms (default `400`) on first appearance and on hide; switching directly between bars while already visible updates instantly.
394
+ - `"inline"` — swaps the title overlay-text (top-left) for the hovered bucket's value/frequency instantly (no debounce), reverting to `title` when the pointer leaves.
395
+ - `"none"` — no hover feedback.
396
+
397
+ While hovering, both `hover` and `inline` refresh their displayed value at most every `valueUpdateInterval` ms (default `500`) as the underlying bucket's data changes, rather than on every `add()`.
398
+
399
+ Note: `title` is not reflected to the native `title` attribute, so hovering the plot doesn't also trigger the browser's own tooltip.
400
+
341
401
  ### Example
342
402
 
343
403
  ```html