stimeo-ui 0.15.0 → 0.16.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/CHANGELOG.md +178 -0
- package/README.md +120 -0
- package/dist/cable/index.js +63 -15
- package/dist/cable/index.js.map +1 -1
- package/dist/controllers/accordion_controller.d.ts +30 -3
- package/dist/controllers/accordion_controller.js +98 -9
- package/dist/controllers/accordion_controller.js.map +1 -1
- package/dist/controllers/alert_dialog_controller.d.ts +8 -7
- package/dist/controllers/alert_dialog_controller.js.map +1 -1
- package/dist/controllers/announcer_controller.d.ts +3 -2
- package/dist/controllers/announcer_controller.js +8 -1
- package/dist/controllers/announcer_controller.js.map +1 -1
- package/dist/controllers/auto_submit_controller.js +43 -2
- package/dist/controllers/auto_submit_controller.js.map +1 -1
- package/dist/controllers/avatar_controller.js +1 -1
- package/dist/controllers/avatar_controller.js.map +1 -1
- package/dist/controllers/breadcrumb_controller.d.ts +10 -7
- package/dist/controllers/breadcrumb_controller.js +9 -8
- package/dist/controllers/breadcrumb_controller.js.map +1 -1
- package/dist/controllers/bulk_select_controller.d.ts +4 -4
- package/dist/controllers/bulk_select_controller.js +7 -6
- package/dist/controllers/bulk_select_controller.js.map +1 -1
- package/dist/controllers/calendar_controller.d.ts +85 -23
- package/dist/controllers/calendar_controller.js +323 -123
- package/dist/controllers/calendar_controller.js.map +1 -1
- package/dist/controllers/carousel_controller.d.ts +67 -22
- package/dist/controllers/carousel_controller.js +263 -38
- package/dist/controllers/carousel_controller.js.map +1 -1
- package/dist/controllers/character_counter_controller.d.ts +1 -1
- package/dist/controllers/character_counter_controller.js +40 -2
- package/dist/controllers/character_counter_controller.js.map +1 -1
- package/dist/controllers/checkbox_controller.js +54 -10
- package/dist/controllers/checkbox_controller.js.map +1 -1
- package/dist/controllers/clipboard_controller.d.ts +28 -2
- package/dist/controllers/clipboard_controller.js +63 -5
- package/dist/controllers/clipboard_controller.js.map +1 -1
- package/dist/controllers/collapsible_controller.d.ts +25 -1
- package/dist/controllers/collapsible_controller.js +99 -14
- package/dist/controllers/collapsible_controller.js.map +1 -1
- package/dist/controllers/color_picker_controller.d.ts +29 -8
- package/dist/controllers/color_picker_controller.js +80 -34
- package/dist/controllers/color_picker_controller.js.map +1 -1
- package/dist/controllers/combobox_controller.d.ts +10 -1
- package/dist/controllers/combobox_controller.js +106 -16
- package/dist/controllers/combobox_controller.js.map +1 -1
- package/dist/controllers/command_palette_controller.d.ts +3 -3
- package/dist/controllers/command_palette_controller.js +35 -3
- package/dist/controllers/command_palette_controller.js.map +1 -1
- package/dist/controllers/conditional_fields_controller.js +56 -11
- package/dist/controllers/conditional_fields_controller.js.map +1 -1
- package/dist/controllers/confirm_controller.js +3 -0
- package/dist/controllers/confirm_controller.js.map +1 -1
- package/dist/controllers/context_menu_controller.d.ts +6 -0
- package/dist/controllers/context_menu_controller.js +32 -12
- package/dist/controllers/context_menu_controller.js.map +1 -1
- package/dist/controllers/countdown_controller.d.ts +30 -1
- package/dist/controllers/countdown_controller.js +129 -26
- package/dist/controllers/countdown_controller.js.map +1 -1
- package/dist/controllers/currency_input_controller.d.ts +74 -15
- package/dist/controllers/currency_input_controller.js +205 -58
- package/dist/controllers/currency_input_controller.js.map +1 -1
- package/dist/controllers/data_grid_controller.d.ts +63 -18
- package/dist/controllers/data_grid_controller.js +195 -29
- package/dist/controllers/data_grid_controller.js.map +1 -1
- package/dist/controllers/date_range_picker_controller.d.ts +34 -6
- package/dist/controllers/date_range_picker_controller.js +139 -27
- package/dist/controllers/date_range_picker_controller.js.map +1 -1
- package/dist/controllers/dialog_controller.d.ts +10 -3
- package/dist/controllers/dialog_controller.js +35 -8
- package/dist/controllers/dialog_controller.js.map +1 -1
- package/dist/controllers/direct_upload_controller.js +22 -4
- package/dist/controllers/direct_upload_controller.js.map +1 -1
- package/dist/controllers/dirty_form_controller.d.ts +2 -2
- package/dist/controllers/dirty_form_controller.js +14 -1
- package/dist/controllers/dirty_form_controller.js.map +1 -1
- package/dist/controllers/dismissible_controller.js +1 -0
- package/dist/controllers/dismissible_controller.js.map +1 -1
- package/dist/controllers/drawer_controller.d.ts +18 -10
- package/dist/controllers/drawer_controller.js +54 -19
- package/dist/controllers/drawer_controller.js.map +1 -1
- package/dist/controllers/dropdown_controller.d.ts +9 -3
- package/dist/controllers/dropdown_controller.js +36 -9
- package/dist/controllers/dropdown_controller.js.map +1 -1
- package/dist/controllers/editable_controller.js +34 -0
- package/dist/controllers/editable_controller.js.map +1 -1
- package/dist/controllers/file_dropzone_controller.js +144 -51
- package/dist/controllers/file_dropzone_controller.js.map +1 -1
- package/dist/controllers/filter_controller.d.ts +10 -4
- package/dist/controllers/filter_controller.js +20 -6
- package/dist/controllers/filter_controller.js.map +1 -1
- package/dist/controllers/flash_controller.d.ts +26 -6
- package/dist/controllers/flash_controller.js +305 -46
- package/dist/controllers/flash_controller.js.map +1 -1
- package/dist/controllers/focus_controller.js +1 -0
- package/dist/controllers/focus_controller.js.map +1 -1
- package/dist/controllers/form_field_controller.js +7 -5
- package/dist/controllers/form_field_controller.js.map +1 -1
- package/dist/controllers/form_validation_controller.js +19 -13
- package/dist/controllers/form_validation_controller.js.map +1 -1
- package/dist/controllers/frame_loading_controller.js +16 -2
- package/dist/controllers/frame_loading_controller.js.map +1 -1
- package/dist/controllers/highlight_controller.js +19 -2
- package/dist/controllers/highlight_controller.js.map +1 -1
- package/dist/controllers/hover_card_controller.d.ts +10 -2
- package/dist/controllers/hover_card_controller.js +40 -14
- package/dist/controllers/hover_card_controller.js.map +1 -1
- package/dist/controllers/idle_controller.d.ts +16 -3
- package/dist/controllers/idle_controller.js +90 -5
- package/dist/controllers/idle_controller.js.map +1 -1
- package/dist/controllers/input_mask_controller.d.ts +5 -2
- package/dist/controllers/input_mask_controller.js +65 -9
- package/dist/controllers/input_mask_controller.js.map +1 -1
- package/dist/controllers/intersection_controller.js +3 -0
- package/dist/controllers/intersection_controller.js.map +1 -1
- package/dist/controllers/lazy_frame_controller.js +11 -2
- package/dist/controllers/lazy_frame_controller.js.map +1 -1
- package/dist/controllers/listbox_controller.d.ts +50 -8
- package/dist/controllers/listbox_controller.js +203 -45
- package/dist/controllers/listbox_controller.js.map +1 -1
- package/dist/controllers/masonry_controller.js +0 -2
- package/dist/controllers/masonry_controller.js.map +1 -1
- package/dist/controllers/menu_controller.d.ts +9 -3
- package/dist/controllers/menu_controller.js +45 -16
- package/dist/controllers/menu_controller.js.map +1 -1
- package/dist/controllers/menubar_controller.d.ts +11 -0
- package/dist/controllers/menubar_controller.js +58 -24
- package/dist/controllers/menubar_controller.js.map +1 -1
- package/dist/controllers/meter_controller.js +9 -5
- package/dist/controllers/meter_controller.js.map +1 -1
- package/dist/controllers/multi_select_controller.d.ts +18 -3
- package/dist/controllers/multi_select_controller.js +278 -104
- package/dist/controllers/multi_select_controller.js.map +1 -1
- package/dist/controllers/navigation_menu_controller.d.ts +11 -0
- package/dist/controllers/navigation_menu_controller.js +48 -15
- package/dist/controllers/navigation_menu_controller.js.map +1 -1
- package/dist/controllers/nested_form_controller.js +37 -8
- package/dist/controllers/nested_form_controller.js.map +1 -1
- package/dist/controllers/network_status_controller.js +9 -1
- package/dist/controllers/network_status_controller.js.map +1 -1
- package/dist/controllers/number_input_controller.d.ts +36 -8
- package/dist/controllers/number_input_controller.js +124 -21
- package/dist/controllers/number_input_controller.js.map +1 -1
- package/dist/controllers/optimistic_controller.js +14 -1
- package/dist/controllers/optimistic_controller.js.map +1 -1
- package/dist/controllers/otp_controller.d.ts +22 -7
- package/dist/controllers/otp_controller.js +198 -55
- package/dist/controllers/otp_controller.js.map +1 -1
- package/dist/controllers/overflow_indicator_controller.d.ts +8 -12
- package/dist/controllers/overflow_indicator_controller.js +84 -13
- package/dist/controllers/overflow_indicator_controller.js.map +1 -1
- package/dist/controllers/overflow_menu_controller.d.ts +26 -6
- package/dist/controllers/overflow_menu_controller.js +112 -41
- package/dist/controllers/overflow_menu_controller.js.map +1 -1
- package/dist/controllers/pagination_controller.d.ts +19 -11
- package/dist/controllers/pagination_controller.js +74 -28
- package/dist/controllers/pagination_controller.js.map +1 -1
- package/dist/controllers/password_reveal_controller.d.ts +15 -1
- package/dist/controllers/password_reveal_controller.js +59 -2
- package/dist/controllers/password_reveal_controller.js.map +1 -1
- package/dist/controllers/persist_controller.js +30 -8
- package/dist/controllers/persist_controller.js.map +1 -1
- package/dist/controllers/pointer_drag_controller.js +131 -52
- package/dist/controllers/pointer_drag_controller.js.map +1 -1
- package/dist/controllers/popover_controller.d.ts +9 -3
- package/dist/controllers/popover_controller.js +45 -11
- package/dist/controllers/popover_controller.js.map +1 -1
- package/dist/controllers/portal_controller.d.ts +1 -1
- package/dist/controllers/portal_controller.js +6 -2
- package/dist/controllers/portal_controller.js.map +1 -1
- package/dist/controllers/preview_guard_controller.js +16 -1
- package/dist/controllers/preview_guard_controller.js.map +1 -1
- package/dist/controllers/progress_controller.js +8 -4
- package/dist/controllers/progress_controller.js.map +1 -1
- package/dist/controllers/radio_group_controller.d.ts +6 -4
- package/dist/controllers/radio_group_controller.js +42 -17
- package/dist/controllers/radio_group_controller.js.map +1 -1
- package/dist/controllers/range_slider_controller.d.ts +49 -1
- package/dist/controllers/range_slider_controller.js +88 -42
- package/dist/controllers/range_slider_controller.js.map +1 -1
- package/dist/controllers/rating_controller.d.ts +14 -3
- package/dist/controllers/rating_controller.js +39 -15
- package/dist/controllers/rating_controller.js.map +1 -1
- package/dist/controllers/read_more_controller.d.ts +24 -2
- package/dist/controllers/read_more_controller.js +69 -2
- package/dist/controllers/read_more_controller.js.map +1 -1
- package/dist/controllers/resizable_controller.d.ts +16 -2
- package/dist/controllers/resizable_controller.js +82 -22
- package/dist/controllers/resizable_controller.js.map +1 -1
- package/dist/controllers/scroll_area_controller.js +5 -1
- package/dist/controllers/scroll_area_controller.js.map +1 -1
- package/dist/controllers/scroll_visibility_controller.js +0 -1
- package/dist/controllers/scroll_visibility_controller.js.map +1 -1
- package/dist/controllers/scrollspy_controller.d.ts +3 -2
- package/dist/controllers/scrollspy_controller.js +6 -0
- package/dist/controllers/scrollspy_controller.js.map +1 -1
- package/dist/controllers/separator_controller.d.ts +41 -14
- package/dist/controllers/separator_controller.js +66 -37
- package/dist/controllers/separator_controller.js.map +1 -1
- package/dist/controllers/sidebar_controller.d.ts +20 -3
- package/dist/controllers/sidebar_controller.js +77 -18
- package/dist/controllers/sidebar_controller.js.map +1 -1
- package/dist/controllers/skeleton_controller.js +6 -1
- package/dist/controllers/skeleton_controller.js.map +1 -1
- package/dist/controllers/slider_controller.d.ts +45 -7
- package/dist/controllers/slider_controller.js +82 -47
- package/dist/controllers/slider_controller.js.map +1 -1
- package/dist/controllers/smart_sticky_header_controller.js +11 -1
- package/dist/controllers/smart_sticky_header_controller.js.map +1 -1
- package/dist/controllers/sortable_controller.js +17 -2
- package/dist/controllers/sortable_controller.js.map +1 -1
- package/dist/controllers/spinner_controller.js +10 -2
- package/dist/controllers/spinner_controller.js.map +1 -1
- package/dist/controllers/step_indicator_controller.d.ts +19 -17
- package/dist/controllers/step_indicator_controller.js +18 -17
- package/dist/controllers/step_indicator_controller.js.map +1 -1
- package/dist/controllers/stepper_controller.d.ts +34 -9
- package/dist/controllers/stepper_controller.js +101 -19
- package/dist/controllers/stepper_controller.js.map +1 -1
- package/dist/controllers/stick_to_bottom_controller.d.ts +19 -0
- package/dist/controllers/stick_to_bottom_controller.js +75 -5
- package/dist/controllers/stick_to_bottom_controller.js.map +1 -1
- package/dist/controllers/submit_once_controller.d.ts +3 -2
- package/dist/controllers/submit_once_controller.js +16 -3
- package/dist/controllers/submit_once_controller.js.map +1 -1
- package/dist/controllers/switch_controller.d.ts +29 -7
- package/dist/controllers/switch_controller.js +101 -10
- package/dist/controllers/switch_controller.js.map +1 -1
- package/dist/controllers/tabs_controller.d.ts +12 -0
- package/dist/controllers/tabs_controller.js +21 -2
- package/dist/controllers/tabs_controller.js.map +1 -1
- package/dist/controllers/tags_input_controller.d.ts +15 -3
- package/dist/controllers/tags_input_controller.js +209 -59
- package/dist/controllers/tags_input_controller.js.map +1 -1
- package/dist/controllers/theme_controller.d.ts +20 -3
- package/dist/controllers/theme_controller.js +64 -14
- package/dist/controllers/theme_controller.js.map +1 -1
- package/dist/controllers/time_picker_controller.js +23 -8
- package/dist/controllers/time_picker_controller.js.map +1 -1
- package/dist/controllers/toast_controller.d.ts +52 -15
- package/dist/controllers/toast_controller.js +337 -54
- package/dist/controllers/toast_controller.js.map +1 -1
- package/dist/controllers/toggle_group_controller.d.ts +49 -7
- package/dist/controllers/toggle_group_controller.js +159 -23
- package/dist/controllers/toggle_group_controller.js.map +1 -1
- package/dist/controllers/toolbar_controller.js +32 -0
- package/dist/controllers/toolbar_controller.js.map +1 -1
- package/dist/controllers/tooltip_controller.d.ts +8 -0
- package/dist/controllers/tooltip_controller.js +39 -13
- package/dist/controllers/tooltip_controller.js.map +1 -1
- package/dist/controllers/transition_controller.js +4 -0
- package/dist/controllers/transition_controller.js.map +1 -1
- package/dist/controllers/tree_view_controller.d.ts +39 -8
- package/dist/controllers/tree_view_controller.js +169 -16
- package/dist/controllers/tree_view_controller.js.map +1 -1
- package/dist/index.d.ts +28 -1
- package/dist/index.js +4588 -1535
- package/dist/index.js.map +1 -1
- package/dist/inspector/cli.d.ts +72 -6
- package/dist/inspector/cli.js +262 -51
- package/dist/inspector/cli.js.map +1 -1
- package/dist/inspector/cli_bin.js +309 -51
- package/dist/inspector/cli_bin.js.map +1 -1
- package/dist/inspector/examples.json +40 -40
- package/dist/inspector/manifest.json +525 -59
- package/dist/positioning/index.js +2 -0
- package/dist/positioning/index.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,183 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
While the version is `0.x`, the public API (the `stimeo--*` data attributes) may
|
|
8
8
|
change between releases.
|
|
9
9
|
|
|
10
|
+
## [0.16.0] - 2026-09-26
|
|
11
|
+
|
|
12
|
+
Minor release with no new components. Widgets now report their own state
|
|
13
|
+
changes — `open` / `close`, and `reconcile` when the page rather than the user
|
|
14
|
+
moves committed state — mirror their value into hidden form fields that fire a
|
|
15
|
+
native `change`, and no longer write normalized values back to their Values.
|
|
16
|
+
Several event, detail, action, and Value names were unified, so read Changed and
|
|
17
|
+
Removed before upgrading. The Inspector manifest moves to schema v14, and
|
|
18
|
+
**`stimeo check` can report errors on views that passed under 0.15.0** (row
|
|
19
|
+
templates, action params, event names, submit-once's `idle` / `busy` pairs), so
|
|
20
|
+
run it before deploying.
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
|
|
24
|
+
- accordion, collapsible, context-menu, dialog, drawer, dropdown, hover-card,
|
|
25
|
+
menu, menubar, navigation-menu, popover, read-more, sidebar, and tooltip:
|
|
26
|
+
`open` / `close` events whose `detail.reason` says why the state moved, typed
|
|
27
|
+
by the new `StateReason` type export. accordion also carries
|
|
28
|
+
`{ index, trigger, panel }`, menubar `{ index, menu }`, navigation-menu
|
|
29
|
+
`{ index, panel }`, and sidebar `{ mode }`.
|
|
30
|
+
- tabs: a `change` event with `{ index, total, previous }`.
|
|
31
|
+
- A `reconcile` event, once per batch and never on connect, when the page — code
|
|
32
|
+
writing a Value or an attribute, or a morph — rather than the user moves
|
|
33
|
+
committed state: calendar `{ date }`, currency-input `{ value, formatted }`,
|
|
34
|
+
data-grid `{ rows }`, date-range-picker `{ start, end }`, listbox
|
|
35
|
+
`{ value, option }`, pagination `{ page, total, previous }`, range-slider
|
|
36
|
+
`{ start, end }`, resizable `{ value, fraction }`, separator and slider
|
|
37
|
+
`{ value }`, stepper `{ index, previous, total, step }`, switch `{ checked }`,
|
|
38
|
+
theme `{ mode, resolved }`, toggle-group `{ values }`, and tree-view
|
|
39
|
+
`{ item }`. sidebar reports `reconcile` `{ mode, open }` when crossing its
|
|
40
|
+
breakpoint switches the mode.
|
|
41
|
+
- Hidden form fields that fire a native `change` on a user commit and stay
|
|
42
|
+
silent on connect, morphs, and Value writes: calendar `field` / `monthField`,
|
|
43
|
+
range-slider `startField` / `endField`, and a `field` on slider, switch
|
|
44
|
+
(`"true"` / `"false"`), and tree-view (the selected item's `data-value`).
|
|
45
|
+
toggle-group and data-grid mirror into a `fields` container with `name`
|
|
46
|
+
(`values[]` / `rows[]`) and `form` Values, data-grid from the selected rows'
|
|
47
|
+
`data-value`. tags-input gains the `form` Value multi-select already has.
|
|
48
|
+
- Label pairs the controller swaps with the state: `expandedLabel` /
|
|
49
|
+
`collapsedLabel` on accordion, collapsible, and read-more, and `onLabel` /
|
|
50
|
+
`offLabel` on carousel's play toggle and password-reveal. Regions it shows
|
|
51
|
+
only in their state: `empty` on combobox and multi-select, `hasNew` on
|
|
52
|
+
stick-to-bottom, and `prompt` / `idle` on idle, which also sets `data-prompt`
|
|
53
|
+
while the warning stands.
|
|
54
|
+
- listbox: a `placeholder` Value the trigger shows while nothing is selected.
|
|
55
|
+
- clipboard: `copy` carries `message`, the `copiedLabel` or `errorLabel` for the
|
|
56
|
+
outcome, so `stimeo--clipboard:copy->stimeo--toast#show` needs no script.
|
|
57
|
+
- stepper: `change` also carries `total`, so it wires straight into
|
|
58
|
+
step-indicator's `setIndex`.
|
|
59
|
+
- Inspector: `unknown-action-event`, `invalid-template-root`, and action-param
|
|
60
|
+
checks (`missing-action-param`, `invalid-action-param`, and the warning
|
|
61
|
+
`confusable-action-param`) for overflow-indicator's `direction`, stepper's
|
|
62
|
+
`index`, toast's `type`, and announcer's `assertive`.
|
|
63
|
+
|
|
64
|
+
### Changed
|
|
65
|
+
|
|
66
|
+
- **Breaking** switch: the event is `change` (was `changed`).
|
|
67
|
+
- **Breaking** step-indicator: the `current` Value is `index`, `setCurrent` is
|
|
68
|
+
`setIndex` and reads `detail.index`, and `change` carries
|
|
69
|
+
`{ index, previous, total }`.
|
|
70
|
+
- **Breaking** toast: `body` → `message` (param, detail, and
|
|
71
|
+
`data-toast-slot`).
|
|
72
|
+
- **Breaking** toast, tags-input, multi-select, and file-dropzone: the row
|
|
73
|
+
`<template>` must hold exactly one element, and that element carries the
|
|
74
|
+
`item` / `tag` target itself. A wrapped row or a second element adds nothing;
|
|
75
|
+
tags-input, multi-select, and file-dropzone say so on the console once per
|
|
76
|
+
connection, and `stimeo check` reports `invalid-template-root`.
|
|
77
|
+
- **Breaking** detail keys: filter `visible` → `visibleCount`, overflow-menu
|
|
78
|
+
`{ visible, hidden }` → `{ overflowCount, total }`, portal `mount`
|
|
79
|
+
`target` → `destination`.
|
|
80
|
+
- **Breaking** slider, range-slider, separator, resizable, rating, color-picker,
|
|
81
|
+
stepper, pagination, bulk-select, carousel (`autoplay`), and calendar (`month`)
|
|
82
|
+
no longer write a normalized value back to their Values: the attribute keeps
|
|
83
|
+
what the page wrote, only a user move writes it, and a declared value takes
|
|
84
|
+
effect again once the bounds allow it. Read the published state
|
|
85
|
+
from ARIA, the hidden field, or the events. theme still writes a stored choice
|
|
86
|
+
back to `mode`.
|
|
87
|
+
- **Breaking** a page-driven move reports `reconcile`, not `change`:
|
|
88
|
+
currency-input on a `locale`, `currency`, or `precision` change, a swapped-in
|
|
89
|
+
display, or a reconnect that re-rounds; otp on a native form reset or a
|
|
90
|
+
`pattern` change that drops entered characters, with no `complete` either.
|
|
91
|
+
rating's `reconcile` reports every move of the shown rating the page causes, an
|
|
92
|
+
in-range `value` write included, and nothing for a clamp that leaves it where
|
|
93
|
+
it was.
|
|
94
|
+
- **Breaking** color-picker, date-range-picker, multi-select, rating, and
|
|
95
|
+
tags-input fire a native `change` on a user commit — from the hidden `field`,
|
|
96
|
+
or from the `fields` container on multi-select and tags-input — so a form with
|
|
97
|
+
`stimeo--auto-submit` or a `change` listener now reacts to it.
|
|
98
|
+
- **Breaking** number-input: a step from the buttons, the arrow and Page keys,
|
|
99
|
+
Home and End, or press-and-hold fires the native `input` and `change` a typed
|
|
100
|
+
value does, ahead of `stimeo--number-input:change`, so a form with
|
|
101
|
+
`stimeo--auto-submit` or a `change` listener now reacts to each step.
|
|
102
|
+
- **Breaking** calendar: without a `month`, the grid opens on the selected day's
|
|
103
|
+
month instead of today's and leaves `month` empty (read the shown month from
|
|
104
|
+
`monthField`). A `selected` day outside `min` / `max` is withheld — no
|
|
105
|
+
`aria-selected`, an empty `field` — and published again once the bounds allow
|
|
106
|
+
it; the `selected` Value is never rewritten. Focus inside the grid follows a
|
|
107
|
+
`month` change that moves the painted month to the new month's tab stop.
|
|
108
|
+
- **Breaking** date-range-picker: a confirmed range whose ends `min`, `max`, or
|
|
109
|
+
`disabledDates` exclude narrows to the nearest selectable days, or clears when
|
|
110
|
+
none remain, and reports `reconcile`; `connect()` narrows a range read from its
|
|
111
|
+
fields the same way, silently.
|
|
112
|
+
- **Breaking** flash and toast never evict a hovered or focused notification for
|
|
113
|
+
`max`: the stack stays over the cap until that hold ends, then the oldest
|
|
114
|
+
unheld ones go. toast evicts with reason `limit` (was `timeout`), and a `max`
|
|
115
|
+
of `0` or less, or not a finite number, means no limit (toast used to remove
|
|
116
|
+
every toast).
|
|
117
|
+
- **Breaking** carousel: the `autoplay` Value is no longer switched off at the
|
|
118
|
+
end of a non-looping set or under reduced motion. The declared rotation
|
|
119
|
+
resumes once a slide lies ahead again; reduced motion holds it until the user
|
|
120
|
+
presses play or the page changes `autoplay`.
|
|
121
|
+
- **Breaking** resizable and filter dispatch `change` only when the outcome
|
|
122
|
+
moved: resizable's position, filter's `{ active, visibleCount, total }`.
|
|
123
|
+
- **Breaking** slider, range-slider, and separator decide a user move's
|
|
124
|
+
`change` against the last published value; toggle-group, calendar, and
|
|
125
|
+
date-range-picker skip a `change` or `select` that a listener superseded.
|
|
126
|
+
- Components follow more runtime changes: calendar repaints on `min`, `max`, and
|
|
127
|
+
`weekStart`, and a consumer's `aria-disabled` moves with its date to the cell
|
|
128
|
+
that shows it; countdown follows `completeLabel`; clipboard rewrites a shown
|
|
129
|
+
result on `copiedLabel` / `errorLabel`; flash applies a changed `max` at once;
|
|
130
|
+
theme applies a `mode` declaration, reported as `reconcile`, while a stored
|
|
131
|
+
choice still wins; overflow-menu relabels its More trigger on `moreLabel`;
|
|
132
|
+
stepper re-derives every step when steps are added or removed.
|
|
133
|
+
- countdown: the completion text it wrote, marked
|
|
134
|
+
`data-stimeo--countdown-owns-status`, is taken back when the timer leaves
|
|
135
|
+
`complete`, and a `deadline` moved forward returns it to `paused`.
|
|
136
|
+
overflow-menu marks the More label it wrote the same way
|
|
137
|
+
(`data-stimeo--overflow-menu-owns-label`) and leaves alone a trigger the
|
|
138
|
+
consumer put elements or a name into.
|
|
139
|
+
- listbox: with nothing selected the trigger shows `placeholder`, else the text
|
|
140
|
+
it held before the first selection, instead of keeping the last selected
|
|
141
|
+
option's text.
|
|
142
|
+
- number-input: a text-type spinbutton reads full-width digits and signs
|
|
143
|
+
(`34`, `-5`) as numbers.
|
|
144
|
+
- color-picker: a repaint that does not move the color no longer overwrites text
|
|
145
|
+
being typed into the hex input.
|
|
146
|
+
- carousel: an in-page move keeps a running rotation without a new `play`, and a
|
|
147
|
+
real detach while the element stays in the document emits `pause`.
|
|
148
|
+
- Target attributes are read as a token list: calendar, date-range-picker,
|
|
149
|
+
flash, nested-form, and toast find a target that also carries other names, and
|
|
150
|
+
`stimeo check` resolves them the same way.
|
|
151
|
+
- currency-input, input-mask, number-input, and otp hold a page write that
|
|
152
|
+
arrives during IME composition until the composition ends.
|
|
153
|
+
- Inspector: submit-once's `idle` / `busy` pair is checked per submit control,
|
|
154
|
+
so a button holding one half is reported (`missing-conditional-target`) even
|
|
155
|
+
when another button holds both.
|
|
156
|
+
|
|
157
|
+
### Removed
|
|
158
|
+
|
|
159
|
+
- **Breaking** overflow-indicator: the `update` action. The controller listens
|
|
160
|
+
to its viewport's `scroll` itself, and `stimeo check` reports a leftover
|
|
161
|
+
`scroll->stimeo--overflow-indicator#update` as `unknown-action-method`.
|
|
162
|
+
- **Breaking** calendar: the public `render()` method; the grid repaints itself
|
|
163
|
+
when `min`, `max`, or `weekStart` change.
|
|
164
|
+
|
|
165
|
+
### Fixed
|
|
166
|
+
|
|
167
|
+
- A user-clicked form reset re-derives checkbox, conditional-fields, and otp
|
|
168
|
+
state.
|
|
169
|
+
- pointer-drag: a `setPointerCapture()` that throws no longer locks the handle
|
|
170
|
+
out of both pointer and keyboard dragging. slider, range-slider, and
|
|
171
|
+
color-picker: another element taking the pointer capture mid-drag no longer
|
|
172
|
+
ends the drag.
|
|
173
|
+
- otp: an edit that reaches a field right after an IME confirmation without a
|
|
174
|
+
keystroke — dictation, autofill, a drop — is taken instead of dropped.
|
|
175
|
+
- otp: the authored `aria-invalid`, `aria-errormessage`, and `aria-describedby`
|
|
176
|
+
come back even when a page cached while an error showed is restored under
|
|
177
|
+
another connection; while the error shows, each field carries a
|
|
178
|
+
`data-otp-*-lease` marker holding them.
|
|
179
|
+
- tags-input, multi-select, and file-dropzone: a row whose root is itself the
|
|
180
|
+
`remove` button or the `label` can be removed, focused, and relabelled.
|
|
181
|
+
- stepper: `goto` stays put on an `index` param that is empty or that Stimulus
|
|
182
|
+
reads as a boolean, `null`, or an array (`"true"`, `"null"`, `"[1]"`), instead
|
|
183
|
+
of jumping to a step; `stimeo check` already reports these params.
|
|
184
|
+
- The type declarations link `open`, `close`, `confirm`, and `scrollTo` to the
|
|
185
|
+
component's own method instead of the DOM global of the same name.
|
|
186
|
+
|
|
10
187
|
## [0.15.0] - 2026-09-20
|
|
11
188
|
|
|
12
189
|
Minor release with no new components. Shared internals were consolidated across
|
|
@@ -1101,6 +1278,7 @@ Initial public alpha: 101 behavior-only, accessible Stimulus controllers driven
|
|
|
1101
1278
|
by `data-*` attributes, shipping no CSS. Published to npm (with provenance) and
|
|
1102
1279
|
RubyGems.
|
|
1103
1280
|
|
|
1281
|
+
[0.16.0]: https://github.com/taiyaky/stimeo-ui/releases/tag/v0.16.0
|
|
1104
1282
|
[0.15.0]: https://github.com/taiyaky/stimeo-ui/releases/tag/v0.15.0
|
|
1105
1283
|
[0.14.0]: https://github.com/taiyaky/stimeo-ui/releases/tag/v0.14.0
|
|
1106
1284
|
[0.13.0]: https://github.com/taiyaky/stimeo-ui/releases/tag/v0.13.0
|
package/README.md
CHANGED
|
@@ -114,6 +114,126 @@ The `eslint-plugin-jsx-a11y` equivalents are
|
|
|
114
114
|
`no-noninteractive-tabindex`. These components' real accessibility is exercised
|
|
115
115
|
with axe-core and real screen readers in this project's own test suite.
|
|
116
116
|
|
|
117
|
+
## Composing components
|
|
118
|
+
|
|
119
|
+
Parts dispatch `stimeo--<identifier>:<event>` with a `detail`, and Stimulus can bind
|
|
120
|
+
one part's event straight to another part's action. Wiring two parts is a
|
|
121
|
+
`data-action`, not a `<script>`.
|
|
122
|
+
|
|
123
|
+
```html
|
|
124
|
+
<!-- Copy a link and say so, with nothing in between. -->
|
|
125
|
+
<div data-controller="stimeo--toast"
|
|
126
|
+
data-action="stimeo--clipboard:copy->stimeo--toast#show">
|
|
127
|
+
<div data-controller="stimeo--clipboard"
|
|
128
|
+
data-stimeo--clipboard-text-value="https://example.com/share"
|
|
129
|
+
data-stimeo--clipboard-copied-label-value="Copied"
|
|
130
|
+
data-stimeo--clipboard-error-label-value="Copy failed">
|
|
131
|
+
<button type="button" data-stimeo--clipboard-target="button"
|
|
132
|
+
data-action="click->stimeo--clipboard#copy">Copy</button>
|
|
133
|
+
</div>
|
|
134
|
+
<ol data-stimeo--toast-target="list"></ol>
|
|
135
|
+
<template data-stimeo--toast-target="template">
|
|
136
|
+
<li data-stimeo--toast-target="item"><span data-toast-slot="message"></span></li>
|
|
137
|
+
</template>
|
|
138
|
+
</div>
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
```html
|
|
142
|
+
<!-- A wizard moves a read-only progress indicator. -->
|
|
143
|
+
<div data-controller="stimeo--stepper">
|
|
144
|
+
<ol data-controller="stimeo--step-indicator"
|
|
145
|
+
data-action="stimeo--stepper:change@window->stimeo--step-indicator#setIndex">
|
|
146
|
+
<li data-stimeo--step-indicator-target="step">Cart</li>
|
|
147
|
+
<li data-stimeo--step-indicator-target="step">Shipping</li>
|
|
148
|
+
</ol>
|
|
149
|
+
<!-- the stepper's own step targets and buttons -->
|
|
150
|
+
</div>
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
```html
|
|
154
|
+
<!-- A value a widget stepped submits the form, through the events a browser
|
|
155
|
+
would have fired for its own control. -->
|
|
156
|
+
<form data-controller="stimeo--auto-submit"
|
|
157
|
+
data-action="change->stimeo--auto-submit#submit">
|
|
158
|
+
<div data-controller="stimeo--number-input">
|
|
159
|
+
<input type="number" name="quantity" value="1" aria-label="Quantity"
|
|
160
|
+
data-stimeo--number-input-target="input"
|
|
161
|
+
data-action="change->stimeo--number-input#onInput
|
|
162
|
+
keydown->stimeo--number-input#onKeydown" />
|
|
163
|
+
<button type="button" aria-label="Increase" tabindex="-1"
|
|
164
|
+
data-stimeo--number-input-target="increment"
|
|
165
|
+
data-action="click->stimeo--number-input#increment">+</button>
|
|
166
|
+
</div>
|
|
167
|
+
</form>
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Two things to know:
|
|
171
|
+
|
|
172
|
+
- **Events bubble from the part that dispatched them.** The receiver has to be an
|
|
173
|
+
ancestor. Anywhere else — a sibling, or a receiver nested *inside* the part that
|
|
174
|
+
dispatches — needs `@window`, because bubbling only ever goes up:
|
|
175
|
+
`stimeo--clipboard:copy@window->stimeo--toast#show`.
|
|
176
|
+
- **Do not say the same thing twice.** A toast's message slot is a `role="status"`
|
|
177
|
+
live region. Wiring the same result to the shared announcer as well
|
|
178
|
+
(`announce-copied-text`, …) reads it out twice. Pick one.
|
|
179
|
+
|
|
180
|
+
`stimeo check` verifies both halves of a wire: the controller and action on the
|
|
181
|
+
receiving side, and the event name on the emitting side.
|
|
182
|
+
|
|
183
|
+
## Styling notes
|
|
184
|
+
|
|
185
|
+
### `hidden` under a utility CSS layer
|
|
186
|
+
|
|
187
|
+
Controllers show and hide their own declared regions with the `hidden` attribute —
|
|
188
|
+
a listbox option filtered out, an "empty" row, the half of a label that does not
|
|
189
|
+
belong to the current state. `hidden` only carries `display: none` from the user-agent
|
|
190
|
+
stylesheet, so any rule that sets `display` wins over it.
|
|
191
|
+
|
|
192
|
+
Utility-first frameworks make that collision likely. Tailwind v4 declares
|
|
193
|
+
`@layer theme, base, components, utilities`, and DaisyUI puts component classes such
|
|
194
|
+
as `.menu li`, `.tabs`, and `.steps` in the **last** layer. A hidden element inside one
|
|
195
|
+
of them stays visible, and a `display: none` you add in `@layer components` still loses.
|
|
196
|
+
|
|
197
|
+
Put the override **outside every layer** — unlayered rules beat layered ones, so no
|
|
198
|
+
`!important` is needed:
|
|
199
|
+
|
|
200
|
+
```css
|
|
201
|
+
/* not inside @layer */
|
|
202
|
+
.menu li[hidden],
|
|
203
|
+
.menu [role="option"][hidden] {
|
|
204
|
+
display: none;
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Most visible with `combobox`, `listbox`, `multi-select`, `empty-state`, `filter`, and
|
|
209
|
+
`command-palette`, whose options and empty rows are the ones being hidden.
|
|
210
|
+
|
|
211
|
+
### State-dependent text belongs in markup
|
|
212
|
+
|
|
213
|
+
It is tempting to put the words that change with a state into CSS:
|
|
214
|
+
|
|
215
|
+
```css
|
|
216
|
+
/* don't */
|
|
217
|
+
.play::after { content: "Auto-advance: off"; }
|
|
218
|
+
.play[aria-pressed="true"]::after { content: "Auto-advance: on"; }
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Text in `content` never reaches a translation catalogue, and the usual "find untranslated
|
|
222
|
+
strings" scan reads HTML, so it does not turn up there either. `content: attr(aria-valuetext)`
|
|
223
|
+
has the same problem from the other side: the attribute is composed at runtime in one
|
|
224
|
+
language. Keep the words in markup and let the controller show the half that applies:
|
|
225
|
+
|
|
226
|
+
```html
|
|
227
|
+
<button data-stimeo--read-more-target="trigger" aria-expanded="false">
|
|
228
|
+
<span data-stimeo--read-more-target="collapsedLabel">Read more</span>
|
|
229
|
+
<span data-stimeo--read-more-target="expandedLabel" hidden>Show less</span>
|
|
230
|
+
</button>
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Controllers that read out a composed value take the wording as an attribute instead —
|
|
234
|
+
`color-picker` accepts `data-value-text`, and the announcing controllers accept
|
|
235
|
+
`announce-*-text`.
|
|
236
|
+
|
|
117
237
|
## Inspector CLI & MCP server
|
|
118
238
|
|
|
119
239
|
Stimeo UI bundles a zero-dependency static checker for its own markup contract
|
package/dist/cable/index.js
CHANGED
|
@@ -164,6 +164,18 @@ var SafeInterval = class extends TimerRegistry {
|
|
|
164
164
|
window.clearInterval(id);
|
|
165
165
|
}
|
|
166
166
|
};
|
|
167
|
+
|
|
168
|
+
// src/utils/transient_hooks.ts
|
|
169
|
+
var TransientHooks = class {
|
|
170
|
+
#attributes;
|
|
171
|
+
constructor(options) {
|
|
172
|
+
this.#attributes = options.attributes;
|
|
173
|
+
}
|
|
174
|
+
/** Drops the declared hooks from `element`; what it carries besides stays. */
|
|
175
|
+
reset(element) {
|
|
176
|
+
for (const attribute of this.#attributes) element.removeAttribute(attribute);
|
|
177
|
+
}
|
|
178
|
+
};
|
|
167
179
|
function parseSubscriptionParams(raw) {
|
|
168
180
|
try {
|
|
169
181
|
const parsed = JSON.parse(raw);
|
|
@@ -270,6 +282,7 @@ function openSharedSubscription(consumer, channel) {
|
|
|
270
282
|
}
|
|
271
283
|
|
|
272
284
|
// src/cable/live_counter_controller.ts
|
|
285
|
+
var TRANSIENT = new TransientHooks({ attributes: ["data-live-counter-rejected"] });
|
|
273
286
|
var DISABLED_MARKER = "data-live-counter-disabled";
|
|
274
287
|
var LiveCounterController = class _LiveCounterController extends Controller {
|
|
275
288
|
static targets = ["value", "trigger"];
|
|
@@ -323,9 +336,12 @@ var LiveCounterController = class _LiveCounterController extends Controller {
|
|
|
323
336
|
* The rejected hook is transient server state: a Turbo cache snapshot must not
|
|
324
337
|
* resurrect it — the fresh subscription re-decides it. An outstanding guess
|
|
325
338
|
* belongs to the identifier that is going away, so it is dropped with it.
|
|
339
|
+
*
|
|
340
|
+
* @stimeoRuntimeOnly `channel` decides whether this call opens a subscription at all; the
|
|
341
|
+
* rejected hook it clears does not depend on it.
|
|
326
342
|
*/
|
|
327
343
|
#subscribe() {
|
|
328
|
-
this.element
|
|
344
|
+
TRANSIENT.reset(this.element);
|
|
329
345
|
this.#outstanding.length = 0;
|
|
330
346
|
if (this.channelValue) {
|
|
331
347
|
this.#subscription = this.#open();
|
|
@@ -340,6 +356,9 @@ var LiveCounterController = class _LiveCounterController extends Controller {
|
|
|
340
356
|
* half-wired: no gate reflected, and a trigger that looks live. The gate reads
|
|
341
357
|
* the declaration, so a null subscription keeps it shut and the display never
|
|
342
358
|
* moves past what the server can receive.
|
|
359
|
+
*
|
|
360
|
+
* @stimeoRuntimeOnly `channel` and its params choose the one subscription this call opens; `id`
|
|
361
|
+
* is read by the handlers it wires.
|
|
343
362
|
*/
|
|
344
363
|
#open() {
|
|
345
364
|
try {
|
|
@@ -388,7 +407,7 @@ var LiveCounterController = class _LiveCounterController extends Controller {
|
|
|
388
407
|
this.#focusedTriggers.releaseAll();
|
|
389
408
|
this.#subscription?.unsubscribe();
|
|
390
409
|
this.#subscription = null;
|
|
391
|
-
this.element
|
|
410
|
+
TRANSIENT.reset(this.element);
|
|
392
411
|
for (const trigger of this.triggerTargets) this.#release(trigger);
|
|
393
412
|
}
|
|
394
413
|
/** Late-added triggers (e.g. via a Turbo Stream) pick up the current gate. */
|
|
@@ -467,6 +486,8 @@ var LiveCounterController = class _LiveCounterController extends Controller {
|
|
|
467
486
|
* authored-disabled trigger ("disabled until valid", say) is never
|
|
468
487
|
* re-enabled by the gate. A marked disabled restored from a Turbo cache
|
|
469
488
|
* snapshot is recognized as ours and lifted once the gate opens.
|
|
489
|
+
*
|
|
490
|
+
* @stimeoRenderRoot
|
|
470
491
|
*/
|
|
471
492
|
#syncTrigger(trigger) {
|
|
472
493
|
if (this.#ready) {
|
|
@@ -510,6 +531,9 @@ var LiveCounterController = class _LiveCounterController extends Controller {
|
|
|
510
531
|
* Settles the display on a count the server stated, announcing what it settled
|
|
511
532
|
* on. Announcing the optimistic bump instead would read a guess out and then
|
|
512
533
|
* correct it, so the announcement rides this path only.
|
|
534
|
+
*
|
|
535
|
+
* @stimeoRuntimeOnly The count shown is the value received; `announceText` words the one
|
|
536
|
+
* announcement of this change.
|
|
513
537
|
*/
|
|
514
538
|
#reconcile(count) {
|
|
515
539
|
if (this.#write(count)) this.#announce(count);
|
|
@@ -574,7 +598,16 @@ var KeyedTimers = class {
|
|
|
574
598
|
}
|
|
575
599
|
};
|
|
576
600
|
|
|
601
|
+
// src/utils/template_row.ts
|
|
602
|
+
function cloneTemplateRoot(template) {
|
|
603
|
+
const root = template.content.firstElementChild;
|
|
604
|
+
return root instanceof HTMLElement ? root.cloneNode(true) : null;
|
|
605
|
+
}
|
|
606
|
+
|
|
577
607
|
// src/cable/presence_controller.ts
|
|
608
|
+
var TRANSIENT2 = new TransientHooks({
|
|
609
|
+
attributes: ["data-present", "data-present-count", "data-presence-rejected"]
|
|
610
|
+
});
|
|
578
611
|
var BEACON_THROTTLE_MS = 2e3;
|
|
579
612
|
var DEFAULT_HEARTBEAT_MS = 15e3;
|
|
580
613
|
var DEFAULT_TIMEOUT_MS = 4e4;
|
|
@@ -669,7 +702,6 @@ var PresenceController = class _PresenceController extends Controller {
|
|
|
669
702
|
}
|
|
670
703
|
connect() {
|
|
671
704
|
this.#reset();
|
|
672
|
-
this.element.removeAttribute("data-presence-rejected");
|
|
673
705
|
if (this.hasCountTarget) this.countTarget.textContent = this.#countMessage(0);
|
|
674
706
|
if (!this.channelValue) return;
|
|
675
707
|
this.#claimSpeaker();
|
|
@@ -695,7 +727,6 @@ var PresenceController = class _PresenceController extends Controller {
|
|
|
695
727
|
this.#subscription = null;
|
|
696
728
|
this.#intervals.clearAll();
|
|
697
729
|
this.#reset();
|
|
698
|
-
this.element.removeAttribute("data-presence-rejected");
|
|
699
730
|
}
|
|
700
731
|
/**
|
|
701
732
|
* Registers this element as one of the voices for its peer, so a sibling on the
|
|
@@ -775,6 +806,9 @@ ${this.idValue}`;
|
|
|
775
806
|
* Tracks a broadcast beacon: upserts the peer (restarting its expiry timer),
|
|
776
807
|
* removes it on a `leaving` notice, and re-announces this client when the
|
|
777
808
|
* peer was unknown (roster convergence — see the class doc).
|
|
809
|
+
*
|
|
810
|
+
* @stimeoRuntimeOnly `id` filters this client's own echo, `timeout` arms one peer's expiry,
|
|
811
|
+
* `name` answers one beacon and the texts word one announcement.
|
|
778
812
|
*/
|
|
779
813
|
#onReceived(data) {
|
|
780
814
|
const beacon = data;
|
|
@@ -799,7 +833,11 @@ ${this.idValue}`;
|
|
|
799
833
|
this.#render();
|
|
800
834
|
}
|
|
801
835
|
}
|
|
802
|
-
/**
|
|
836
|
+
/**
|
|
837
|
+
* Removes a peer (expiry or graceful leave) and reflects the change.
|
|
838
|
+
*
|
|
839
|
+
* @stimeoRuntimeOnly `announceLeaveText` words the one announcement this departure makes.
|
|
840
|
+
*/
|
|
803
841
|
#drop(id) {
|
|
804
842
|
const peer = this.#peers.get(id);
|
|
805
843
|
if (peer === void 0) return;
|
|
@@ -810,7 +848,9 @@ ${this.idValue}`;
|
|
|
810
848
|
this.#announce(this.announceLeaveTextValue, peer.name);
|
|
811
849
|
this.dispatch("leave", { detail: { id } });
|
|
812
850
|
}
|
|
813
|
-
/**
|
|
851
|
+
/**
|
|
852
|
+
* Reflects the roster onto the hooks + count target and emits `change`.
|
|
853
|
+
*/
|
|
814
854
|
#render() {
|
|
815
855
|
const users = [...this.#peers.entries()].map(([id, peer]) => ({ id, name: peer.name }));
|
|
816
856
|
this.element.setAttribute("data-present", users.length > 0 ? "true" : "false");
|
|
@@ -849,8 +889,8 @@ ${this.idValue}`;
|
|
|
849
889
|
/** Appends one template clone for a newly present peer (list + template only). */
|
|
850
890
|
#appendClone(id, name) {
|
|
851
891
|
if (!this.hasListTarget || !this.hasTemplateTarget) return;
|
|
852
|
-
const root = this.templateTarget
|
|
853
|
-
if (!
|
|
892
|
+
const root = cloneTemplateRoot(this.templateTarget);
|
|
893
|
+
if (!root) return;
|
|
854
894
|
root.setAttribute("data-presence-id", id);
|
|
855
895
|
this.#fillName(root, name);
|
|
856
896
|
this.listTarget.appendChild(root);
|
|
@@ -885,8 +925,7 @@ ${this.idValue}`;
|
|
|
885
925
|
this.#announceId = null;
|
|
886
926
|
this.#peers.clear();
|
|
887
927
|
this.#lastBeaconAt = 0;
|
|
888
|
-
this.element
|
|
889
|
-
this.element.removeAttribute("data-present-count");
|
|
928
|
+
TRANSIENT2.reset(this.element);
|
|
890
929
|
if (this.hasCountTarget) this.countTarget.textContent = "";
|
|
891
930
|
if (this.hasListTarget) {
|
|
892
931
|
for (const child of this.listTarget.querySelectorAll("[data-presence-id]")) {
|
|
@@ -895,6 +934,9 @@ ${this.idValue}`;
|
|
|
895
934
|
}
|
|
896
935
|
}
|
|
897
936
|
};
|
|
937
|
+
var TRANSIENT3 = new TransientHooks({
|
|
938
|
+
attributes: ["data-typing", "data-typing-indicator-rejected"]
|
|
939
|
+
});
|
|
898
940
|
var DEFAULT_TIMEOUT = 3e3;
|
|
899
941
|
var DEFAULT_THROTTLE = 2e3;
|
|
900
942
|
var fillTokens = (template, values) => template.replace(/%\{(name|names|count)\}/g, (match, token) => values[token] ?? match);
|
|
@@ -948,8 +990,7 @@ var TypingIndicatorController = class _TypingIndicatorController extends Control
|
|
|
948
990
|
if (this.#typers.size > 0) this.#paint();
|
|
949
991
|
}
|
|
950
992
|
connect() {
|
|
951
|
-
this.element
|
|
952
|
-
this.element.removeAttribute("data-typing-indicator-rejected");
|
|
993
|
+
TRANSIENT3.reset(this.element);
|
|
953
994
|
if (this.hasStatusTarget) this.statusTarget.textContent = "";
|
|
954
995
|
this.element.addEventListener("input", this.#onInput);
|
|
955
996
|
if (this.channelValue) {
|
|
@@ -974,8 +1015,7 @@ var TypingIndicatorController = class _TypingIndicatorController extends Control
|
|
|
974
1015
|
this.#expiry.clearAll();
|
|
975
1016
|
this.#announceId = null;
|
|
976
1017
|
this.#typers.clear();
|
|
977
|
-
this.element
|
|
978
|
-
this.element.removeAttribute("data-typing-indicator-rejected");
|
|
1018
|
+
TRANSIENT3.reset(this.element);
|
|
979
1019
|
if (this.hasStatusTarget) this.statusTarget.textContent = "";
|
|
980
1020
|
this.#lastSentAt = 0;
|
|
981
1021
|
}
|
|
@@ -991,6 +1031,9 @@ var TypingIndicatorController = class _TypingIndicatorController extends Control
|
|
|
991
1031
|
* Tracks a broadcast typer. The own echo is dropped (same `name`); every
|
|
992
1032
|
* further signal from a name restarts its auto-clear timer, so the indicator
|
|
993
1033
|
* survives continuous typing and clears `timeout` ms after the last signal.
|
|
1034
|
+
*
|
|
1035
|
+
* @stimeoRuntimeOnly `name` filters this client's own echo and `timeout` arms one typer's expiry;
|
|
1036
|
+
* the typers shown come from what is received.
|
|
994
1037
|
*/
|
|
995
1038
|
#onReceived(data) {
|
|
996
1039
|
const name = data?.name;
|
|
@@ -1027,7 +1070,9 @@ var TypingIndicatorController = class _TypingIndicatorController extends Control
|
|
|
1027
1070
|
this.#typers.delete(name);
|
|
1028
1071
|
this.#render();
|
|
1029
1072
|
}
|
|
1030
|
-
/**
|
|
1073
|
+
/**
|
|
1074
|
+
* Reflects the typer set onto the display, announces it, and emits `change`.
|
|
1075
|
+
*/
|
|
1031
1076
|
#render() {
|
|
1032
1077
|
const names = this.#paint();
|
|
1033
1078
|
this.#announce(names);
|
|
@@ -1041,6 +1086,9 @@ var TypingIndicatorController = class _TypingIndicatorController extends Control
|
|
|
1041
1086
|
* a reader for, and the visible copy already clears. Wording comes from the
|
|
1042
1087
|
* consumer, and {@link announce} drops an empty message, so an undeclared template
|
|
1043
1088
|
* announces nothing at all.
|
|
1089
|
+
*
|
|
1090
|
+
* @stimeoRuntimeOnly The wording Values are read to compose one announcement; the
|
|
1091
|
+
* visible typer list is rendered from the set, not from them.
|
|
1044
1092
|
*/
|
|
1045
1093
|
#announce(names) {
|
|
1046
1094
|
if (this.#announceId !== null) this.#timers.clear(this.#announceId);
|