stimeo-ui 0.11.0 → 0.13.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 +107 -0
- package/dist/cable/index.d.ts +67 -13
- package/dist/cable/index.js +461 -154
- package/dist/cable/index.js.map +1 -1
- package/dist/controllers/alert_dialog_controller.d.ts +1 -1
- package/dist/controllers/alert_dialog_controller.js.map +1 -1
- package/dist/controllers/announcer_controller.d.ts +1 -1
- package/dist/controllers/announcer_controller.js.map +1 -1
- package/dist/controllers/auto_submit_controller.js.map +1 -1
- package/dist/controllers/breadcrumb_controller.d.ts +1 -1
- package/dist/controllers/breadcrumb_controller.js.map +1 -1
- package/dist/controllers/calendar_controller.d.ts +2 -1
- package/dist/controllers/calendar_controller.js +10 -2
- package/dist/controllers/calendar_controller.js.map +1 -1
- package/dist/controllers/carousel_controller.js +1 -1
- package/dist/controllers/carousel_controller.js.map +1 -1
- package/dist/controllers/character_counter_controller.js.map +1 -1
- package/dist/controllers/clipboard_controller.d.ts +1 -1
- package/dist/controllers/clipboard_controller.js.map +1 -1
- package/dist/controllers/collapsible_controller.js.map +1 -1
- package/dist/controllers/color_picker_controller.d.ts +1 -1
- package/dist/controllers/color_picker_controller.js.map +1 -1
- package/dist/controllers/command_palette_controller.d.ts +3 -3
- package/dist/controllers/command_palette_controller.js +2 -2
- package/dist/controllers/command_palette_controller.js.map +1 -1
- package/dist/controllers/conditional_fields_controller.js.map +1 -1
- package/dist/controllers/confirm_controller.d.ts +2 -2
- package/dist/controllers/confirm_controller.js.map +1 -1
- package/dist/controllers/context_menu_controller.d.ts +1 -1
- package/dist/controllers/context_menu_controller.js.map +1 -1
- package/dist/controllers/count_up_controller.d.ts +12 -10
- package/dist/controllers/count_up_controller.js +74 -35
- package/dist/controllers/count_up_controller.js.map +1 -1
- package/dist/controllers/countdown_controller.d.ts +1 -1
- package/dist/controllers/countdown_controller.js.map +1 -1
- package/dist/controllers/data_grid_controller.d.ts +1 -1
- package/dist/controllers/data_grid_controller.js.map +1 -1
- package/dist/controllers/date_range_picker_controller.js +10 -10
- package/dist/controllers/date_range_picker_controller.js.map +1 -1
- package/dist/controllers/dialog_controller.d.ts +1 -1
- package/dist/controllers/dialog_controller.js.map +1 -1
- package/dist/controllers/direct_upload_controller.js.map +1 -1
- package/dist/controllers/dirty_form_controller.js.map +1 -1
- package/dist/controllers/dismissible_controller.js.map +1 -1
- package/dist/controllers/drawer_controller.d.ts +2 -2
- package/dist/controllers/drawer_controller.js +2 -2
- package/dist/controllers/drawer_controller.js.map +1 -1
- package/dist/controllers/dropdown_controller.d.ts +1 -1
- package/dist/controllers/dropdown_controller.js.map +1 -1
- package/dist/controllers/file_dropzone_controller.js.map +1 -1
- package/dist/controllers/flash_controller.js.map +1 -1
- package/dist/controllers/focus_controller.d.ts +2 -2
- package/dist/controllers/focus_controller.js.map +1 -1
- package/dist/controllers/form_validation_controller.js.map +1 -1
- package/dist/controllers/frame_loading_controller.d.ts +3 -3
- package/dist/controllers/frame_loading_controller.js.map +1 -1
- package/dist/controllers/highlight_controller.js.map +1 -1
- package/dist/controllers/hover_card_controller.d.ts +1 -1
- package/dist/controllers/hover_card_controller.js.map +1 -1
- package/dist/controllers/idle_controller.d.ts +1 -1
- package/dist/controllers/idle_controller.js.map +1 -1
- package/dist/controllers/input_mask_controller.js.map +1 -1
- package/dist/controllers/intersection_controller.d.ts +20 -7
- package/dist/controllers/intersection_controller.js +55 -8
- package/dist/controllers/intersection_controller.js.map +1 -1
- package/dist/controllers/lazy_frame_controller.d.ts +31 -9
- package/dist/controllers/lazy_frame_controller.js +81 -19
- package/dist/controllers/lazy_frame_controller.js.map +1 -1
- package/dist/controllers/listbox_controller.js.map +1 -1
- package/dist/controllers/local_time_controller.d.ts +1 -1
- package/dist/controllers/local_time_controller.js.map +1 -1
- package/dist/controllers/masonry_controller.d.ts +1 -1
- package/dist/controllers/masonry_controller.js.map +1 -1
- package/dist/controllers/menu_controller.d.ts +1 -1
- package/dist/controllers/menu_controller.js.map +1 -1
- package/dist/controllers/menubar_controller.d.ts +2 -2
- package/dist/controllers/menubar_controller.js.map +1 -1
- package/dist/controllers/navigation_menu_controller.d.ts +1 -1
- package/dist/controllers/navigation_menu_controller.js.map +1 -1
- package/dist/controllers/nested_form_controller.js.map +1 -1
- package/dist/controllers/network_status_controller.js.map +1 -1
- package/dist/controllers/number_input_controller.js.map +1 -1
- package/dist/controllers/optimistic_controller.d.ts +23 -10
- package/dist/controllers/optimistic_controller.js +141 -20
- package/dist/controllers/optimistic_controller.js.map +1 -1
- package/dist/controllers/overflow_indicator_controller.d.ts +1 -1
- package/dist/controllers/overflow_indicator_controller.js.map +1 -1
- package/dist/controllers/overflow_menu_controller.js.map +1 -1
- package/dist/controllers/pagination_controller.js.map +1 -1
- package/dist/controllers/password_reveal_controller.js.map +1 -1
- package/dist/controllers/password_strength_controller.d.ts +2 -1
- package/dist/controllers/password_strength_controller.js.map +1 -1
- package/dist/controllers/persist_controller.js.map +1 -1
- package/dist/controllers/pointer_drag_controller.js +4 -0
- package/dist/controllers/pointer_drag_controller.js.map +1 -1
- package/dist/controllers/popover_controller.d.ts +1 -1
- package/dist/controllers/popover_controller.js.map +1 -1
- package/dist/controllers/portal_controller.d.ts +2 -2
- package/dist/controllers/portal_controller.js.map +1 -1
- package/dist/controllers/radio_group_controller.d.ts +1 -1
- package/dist/controllers/radio_group_controller.js.map +1 -1
- package/dist/controllers/reading_progress_controller.d.ts +18 -9
- package/dist/controllers/reading_progress_controller.js +177 -6
- package/dist/controllers/reading_progress_controller.js.map +1 -1
- package/dist/controllers/relative_time_controller.d.ts +3 -3
- package/dist/controllers/relative_time_controller.js.map +1 -1
- package/dist/controllers/roving_controller.d.ts +1 -1
- package/dist/controllers/roving_controller.js.map +1 -1
- package/dist/controllers/scroll_area_controller.js.map +1 -1
- package/dist/controllers/scrollspy_controller.js +13 -2
- package/dist/controllers/scrollspy_controller.js.map +1 -1
- package/dist/controllers/sidebar_controller.d.ts +1 -1
- package/dist/controllers/sidebar_controller.js.map +1 -1
- package/dist/controllers/skeleton_controller.d.ts +2 -2
- package/dist/controllers/skeleton_controller.js.map +1 -1
- package/dist/controllers/smart_sticky_header_controller.d.ts +17 -8
- package/dist/controllers/smart_sticky_header_controller.js +52 -10
- package/dist/controllers/smart_sticky_header_controller.js.map +1 -1
- package/dist/controllers/sortable_controller.d.ts +38 -8
- package/dist/controllers/sortable_controller.js +241 -67
- package/dist/controllers/sortable_controller.js.map +1 -1
- package/dist/controllers/spinner_controller.d.ts +3 -3
- package/dist/controllers/spinner_controller.js.map +1 -1
- package/dist/controllers/sticky_observer_controller.js +13 -2
- package/dist/controllers/sticky_observer_controller.js.map +1 -1
- package/dist/controllers/submit_once_controller.d.ts +3 -3
- package/dist/controllers/submit_once_controller.js.map +1 -1
- package/dist/controllers/switch_controller.js.map +1 -1
- package/dist/controllers/textarea_autosize_controller.d.ts +1 -1
- package/dist/controllers/textarea_autosize_controller.js.map +1 -1
- package/dist/controllers/theme_controller.d.ts +3 -2
- package/dist/controllers/theme_controller.js.map +1 -1
- package/dist/controllers/toast_controller.js +1 -1
- package/dist/controllers/toast_controller.js.map +1 -1
- package/dist/controllers/toggle_group_controller.js.map +1 -1
- package/dist/controllers/toolbar_controller.d.ts +1 -1
- package/dist/controllers/toolbar_controller.js.map +1 -1
- package/dist/controllers/tooltip_controller.d.ts +1 -1
- package/dist/controllers/tooltip_controller.js.map +1 -1
- package/dist/controllers/transition_controller.d.ts +1 -1
- package/dist/controllers/transition_controller.js.map +1 -1
- package/dist/controllers/tree_view_controller.d.ts +4 -3
- package/dist/controllers/tree_view_controller.js.map +1 -1
- package/dist/index.js +587 -183
- package/dist/index.js.map +1 -1
- package/dist/inspector/cli.d.ts +1 -1
- package/dist/inspector/cli.js +2 -1
- package/dist/inspector/cli.js.map +1 -1
- package/dist/inspector/cli_bin.js +2 -1
- package/dist/inspector/cli_bin.js.map +1 -1
- package/dist/inspector/examples.json +2 -2
- package/dist/inspector/manifest.json +13 -30
- package/package.json +1 -1
|
@@ -11,17 +11,22 @@ import { Controller } from '@hotwired/stimulus';
|
|
|
11
11
|
* style="position: sticky; top: 0;">…</header>
|
|
12
12
|
*
|
|
13
13
|
* The scroll source is the window by default; inside an overflow container,
|
|
14
|
-
* point `containerSelector` at it (the header usually sits inside it too).
|
|
14
|
+
* point `containerSelector` at it (the header usually sits inside it too). A
|
|
15
|
+
* declaration that cannot be parsed as a selector reads as the window, so a
|
|
16
|
+
* typo costs the container binding rather than the whole header.
|
|
15
17
|
* <!-- [data-header-hidden="true"] { transform: translateY(-100%); } -->
|
|
16
18
|
*
|
|
17
|
-
* Scrolling down past `offset` px sets `data-header-hidden="true"
|
|
18
|
-
* scroll-up
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
19
|
+
* Scrolling down past `offset` px sets `data-header-hidden="true"`, and a
|
|
20
|
+
* scroll-up beyond the `tolerance` jitter guard reveals it again. Within the
|
|
21
|
+
* `offset` zone the header is always revealed, decided ahead of that jitter
|
|
22
|
+
* guard: a header stranded off-screen near the top cannot be scrolled back
|
|
23
|
+
* into view. Focus reaching the header always reveals it, and while focus
|
|
24
|
+
* stays inside the header a scroll-down never hides it — a keyboard user must
|
|
25
|
+
* be able to see where focus went AND keep seeing the element that owns it
|
|
26
|
+
* (WCAG 2.4.7 / 2.4.11).
|
|
23
27
|
*
|
|
24
|
-
* `change` dispatches `{ hidden }
|
|
28
|
+
* `change` dispatches `{ hidden }` on transitions only: the reflection
|
|
29
|
+
* `connect()` performs is the current state rather than a change.
|
|
25
30
|
*
|
|
26
31
|
* @remarks
|
|
27
32
|
* Behavior only — `position: sticky`, the translate animation, and
|
|
@@ -51,6 +56,10 @@ declare class SmartStickyHeaderController extends Controller<HTMLElement> {
|
|
|
51
56
|
containerSelectorValue: string;
|
|
52
57
|
offsetValue: number;
|
|
53
58
|
toleranceValue: number;
|
|
59
|
+
/** Validates `containerSelector` once so connect never parses a selector that throws. */
|
|
60
|
+
containerSelectorValueChanged(): void;
|
|
61
|
+
/** Re-decides when application code (or a Turbo morph) changes `offset` at runtime. */
|
|
62
|
+
offsetValueChanged(): void;
|
|
54
63
|
connect(): void;
|
|
55
64
|
disconnect(): void;
|
|
56
65
|
}
|
|
@@ -1,19 +1,32 @@
|
|
|
1
1
|
import { Controller } from '@hotwired/stimulus';
|
|
2
2
|
|
|
3
3
|
// src/controllers/smart_sticky_header_controller.ts
|
|
4
|
+
var DEFAULT_OFFSET = 80;
|
|
4
5
|
var SmartStickyHeaderController = class extends Controller {
|
|
5
6
|
static values = {
|
|
6
7
|
containerSelector: { type: String, default: "" },
|
|
7
|
-
offset: { type: Number, default:
|
|
8
|
+
offset: { type: Number, default: DEFAULT_OFFSET },
|
|
8
9
|
tolerance: { type: Number, default: 4 }
|
|
9
10
|
};
|
|
10
11
|
static events = ["change"];
|
|
12
|
+
#connected = false;
|
|
11
13
|
#frame = null;
|
|
12
14
|
/** The scroll source resolved at connect — disconnect must unbind the SAME node. */
|
|
13
15
|
#scrollerEl = window;
|
|
16
|
+
/** The validated `containerSelector`, or `""` when the declaration cannot be parsed. */
|
|
17
|
+
#containerSelector = "";
|
|
14
18
|
#lastY = 0;
|
|
15
19
|
/** Last published state, so `change` fires only on transitions. */
|
|
16
20
|
#hidden = null;
|
|
21
|
+
/**
|
|
22
|
+
* The depth that never hides. A declaration that is not a finite number reads
|
|
23
|
+
* as the default, so the comparison path never sees `NaN` — which would
|
|
24
|
+
* answer `false` to every comparison and hide the header inside the very
|
|
25
|
+
* zone the value exists to protect.
|
|
26
|
+
*/
|
|
27
|
+
get #offset() {
|
|
28
|
+
return Number.isFinite(this.offsetValue) ? this.offsetValue : DEFAULT_OFFSET;
|
|
29
|
+
}
|
|
17
30
|
#onScroll = () => {
|
|
18
31
|
if (this.#frame !== null) return;
|
|
19
32
|
this.#frame = requestAnimationFrame(() => {
|
|
@@ -26,15 +39,25 @@ var SmartStickyHeaderController = class extends Controller {
|
|
|
26
39
|
* hold while focus *stays* inside is the `#apply` hide invariant.
|
|
27
40
|
*/
|
|
28
41
|
#onFocusin = () => this.#apply(false);
|
|
42
|
+
/** Validates `containerSelector` once so connect never parses a selector that throws. */
|
|
43
|
+
containerSelectorValueChanged() {
|
|
44
|
+
this.#containerSelector = this.#validSelector(this.containerSelectorValue);
|
|
45
|
+
}
|
|
46
|
+
/** Re-decides when application code (or a Turbo morph) changes `offset` at runtime. */
|
|
47
|
+
offsetValueChanged() {
|
|
48
|
+
if (this.#connected) this.#measure();
|
|
49
|
+
}
|
|
29
50
|
connect() {
|
|
30
51
|
this.#hidden = null;
|
|
31
52
|
this.#scrollerEl = this.#resolveScroller();
|
|
32
53
|
this.#lastY = this.#scrollY;
|
|
33
54
|
this.#scrollerEl.addEventListener("scroll", this.#onScroll, { passive: true });
|
|
34
55
|
this.element.addEventListener("focusin", this.#onFocusin);
|
|
35
|
-
this.#apply(false);
|
|
56
|
+
this.#apply(false, false);
|
|
57
|
+
this.#connected = true;
|
|
36
58
|
}
|
|
37
59
|
disconnect() {
|
|
60
|
+
this.#connected = false;
|
|
38
61
|
this.#scrollerEl.removeEventListener("scroll", this.#onScroll);
|
|
39
62
|
this.element.removeEventListener("focusin", this.#onFocusin);
|
|
40
63
|
if (this.#frame !== null) cancelAnimationFrame(this.#frame);
|
|
@@ -42,32 +65,51 @@ var SmartStickyHeaderController = class extends Controller {
|
|
|
42
65
|
}
|
|
43
66
|
/** Resolves the scroll source: the `containerSelector` match, else the window. */
|
|
44
67
|
#resolveScroller() {
|
|
45
|
-
if (this
|
|
46
|
-
const container = document.querySelector(this
|
|
68
|
+
if (this.#containerSelector) {
|
|
69
|
+
const container = document.querySelector(this.#containerSelector);
|
|
47
70
|
if (container) return container;
|
|
48
71
|
}
|
|
49
72
|
return window;
|
|
50
73
|
}
|
|
74
|
+
/** Returns `declared` when it parses as a selector, and `""` when it does not. */
|
|
75
|
+
#validSelector(declared) {
|
|
76
|
+
if (declared.length > 0) {
|
|
77
|
+
try {
|
|
78
|
+
this.element.matches(declared);
|
|
79
|
+
return declared;
|
|
80
|
+
} catch {
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return "";
|
|
84
|
+
}
|
|
51
85
|
get #scrollY() {
|
|
52
86
|
const scroller = this.#scrollerEl;
|
|
53
87
|
return scroller === window ? window.scrollY : scroller.scrollTop;
|
|
54
88
|
}
|
|
55
89
|
#measure() {
|
|
56
90
|
const y = this.#scrollY;
|
|
91
|
+
if (y <= this.#offset) {
|
|
92
|
+
this.#lastY = y;
|
|
93
|
+
this.#apply(false);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
57
96
|
const delta = y - this.#lastY;
|
|
58
97
|
if (Math.abs(delta) < this.toleranceValue) return;
|
|
59
98
|
this.#lastY = y;
|
|
60
|
-
|
|
61
|
-
else if (delta > 0) this.#apply(true);
|
|
62
|
-
else this.#apply(false);
|
|
99
|
+
this.#apply(delta > 0);
|
|
63
100
|
}
|
|
64
|
-
/**
|
|
65
|
-
|
|
101
|
+
/**
|
|
102
|
+
* Reflects the state onto the hook and emits `change` on transitions.
|
|
103
|
+
*
|
|
104
|
+
* @param notify - whether a transition announces itself. The reflection
|
|
105
|
+
* `connect()` performs is the current state, not a change.
|
|
106
|
+
*/
|
|
107
|
+
#apply(hidden, notify = true) {
|
|
66
108
|
if (hidden && this.element.contains(document.activeElement)) return;
|
|
67
109
|
if (hidden === this.#hidden) return;
|
|
68
110
|
this.#hidden = hidden;
|
|
69
111
|
this.element.setAttribute("data-header-hidden", hidden ? "true" : "false");
|
|
70
|
-
this.dispatch("change", { detail: { hidden } });
|
|
112
|
+
if (notify) this.dispatch("change", { detail: { hidden } });
|
|
71
113
|
}
|
|
72
114
|
};
|
|
73
115
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/controllers/smart_sticky_header_controller.ts"],"names":[],"mappings":"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","file":"smart_sticky_header_controller.js","sourcesContent":["import { Controller } from \"@hotwired/stimulus\";\n\n/**\n * Headless **smart sticky header**: hides the header on scroll-down and\n * reveals it on scroll-up, published as a `data-header-hidden` hook the\n * consumer's CSS translates away (`stimeo--sticky-observer` detects *stuck*,\n * but has no direction sense; this adds it). Core (zero dependencies).\n *\n * Markup contract (identifier: `stimeo--smart-sticky-header`):\n * <header data-controller=\"stimeo--smart-sticky-header\"\n * style=\"position: sticky; top: 0;\">…</header>\n *\n * The scroll source is the window by default; inside an overflow container,\n * point `containerSelector` at it (the header usually sits inside it too).\n * <!-- [data-header-hidden=\"true\"] { transform: translateY(-100%); } -->\n *\n * Scrolling down past `offset` px sets `data-header-hidden=\"true\"`; any\n * scroll-up (beyond the `tolerance` jitter guard) or returning above `offset`\n * reveals it again. Focus reaching the header always reveals it, and while\n * focus stays inside the header a scroll-down never hides it — a keyboard\n * user must be able to see where focus went AND keep seeing the element that\n * owns it (WCAG 2.4.7 / 2.4.11).\n *\n * `change` dispatches `{ hidden }`.\n *\n * @remarks\n * Behavior only — `position: sticky`, the translate animation, and\n * reduced-motion handling are the consumer's CSS (`prefers-reduced-motion`\n * should disable the transition, not the behavior). Scroll work is\n * rAF-throttled; listeners and any pending frame are released on\n * `disconnect()`, and `connect()` resets the transient hook (a Turbo cache\n * snapshot must not restore a hidden header at scroll top).\n */\nexport class SmartStickyHeaderController extends Controller<HTMLElement> {\n static override values = {\n containerSelector: { type: String, default: \"\" },\n offset: { type: Number, default: 80 },\n tolerance: { type: Number, default: 4 },\n };\n static events = [\"change\"] as const;\n\n declare containerSelectorValue: string;\n declare offsetValue: number;\n declare toleranceValue: number;\n\n #frame: number | null = null;\n /** The scroll source resolved at connect — disconnect must unbind the SAME node. */\n #scrollerEl: HTMLElement | Window = window;\n #lastY = 0;\n /** Last published state, so `change` fires only on transitions. */\n #hidden: boolean | null = null;\n\n readonly #onScroll = (): void => {\n if (this.#frame !== null) return;\n this.#frame = requestAnimationFrame(() => {\n this.#frame = null;\n this.#measure();\n });\n };\n\n /**\n * Focus inside a hidden header must reveal it (WCAG 2.4.7 / 2.4.11); the\n * hold while focus *stays* inside is the `#apply` hide invariant.\n */\n readonly #onFocusin = (): void => this.#apply(false);\n\n override connect(): void {\n // The hook is scroll-derived: recompute from the live scroll position\n // instead of trusting a cached snapshot (which may say hidden at y=0).\n this.#hidden = null;\n this.#scrollerEl = this.#resolveScroller();\n this.#lastY = this.#scrollY;\n this.#scrollerEl.addEventListener(\"scroll\", this.#onScroll, { passive: true });\n this.element.addEventListener(\"focusin\", this.#onFocusin);\n this.#apply(false);\n }\n\n override disconnect(): void {\n this.#scrollerEl.removeEventListener(\"scroll\", this.#onScroll);\n this.element.removeEventListener(\"focusin\", this.#onFocusin);\n if (this.#frame !== null) cancelAnimationFrame(this.#frame);\n this.#frame = null;\n }\n\n /** Resolves the scroll source: the `containerSelector` match, else the window. */\n #resolveScroller(): HTMLElement | Window {\n if (this.containerSelectorValue) {\n const container = document.querySelector<HTMLElement>(this.containerSelectorValue);\n if (container) return container;\n }\n return window;\n }\n\n get #scrollY(): number {\n const scroller = this.#scrollerEl;\n // Identity check, not `instanceof Window` — cross-realm/test DOMs fail it.\n return scroller === window ? window.scrollY : (scroller as HTMLElement).scrollTop;\n }\n\n #measure(): void {\n const y = this.#scrollY;\n const delta = y - this.#lastY;\n if (Math.abs(delta) < this.toleranceValue) return;\n this.#lastY = y;\n\n if (y <= this.offsetValue) this.#apply(false);\n else if (delta > 0) this.#apply(true);\n else this.#apply(false);\n }\n\n /** Reflects the state onto the hook and emits `change` on transitions. */\n #apply(hidden: boolean): void {\n // Invariant: a header holding focus is never hidden — `focusin` revealed\n // it, and no transition may slide the focus owner away mid-interaction\n // (WCAG 2.4.7 / 2.4.11). Vetoed here at the single state-transition choke\n // point (not in each caller), so any future hide path — a timer, an\n // action — cannot bypass it. Reveals are never vetoed.\n if (hidden && this.element.contains(document.activeElement)) return;\n if (hidden === this.#hidden) return;\n this.#hidden = hidden;\n this.element.setAttribute(\"data-header-hidden\", hidden ? \"true\" : \"false\");\n this.dispatch(\"change\", { detail: { hidden } });\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/controllers/smart_sticky_header_controller.ts"],"names":[],"mappings":"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","file":"smart_sticky_header_controller.js","sourcesContent":["import { Controller } from \"@hotwired/stimulus\";\n\n/** The depth that never hides, used when `offset` is not a finite number. */\nconst DEFAULT_OFFSET = 80;\n\n/**\n * Headless **smart sticky header**: hides the header on scroll-down and\n * reveals it on scroll-up, published as a `data-header-hidden` hook the\n * consumer's CSS translates away (`stimeo--sticky-observer` detects *stuck*,\n * but has no direction sense; this adds it). Core (zero dependencies).\n *\n * Markup contract (identifier: `stimeo--smart-sticky-header`):\n * <header data-controller=\"stimeo--smart-sticky-header\"\n * style=\"position: sticky; top: 0;\">…</header>\n *\n * The scroll source is the window by default; inside an overflow container,\n * point `containerSelector` at it (the header usually sits inside it too). A\n * declaration that cannot be parsed as a selector reads as the window, so a\n * typo costs the container binding rather than the whole header.\n * <!-- [data-header-hidden=\"true\"] { transform: translateY(-100%); } -->\n *\n * Scrolling down past `offset` px sets `data-header-hidden=\"true\"`, and a\n * scroll-up beyond the `tolerance` jitter guard reveals it again. Within the\n * `offset` zone the header is always revealed, decided ahead of that jitter\n * guard: a header stranded off-screen near the top cannot be scrolled back\n * into view. Focus reaching the header always reveals it, and while focus\n * stays inside the header a scroll-down never hides it — a keyboard user must\n * be able to see where focus went AND keep seeing the element that owns it\n * (WCAG 2.4.7 / 2.4.11).\n *\n * `change` dispatches `{ hidden }` on transitions only: the reflection\n * `connect()` performs is the current state rather than a change.\n *\n * @remarks\n * Behavior only — `position: sticky`, the translate animation, and\n * reduced-motion handling are the consumer's CSS (`prefers-reduced-motion`\n * should disable the transition, not the behavior). Scroll work is\n * rAF-throttled; listeners and any pending frame are released on\n * `disconnect()`, and `connect()` resets the transient hook (a Turbo cache\n * snapshot must not restore a hidden header at scroll top).\n */\nexport class SmartStickyHeaderController extends Controller<HTMLElement> {\n static override values = {\n containerSelector: { type: String, default: \"\" },\n offset: { type: Number, default: DEFAULT_OFFSET },\n tolerance: { type: Number, default: 4 },\n };\n static events = [\"change\"] as const;\n\n declare containerSelectorValue: string;\n declare offsetValue: number;\n declare toleranceValue: number;\n\n #connected = false;\n #frame: number | null = null;\n /** The scroll source resolved at connect — disconnect must unbind the SAME node. */\n #scrollerEl: HTMLElement | Window = window;\n /** The validated `containerSelector`, or `\"\"` when the declaration cannot be parsed. */\n #containerSelector = \"\";\n #lastY = 0;\n /** Last published state, so `change` fires only on transitions. */\n #hidden: boolean | null = null;\n\n /**\n * The depth that never hides. A declaration that is not a finite number reads\n * as the default, so the comparison path never sees `NaN` — which would\n * answer `false` to every comparison and hide the header inside the very\n * zone the value exists to protect.\n */\n get #offset(): number {\n return Number.isFinite(this.offsetValue) ? this.offsetValue : DEFAULT_OFFSET;\n }\n\n readonly #onScroll = (): void => {\n if (this.#frame !== null) return;\n this.#frame = requestAnimationFrame(() => {\n this.#frame = null;\n this.#measure();\n });\n };\n\n /**\n * Focus inside a hidden header must reveal it (WCAG 2.4.7 / 2.4.11); the\n * hold while focus *stays* inside is the `#apply` hide invariant.\n */\n readonly #onFocusin = (): void => this.#apply(false);\n\n /** Validates `containerSelector` once so connect never parses a selector that throws. */\n containerSelectorValueChanged(): void {\n this.#containerSelector = this.#validSelector(this.containerSelectorValue);\n }\n\n /** Re-decides when application code (or a Turbo morph) changes `offset` at runtime. */\n offsetValueChanged(): void {\n if (this.#connected) this.#measure();\n }\n\n override connect(): void {\n // The hook is scroll-derived: recompute from the live scroll position\n // instead of trusting a cached snapshot (which may say hidden at y=0).\n this.#hidden = null;\n this.#scrollerEl = this.#resolveScroller();\n this.#lastY = this.#scrollY;\n this.#scrollerEl.addEventListener(\"scroll\", this.#onScroll, { passive: true });\n this.element.addEventListener(\"focusin\", this.#onFocusin);\n this.#apply(false, false);\n this.#connected = true;\n }\n\n override disconnect(): void {\n this.#connected = false;\n this.#scrollerEl.removeEventListener(\"scroll\", this.#onScroll);\n this.element.removeEventListener(\"focusin\", this.#onFocusin);\n if (this.#frame !== null) cancelAnimationFrame(this.#frame);\n this.#frame = null;\n }\n\n /** Resolves the scroll source: the `containerSelector` match, else the window. */\n #resolveScroller(): HTMLElement | Window {\n if (this.#containerSelector) {\n const container = document.querySelector<HTMLElement>(this.#containerSelector);\n if (container) return container;\n }\n return window;\n }\n\n /** Returns `declared` when it parses as a selector, and `\"\"` when it does not. */\n #validSelector(declared: string): string {\n if (declared.length > 0) {\n try {\n this.element.matches(declared);\n return declared;\n } catch {\n // Unparsable selector: fall through to the default below.\n }\n }\n return \"\";\n }\n\n get #scrollY(): number {\n const scroller = this.#scrollerEl;\n // Identity check, not `instanceof Window` — cross-realm/test DOMs fail it.\n return scroller === window ? window.scrollY : (scroller as HTMLElement).scrollTop;\n }\n\n #measure(): void {\n const y = this.#scrollY;\n // The offset zone decides before the jitter guard: a move small enough to\n // be jitter can still be the one that re-enters the zone, and a header\n // left hidden there cannot be scrolled back into view.\n if (y <= this.#offset) {\n this.#lastY = y;\n this.#apply(false);\n return;\n }\n\n const delta = y - this.#lastY;\n if (Math.abs(delta) < this.toleranceValue) return;\n this.#lastY = y;\n this.#apply(delta > 0);\n }\n\n /**\n * Reflects the state onto the hook and emits `change` on transitions.\n *\n * @param notify - whether a transition announces itself. The reflection\n * `connect()` performs is the current state, not a change.\n */\n #apply(hidden: boolean, notify = true): void {\n // Invariant: a header holding focus is never hidden — `focusin` revealed\n // it, and no transition may slide the focus owner away mid-interaction\n // (WCAG 2.4.7 / 2.4.11). Vetoed here at the single state-transition choke\n // point (not in each caller), so any future hide path — a timer, an\n // action — cannot bypass it. Reveals are never vetoed.\n if (hidden && this.element.contains(document.activeElement)) return;\n if (hidden === this.#hidden) return;\n this.#hidden = hidden;\n this.element.setAttribute(\"data-header-hidden\", hidden ? \"true\" : \"false\");\n if (notify) this.dispatch(\"change\", { detail: { hidden } });\n }\n}\n"]}
|
|
@@ -7,7 +7,7 @@ import { Controller } from '@hotwired/stimulus';
|
|
|
7
7
|
* layer keeps its job: `pointer-drag` (on every item) emits the normalized drag
|
|
8
8
|
* signal with its built-in keyboard alternative, `roving` (on the list) keeps
|
|
9
9
|
* the handles a single Tab stop, and this controller interprets the signal —
|
|
10
|
-
* live-reordering the DOM,
|
|
10
|
+
* live-reordering the DOM, handing each step to the page's shared announcer,
|
|
11
11
|
* and reporting the final `reorder`. No dedicated APG pattern exists for
|
|
12
12
|
* drag-and-drop; the keyboard model (grab → arrows → drop / Escape) comes from
|
|
13
13
|
* `pointer-drag` and the announcements make it non-visually trackable
|
|
@@ -27,7 +27,6 @@ import { Controller } from '@hotwired/stimulus';
|
|
|
27
27
|
* </li>
|
|
28
28
|
* …
|
|
29
29
|
* </ul>
|
|
30
|
-
* <span role="status" data-stimeo--sortable-target="status"></span>
|
|
31
30
|
* </div>
|
|
32
31
|
*
|
|
33
32
|
* The composed values must follow the sort axis: roving's `orientation`
|
|
@@ -41,10 +40,11 @@ import { Controller } from '@hotwired/stimulus';
|
|
|
41
40
|
* `dir="rtl"` reverses both, since DOM order then runs right-to-left while
|
|
42
41
|
* `pointer-drag` reports physical coordinates. Dropping dispatches
|
|
43
42
|
* `reorder` (`{ item, from, to }`, zero-based) when the position changed;
|
|
44
|
-
* Escape / `pointercancel` restores the pickup position. Every step is
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
43
|
+
* Escape / `pointercancel` restores the pickup position. Every step is handed to
|
|
44
|
+
* the page's shared `stimeo--announcer` as the consumer's own wording —
|
|
45
|
+
* `announceGrabbedText` / `announceMovedText` / `announceDroppedText` /
|
|
46
|
+
* `announceCanceledText`, with `{name}` / `{position}` / `{total}` placeholders —
|
|
47
|
+
* and an unset one announces nothing.
|
|
48
48
|
*
|
|
49
49
|
* @remarks
|
|
50
50
|
* Behavior only — the ghost/placeholder/drop-hint visuals are the consumer's
|
|
@@ -67,16 +67,46 @@ declare class SortableController extends Controller<HTMLElement> {
|
|
|
67
67
|
type: StringConstructor;
|
|
68
68
|
default: string;
|
|
69
69
|
};
|
|
70
|
+
announceGrabbedText: {
|
|
71
|
+
type: StringConstructor;
|
|
72
|
+
default: string;
|
|
73
|
+
};
|
|
74
|
+
announceMovedText: {
|
|
75
|
+
type: StringConstructor;
|
|
76
|
+
default: string;
|
|
77
|
+
};
|
|
78
|
+
announceDroppedText: {
|
|
79
|
+
type: StringConstructor;
|
|
80
|
+
default: string;
|
|
81
|
+
};
|
|
82
|
+
announceCanceledText: {
|
|
83
|
+
type: StringConstructor;
|
|
84
|
+
default: string;
|
|
85
|
+
};
|
|
70
86
|
};
|
|
71
87
|
static events: readonly ["reorder"];
|
|
72
88
|
readonly hasListTarget: boolean;
|
|
73
89
|
readonly listTarget: HTMLElement;
|
|
74
90
|
readonly itemTargets: HTMLElement[];
|
|
75
|
-
readonly hasStatusTarget: boolean;
|
|
76
|
-
readonly statusTarget: HTMLElement;
|
|
77
91
|
orientationValue: string;
|
|
92
|
+
announceGrabbedTextValue: string;
|
|
93
|
+
announceMovedTextValue: string;
|
|
94
|
+
announceDroppedTextValue: string;
|
|
95
|
+
announceCanceledTextValue: string;
|
|
78
96
|
connect(): void;
|
|
79
97
|
disconnect(): void;
|
|
98
|
+
/**
|
|
99
|
+
* Ends a session whose item left the item set.
|
|
100
|
+
*
|
|
101
|
+
* The controller's own reorder detaches and reattaches the item inside one
|
|
102
|
+
* mutation batch, so the loss is only real once the batch has settled — the
|
|
103
|
+
* check therefore runs a microtask later and asks whether the item is a target
|
|
104
|
+
* again. Without it a deleted row (a broadcast that drops it from the board)
|
|
105
|
+
* or a morph that strips the item's target attribute would hold the
|
|
106
|
+
* one-at-a-time session for the rest of the page's life, with the root hook
|
|
107
|
+
* stuck on and every later grab refused with no way out.
|
|
108
|
+
*/
|
|
109
|
+
itemTargetDisconnected(item: HTMLElement): void;
|
|
80
110
|
}
|
|
81
111
|
|
|
82
112
|
export { SortableController };
|