stimeo-ui 0.13.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 +39 -5
- data/dist/controllers/calendar_controller.js +31 -7
- data/dist/controllers/carousel_controller.js +8 -6
- 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 +31 -7
- data/dist/controllers/direct_upload_controller.js +21 -10
- 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/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/toggle_group_controller.js +11 -3
- data/dist/controllers/toolbar_controller.js +7 -3
- data/dist/index.js +165 -171
- 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,14 +1916,9 @@ 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" };
|
|
1889
1920
|
function monthLabelFormatter(locale) {
|
|
1890
|
-
|
|
1891
|
-
try {
|
|
1892
|
-
return new Intl.DateTimeFormat(locale, options);
|
|
1893
|
-
} catch (error) {
|
|
1894
|
-
if (!(error instanceof RangeError)) throw error;
|
|
1895
|
-
return new Intl.DateTimeFormat("en", options);
|
|
1896
|
-
}
|
|
1921
|
+
return intlFormatter(Intl.DateTimeFormat, locale, MONTH_LABEL_OPTIONS, "en");
|
|
1897
1922
|
}
|
|
1898
1923
|
|
|
1899
1924
|
// src/controllers/calendar_controller.ts
|
|
@@ -2246,6 +2271,15 @@ var CalendarController = class extends Controller {
|
|
|
2246
2271
|
}
|
|
2247
2272
|
};
|
|
2248
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
|
+
|
|
2249
2283
|
// src/utils/reduced_motion.ts
|
|
2250
2284
|
function prefersReducedMotion() {
|
|
2251
2285
|
return typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
@@ -2589,9 +2623,7 @@ var CarouselController = class extends Controller {
|
|
|
2589
2623
|
}
|
|
2590
2624
|
/** Position of the picker that is or contains `node`, or `-1` when none does. */
|
|
2591
2625
|
#pickerIndexFor(node) {
|
|
2592
|
-
return this.pickerTargets
|
|
2593
|
-
(picker) => node instanceof Node && (picker === node || picker.contains(node))
|
|
2594
|
-
);
|
|
2626
|
+
return ownerIndex(this.pickerTargets, node);
|
|
2595
2627
|
}
|
|
2596
2628
|
/** Whether a focus transition lands on another control of this same carousel. */
|
|
2597
2629
|
#focusStaysInside(event) {
|
|
@@ -2810,9 +2842,7 @@ function hasModifier(event) {
|
|
|
2810
2842
|
return event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
|
|
2811
2843
|
}
|
|
2812
2844
|
function hits(elements, node) {
|
|
2813
|
-
return elements
|
|
2814
|
-
(element) => node instanceof Node && (element === node || element.contains(node))
|
|
2815
|
-
);
|
|
2845
|
+
return ownerIndex(elements, node) !== -1;
|
|
2816
2846
|
}
|
|
2817
2847
|
function setAttributeIfChanged(element, name, value) {
|
|
2818
2848
|
if (element.getAttribute(name) !== value) element.setAttribute(name, value);
|
|
@@ -5068,7 +5098,7 @@ var ConditionalFieldsController = class extends Controller {
|
|
|
5068
5098
|
}
|
|
5069
5099
|
/** Whether an authored mutation target belongs to a trigger, region, or managed control. */
|
|
5070
5100
|
#elementAffectsState(target, triggers, regions) {
|
|
5071
|
-
return triggers
|
|
5101
|
+
return ownerIndex(triggers, target) !== -1 || ownerIndex(regions, target) !== -1;
|
|
5072
5102
|
}
|
|
5073
5103
|
/** Whether a form owns at least one current trigger, including `form=` associations. */
|
|
5074
5104
|
#hasTriggerOwnedBy(form) {
|
|
@@ -5928,37 +5958,52 @@ var CurrencyInputController = class extends Controller {
|
|
|
5928
5958
|
* formatters from the validated set.
|
|
5929
5959
|
*/
|
|
5930
5960
|
#revalidate() {
|
|
5931
|
-
|
|
5932
|
-
|
|
5933
|
-
new Intl.NumberFormat(this.localeValue);
|
|
5934
|
-
this.#locale = this.localeValue;
|
|
5935
|
-
} catch {
|
|
5936
|
-
}
|
|
5961
|
+
const declaredLocale = intlFormatter(Intl.NumberFormat, this.localeValue, {});
|
|
5962
|
+
this.#locale = declaredLocale === null ? "en-US" : this.localeValue;
|
|
5937
5963
|
const precision = this.precisionValue;
|
|
5938
5964
|
this.#precision = Number.isInteger(precision) && precision >= 0 && precision <= 100 ? precision : 2;
|
|
5939
5965
|
this.#currency = "";
|
|
5940
5966
|
if (this.currencyValue !== "") {
|
|
5941
|
-
|
|
5942
|
-
|
|
5943
|
-
|
|
5944
|
-
}
|
|
5945
|
-
|
|
5967
|
+
const declaredCurrency = intlFormatter(Intl.NumberFormat, this.#locale, {
|
|
5968
|
+
style: "currency",
|
|
5969
|
+
currency: this.currencyValue
|
|
5970
|
+
});
|
|
5971
|
+
if (declaredCurrency !== null) this.#currency = this.currencyValue;
|
|
5946
5972
|
}
|
|
5947
|
-
this.#grouping =
|
|
5948
|
-
|
|
5949
|
-
|
|
5950
|
-
|
|
5951
|
-
|
|
5952
|
-
|
|
5953
|
-
|
|
5954
|
-
|
|
5955
|
-
|
|
5956
|
-
|
|
5957
|
-
|
|
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
|
+
);
|
|
5958
5998
|
this.#group = parts.find((p) => p.type === "group")?.value ?? ",";
|
|
5959
5999
|
this.#decimal = parts.find((p) => p.type === "decimal")?.value ?? ".";
|
|
5960
6000
|
this.#digits.clear();
|
|
5961
|
-
const digitFormatter =
|
|
6001
|
+
const digitFormatter = intlFormatter(
|
|
6002
|
+
Intl.NumberFormat,
|
|
6003
|
+
this.#locale,
|
|
6004
|
+
{ useGrouping: false },
|
|
6005
|
+
this.#locale
|
|
6006
|
+
);
|
|
5962
6007
|
for (let i = 0; i <= 9; i++) {
|
|
5963
6008
|
const digit = digitFormatter.format(i);
|
|
5964
6009
|
if (digit !== String(i)) this.#digits.set(digit, String(i));
|
|
@@ -6790,6 +6835,43 @@ var DialogController = class extends Controller {
|
|
|
6790
6835
|
return this.hasDialogTarget && !this.dialogTarget.hidden;
|
|
6791
6836
|
}
|
|
6792
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
|
|
6793
6875
|
var REMOVE_DELAY = 4e3;
|
|
6794
6876
|
var DirectUploadController = class extends Controller {
|
|
6795
6877
|
static targets = ["list", "row"];
|
|
@@ -6844,16 +6926,7 @@ var DirectUploadController = class extends Controller {
|
|
|
6844
6926
|
}
|
|
6845
6927
|
/** Validates `scope` once so the per-event path never parses or throws. */
|
|
6846
6928
|
scopeValueChanged() {
|
|
6847
|
-
|
|
6848
|
-
if (selector.length > 0) {
|
|
6849
|
-
try {
|
|
6850
|
-
this.element.matches(selector);
|
|
6851
|
-
this.#scopeSelector = selector;
|
|
6852
|
-
return;
|
|
6853
|
-
} catch {
|
|
6854
|
-
}
|
|
6855
|
-
}
|
|
6856
|
-
this.#scopeSelector = "";
|
|
6929
|
+
this.#scopeSelector = validSelector(this.element, this.scopeValue, "");
|
|
6857
6930
|
}
|
|
6858
6931
|
/** Updates a row's progress and the aggregate, emitting `progress`. */
|
|
6859
6932
|
#updateProgress(id, percent, name) {
|
|
@@ -9088,7 +9161,7 @@ var FormFieldController = class _FormFieldController extends Controller {
|
|
|
9088
9161
|
return this.errorTargets.includes(target);
|
|
9089
9162
|
return record.attributeName === "id" && [...this.descriptionTargets, ...this.errorTargets].includes(target);
|
|
9090
9163
|
}
|
|
9091
|
-
return this.errorTargets
|
|
9164
|
+
return ownerIndex(this.errorTargets, target) !== -1;
|
|
9092
9165
|
}
|
|
9093
9166
|
/** Returns borrowed control ARIA before Turbo snapshots the page. */
|
|
9094
9167
|
#rewindForCache() {
|
|
@@ -10008,22 +10081,19 @@ function applyMask(value, pattern, tokens) {
|
|
|
10008
10081
|
}
|
|
10009
10082
|
function compileTokens(declaration) {
|
|
10010
10083
|
const map = /* @__PURE__ */ new Map();
|
|
10011
|
-
for (const [key, source] of Object.entries(
|
|
10012
|
-
|
|
10013
|
-
|
|
10014
|
-
|
|
10015
|
-
|
|
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);
|
|
10016
10091
|
}
|
|
10017
10092
|
return map;
|
|
10018
10093
|
}
|
|
10019
10094
|
function parseTokens(declaration) {
|
|
10020
|
-
|
|
10021
|
-
|
|
10022
|
-
parsed = JSON.parse(declaration);
|
|
10023
|
-
} catch {
|
|
10024
|
-
return {};
|
|
10025
|
-
}
|
|
10026
|
-
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return {};
|
|
10095
|
+
const parsed = parseJsonObject(declaration);
|
|
10096
|
+
if (parsed === null) return {};
|
|
10027
10097
|
const tokens = {};
|
|
10028
10098
|
for (const [key, source] of Object.entries(parsed)) {
|
|
10029
10099
|
if (typeof source === "string") tokens[key] = source;
|
|
@@ -10235,11 +10305,7 @@ function isBeforeRootStart(entry) {
|
|
|
10235
10305
|
}
|
|
10236
10306
|
function queryRoot(selector) {
|
|
10237
10307
|
if (!selector) return null;
|
|
10238
|
-
|
|
10239
|
-
return document.querySelector(selector);
|
|
10240
|
-
} catch {
|
|
10241
|
-
}
|
|
10242
|
-
return null;
|
|
10308
|
+
return parseDeclared(selector, (raw) => document.querySelector(raw), null);
|
|
10243
10309
|
}
|
|
10244
10310
|
var IntersectionWatcher = class {
|
|
10245
10311
|
#onEntries;
|
|
@@ -11070,8 +11136,9 @@ var LocalTimeController = class extends Controller {
|
|
|
11070
11136
|
/**
|
|
11071
11137
|
* Formats `date` with `Intl.DateTimeFormat`, including each style only when it
|
|
11072
11138
|
* is a valid keyword (so a consumer can show date-only or time-only by clearing
|
|
11073
|
-
* the other). Returns `null` when neither style is usable or
|
|
11074
|
-
* 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.
|
|
11075
11142
|
*/
|
|
11076
11143
|
#applyFormat(date, dateStyle, timeStyle) {
|
|
11077
11144
|
const options = {
|
|
@@ -11080,11 +11147,8 @@ var LocalTimeController = class extends Controller {
|
|
|
11080
11147
|
};
|
|
11081
11148
|
if (options.dateStyle === void 0 && options.timeStyle === void 0) return null;
|
|
11082
11149
|
if (this.timeZoneValue.length > 0) options.timeZone = this.timeZoneValue;
|
|
11083
|
-
|
|
11084
|
-
|
|
11085
|
-
} catch {
|
|
11086
|
-
return null;
|
|
11087
|
-
}
|
|
11150
|
+
const formatter = intlFormatter(Intl.DateTimeFormat, this.#locale, options);
|
|
11151
|
+
return formatter === null ? null : formatter.format(date);
|
|
11088
11152
|
}
|
|
11089
11153
|
/** Locale precedence: the value, then the nearest `lang` up the ancestor chain. */
|
|
11090
11154
|
get #locale() {
|
|
@@ -11152,7 +11216,7 @@ var MasonryController = class extends Controller {
|
|
|
11152
11216
|
*
|
|
11153
11217
|
* The removal is queued rather than immediate because teardown reports every
|
|
11154
11218
|
* target as disconnected: doing it here would strip the whole grid just before
|
|
11155
|
-
* a Turbo snapshot is taken.
|
|
11219
|
+
* a Turbo snapshot is taken. The coalescer's `cancel` drops the queue
|
|
11156
11220
|
* with the pass, so only a genuine target change reaches it.
|
|
11157
11221
|
*/
|
|
11158
11222
|
itemTargetDisconnected(item) {
|
|
@@ -11433,8 +11497,7 @@ var MenuController = class extends Controller {
|
|
|
11433
11497
|
};
|
|
11434
11498
|
/** The item target that is, or contains, `node`; `null` when it is neither. */
|
|
11435
11499
|
#itemFrom(node) {
|
|
11436
|
-
|
|
11437
|
-
return this.itemTargets.find((item) => item === node || item.contains(node)) ?? null;
|
|
11500
|
+
return ownerOf(this.itemTargets, node);
|
|
11438
11501
|
}
|
|
11439
11502
|
/**
|
|
11440
11503
|
* First look at every click inside the controller, and the only point at which
|
|
@@ -11810,8 +11873,7 @@ var MenubarController = class extends Controller {
|
|
|
11810
11873
|
* menu without moving focus.
|
|
11811
11874
|
*/
|
|
11812
11875
|
#dismissOpenMenu() {
|
|
11813
|
-
const
|
|
11814
|
-
const menu = this.menuTargets.find((candidate) => candidate.contains(active));
|
|
11876
|
+
const menu = ownerOf(this.menuTargets, document.activeElement);
|
|
11815
11877
|
if (menu) {
|
|
11816
11878
|
const top = this.#topFor(menu);
|
|
11817
11879
|
this.#closeMenu(top);
|
|
@@ -13225,7 +13287,7 @@ var NavigationMenuController = class extends Controller {
|
|
|
13225
13287
|
*/
|
|
13226
13288
|
#onPointerLeave = (event) => {
|
|
13227
13289
|
const next = event instanceof MouseEvent ? event.relatedTarget : null;
|
|
13228
|
-
if (
|
|
13290
|
+
if (ownerIndex(this.#hoverElements, next) !== -1) return;
|
|
13229
13291
|
this.#hoveredTrigger = null;
|
|
13230
13292
|
this.#hoverTimers.clearAll();
|
|
13231
13293
|
this.#hoverTimers.set(() => this.#closeFromHover(), this.hoverDelayValue);
|
|
@@ -13295,7 +13357,7 @@ var NavigationMenuController = class extends Controller {
|
|
|
13295
13357
|
*/
|
|
13296
13358
|
get #hoverElements() {
|
|
13297
13359
|
const areas = this.hoverAreaTargets;
|
|
13298
|
-
const covered = (element) => areas
|
|
13360
|
+
const covered = (element) => ownerIndex(areas, element) !== -1;
|
|
13299
13361
|
return [
|
|
13300
13362
|
...areas,
|
|
13301
13363
|
...this.triggerTargets.filter((trigger) => !covered(trigger)),
|
|
@@ -14336,13 +14398,7 @@ var OptimisticController = class extends Controller {
|
|
|
14336
14398
|
}
|
|
14337
14399
|
};
|
|
14338
14400
|
var DEFAULT_PATTERN = "[0-9]";
|
|
14339
|
-
|
|
14340
|
-
try {
|
|
14341
|
-
return new RegExp(`^${source}$`);
|
|
14342
|
-
} catch {
|
|
14343
|
-
return null;
|
|
14344
|
-
}
|
|
14345
|
-
}
|
|
14401
|
+
var DEFAULT_MATCHER = new RegExp(`^(?:${DEFAULT_PATTERN})$`);
|
|
14346
14402
|
function hasModifier2(event) {
|
|
14347
14403
|
return event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
|
|
14348
14404
|
}
|
|
@@ -14357,7 +14413,7 @@ var OtpController = class extends Controller {
|
|
|
14357
14413
|
static actions = ["onInput", "onKeydown", "onPaste", "onPointerDown", "clear"];
|
|
14358
14414
|
static events = ["change", "complete", "invalid", "reconcile"];
|
|
14359
14415
|
/** Validated matcher; the hot path never compiles a raw declaration. */
|
|
14360
|
-
#pattern =
|
|
14416
|
+
#pattern = DEFAULT_MATCHER;
|
|
14361
14417
|
/** Source of {@link #pattern}, reported in `invalid` so consumers can word it. */
|
|
14362
14418
|
#patternSource = DEFAULT_PATTERN;
|
|
14363
14419
|
/** Public state carried by the last dispatch; keeps a no-op sync silent. */
|
|
@@ -14430,9 +14486,9 @@ var OtpController = class extends Controller {
|
|
|
14430
14486
|
* the new pattern no longer accepts, so the combined value stays interpretable.
|
|
14431
14487
|
*/
|
|
14432
14488
|
patternValueChanged() {
|
|
14433
|
-
const compiled =
|
|
14489
|
+
const compiled = compileRegExp(this.patternValue, "exact");
|
|
14434
14490
|
this.#patternSource = compiled ? this.patternValue : DEFAULT_PATTERN;
|
|
14435
|
-
this.#pattern = compiled ??
|
|
14491
|
+
this.#pattern = compiled ?? DEFAULT_MATCHER;
|
|
14436
14492
|
if (!this.#connected) return;
|
|
14437
14493
|
let dropped = false;
|
|
14438
14494
|
for (const field of this.fieldTargets) {
|
|
@@ -15316,7 +15372,7 @@ var OverflowMenuController = class extends Controller {
|
|
|
15316
15372
|
}
|
|
15317
15373
|
/** The managed item that is, or contains, `el` — focus rescue works on either. */
|
|
15318
15374
|
#ownerOf(el) {
|
|
15319
|
-
return this.#items
|
|
15375
|
+
return ownerOf(this.#items, el);
|
|
15320
15376
|
}
|
|
15321
15377
|
/** Whether the item takes up room in the bar; an authored `hidden` one does not. */
|
|
15322
15378
|
#rendered(item) {
|
|
@@ -16833,9 +16889,7 @@ var PointerDragController = class _PointerDragController extends Controller {
|
|
|
16833
16889
|
}
|
|
16834
16890
|
/** Resolves the handle owning an event target (the handle or a descendant). */
|
|
16835
16891
|
#handleFor(target) {
|
|
16836
|
-
|
|
16837
|
-
if (!node) return null;
|
|
16838
|
-
return this.#handles().find((handle) => handle === node || handle.contains(node)) ?? null;
|
|
16892
|
+
return ownerOf(this.#handles(), target);
|
|
16839
16893
|
}
|
|
16840
16894
|
#pointerTypeOf(event) {
|
|
16841
16895
|
const type = event.pointerType;
|
|
@@ -17016,16 +17070,7 @@ var PortalController = class extends Controller {
|
|
|
17016
17070
|
* instead, which reads as a mistake and can be traced back to the declaration.
|
|
17017
17071
|
*/
|
|
17018
17072
|
toValueChanged() {
|
|
17019
|
-
|
|
17020
|
-
if (selector.length > 0) {
|
|
17021
|
-
try {
|
|
17022
|
-
this.element.matches(selector);
|
|
17023
|
-
this.#toSelector = selector;
|
|
17024
|
-
return;
|
|
17025
|
-
} catch {
|
|
17026
|
-
}
|
|
17027
|
-
}
|
|
17028
|
-
this.#toSelector = "body";
|
|
17073
|
+
this.#toSelector = validSelector(this.element, this.toValue, "body");
|
|
17029
17074
|
}
|
|
17030
17075
|
connect() {
|
|
17031
17076
|
this.#gate.cancel();
|
|
@@ -17751,9 +17796,8 @@ var RadioGroupController = class extends Controller {
|
|
|
17751
17796
|
}
|
|
17752
17797
|
/** Finds this group's radio containing an event target, excluding nested groups. */
|
|
17753
17798
|
#radioForEventTarget(target) {
|
|
17754
|
-
if (!this.#ownsEventTarget(target)) return
|
|
17755
|
-
|
|
17756
|
-
return this.radioTargets.find((radio) => radio === node || radio.contains(node));
|
|
17799
|
+
if (!this.#ownsEventTarget(target)) return null;
|
|
17800
|
+
return ownerOf(this.radioTargets, target);
|
|
17757
17801
|
}
|
|
17758
17802
|
/** Whether the closest Radio Group scope around a target is this instance. */
|
|
17759
17803
|
#ownsEventTarget(target) {
|
|
@@ -18660,6 +18704,7 @@ var UNITS = [
|
|
|
18660
18704
|
{ limit: 31557600, unit: "month", ms: 26298e5 },
|
|
18661
18705
|
YEAR_SCALE
|
|
18662
18706
|
];
|
|
18707
|
+
var RELATIVE_OPTIONS = { numeric: "auto" };
|
|
18663
18708
|
var RelativeTimeController = class extends Controller {
|
|
18664
18709
|
static values = {
|
|
18665
18710
|
locale: { type: String, default: "" },
|
|
@@ -18767,11 +18812,7 @@ var RelativeTimeController = class extends Controller {
|
|
|
18767
18812
|
* when the runtime rejects that locale.
|
|
18768
18813
|
*/
|
|
18769
18814
|
get #formatter() {
|
|
18770
|
-
|
|
18771
|
-
return new Intl.RelativeTimeFormat(this.#locale, { numeric: "auto" });
|
|
18772
|
-
} catch {
|
|
18773
|
-
return null;
|
|
18774
|
-
}
|
|
18815
|
+
return intlFormatter(Intl.RelativeTimeFormat, this.#locale, RELATIVE_OPTIONS);
|
|
18775
18816
|
}
|
|
18776
18817
|
/** Locale precedence: the value, then the nearest `lang` up the ancestor chain. */
|
|
18777
18818
|
get #locale() {
|
|
@@ -18820,16 +18861,7 @@ var ResetBeforeCacheController = class extends Controller {
|
|
|
18820
18861
|
* silently taking the sweep down.
|
|
18821
18862
|
*/
|
|
18822
18863
|
scopeValueChanged() {
|
|
18823
|
-
|
|
18824
|
-
if (selector.length > 0) {
|
|
18825
|
-
try {
|
|
18826
|
-
this.element.matches(selector);
|
|
18827
|
-
this.#scopeSelector = selector;
|
|
18828
|
-
return;
|
|
18829
|
-
} catch {
|
|
18830
|
-
}
|
|
18831
|
-
}
|
|
18832
|
-
this.#scopeSelector = "";
|
|
18864
|
+
this.#scopeSelector = validSelector(this.element, this.scopeValue, "");
|
|
18833
18865
|
}
|
|
18834
18866
|
connect() {
|
|
18835
18867
|
document.addEventListener("turbo:before-cache", this.#onBeforeCache);
|
|
@@ -18931,8 +18963,7 @@ var ResizableController = class extends Controller {
|
|
|
18931
18963
|
const panes = [];
|
|
18932
18964
|
if (this.hasPrimaryTarget) panes.push(this.primaryTarget);
|
|
18933
18965
|
if (this.hasSecondaryTarget) panes.push(this.secondaryTarget);
|
|
18934
|
-
const
|
|
18935
|
-
const current = panes.findIndex((pane) => target instanceof Node && pane.contains(target));
|
|
18966
|
+
const current = ownerIndex(panes, event.target);
|
|
18936
18967
|
const next = panes[(current + 1) % panes.length];
|
|
18937
18968
|
if (!next) return;
|
|
18938
18969
|
event.preventDefault();
|
|
@@ -19184,9 +19215,7 @@ var RovingController = class extends Controller {
|
|
|
19184
19215
|
};
|
|
19185
19216
|
/** Resolves the item index owning an event target (the item or a descendant). */
|
|
19186
19217
|
#indexOf(target) {
|
|
19187
|
-
|
|
19188
|
-
if (!node) return -1;
|
|
19189
|
-
return this.itemTargets.findIndex((item) => item === node || item.contains(node));
|
|
19218
|
+
return ownerIndex(this.itemTargets, target);
|
|
19190
19219
|
}
|
|
19191
19220
|
/** Makes `index` the tab stop (optionally focusing it), emitting `change` once. */
|
|
19192
19221
|
#activate(index, focus) {
|
|
@@ -19941,11 +19970,11 @@ var ScrollVisibilityController = class extends Controller {
|
|
|
19941
19970
|
}
|
|
19942
19971
|
/** Validates `root` once so connect never parses a selector that throws. */
|
|
19943
19972
|
rootValueChanged() {
|
|
19944
|
-
this.#rootSelector =
|
|
19973
|
+
this.#rootSelector = validSelector(this.element, this.rootValue, "");
|
|
19945
19974
|
}
|
|
19946
19975
|
/** Validates `focusSelector` once so `toTop` never parses a selector that throws. */
|
|
19947
19976
|
focusSelectorValueChanged() {
|
|
19948
|
-
this.#focusSelector =
|
|
19977
|
+
this.#focusSelector = validSelector(this.element, this.focusSelectorValue, "");
|
|
19949
19978
|
}
|
|
19950
19979
|
/** Scrolls the source to the top and, optionally, moves focus to a safe target. */
|
|
19951
19980
|
toTop() {
|
|
@@ -20017,17 +20046,6 @@ var ScrollVisibilityController = class extends Controller {
|
|
|
20017
20046
|
if (focused instanceof HTMLElement && this.elementTarget.contains(focused)) return focused;
|
|
20018
20047
|
return null;
|
|
20019
20048
|
}
|
|
20020
|
-
/** Returns `declared` when it parses as a selector, and `""` when it does not. */
|
|
20021
|
-
#validSelector(declared) {
|
|
20022
|
-
if (declared.length > 0) {
|
|
20023
|
-
try {
|
|
20024
|
-
this.element.matches(declared);
|
|
20025
|
-
return declared;
|
|
20026
|
-
} catch {
|
|
20027
|
-
}
|
|
20028
|
-
}
|
|
20029
|
-
return "";
|
|
20030
|
-
}
|
|
20031
20049
|
#scrollY() {
|
|
20032
20050
|
if (this.#scrollSource === window) {
|
|
20033
20051
|
return window.scrollY ?? window.pageYOffset ?? 0;
|
|
@@ -20161,7 +20179,7 @@ var ScrollspyController = class extends Controller {
|
|
|
20161
20179
|
* only rewrites attributes, so Stimulus fires no target callback: without
|
|
20162
20180
|
* this, a link re-pointed from `#intro` to `#faq` would keep the controller
|
|
20163
20181
|
* observing `#intro` for the rest of the page's life. The filter is exactly
|
|
20164
|
-
*
|
|
20182
|
+
* `href` and `data-href`; guarding on `MutationObserver` keeps the
|
|
20165
20183
|
* controller usable where the API is absent, matching `IntersectionWatcher`'s
|
|
20166
20184
|
* own support guard.
|
|
20167
20185
|
*/
|
|
@@ -21211,7 +21229,7 @@ var SmartStickyHeaderController = class extends Controller {
|
|
|
21211
21229
|
#onFocusin = () => this.#apply(false);
|
|
21212
21230
|
/** Validates `containerSelector` once so connect never parses a selector that throws. */
|
|
21213
21231
|
containerSelectorValueChanged() {
|
|
21214
|
-
this.#containerSelector =
|
|
21232
|
+
this.#containerSelector = validSelector(this.element, this.containerSelectorValue, "");
|
|
21215
21233
|
}
|
|
21216
21234
|
/** Re-decides when application code (or a Turbo morph) changes `offset` at runtime. */
|
|
21217
21235
|
offsetValueChanged() {
|
|
@@ -21241,17 +21259,6 @@ var SmartStickyHeaderController = class extends Controller {
|
|
|
21241
21259
|
}
|
|
21242
21260
|
return window;
|
|
21243
21261
|
}
|
|
21244
|
-
/** Returns `declared` when it parses as a selector, and `""` when it does not. */
|
|
21245
|
-
#validSelector(declared) {
|
|
21246
|
-
if (declared.length > 0) {
|
|
21247
|
-
try {
|
|
21248
|
-
this.element.matches(declared);
|
|
21249
|
-
return declared;
|
|
21250
|
-
} catch {
|
|
21251
|
-
}
|
|
21252
|
-
}
|
|
21253
|
-
return "";
|
|
21254
|
-
}
|
|
21255
21262
|
get #scrollY() {
|
|
21256
21263
|
const scroller = this.#scrollerEl;
|
|
21257
21264
|
return scroller === window ? window.scrollY : scroller.scrollTop;
|
|
@@ -23199,16 +23206,7 @@ var ThemeController = class extends Controller {
|
|
|
23199
23206
|
}
|
|
23200
23207
|
/** Validates the `target` declaration once, so the render path never parses. */
|
|
23201
23208
|
targetValueChanged() {
|
|
23202
|
-
|
|
23203
|
-
if (selector.length > 0) {
|
|
23204
|
-
try {
|
|
23205
|
-
this.element.matches(selector);
|
|
23206
|
-
this.#targetSelector = selector;
|
|
23207
|
-
return;
|
|
23208
|
-
} catch {
|
|
23209
|
-
}
|
|
23210
|
-
}
|
|
23211
|
-
this.#targetSelector = DEFAULT_TARGET;
|
|
23209
|
+
this.#targetSelector = validSelector(this.element, this.targetValue, DEFAULT_TARGET);
|
|
23212
23210
|
}
|
|
23213
23211
|
/** Re-derives the single Tab stop and ARIA for an option set that changed. */
|
|
23214
23212
|
optionTargetConnected() {
|
|
@@ -23221,9 +23219,8 @@ var ThemeController = class extends Controller {
|
|
|
23221
23219
|
/**
|
|
23222
23220
|
* Selects the mode the activated option declares.
|
|
23223
23221
|
*
|
|
23224
|
-
* Read through
|
|
23225
|
-
*
|
|
23226
|
-
* 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.
|
|
23227
23224
|
*/
|
|
23228
23225
|
set(event) {
|
|
23229
23226
|
const option = event.currentTarget;
|
|
@@ -24280,9 +24277,8 @@ var ToggleGroupController = class extends Controller {
|
|
|
24280
24277
|
}
|
|
24281
24278
|
/** Finds this group's item containing an event target, excluding nested groups. */
|
|
24282
24279
|
#itemForEventTarget(target) {
|
|
24283
|
-
if (!this.#ownsEventTarget(target)) return
|
|
24284
|
-
|
|
24285
|
-
return this.itemTargets.find((item) => item === node || item.contains(node));
|
|
24280
|
+
if (!this.#ownsEventTarget(target)) return null;
|
|
24281
|
+
return ownerOf(this.itemTargets, target);
|
|
24286
24282
|
}
|
|
24287
24283
|
/** Whether the closest Toggle Group scope around a target is this instance. */
|
|
24288
24284
|
#ownsEventTarget(target) {
|
|
@@ -24540,9 +24536,7 @@ var ToolbarController = class extends Controller {
|
|
|
24540
24536
|
}
|
|
24541
24537
|
/** Index in `controlTargets` of the control owning `target` (it or a descendant). */
|
|
24542
24538
|
#indexOf(target) {
|
|
24543
|
-
|
|
24544
|
-
if (!node) return -1;
|
|
24545
|
-
return this.controlTargets.findIndex((control) => control === node || control.contains(node));
|
|
24539
|
+
return ownerIndex(this.controlTargets, target);
|
|
24546
24540
|
}
|
|
24547
24541
|
/** Controls eligible for the roving tab stop (excludes native disabled / hidden). */
|
|
24548
24542
|
get #navigableControls() {
|
data/lib/stimeo/ui/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: stimeo-ui
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.14.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Stimeo Labs
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-09-
|
|
11
|
+
date: 2026-09-19 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: railties
|