stimeo-ui 0.12.0 → 0.14.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +71 -0
- data/dist/cable/index.js +438 -152
- data/dist/controllers/calendar_controller.js +34 -2
- data/dist/controllers/carousel_controller.js +9 -7
- data/dist/controllers/command_palette_controller.js +2 -2
- data/dist/controllers/conditional_fields_controller.js +7 -1
- data/dist/controllers/currency_input_controller.js +68 -23
- data/dist/controllers/date_range_picker_controller.js +34 -10
- data/dist/controllers/direct_upload_controller.js +21 -10
- data/dist/controllers/drawer_controller.js +2 -2
- data/dist/controllers/form_field_controller.js +7 -1
- data/dist/controllers/input_mask_controller.js +33 -12
- data/dist/controllers/intersection_controller.js +10 -5
- data/dist/controllers/lazy_frame_controller.js +10 -5
- data/dist/controllers/local_time_controller.js +34 -7
- data/dist/controllers/masonry_controller.js +1 -1
- data/dist/controllers/menu_controller.js +10 -2
- data/dist/controllers/menubar_controller.js +10 -2
- data/dist/controllers/navigation_menu_controller.js +8 -2
- data/dist/controllers/optimistic_controller.js +141 -20
- data/dist/controllers/otp_controller.js +23 -10
- data/dist/controllers/overflow_menu_controller.js +10 -1
- data/dist/controllers/pointer_drag_controller.js +10 -3
- data/dist/controllers/portal_controller.js +21 -10
- data/dist/controllers/radio_group_controller.js +11 -3
- data/dist/controllers/relative_time_controller.js +31 -5
- data/dist/controllers/reset_before_cache_controller.js +23 -10
- data/dist/controllers/resizable_controller.js +7 -2
- data/dist/controllers/roving_controller.js +7 -3
- data/dist/controllers/scroll_visibility_controller.js +22 -13
- data/dist/controllers/scrollspy_controller.js +11 -6
- data/dist/controllers/smart_sticky_header_controller.js +23 -12
- data/dist/controllers/sticky_observer_controller.js +10 -5
- data/dist/controllers/theme_controller.js +23 -13
- data/dist/controllers/toast_controller.js +1 -1
- data/dist/controllers/toggle_group_controller.js +11 -3
- data/dist/controllers/toolbar_controller.js +7 -3
- data/dist/index.js +259 -202
- data/lib/stimeo/ui/version.rb +1 -1
- metadata +2 -2
data/dist/index.js
CHANGED
|
@@ -1853,6 +1853,36 @@ var BulkSelectController = class extends Controller {
|
|
|
1853
1853
|
}
|
|
1854
1854
|
};
|
|
1855
1855
|
|
|
1856
|
+
// src/utils/intl_format.ts
|
|
1857
|
+
var formatters = /* @__PURE__ */ new WeakMap();
|
|
1858
|
+
function intlFormatter(factory, locale, options, fallbackLocale) {
|
|
1859
|
+
const cache = cacheFor(factory);
|
|
1860
|
+
const key = cacheKey(locale, options, fallbackLocale);
|
|
1861
|
+
if (cache.has(key)) return cache.get(key);
|
|
1862
|
+
const formatter = construct(factory, locale, options, fallbackLocale);
|
|
1863
|
+
cache.set(key, formatter);
|
|
1864
|
+
return formatter;
|
|
1865
|
+
}
|
|
1866
|
+
function cacheFor(factory) {
|
|
1867
|
+
const existing = formatters.get(factory);
|
|
1868
|
+
if (existing) return existing;
|
|
1869
|
+
const created = /* @__PURE__ */ new Map();
|
|
1870
|
+
formatters.set(factory, created);
|
|
1871
|
+
return created;
|
|
1872
|
+
}
|
|
1873
|
+
function cacheKey(locale, options, fallbackLocale) {
|
|
1874
|
+
return JSON.stringify([locale, options, fallbackLocale]);
|
|
1875
|
+
}
|
|
1876
|
+
function construct(factory, locale, options, fallbackLocale) {
|
|
1877
|
+
try {
|
|
1878
|
+
return new factory(locale, options);
|
|
1879
|
+
} catch (error) {
|
|
1880
|
+
if (!(error instanceof RangeError)) throw error;
|
|
1881
|
+
if (fallbackLocale === void 0) return null;
|
|
1882
|
+
return new factory(fallbackLocale, options);
|
|
1883
|
+
}
|
|
1884
|
+
}
|
|
1885
|
+
|
|
1856
1886
|
// src/utils/dates.ts
|
|
1857
1887
|
function toISODateString(date) {
|
|
1858
1888
|
const year = date.getFullYear();
|
|
@@ -1886,6 +1916,10 @@ function parseISOMonthString(monthStr) {
|
|
|
1886
1916
|
function toISOMonthString(date) {
|
|
1887
1917
|
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}`;
|
|
1888
1918
|
}
|
|
1919
|
+
var MONTH_LABEL_OPTIONS = { month: "long", year: "numeric" };
|
|
1920
|
+
function monthLabelFormatter(locale) {
|
|
1921
|
+
return intlFormatter(Intl.DateTimeFormat, locale, MONTH_LABEL_OPTIONS, "en");
|
|
1922
|
+
}
|
|
1889
1923
|
|
|
1890
1924
|
// src/controllers/calendar_controller.ts
|
|
1891
1925
|
var OWNED_DISABLED = "data-stimeo--calendar-owns-disabled";
|
|
@@ -2070,8 +2104,7 @@ var CalendarController = class extends Controller {
|
|
|
2070
2104
|
const month = monthStart.getMonth() + 1;
|
|
2071
2105
|
if (this.hasLabelTarget) {
|
|
2072
2106
|
const lang = document.documentElement.lang || "en";
|
|
2073
|
-
|
|
2074
|
-
this.labelTarget.textContent = formatter.format(monthStart);
|
|
2107
|
+
this.labelTarget.textContent = monthLabelFormatter(lang).format(monthStart);
|
|
2075
2108
|
}
|
|
2076
2109
|
const days = this.#calculateGridDays(year, month);
|
|
2077
2110
|
const dayElements = this.dayTargets;
|
|
@@ -2238,6 +2271,15 @@ var CalendarController = class extends Controller {
|
|
|
2238
2271
|
}
|
|
2239
2272
|
};
|
|
2240
2273
|
|
|
2274
|
+
// src/utils/event_owner.ts
|
|
2275
|
+
function ownerIndex(candidates, node) {
|
|
2276
|
+
if (!(node instanceof Node)) return -1;
|
|
2277
|
+
return candidates.findIndex((candidate) => candidate.contains(node));
|
|
2278
|
+
}
|
|
2279
|
+
function ownerOf(candidates, node) {
|
|
2280
|
+
return candidates[ownerIndex(candidates, node)] ?? null;
|
|
2281
|
+
}
|
|
2282
|
+
|
|
2241
2283
|
// src/utils/reduced_motion.ts
|
|
2242
2284
|
function prefersReducedMotion() {
|
|
2243
2285
|
return typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
@@ -2323,7 +2365,7 @@ var CarouselController = class extends Controller {
|
|
|
2323
2365
|
#handledEvents = /* @__PURE__ */ new WeakSet();
|
|
2324
2366
|
/**
|
|
2325
2367
|
* Whether `connect()` has run. Scheduling is already inert outside that window
|
|
2326
|
-
* (
|
|
2368
|
+
* (`MicrotaskCoalescer`), so this gates the Value callbacks Stimulus
|
|
2327
2369
|
* delivers ahead of `connect()`.
|
|
2328
2370
|
*/
|
|
2329
2371
|
#connected = false;
|
|
@@ -2581,9 +2623,7 @@ var CarouselController = class extends Controller {
|
|
|
2581
2623
|
}
|
|
2582
2624
|
/** Position of the picker that is or contains `node`, or `-1` when none does. */
|
|
2583
2625
|
#pickerIndexFor(node) {
|
|
2584
|
-
return this.pickerTargets
|
|
2585
|
-
(picker) => node instanceof Node && (picker === node || picker.contains(node))
|
|
2586
|
-
);
|
|
2626
|
+
return ownerIndex(this.pickerTargets, node);
|
|
2587
2627
|
}
|
|
2588
2628
|
/** Whether a focus transition lands on another control of this same carousel. */
|
|
2589
2629
|
#focusStaysInside(event) {
|
|
@@ -2802,9 +2842,7 @@ function hasModifier(event) {
|
|
|
2802
2842
|
return event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
|
|
2803
2843
|
}
|
|
2804
2844
|
function hits(elements, node) {
|
|
2805
|
-
return elements
|
|
2806
|
-
(element) => node instanceof Node && (element === node || element.contains(node))
|
|
2807
|
-
);
|
|
2845
|
+
return ownerIndex(elements, node) !== -1;
|
|
2808
2846
|
}
|
|
2809
2847
|
function setAttributeIfChanged(element, name, value) {
|
|
2810
2848
|
if (element.getAttribute(name) !== value) element.setAttribute(name, value);
|
|
@@ -4383,7 +4421,7 @@ var CommandPaletteController = class _CommandPaletteController extends Controlle
|
|
|
4383
4421
|
* re-deriving from the declarative `open` Value (which would slam a user-opened
|
|
4384
4422
|
* palette shut). The `open` Value only seeds the initial state of a genuinely
|
|
4385
4423
|
* fresh render. We normalize to a clean closed baseline first so {@link open}
|
|
4386
|
-
* runs its full setup — the
|
|
4424
|
+
* runs its full setup — the `FocusTrap` is a fresh instance after a
|
|
4387
4425
|
* reconnect and must be re-activated.
|
|
4388
4426
|
*/
|
|
4389
4427
|
connect() {
|
|
@@ -4488,7 +4526,7 @@ var CommandPaletteController = class _CommandPaletteController extends Controlle
|
|
|
4488
4526
|
}
|
|
4489
4527
|
/**
|
|
4490
4528
|
* Combobox navigation keys (arrows / Home / End / Enter), bound to the input.
|
|
4491
|
-
* `Tab` (focus trap) and `Escape` (close) are owned by the
|
|
4529
|
+
* `Tab` (focus trap) and `Escape` (close) are owned by the shared `FocusTrap` at
|
|
4492
4530
|
* the document level, so they work no matter which element inside the dialog has
|
|
4493
4531
|
* focus — not only the input.
|
|
4494
4532
|
*/
|
|
@@ -5060,7 +5098,7 @@ var ConditionalFieldsController = class extends Controller {
|
|
|
5060
5098
|
}
|
|
5061
5099
|
/** Whether an authored mutation target belongs to a trigger, region, or managed control. */
|
|
5062
5100
|
#elementAffectsState(target, triggers, regions) {
|
|
5063
|
-
return triggers
|
|
5101
|
+
return ownerIndex(triggers, target) !== -1 || ownerIndex(regions, target) !== -1;
|
|
5064
5102
|
}
|
|
5065
5103
|
/** Whether a form owns at least one current trigger, including `form=` associations. */
|
|
5066
5104
|
#hasTriggerOwnedBy(form) {
|
|
@@ -5920,37 +5958,52 @@ var CurrencyInputController = class extends Controller {
|
|
|
5920
5958
|
* formatters from the validated set.
|
|
5921
5959
|
*/
|
|
5922
5960
|
#revalidate() {
|
|
5923
|
-
|
|
5924
|
-
|
|
5925
|
-
new Intl.NumberFormat(this.localeValue);
|
|
5926
|
-
this.#locale = this.localeValue;
|
|
5927
|
-
} catch {
|
|
5928
|
-
}
|
|
5961
|
+
const declaredLocale = intlFormatter(Intl.NumberFormat, this.localeValue, {});
|
|
5962
|
+
this.#locale = declaredLocale === null ? "en-US" : this.localeValue;
|
|
5929
5963
|
const precision = this.precisionValue;
|
|
5930
5964
|
this.#precision = Number.isInteger(precision) && precision >= 0 && precision <= 100 ? precision : 2;
|
|
5931
5965
|
this.#currency = "";
|
|
5932
5966
|
if (this.currencyValue !== "") {
|
|
5933
|
-
|
|
5934
|
-
|
|
5935
|
-
|
|
5936
|
-
}
|
|
5937
|
-
|
|
5967
|
+
const declaredCurrency = intlFormatter(Intl.NumberFormat, this.#locale, {
|
|
5968
|
+
style: "currency",
|
|
5969
|
+
currency: this.currencyValue
|
|
5970
|
+
});
|
|
5971
|
+
if (declaredCurrency !== null) this.#currency = this.currencyValue;
|
|
5938
5972
|
}
|
|
5939
|
-
this.#grouping =
|
|
5940
|
-
|
|
5941
|
-
|
|
5942
|
-
|
|
5943
|
-
|
|
5944
|
-
|
|
5945
|
-
|
|
5946
|
-
|
|
5947
|
-
|
|
5948
|
-
|
|
5949
|
-
|
|
5973
|
+
this.#grouping = intlFormatter(
|
|
5974
|
+
Intl.NumberFormat,
|
|
5975
|
+
this.#locale,
|
|
5976
|
+
{ useGrouping: true, maximumFractionDigits: 0 },
|
|
5977
|
+
this.#locale
|
|
5978
|
+
);
|
|
5979
|
+
this.#fixed = intlFormatter(
|
|
5980
|
+
Intl.NumberFormat,
|
|
5981
|
+
this.#locale,
|
|
5982
|
+
{
|
|
5983
|
+
useGrouping: true,
|
|
5984
|
+
minimumFractionDigits: this.#precision,
|
|
5985
|
+
maximumFractionDigits: this.#precision
|
|
5986
|
+
},
|
|
5987
|
+
this.#locale
|
|
5988
|
+
);
|
|
5989
|
+
this.#accessible = this.#currency ? intlFormatter(
|
|
5990
|
+
Intl.NumberFormat,
|
|
5991
|
+
this.#locale,
|
|
5992
|
+
{ style: "currency", currency: this.#currency },
|
|
5993
|
+
this.#locale
|
|
5994
|
+
) : this.#fixed;
|
|
5995
|
+
const parts = intlFormatter(Intl.NumberFormat, this.#locale, {}, this.#locale).formatToParts(
|
|
5996
|
+
11111.1
|
|
5997
|
+
);
|
|
5950
5998
|
this.#group = parts.find((p) => p.type === "group")?.value ?? ",";
|
|
5951
5999
|
this.#decimal = parts.find((p) => p.type === "decimal")?.value ?? ".";
|
|
5952
6000
|
this.#digits.clear();
|
|
5953
|
-
const digitFormatter =
|
|
6001
|
+
const digitFormatter = intlFormatter(
|
|
6002
|
+
Intl.NumberFormat,
|
|
6003
|
+
this.#locale,
|
|
6004
|
+
{ useGrouping: false },
|
|
6005
|
+
this.#locale
|
|
6006
|
+
);
|
|
5954
6007
|
for (let i = 0; i <= 9; i++) {
|
|
5955
6008
|
const digit = digitFormatter.format(i);
|
|
5956
6009
|
if (digit !== String(i)) this.#digits.set(digit, String(i));
|
|
@@ -6566,7 +6619,7 @@ var DateRangePickerController = class extends Controller {
|
|
|
6566
6619
|
if (this.#previewDate && !this.#isSelectable(this.#previewDate)) this.#previewDate = "";
|
|
6567
6620
|
if (this.hasMonthLabelTarget) {
|
|
6568
6621
|
const lang = document.documentElement.lang || "en";
|
|
6569
|
-
const formatter =
|
|
6622
|
+
const formatter = monthLabelFormatter(lang);
|
|
6570
6623
|
this.monthLabelTarget.textContent = formatter.format(new Date(year, month - 1, 1));
|
|
6571
6624
|
}
|
|
6572
6625
|
const [rangeStart, rangeEnd] = this.#visualRange();
|
|
@@ -6721,15 +6774,6 @@ function normalizeISO(value) {
|
|
|
6721
6774
|
function orderRange(start, end) {
|
|
6722
6775
|
return start && end && end < start ? [end, start] : [start, end];
|
|
6723
6776
|
}
|
|
6724
|
-
function monthFormatter(locale) {
|
|
6725
|
-
const options = { month: "long", year: "numeric" };
|
|
6726
|
-
try {
|
|
6727
|
-
return new Intl.DateTimeFormat(locale, options);
|
|
6728
|
-
} catch (error) {
|
|
6729
|
-
if (!(error instanceof RangeError)) throw error;
|
|
6730
|
-
return new Intl.DateTimeFormat("en", options);
|
|
6731
|
-
}
|
|
6732
|
-
}
|
|
6733
6777
|
function computePreset(name) {
|
|
6734
6778
|
const today = /* @__PURE__ */ new Date();
|
|
6735
6779
|
const todayStr = toISODateString(today);
|
|
@@ -6791,6 +6835,43 @@ var DialogController = class extends Controller {
|
|
|
6791
6835
|
return this.hasDialogTarget && !this.dialogTarget.hidden;
|
|
6792
6836
|
}
|
|
6793
6837
|
};
|
|
6838
|
+
|
|
6839
|
+
// src/utils/declared_value.ts
|
|
6840
|
+
function parseDeclared(raw, parse, fallback) {
|
|
6841
|
+
try {
|
|
6842
|
+
return parse(raw);
|
|
6843
|
+
} catch {
|
|
6844
|
+
return fallback;
|
|
6845
|
+
}
|
|
6846
|
+
}
|
|
6847
|
+
function validSelector(element, raw, fallback) {
|
|
6848
|
+
if (raw.length === 0) return fallback;
|
|
6849
|
+
return parseDeclared(
|
|
6850
|
+
raw,
|
|
6851
|
+
(selector) => {
|
|
6852
|
+
element.matches(selector);
|
|
6853
|
+
return selector;
|
|
6854
|
+
},
|
|
6855
|
+
fallback
|
|
6856
|
+
);
|
|
6857
|
+
}
|
|
6858
|
+
function compileRegExp(source, anchor = "none") {
|
|
6859
|
+
return parseDeclared(
|
|
6860
|
+
source,
|
|
6861
|
+
(text) => {
|
|
6862
|
+
const bare = new RegExp(text);
|
|
6863
|
+
return anchor === "exact" ? new RegExp(`^(?:${text})$`) : bare;
|
|
6864
|
+
},
|
|
6865
|
+
null
|
|
6866
|
+
);
|
|
6867
|
+
}
|
|
6868
|
+
function parseJsonObject(raw) {
|
|
6869
|
+
const parsed = parseDeclared(raw, (text) => JSON.parse(text), null);
|
|
6870
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
6871
|
+
return parsed;
|
|
6872
|
+
}
|
|
6873
|
+
|
|
6874
|
+
// src/controllers/direct_upload_controller.ts
|
|
6794
6875
|
var REMOVE_DELAY = 4e3;
|
|
6795
6876
|
var DirectUploadController = class extends Controller {
|
|
6796
6877
|
static targets = ["list", "row"];
|
|
@@ -6845,16 +6926,7 @@ var DirectUploadController = class extends Controller {
|
|
|
6845
6926
|
}
|
|
6846
6927
|
/** Validates `scope` once so the per-event path never parses or throws. */
|
|
6847
6928
|
scopeValueChanged() {
|
|
6848
|
-
|
|
6849
|
-
if (selector.length > 0) {
|
|
6850
|
-
try {
|
|
6851
|
-
this.element.matches(selector);
|
|
6852
|
-
this.#scopeSelector = selector;
|
|
6853
|
-
return;
|
|
6854
|
-
} catch {
|
|
6855
|
-
}
|
|
6856
|
-
}
|
|
6857
|
-
this.#scopeSelector = "";
|
|
6929
|
+
this.#scopeSelector = validSelector(this.element, this.scopeValue, "");
|
|
6858
6930
|
}
|
|
6859
6931
|
/** Updates a row's progress and the aggregate, emitting `progress`. */
|
|
6860
6932
|
#updateProgress(id, percent, name) {
|
|
@@ -7411,7 +7483,7 @@ var DrawerController = class extends Controller {
|
|
|
7411
7483
|
* rather than being re-derived from the declarative `open` Value (which would
|
|
7412
7484
|
* close a user-opened drawer). The `open` Value only seeds a genuinely fresh
|
|
7413
7485
|
* render. We normalize to a clean closed baseline first so {@link open} runs its
|
|
7414
|
-
* full reveal + trap activation — the
|
|
7486
|
+
* full reveal + trap activation — the `FocusTrap` is inactive after a
|
|
7415
7487
|
* disconnect and must be re-activated.
|
|
7416
7488
|
*/
|
|
7417
7489
|
connect() {
|
|
@@ -7544,7 +7616,7 @@ var DrawerController = class extends Controller {
|
|
|
7544
7616
|
* Runs once the close transition has finished: applies `hidden` to the panel
|
|
7545
7617
|
* and overlay, then reverts the modal side effects (scroll lock, background
|
|
7546
7618
|
* `inert`, keydown listener) and restores focus to the opener. Deferring the
|
|
7547
|
-
*
|
|
7619
|
+
* `FocusTrap` teardown to here — rather than at {@link close} time — keeps
|
|
7548
7620
|
* the background unreachable and focus trapped for the whole exit animation.
|
|
7549
7621
|
*/
|
|
7550
7622
|
#applyHidden(panel) {
|
|
@@ -9089,7 +9161,7 @@ var FormFieldController = class _FormFieldController extends Controller {
|
|
|
9089
9161
|
return this.errorTargets.includes(target);
|
|
9090
9162
|
return record.attributeName === "id" && [...this.descriptionTargets, ...this.errorTargets].includes(target);
|
|
9091
9163
|
}
|
|
9092
|
-
return this.errorTargets
|
|
9164
|
+
return ownerIndex(this.errorTargets, target) !== -1;
|
|
9093
9165
|
}
|
|
9094
9166
|
/** Returns borrowed control ARIA before Turbo snapshots the page. */
|
|
9095
9167
|
#rewindForCache() {
|
|
@@ -10009,22 +10081,19 @@ function applyMask(value, pattern, tokens) {
|
|
|
10009
10081
|
}
|
|
10010
10082
|
function compileTokens(declaration) {
|
|
10011
10083
|
const map = /* @__PURE__ */ new Map();
|
|
10012
|
-
for (const [key, source] of Object.entries(
|
|
10013
|
-
|
|
10014
|
-
|
|
10015
|
-
|
|
10016
|
-
|
|
10084
|
+
for (const [key, source] of Object.entries(DEFAULT_TOKENS)) {
|
|
10085
|
+
const compiled = compileRegExp(source, "exact");
|
|
10086
|
+
if (compiled) map.set(key, compiled);
|
|
10087
|
+
}
|
|
10088
|
+
for (const [key, source] of Object.entries(parseTokens(declaration))) {
|
|
10089
|
+
const compiled = compileRegExp(source, "exact");
|
|
10090
|
+
if (compiled) map.set(key, compiled);
|
|
10017
10091
|
}
|
|
10018
10092
|
return map;
|
|
10019
10093
|
}
|
|
10020
10094
|
function parseTokens(declaration) {
|
|
10021
|
-
|
|
10022
|
-
|
|
10023
|
-
parsed = JSON.parse(declaration);
|
|
10024
|
-
} catch {
|
|
10025
|
-
return {};
|
|
10026
|
-
}
|
|
10027
|
-
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return {};
|
|
10095
|
+
const parsed = parseJsonObject(declaration);
|
|
10096
|
+
if (parsed === null) return {};
|
|
10028
10097
|
const tokens = {};
|
|
10029
10098
|
for (const [key, source] of Object.entries(parsed)) {
|
|
10030
10099
|
if (typeof source === "string") tokens[key] = source;
|
|
@@ -10236,11 +10305,7 @@ function isBeforeRootStart(entry) {
|
|
|
10236
10305
|
}
|
|
10237
10306
|
function queryRoot(selector) {
|
|
10238
10307
|
if (!selector) return null;
|
|
10239
|
-
|
|
10240
|
-
return document.querySelector(selector);
|
|
10241
|
-
} catch {
|
|
10242
|
-
}
|
|
10243
|
-
return null;
|
|
10308
|
+
return parseDeclared(selector, (raw) => document.querySelector(raw), null);
|
|
10244
10309
|
}
|
|
10245
10310
|
var IntersectionWatcher = class {
|
|
10246
10311
|
#onEntries;
|
|
@@ -11071,8 +11136,9 @@ var LocalTimeController = class extends Controller {
|
|
|
11071
11136
|
/**
|
|
11072
11137
|
* Formats `date` with `Intl.DateTimeFormat`, including each style only when it
|
|
11073
11138
|
* is a valid keyword (so a consumer can show date-only or time-only by clearing
|
|
11074
|
-
* the other). Returns `null` when neither style is usable or
|
|
11075
|
-
* the caller can leave the
|
|
11139
|
+
* the other). Returns `null` when neither style is usable or the declaration
|
|
11140
|
+
* names a locale or time zone `Intl` rejects, so the caller can leave the
|
|
11141
|
+
* authored text untouched.
|
|
11076
11142
|
*/
|
|
11077
11143
|
#applyFormat(date, dateStyle, timeStyle) {
|
|
11078
11144
|
const options = {
|
|
@@ -11081,11 +11147,8 @@ var LocalTimeController = class extends Controller {
|
|
|
11081
11147
|
};
|
|
11082
11148
|
if (options.dateStyle === void 0 && options.timeStyle === void 0) return null;
|
|
11083
11149
|
if (this.timeZoneValue.length > 0) options.timeZone = this.timeZoneValue;
|
|
11084
|
-
|
|
11085
|
-
|
|
11086
|
-
} catch {
|
|
11087
|
-
return null;
|
|
11088
|
-
}
|
|
11150
|
+
const formatter = intlFormatter(Intl.DateTimeFormat, this.#locale, options);
|
|
11151
|
+
return formatter === null ? null : formatter.format(date);
|
|
11089
11152
|
}
|
|
11090
11153
|
/** Locale precedence: the value, then the nearest `lang` up the ancestor chain. */
|
|
11091
11154
|
get #locale() {
|
|
@@ -11153,7 +11216,7 @@ var MasonryController = class extends Controller {
|
|
|
11153
11216
|
*
|
|
11154
11217
|
* The removal is queued rather than immediate because teardown reports every
|
|
11155
11218
|
* target as disconnected: doing it here would strip the whole grid just before
|
|
11156
|
-
* a Turbo snapshot is taken.
|
|
11219
|
+
* a Turbo snapshot is taken. The coalescer's `cancel` drops the queue
|
|
11157
11220
|
* with the pass, so only a genuine target change reaches it.
|
|
11158
11221
|
*/
|
|
11159
11222
|
itemTargetDisconnected(item) {
|
|
@@ -11434,8 +11497,7 @@ var MenuController = class extends Controller {
|
|
|
11434
11497
|
};
|
|
11435
11498
|
/** The item target that is, or contains, `node`; `null` when it is neither. */
|
|
11436
11499
|
#itemFrom(node) {
|
|
11437
|
-
|
|
11438
|
-
return this.itemTargets.find((item) => item === node || item.contains(node)) ?? null;
|
|
11500
|
+
return ownerOf(this.itemTargets, node);
|
|
11439
11501
|
}
|
|
11440
11502
|
/**
|
|
11441
11503
|
* First look at every click inside the controller, and the only point at which
|
|
@@ -11811,8 +11873,7 @@ var MenubarController = class extends Controller {
|
|
|
11811
11873
|
* menu without moving focus.
|
|
11812
11874
|
*/
|
|
11813
11875
|
#dismissOpenMenu() {
|
|
11814
|
-
const
|
|
11815
|
-
const menu = this.menuTargets.find((candidate) => candidate.contains(active));
|
|
11876
|
+
const menu = ownerOf(this.menuTargets, document.activeElement);
|
|
11816
11877
|
if (menu) {
|
|
11817
11878
|
const top = this.#topFor(menu);
|
|
11818
11879
|
this.#closeMenu(top);
|
|
@@ -13226,7 +13287,7 @@ var NavigationMenuController = class extends Controller {
|
|
|
13226
13287
|
*/
|
|
13227
13288
|
#onPointerLeave = (event) => {
|
|
13228
13289
|
const next = event instanceof MouseEvent ? event.relatedTarget : null;
|
|
13229
|
-
if (
|
|
13290
|
+
if (ownerIndex(this.#hoverElements, next) !== -1) return;
|
|
13230
13291
|
this.#hoveredTrigger = null;
|
|
13231
13292
|
this.#hoverTimers.clearAll();
|
|
13232
13293
|
this.#hoverTimers.set(() => this.#closeFromHover(), this.hoverDelayValue);
|
|
@@ -13296,7 +13357,7 @@ var NavigationMenuController = class extends Controller {
|
|
|
13296
13357
|
*/
|
|
13297
13358
|
get #hoverElements() {
|
|
13298
13359
|
const areas = this.hoverAreaTargets;
|
|
13299
|
-
const covered = (element) => areas
|
|
13360
|
+
const covered = (element) => ownerIndex(areas, element) !== -1;
|
|
13300
13361
|
return [
|
|
13301
13362
|
...areas,
|
|
13302
13363
|
...this.triggerTargets.filter((trigger) => !covered(trigger)),
|
|
@@ -14221,32 +14282,58 @@ var NumberInputController = class _NumberInputController extends Controller {
|
|
|
14221
14282
|
this.#ariaValueMax.returnAll();
|
|
14222
14283
|
}
|
|
14223
14284
|
};
|
|
14224
|
-
var
|
|
14285
|
+
var HIDDEN_MARKER = "data-optimistic-toggled";
|
|
14286
|
+
var BUSY_MARKER = "data-optimistic-busy";
|
|
14287
|
+
var AUTHORED_ABSENT = "absent";
|
|
14288
|
+
var AUTHORED_VALUE = "value:";
|
|
14289
|
+
var SYNTHETIC_SUBMISSION = {};
|
|
14290
|
+
function submissionOf(event) {
|
|
14291
|
+
const detail = event.detail;
|
|
14292
|
+
return detail?.formSubmission ?? SYNTHETIC_SUBMISSION;
|
|
14293
|
+
}
|
|
14225
14294
|
var OptimisticController = class extends Controller {
|
|
14226
14295
|
static targets = ["show", "hide"];
|
|
14227
14296
|
static events = ["commit", "rollback"];
|
|
14297
|
+
/** The submission that owns the applied optimistic state, if any. */
|
|
14298
|
+
#pending = null;
|
|
14299
|
+
#gate = new DetachGate();
|
|
14300
|
+
/** True between `connect()` and `disconnect()`, so a repeat connect rewinds nothing. */
|
|
14301
|
+
#connected = false;
|
|
14228
14302
|
connect() {
|
|
14229
|
-
|
|
14303
|
+
const restored = !this.#connected && !this.#gate.pending;
|
|
14304
|
+
this.#gate.cancel();
|
|
14305
|
+
this.#connected = true;
|
|
14306
|
+
if (restored && this.element.hasAttribute("data-optimistic")) this.#revert();
|
|
14230
14307
|
this.element.addEventListener("turbo:submit-start", this.#onSubmitStart);
|
|
14231
14308
|
this.element.addEventListener("turbo:submit-end", this.#onSubmitEnd);
|
|
14232
14309
|
}
|
|
14233
14310
|
disconnect() {
|
|
14311
|
+
this.#connected = false;
|
|
14234
14312
|
this.element.removeEventListener("turbo:submit-start", this.#onSubmitStart);
|
|
14235
14313
|
this.element.removeEventListener("turbo:submit-end", this.#onSubmitEnd);
|
|
14314
|
+
this.#gate.disconnected(this, () => {
|
|
14315
|
+
this.#pending = null;
|
|
14316
|
+
});
|
|
14236
14317
|
}
|
|
14237
|
-
#onSubmitStart = () => {
|
|
14318
|
+
#onSubmitStart = (event) => {
|
|
14319
|
+
this.#pending = submissionOf(event);
|
|
14320
|
+
if (this.element instanceof HTMLFormElement && !this.element.hasAttribute(BUSY_MARKER)) {
|
|
14321
|
+
this.element.setAttribute(BUSY_MARKER, AUTHORED_ABSENT);
|
|
14322
|
+
}
|
|
14323
|
+
this.#write(this.element, "aria-busy", "true", BUSY_MARKER);
|
|
14238
14324
|
this.element.setAttribute("data-optimistic", "true");
|
|
14239
|
-
this.
|
|
14240
|
-
for (const target of this.
|
|
14241
|
-
for (const target of this.hideTargets) this.#toggleHidden(target, true);
|
|
14325
|
+
for (const target of this.showTargets) this.#setHidden(target, false);
|
|
14326
|
+
for (const target of this.hideTargets) this.#setHidden(target, true);
|
|
14242
14327
|
};
|
|
14243
14328
|
#onSubmitEnd = (event) => {
|
|
14329
|
+
if (submissionOf(event) !== this.#pending) return;
|
|
14330
|
+
this.#pending = null;
|
|
14244
14331
|
const success = event.detail?.success === true;
|
|
14245
|
-
this.element.removeAttribute("aria-busy");
|
|
14246
14332
|
if (success) {
|
|
14247
14333
|
this.element.removeAttribute("data-optimistic");
|
|
14334
|
+
this.#restore(this.element, "aria-busy", BUSY_MARKER, "true");
|
|
14248
14335
|
for (const target of [...this.showTargets, ...this.hideTargets]) {
|
|
14249
|
-
target.removeAttribute(
|
|
14336
|
+
target.removeAttribute(HIDDEN_MARKER);
|
|
14250
14337
|
}
|
|
14251
14338
|
this.dispatch("commit");
|
|
14252
14339
|
} else {
|
|
@@ -14254,32 +14341,64 @@ var OptimisticController = class extends Controller {
|
|
|
14254
14341
|
this.dispatch("rollback");
|
|
14255
14342
|
}
|
|
14256
14343
|
};
|
|
14257
|
-
/**
|
|
14258
|
-
#
|
|
14259
|
-
if (target.hidden === hidden) return;
|
|
14260
|
-
target
|
|
14261
|
-
|
|
14344
|
+
/** Hides or reveals a target, recording the authored `hidden` on first write. */
|
|
14345
|
+
#setHidden(target, hidden) {
|
|
14346
|
+
if (target.hasAttribute("hidden") === hidden) return;
|
|
14347
|
+
this.#write(target, "hidden", hidden ? "" : null, HIDDEN_MARKER);
|
|
14348
|
+
}
|
|
14349
|
+
/** Writes an attribute, recording what it displaced under `marker` once. */
|
|
14350
|
+
#write(element, attribute, value, marker) {
|
|
14351
|
+
if (!element.hasAttribute(marker)) {
|
|
14352
|
+
const authored = element.getAttribute(attribute);
|
|
14353
|
+
element.setAttribute(
|
|
14354
|
+
marker,
|
|
14355
|
+
authored === null ? AUTHORED_ABSENT : `${AUTHORED_VALUE}${authored}`
|
|
14356
|
+
);
|
|
14357
|
+
}
|
|
14358
|
+
if (value === null) element.removeAttribute(attribute);
|
|
14359
|
+
else element.setAttribute(attribute, value);
|
|
14360
|
+
}
|
|
14361
|
+
/**
|
|
14362
|
+
* Puts back the value `marker` recorded and drops the record.
|
|
14363
|
+
*
|
|
14364
|
+
* `written` is what this controller last put in the attribute. Anything else
|
|
14365
|
+
* there now belongs to whoever wrote it — Turbo owns `aria-busy` on a form and
|
|
14366
|
+
* clears it before the terminal arrives, and a consumer may have moved a face
|
|
14367
|
+
* mid-flight — so the record is dropped without touching the attribute. A
|
|
14368
|
+
* marker this build did not write names no authored value, so the attribute
|
|
14369
|
+
* goes back to being absent.
|
|
14370
|
+
*/
|
|
14371
|
+
#restore(element, attribute, marker, written) {
|
|
14372
|
+
const recorded = element.getAttribute(marker);
|
|
14373
|
+
if (recorded === null) return;
|
|
14374
|
+
element.removeAttribute(marker);
|
|
14375
|
+
if (element.getAttribute(attribute) !== written) return;
|
|
14376
|
+
if (recorded.startsWith(AUTHORED_VALUE)) {
|
|
14377
|
+
element.setAttribute(attribute, recorded.slice(AUTHORED_VALUE.length));
|
|
14378
|
+
return;
|
|
14379
|
+
}
|
|
14380
|
+
element.removeAttribute(attribute);
|
|
14262
14381
|
}
|
|
14263
|
-
/**
|
|
14382
|
+
/**
|
|
14383
|
+
* Puts back exactly the markup this controller displaced (record-owned only).
|
|
14384
|
+
*
|
|
14385
|
+
* A face can be registered on both sides, and the hide pass runs last, so what
|
|
14386
|
+
* this controller wrote there is `hidden` — matching it against the reveal's
|
|
14387
|
+
* absent value instead would read as someone else's write and leave the face
|
|
14388
|
+
* hidden. Each target is therefore restored once, against the write it last
|
|
14389
|
+
* received.
|
|
14390
|
+
*/
|
|
14264
14391
|
#revert() {
|
|
14265
14392
|
this.element.removeAttribute("data-optimistic");
|
|
14266
|
-
this.element
|
|
14267
|
-
|
|
14268
|
-
|
|
14269
|
-
|
|
14270
|
-
target.removeAttribute(TOGGLED_MARKER);
|
|
14271
|
-
}
|
|
14393
|
+
this.#restore(this.element, "aria-busy", BUSY_MARKER, "true");
|
|
14394
|
+
const hidden = new Set(this.hideTargets);
|
|
14395
|
+
for (const target of /* @__PURE__ */ new Set([...this.showTargets, ...this.hideTargets])) {
|
|
14396
|
+
this.#restore(target, "hidden", HIDDEN_MARKER, hidden.has(target) ? "" : null);
|
|
14272
14397
|
}
|
|
14273
14398
|
}
|
|
14274
14399
|
};
|
|
14275
14400
|
var DEFAULT_PATTERN = "[0-9]";
|
|
14276
|
-
|
|
14277
|
-
try {
|
|
14278
|
-
return new RegExp(`^${source}$`);
|
|
14279
|
-
} catch {
|
|
14280
|
-
return null;
|
|
14281
|
-
}
|
|
14282
|
-
}
|
|
14401
|
+
var DEFAULT_MATCHER = new RegExp(`^(?:${DEFAULT_PATTERN})$`);
|
|
14283
14402
|
function hasModifier2(event) {
|
|
14284
14403
|
return event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
|
|
14285
14404
|
}
|
|
@@ -14294,7 +14413,7 @@ var OtpController = class extends Controller {
|
|
|
14294
14413
|
static actions = ["onInput", "onKeydown", "onPaste", "onPointerDown", "clear"];
|
|
14295
14414
|
static events = ["change", "complete", "invalid", "reconcile"];
|
|
14296
14415
|
/** Validated matcher; the hot path never compiles a raw declaration. */
|
|
14297
|
-
#pattern =
|
|
14416
|
+
#pattern = DEFAULT_MATCHER;
|
|
14298
14417
|
/** Source of {@link #pattern}, reported in `invalid` so consumers can word it. */
|
|
14299
14418
|
#patternSource = DEFAULT_PATTERN;
|
|
14300
14419
|
/** Public state carried by the last dispatch; keeps a no-op sync silent. */
|
|
@@ -14367,9 +14486,9 @@ var OtpController = class extends Controller {
|
|
|
14367
14486
|
* the new pattern no longer accepts, so the combined value stays interpretable.
|
|
14368
14487
|
*/
|
|
14369
14488
|
patternValueChanged() {
|
|
14370
|
-
const compiled =
|
|
14489
|
+
const compiled = compileRegExp(this.patternValue, "exact");
|
|
14371
14490
|
this.#patternSource = compiled ? this.patternValue : DEFAULT_PATTERN;
|
|
14372
|
-
this.#pattern = compiled ??
|
|
14491
|
+
this.#pattern = compiled ?? DEFAULT_MATCHER;
|
|
14373
14492
|
if (!this.#connected) return;
|
|
14374
14493
|
let dropped = false;
|
|
14375
14494
|
for (const field of this.fieldTargets) {
|
|
@@ -15253,7 +15372,7 @@ var OverflowMenuController = class extends Controller {
|
|
|
15253
15372
|
}
|
|
15254
15373
|
/** The managed item that is, or contains, `el` — focus rescue works on either. */
|
|
15255
15374
|
#ownerOf(el) {
|
|
15256
|
-
return this.#items
|
|
15375
|
+
return ownerOf(this.#items, el);
|
|
15257
15376
|
}
|
|
15258
15377
|
/** Whether the item takes up room in the bar; an authored `hidden` one does not. */
|
|
15259
15378
|
#rendered(item) {
|
|
@@ -16770,9 +16889,7 @@ var PointerDragController = class _PointerDragController extends Controller {
|
|
|
16770
16889
|
}
|
|
16771
16890
|
/** Resolves the handle owning an event target (the handle or a descendant). */
|
|
16772
16891
|
#handleFor(target) {
|
|
16773
|
-
|
|
16774
|
-
if (!node) return null;
|
|
16775
|
-
return this.#handles().find((handle) => handle === node || handle.contains(node)) ?? null;
|
|
16892
|
+
return ownerOf(this.#handles(), target);
|
|
16776
16893
|
}
|
|
16777
16894
|
#pointerTypeOf(event) {
|
|
16778
16895
|
const type = event.pointerType;
|
|
@@ -16953,16 +17070,7 @@ var PortalController = class extends Controller {
|
|
|
16953
17070
|
* instead, which reads as a mistake and can be traced back to the declaration.
|
|
16954
17071
|
*/
|
|
16955
17072
|
toValueChanged() {
|
|
16956
|
-
|
|
16957
|
-
if (selector.length > 0) {
|
|
16958
|
-
try {
|
|
16959
|
-
this.element.matches(selector);
|
|
16960
|
-
this.#toSelector = selector;
|
|
16961
|
-
return;
|
|
16962
|
-
} catch {
|
|
16963
|
-
}
|
|
16964
|
-
}
|
|
16965
|
-
this.#toSelector = "body";
|
|
17073
|
+
this.#toSelector = validSelector(this.element, this.toValue, "body");
|
|
16966
17074
|
}
|
|
16967
17075
|
connect() {
|
|
16968
17076
|
this.#gate.cancel();
|
|
@@ -17688,9 +17796,8 @@ var RadioGroupController = class extends Controller {
|
|
|
17688
17796
|
}
|
|
17689
17797
|
/** Finds this group's radio containing an event target, excluding nested groups. */
|
|
17690
17798
|
#radioForEventTarget(target) {
|
|
17691
|
-
if (!this.#ownsEventTarget(target)) return
|
|
17692
|
-
|
|
17693
|
-
return this.radioTargets.find((radio) => radio === node || radio.contains(node));
|
|
17799
|
+
if (!this.#ownsEventTarget(target)) return null;
|
|
17800
|
+
return ownerOf(this.radioTargets, target);
|
|
17694
17801
|
}
|
|
17695
17802
|
/** Whether the closest Radio Group scope around a target is this instance. */
|
|
17696
17803
|
#ownsEventTarget(target) {
|
|
@@ -18597,6 +18704,7 @@ var UNITS = [
|
|
|
18597
18704
|
{ limit: 31557600, unit: "month", ms: 26298e5 },
|
|
18598
18705
|
YEAR_SCALE
|
|
18599
18706
|
];
|
|
18707
|
+
var RELATIVE_OPTIONS = { numeric: "auto" };
|
|
18600
18708
|
var RelativeTimeController = class extends Controller {
|
|
18601
18709
|
static values = {
|
|
18602
18710
|
locale: { type: String, default: "" },
|
|
@@ -18704,11 +18812,7 @@ var RelativeTimeController = class extends Controller {
|
|
|
18704
18812
|
* when the runtime rejects that locale.
|
|
18705
18813
|
*/
|
|
18706
18814
|
get #formatter() {
|
|
18707
|
-
|
|
18708
|
-
return new Intl.RelativeTimeFormat(this.#locale, { numeric: "auto" });
|
|
18709
|
-
} catch {
|
|
18710
|
-
return null;
|
|
18711
|
-
}
|
|
18815
|
+
return intlFormatter(Intl.RelativeTimeFormat, this.#locale, RELATIVE_OPTIONS);
|
|
18712
18816
|
}
|
|
18713
18817
|
/** Locale precedence: the value, then the nearest `lang` up the ancestor chain. */
|
|
18714
18818
|
get #locale() {
|
|
@@ -18757,16 +18861,7 @@ var ResetBeforeCacheController = class extends Controller {
|
|
|
18757
18861
|
* silently taking the sweep down.
|
|
18758
18862
|
*/
|
|
18759
18863
|
scopeValueChanged() {
|
|
18760
|
-
|
|
18761
|
-
if (selector.length > 0) {
|
|
18762
|
-
try {
|
|
18763
|
-
this.element.matches(selector);
|
|
18764
|
-
this.#scopeSelector = selector;
|
|
18765
|
-
return;
|
|
18766
|
-
} catch {
|
|
18767
|
-
}
|
|
18768
|
-
}
|
|
18769
|
-
this.#scopeSelector = "";
|
|
18864
|
+
this.#scopeSelector = validSelector(this.element, this.scopeValue, "");
|
|
18770
18865
|
}
|
|
18771
18866
|
connect() {
|
|
18772
18867
|
document.addEventListener("turbo:before-cache", this.#onBeforeCache);
|
|
@@ -18868,8 +18963,7 @@ var ResizableController = class extends Controller {
|
|
|
18868
18963
|
const panes = [];
|
|
18869
18964
|
if (this.hasPrimaryTarget) panes.push(this.primaryTarget);
|
|
18870
18965
|
if (this.hasSecondaryTarget) panes.push(this.secondaryTarget);
|
|
18871
|
-
const
|
|
18872
|
-
const current = panes.findIndex((pane) => target instanceof Node && pane.contains(target));
|
|
18966
|
+
const current = ownerIndex(panes, event.target);
|
|
18873
18967
|
const next = panes[(current + 1) % panes.length];
|
|
18874
18968
|
if (!next) return;
|
|
18875
18969
|
event.preventDefault();
|
|
@@ -19121,9 +19215,7 @@ var RovingController = class extends Controller {
|
|
|
19121
19215
|
};
|
|
19122
19216
|
/** Resolves the item index owning an event target (the item or a descendant). */
|
|
19123
19217
|
#indexOf(target) {
|
|
19124
|
-
|
|
19125
|
-
if (!node) return -1;
|
|
19126
|
-
return this.itemTargets.findIndex((item) => item === node || item.contains(node));
|
|
19218
|
+
return ownerIndex(this.itemTargets, target);
|
|
19127
19219
|
}
|
|
19128
19220
|
/** Makes `index` the tab stop (optionally focusing it), emitting `change` once. */
|
|
19129
19221
|
#activate(index, focus) {
|
|
@@ -19878,11 +19970,11 @@ var ScrollVisibilityController = class extends Controller {
|
|
|
19878
19970
|
}
|
|
19879
19971
|
/** Validates `root` once so connect never parses a selector that throws. */
|
|
19880
19972
|
rootValueChanged() {
|
|
19881
|
-
this.#rootSelector =
|
|
19973
|
+
this.#rootSelector = validSelector(this.element, this.rootValue, "");
|
|
19882
19974
|
}
|
|
19883
19975
|
/** Validates `focusSelector` once so `toTop` never parses a selector that throws. */
|
|
19884
19976
|
focusSelectorValueChanged() {
|
|
19885
|
-
this.#focusSelector =
|
|
19977
|
+
this.#focusSelector = validSelector(this.element, this.focusSelectorValue, "");
|
|
19886
19978
|
}
|
|
19887
19979
|
/** Scrolls the source to the top and, optionally, moves focus to a safe target. */
|
|
19888
19980
|
toTop() {
|
|
@@ -19954,17 +20046,6 @@ var ScrollVisibilityController = class extends Controller {
|
|
|
19954
20046
|
if (focused instanceof HTMLElement && this.elementTarget.contains(focused)) return focused;
|
|
19955
20047
|
return null;
|
|
19956
20048
|
}
|
|
19957
|
-
/** Returns `declared` when it parses as a selector, and `""` when it does not. */
|
|
19958
|
-
#validSelector(declared) {
|
|
19959
|
-
if (declared.length > 0) {
|
|
19960
|
-
try {
|
|
19961
|
-
this.element.matches(declared);
|
|
19962
|
-
return declared;
|
|
19963
|
-
} catch {
|
|
19964
|
-
}
|
|
19965
|
-
}
|
|
19966
|
-
return "";
|
|
19967
|
-
}
|
|
19968
20049
|
#scrollY() {
|
|
19969
20050
|
if (this.#scrollSource === window) {
|
|
19970
20051
|
return window.scrollY ?? window.pageYOffset ?? 0;
|
|
@@ -20098,7 +20179,7 @@ var ScrollspyController = class extends Controller {
|
|
|
20098
20179
|
* only rewrites attributes, so Stimulus fires no target callback: without
|
|
20099
20180
|
* this, a link re-pointed from `#intro` to `#faq` would keep the controller
|
|
20100
20181
|
* observing `#intro` for the rest of the page's life. The filter is exactly
|
|
20101
|
-
*
|
|
20182
|
+
* `href` and `data-href`; guarding on `MutationObserver` keeps the
|
|
20102
20183
|
* controller usable where the API is absent, matching `IntersectionWatcher`'s
|
|
20103
20184
|
* own support guard.
|
|
20104
20185
|
*/
|
|
@@ -21148,7 +21229,7 @@ var SmartStickyHeaderController = class extends Controller {
|
|
|
21148
21229
|
#onFocusin = () => this.#apply(false);
|
|
21149
21230
|
/** Validates `containerSelector` once so connect never parses a selector that throws. */
|
|
21150
21231
|
containerSelectorValueChanged() {
|
|
21151
|
-
this.#containerSelector =
|
|
21232
|
+
this.#containerSelector = validSelector(this.element, this.containerSelectorValue, "");
|
|
21152
21233
|
}
|
|
21153
21234
|
/** Re-decides when application code (or a Turbo morph) changes `offset` at runtime. */
|
|
21154
21235
|
offsetValueChanged() {
|
|
@@ -21178,17 +21259,6 @@ var SmartStickyHeaderController = class extends Controller {
|
|
|
21178
21259
|
}
|
|
21179
21260
|
return window;
|
|
21180
21261
|
}
|
|
21181
|
-
/** Returns `declared` when it parses as a selector, and `""` when it does not. */
|
|
21182
|
-
#validSelector(declared) {
|
|
21183
|
-
if (declared.length > 0) {
|
|
21184
|
-
try {
|
|
21185
|
-
this.element.matches(declared);
|
|
21186
|
-
return declared;
|
|
21187
|
-
} catch {
|
|
21188
|
-
}
|
|
21189
|
-
}
|
|
21190
|
-
return "";
|
|
21191
|
-
}
|
|
21192
21262
|
get #scrollY() {
|
|
21193
21263
|
const scroller = this.#scrollerEl;
|
|
21194
21264
|
return scroller === window ? window.scrollY : scroller.scrollTop;
|
|
@@ -23136,16 +23206,7 @@ var ThemeController = class extends Controller {
|
|
|
23136
23206
|
}
|
|
23137
23207
|
/** Validates the `target` declaration once, so the render path never parses. */
|
|
23138
23208
|
targetValueChanged() {
|
|
23139
|
-
|
|
23140
|
-
if (selector.length > 0) {
|
|
23141
|
-
try {
|
|
23142
|
-
this.element.matches(selector);
|
|
23143
|
-
this.#targetSelector = selector;
|
|
23144
|
-
return;
|
|
23145
|
-
} catch {
|
|
23146
|
-
}
|
|
23147
|
-
}
|
|
23148
|
-
this.#targetSelector = DEFAULT_TARGET;
|
|
23209
|
+
this.#targetSelector = validSelector(this.element, this.targetValue, DEFAULT_TARGET);
|
|
23149
23210
|
}
|
|
23150
23211
|
/** Re-derives the single Tab stop and ARIA for an option set that changed. */
|
|
23151
23212
|
optionTargetConnected() {
|
|
@@ -23158,9 +23219,8 @@ var ThemeController = class extends Controller {
|
|
|
23158
23219
|
/**
|
|
23159
23220
|
* Selects the mode the activated option declares.
|
|
23160
23221
|
*
|
|
23161
|
-
* Read through
|
|
23162
|
-
*
|
|
23163
|
-
* declares.
|
|
23222
|
+
* Read through the same lane that decides which option is checked, so the two
|
|
23223
|
+
* can never disagree about what an option declares.
|
|
23164
23224
|
*/
|
|
23165
23225
|
set(event) {
|
|
23166
23226
|
const option = event.currentTarget;
|
|
@@ -23635,7 +23695,7 @@ var ToastController = class extends Controller {
|
|
|
23635
23695
|
static events = ["dismiss", "show"];
|
|
23636
23696
|
/**
|
|
23637
23697
|
* Registry for every auto-dismiss and transition-finalize timer the controller
|
|
23638
|
-
* schedules.
|
|
23698
|
+
* schedules. `SafeTimeout` owns *registration and teardown only*; the
|
|
23639
23699
|
* pause/resume remaining-time accounting stays in `#activeTimeouts` so the
|
|
23640
23700
|
* per-widget WCAG 2.2.1 semantics are not flattened into the helper.
|
|
23641
23701
|
*/
|
|
@@ -24217,9 +24277,8 @@ var ToggleGroupController = class extends Controller {
|
|
|
24217
24277
|
}
|
|
24218
24278
|
/** Finds this group's item containing an event target, excluding nested groups. */
|
|
24219
24279
|
#itemForEventTarget(target) {
|
|
24220
|
-
if (!this.#ownsEventTarget(target)) return
|
|
24221
|
-
|
|
24222
|
-
return this.itemTargets.find((item) => item === node || item.contains(node));
|
|
24280
|
+
if (!this.#ownsEventTarget(target)) return null;
|
|
24281
|
+
return ownerOf(this.itemTargets, target);
|
|
24223
24282
|
}
|
|
24224
24283
|
/** Whether the closest Toggle Group scope around a target is this instance. */
|
|
24225
24284
|
#ownsEventTarget(target) {
|
|
@@ -24477,9 +24536,7 @@ var ToolbarController = class extends Controller {
|
|
|
24477
24536
|
}
|
|
24478
24537
|
/** Index in `controlTargets` of the control owning `target` (it or a descendant). */
|
|
24479
24538
|
#indexOf(target) {
|
|
24480
|
-
|
|
24481
|
-
if (!node) return -1;
|
|
24482
|
-
return this.controlTargets.findIndex((control) => control === node || control.contains(node));
|
|
24539
|
+
return ownerIndex(this.controlTargets, target);
|
|
24483
24540
|
}
|
|
24484
24541
|
/** Controls eligible for the roving tab stop (excludes native disabled / hidden). */
|
|
24485
24542
|
get #navigableControls() {
|