@odx/foundation 1.0.0-rc.1 → 1.0.0-rc.11
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 +82 -0
- package/README.md +13 -1
- package/dist/lib/breakpoints.d.ts +46 -49
- package/dist/lib/breakpoints.js +139 -122
- package/dist/lib/format.d.ts +49 -50
- package/dist/lib/format.js +51 -50
- package/dist/lib/localization.d.ts +11 -11
- package/dist/lib/localization.js +13 -15
- package/dist/lib/models.d.ts +3 -39
- package/dist/lib/scroll-lock.d.ts +7 -0
- package/dist/lib/scroll-lock.js +27 -0
- package/dist/lib/signals.d.ts +15 -15
- package/dist/lib/signals.js +38 -35
- package/dist/lib/theming.d.ts +14 -13
- package/dist/lib/theming.js +29 -25
- package/dist/lib/utils/shared-media-observer.js +31 -35
- package/dist/main.d.ts +8 -7
- package/dist/main.js +7 -5
- package/dist/styles.css +1082 -1
- package/package.json +18 -18
- package/types/styles.d.ts +1 -0
- package/dist/lib/models.js +0 -34
- package/dist/lib/utils/breakpoint.d.ts +0 -38
- package/dist/lib/utils/breakpoint.js +0 -103
- package/dist/lib/utils/shared-media-observer.d.ts +0 -4
- package/dist/oss-licenses.json +0 -1
package/dist/lib/format.js
CHANGED
|
@@ -1,63 +1,64 @@
|
|
|
1
1
|
function parseDate(value) {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
if (Number.isNaN(date.getTime()) && typeof value === "string") {
|
|
8
|
-
return createDate(Number(value));
|
|
9
|
-
}
|
|
10
|
-
return createDate(date.getTime());
|
|
2
|
+
const createDate = (value) => Number.isNaN(value) ? null : new Date(value);
|
|
3
|
+
if (value instanceof Date) return createDate(value.getTime());
|
|
4
|
+
const date = new Date(value);
|
|
5
|
+
if (Number.isNaN(date.getTime()) && typeof value === "string") return createDate(Number(value));
|
|
6
|
+
return createDate(date.getTime());
|
|
11
7
|
}
|
|
12
8
|
function formatDate(input, options) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
return new Intl.DateTimeFormat(options?.locale, options).format(value);
|
|
9
|
+
const value = parseDate(input);
|
|
10
|
+
if (!value) return "";
|
|
11
|
+
if (options?.dateStyle === "iso8601") return new Intl.DateTimeFormat("sv-SE", { dateStyle: "short" }).format(value);
|
|
12
|
+
return new Intl.DateTimeFormat(options?.locale, options).format(value);
|
|
19
13
|
}
|
|
20
14
|
function formatNumber(input, options) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
options.style = "unit";
|
|
27
|
-
}
|
|
28
|
-
return new Intl.NumberFormat(options?.locale, options).format(value);
|
|
15
|
+
const value = Number(input);
|
|
16
|
+
if (Number.isNaN(value)) return "";
|
|
17
|
+
if (options?.currency) options.style = "currency";
|
|
18
|
+
else if (options?.unit) options.style = "unit";
|
|
19
|
+
return new Intl.NumberFormat(options?.locale, options).format(value);
|
|
29
20
|
}
|
|
30
21
|
function formatList(input, options) {
|
|
31
|
-
|
|
32
|
-
|
|
22
|
+
if (input.length === 0) return "";
|
|
23
|
+
return new Intl.ListFormat(options?.locale, options).format(input);
|
|
33
24
|
}
|
|
34
25
|
const TIME_UNIT_MAP = {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
26
|
+
second: {
|
|
27
|
+
max: 59e3,
|
|
28
|
+
value: 1e3
|
|
29
|
+
},
|
|
30
|
+
minute: {
|
|
31
|
+
max: 276e4,
|
|
32
|
+
value: 6e4
|
|
33
|
+
},
|
|
34
|
+
hour: {
|
|
35
|
+
max: 72e6,
|
|
36
|
+
value: 36e5
|
|
37
|
+
},
|
|
38
|
+
day: {
|
|
39
|
+
max: 5184e5,
|
|
40
|
+
value: 864e5
|
|
41
|
+
},
|
|
42
|
+
week: {
|
|
43
|
+
max: 24192e5,
|
|
44
|
+
value: 6048e5
|
|
45
|
+
},
|
|
46
|
+
month: {
|
|
47
|
+
max: 28512e6,
|
|
48
|
+
value: 2592e6
|
|
49
|
+
},
|
|
50
|
+
year: {
|
|
51
|
+
max: Number.POSITIVE_INFINITY,
|
|
52
|
+
value: 31536e6
|
|
53
|
+
}
|
|
48
54
|
};
|
|
49
55
|
function formatRelativeTime(input, options) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
return new Intl.RelativeTimeFormat(options?.locale, options).format(
|
|
58
|
-
Math.round(relativeTime / unitConfig.value),
|
|
59
|
-
unit
|
|
60
|
-
);
|
|
56
|
+
const startDate = parseDate(options?.start ?? Date.now());
|
|
57
|
+
const value = parseDate(input);
|
|
58
|
+
if (!value || !startDate) return "";
|
|
59
|
+
const relativeTime = value.getTime() - startDate.getTime();
|
|
60
|
+
const minUnit = options?.minUnit && TIME_UNIT_MAP[options.minUnit] || TIME_UNIT_MAP.second;
|
|
61
|
+
const [unit, unitConfig] = Object.entries(TIME_UNIT_MAP).find(([_, { value, max }]) => Math.abs(relativeTime) < max && minUnit.value <= value);
|
|
62
|
+
return new Intl.RelativeTimeFormat(options?.locale, options).format(Math.round(relativeTime / unitConfig.value), unit);
|
|
61
63
|
}
|
|
62
|
-
|
|
63
64
|
export { formatDate, formatList, formatNumber, formatRelativeTime, parseDate };
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { FormatOptions } from
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { FormatOptions } from "./format.js";
|
|
2
|
+
interface LocalizationOptions extends FormatOptions {
|
|
3
|
+
defaultLocale: () => Intl.Locale | Intl.UnicodeBCP47LocaleIdentifier;
|
|
4
|
+
fallbackLanguage: () => Intl.UnicodeBCP47LocaleIdentifier;
|
|
5
|
+
fallbackTranslation: (key: string) => string;
|
|
6
6
|
}
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
declare const LocalizationOptions: (config?: Partial<LocalizationOptions>) => LocalizationOptions;
|
|
8
|
+
declare function setLocalizationOptions(options?: Partial<LocalizationOptions> | null): void;
|
|
9
|
+
declare function getLocalizationOptions(options?: Partial<LocalizationOptions> | null): LocalizationOptions;
|
|
10
|
+
declare function getLocale(localeInput?: Intl.Locale | Intl.UnicodeBCP47LocaleIdentifier | null): Intl.Locale;
|
|
11
|
+
declare function setLocale(localeInput?: Intl.Locale | Intl.UnicodeBCP47LocaleIdentifier | null): void;
|
|
12
|
+
export { LocalizationOptions, getLocale, getLocalizationOptions, setLocale, setLocalizationOptions };
|
package/dist/lib/localization.js
CHANGED
|
@@ -1,28 +1,26 @@
|
|
|
1
|
-
import { sharedSignal } from
|
|
2
|
-
|
|
1
|
+
import { sharedSignal } from "./signals.js";
|
|
3
2
|
const locale = sharedSignal("locale", null);
|
|
4
3
|
const localizationOptions = sharedSignal("localizationOptions", null);
|
|
5
4
|
const LocalizationOptions = (config) => ({
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
5
|
+
defaultLocale: () => navigator.language,
|
|
6
|
+
fallbackLanguage: () => "en",
|
|
7
|
+
fallbackTranslation: (key) => key,
|
|
8
|
+
...config,
|
|
9
|
+
relativeTimeFormatOptions: {
|
|
10
|
+
minUnit: "minute",
|
|
11
|
+
...config?.relativeTimeFormatOptions
|
|
12
|
+
}
|
|
14
13
|
});
|
|
15
14
|
function setLocalizationOptions(options) {
|
|
16
|
-
|
|
15
|
+
localizationOptions.set(getLocalizationOptions(options));
|
|
17
16
|
}
|
|
18
17
|
function getLocalizationOptions(options) {
|
|
19
|
-
|
|
18
|
+
return LocalizationOptions(options ?? localizationOptions.get() ?? {});
|
|
20
19
|
}
|
|
21
20
|
function getLocale(localeInput) {
|
|
22
|
-
|
|
21
|
+
return new Intl.Locale(localeInput || locale.get() || getLocalizationOptions().defaultLocale());
|
|
23
22
|
}
|
|
24
23
|
function setLocale(localeInput) {
|
|
25
|
-
|
|
24
|
+
locale.set(localeInput ? getLocale(localeInput) : null);
|
|
26
25
|
}
|
|
27
|
-
|
|
28
26
|
export { LocalizationOptions, getLocale, getLocalizationOptions, setLocale, setLocalizationOptions };
|
package/dist/lib/models.d.ts
CHANGED
|
@@ -1,39 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
readonly CENTER: "center";
|
|
5
|
-
readonly END: "end";
|
|
6
|
-
};
|
|
7
|
-
export type Spacing = (typeof Spacing)[keyof typeof Spacing];
|
|
8
|
-
export declare const Spacing: {
|
|
9
|
-
readonly 0: "0";
|
|
10
|
-
readonly SM: "sm";
|
|
11
|
-
readonly MD: "md";
|
|
12
|
-
readonly LG: "lg";
|
|
13
|
-
};
|
|
14
|
-
export type Justify = (typeof Justify)[keyof typeof Justify];
|
|
15
|
-
export declare const Justify: {
|
|
16
|
-
readonly START: "start";
|
|
17
|
-
readonly END: "end";
|
|
18
|
-
readonly CENTER: "center";
|
|
19
|
-
readonly SPACE_BETWEEN: "space-between";
|
|
20
|
-
readonly SPACE_AROUND: "space-around";
|
|
21
|
-
readonly SPACE_EVENLY: "space-evenly";
|
|
22
|
-
};
|
|
23
|
-
export type Variant = (typeof Variant)[keyof typeof Variant];
|
|
24
|
-
export declare const Variant: {
|
|
25
|
-
readonly NEUTRAL: "neutral";
|
|
26
|
-
readonly PRIMARY: "primary";
|
|
27
|
-
readonly ACCENT: "accent";
|
|
28
|
-
readonly SUCCESS: "success";
|
|
29
|
-
readonly WARNING: "warning";
|
|
30
|
-
readonly DANGER: "danger";
|
|
31
|
-
readonly ACCENT_GHOST: "accent-ghost";
|
|
32
|
-
readonly DANGER_GHOST: "danger-ghost";
|
|
33
|
-
readonly CONFIRMATION: "confirmation";
|
|
34
|
-
readonly SUBTLE: "subtle";
|
|
35
|
-
readonly GHOST: "ghost";
|
|
36
|
-
};
|
|
37
|
-
export type UnitIdentifier = SingleUnitIdentifier | `${SingleUnitIdentifier}-per-${SingleUnitIdentifier}` | (string & {});
|
|
38
|
-
export type SingleUnitIdentifier = 'acre' | 'bit' | 'byte' | 'celsius' | 'centimeter' | 'day' | 'degree' | 'fahrenheit' | 'fluid-ounce' | 'foot' | 'gallon' | 'gigabit' | 'gigabyte' | 'gram' | 'hectare' | 'hour' | 'inch' | 'kilobit' | 'kilobyte' | 'kilogram' | 'kilometer' | 'liter' | 'megabit' | 'megabyte' | 'meter' | 'microsecond' | 'mile' | 'mile-scandinavian' | 'milliliter' | 'millimeter' | 'millisecond' | 'minute' | 'month' | 'nanosecond' | 'ounce' | 'percent' | 'petabyte' | 'pound' | 'second' | 'stone' | 'terabit' | 'terabyte' | 'week' | 'yard' | 'year';
|
|
39
|
-
//# sourceMappingURL=models.d.ts.map
|
|
1
|
+
type UnitIdentifier = SingleUnitIdentifier | `${SingleUnitIdentifier}-per-${SingleUnitIdentifier}` | (string & {});
|
|
2
|
+
type SingleUnitIdentifier = 'acre' | 'bit' | 'byte' | 'celsius' | 'centimeter' | 'day' | 'degree' | 'fahrenheit' | 'fluid-ounce' | 'foot' | 'gallon' | 'gigabit' | 'gigabyte' | 'gram' | 'hectare' | 'hour' | 'inch' | 'kilobit' | 'kilobyte' | 'kilogram' | 'kilometer' | 'liter' | 'megabit' | 'megabyte' | 'meter' | 'microsecond' | 'mile' | 'mile-scandinavian' | 'milliliter' | 'millimeter' | 'millisecond' | 'minute' | 'month' | 'nanosecond' | 'ounce' | 'percent' | 'petabyte' | 'pound' | 'second' | 'stone' | 'terabit' | 'terabyte' | 'week' | 'yard' | 'year';
|
|
3
|
+
export { UnitIdentifier };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** @internal */
|
|
2
|
+
declare function applyScrollLock(source: HTMLElement): void;
|
|
3
|
+
/** @internal */
|
|
4
|
+
declare function removeScrollLock(source: HTMLElement): void;
|
|
5
|
+
/** @internal */
|
|
6
|
+
declare function removeAllScrollLocks(): void;
|
|
7
|
+
export { applyScrollLock, removeAllScrollLocks, removeScrollLock };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const scrollLockClass = "odx-scroll-lock";
|
|
2
|
+
const scrollLocks = /* @__PURE__ */ new Set();
|
|
3
|
+
/** @internal */
|
|
4
|
+
function applyScrollLock(source) {
|
|
5
|
+
const { documentElement } = document;
|
|
6
|
+
scrollLocks.add(source);
|
|
7
|
+
if (documentElement.classList.contains(scrollLockClass)) return;
|
|
8
|
+
const bodyPadding = Number(getComputedStyle(document.body).paddingRight.replace("px", ""));
|
|
9
|
+
let scrollbarWidth = Math.abs(window.innerWidth - documentElement.clientWidth);
|
|
10
|
+
if (!Number.isNaN(bodyPadding) && bodyPadding > 0) scrollbarWidth += bodyPadding;
|
|
11
|
+
let { scrollbarGutter } = getComputedStyle(documentElement);
|
|
12
|
+
if (!scrollbarGutter || scrollbarGutter === "auto") scrollbarGutter = "stable";
|
|
13
|
+
documentElement.classList.add(scrollLockClass);
|
|
14
|
+
documentElement.style.setProperty("--odx-scroll-lock-gutter", scrollbarWidth > 1 ? scrollbarGutter : "");
|
|
15
|
+
}
|
|
16
|
+
/** @internal */
|
|
17
|
+
function removeScrollLock(source) {
|
|
18
|
+
scrollLocks.delete(source);
|
|
19
|
+
if (scrollLocks.size > 0) return;
|
|
20
|
+
document.documentElement.classList.remove(scrollLockClass);
|
|
21
|
+
}
|
|
22
|
+
/** @internal */
|
|
23
|
+
function removeAllScrollLocks() {
|
|
24
|
+
scrollLocks.clear();
|
|
25
|
+
document.documentElement.classList.remove(scrollLockClass);
|
|
26
|
+
}
|
|
27
|
+
export { applyScrollLock, removeAllScrollLocks, removeScrollLock };
|
package/dist/lib/signals.d.ts
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import { Signal
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { Signal } from "signal-polyfill";
|
|
2
|
+
type Signal$1<T> = Signal.State<T> & {
|
|
3
|
+
update: (updateFn: (value: T) => T) => void;
|
|
4
4
|
};
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
type SignalOptions<T> = Signal.Options<T> & {
|
|
6
|
+
watched?(): void;
|
|
7
|
+
unwatched?(): void;
|
|
8
8
|
};
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
type ReadonlySignal<T> = Signal.Computed<T>;
|
|
10
|
+
declare function computed<T>(computeFn: () => T, options?: SignalOptions<T>): ReadonlySignal<T>;
|
|
11
|
+
declare function signal<T>(value: T, options?: SignalOptions<T>): Signal$1<T>;
|
|
12
|
+
declare global {
|
|
13
|
+
var __ODX_SHARED_SIGNALS__: Record<string, unknown>;
|
|
14
|
+
}
|
|
11
15
|
/**
|
|
12
16
|
* Creates or retrieves a shared signal stored on the global object. This is useful for signals that need to be shared across multiple modules without explicitly passing them around, such as localization settings or translation records.
|
|
13
17
|
*/
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
export
|
|
17
|
-
declare global {
|
|
18
|
-
var __ODX_SHARED_SIGNALS__: Record<string, unknown>;
|
|
19
|
-
}
|
|
20
|
-
//# sourceMappingURL=signals.d.ts.map
|
|
18
|
+
declare function sharedSignal<T>(key: string, ...args: Parameters<typeof signal<T>>): ReturnType<typeof signal<T>>;
|
|
19
|
+
declare function effect(callback: (() => void) | (() => () => void)): () => void;
|
|
20
|
+
export { ReadonlySignal, Signal$1 as Signal, SignalOptions, computed, effect, sharedSignal, signal };
|
package/dist/lib/signals.js
CHANGED
|
@@ -1,47 +1,50 @@
|
|
|
1
|
-
import { Signal } from
|
|
2
|
-
|
|
1
|
+
import { Signal } from "signal-polyfill";
|
|
3
2
|
function transformOptions(options) {
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
if (!options) return;
|
|
4
|
+
return {
|
|
5
|
+
equals: options.equals,
|
|
6
|
+
[Signal.subtle.watched]: options.watched,
|
|
7
|
+
[Signal.subtle.unwatched]: options.unwatched
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
function computed(computeFn, options) {
|
|
11
|
+
return new Signal.Computed(computeFn, transformOptions(options));
|
|
6
12
|
}
|
|
7
13
|
function signal(value, options) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
14
|
+
const state = new Signal.State(value, transformOptions(options));
|
|
15
|
+
state.update = (updateFn) => state.set(updateFn(state.get()));
|
|
16
|
+
return state;
|
|
11
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Creates or retrieves a shared signal stored on the global object. This is useful for signals that need to be shared across multiple modules without explicitly passing them around, such as localization settings or translation records.
|
|
20
|
+
*/
|
|
12
21
|
function sharedSignal(key, ...args) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
return globalThis.__ODX_SHARED_SIGNALS__[key];
|
|
17
|
-
}
|
|
18
|
-
function computed(computeFn, options) {
|
|
19
|
-
return new Signal.Computed(computeFn, transformOptions(options));
|
|
22
|
+
globalThis.__ODX_SHARED_SIGNALS__ ||= {};
|
|
23
|
+
if (!(key in globalThis.__ODX_SHARED_SIGNALS__)) globalThis.__ODX_SHARED_SIGNALS__[key] = signal(...args);
|
|
24
|
+
return globalThis.__ODX_SHARED_SIGNALS__[key];
|
|
20
25
|
}
|
|
21
26
|
let needsEnqueue = true;
|
|
22
27
|
const watcher = new Signal.subtle.Watcher(() => {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
if (!needsEnqueue) return;
|
|
29
|
+
needsEnqueue = false;
|
|
30
|
+
queueMicrotask(() => {
|
|
31
|
+
needsEnqueue = true;
|
|
32
|
+
for (const signal of watcher.getPending()) signal.get();
|
|
33
|
+
watcher.watch();
|
|
34
|
+
});
|
|
30
35
|
});
|
|
31
36
|
function effect(callback) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
37
|
+
let cleanup;
|
|
38
|
+
const signal = computed(() => {
|
|
39
|
+
cleanup?.();
|
|
40
|
+
cleanup = callback() || void 0;
|
|
41
|
+
});
|
|
42
|
+
watcher.watch(signal);
|
|
43
|
+
signal.get();
|
|
44
|
+
return () => {
|
|
45
|
+
watcher.unwatch(signal);
|
|
46
|
+
cleanup?.();
|
|
47
|
+
cleanup = void 0;
|
|
48
|
+
};
|
|
44
49
|
}
|
|
45
|
-
globalThis.__ODX_SHARED_SIGNALS__ ||= {};
|
|
46
|
-
|
|
47
50
|
export { computed, effect, sharedSignal, signal };
|
package/dist/lib/theming.d.ts
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import { ThemeConfig } from
|
|
1
|
+
import { ThemeConfig } from "@odx/design-tokens";
|
|
2
2
|
declare global {
|
|
3
|
-
|
|
3
|
+
var __ODX_THEME_ROOT__: HTMLElement;
|
|
4
4
|
}
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
5
|
+
declare const darkModeIcon = "core::night-mode";
|
|
6
|
+
declare const lightModeIcon = "core::brightness";
|
|
7
|
+
declare const userPrefersDarkMode: boolean;
|
|
8
|
+
declare function setTheme$1(config: ThemeConfig, root?: HTMLElement): void;
|
|
9
|
+
declare function isDarkModeEnabled(): boolean;
|
|
10
|
+
declare function toggleDarkMode(enabled?: boolean | 'auto', root?: HTMLElement): void;
|
|
11
|
+
interface AttachDarkModeToggleOptions<T extends HTMLElement> {
|
|
12
|
+
change?(darkModeEnabled: boolean): void;
|
|
13
|
+
update?(host: T, darkModeEnabled: boolean, icon: string): void;
|
|
14
|
+
root?: HTMLElement;
|
|
14
15
|
}
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
declare function attachDarkModeToggle<T extends HTMLElement>(host: T, options?: AttachDarkModeToggleOptions<T>): () => void;
|
|
17
|
+
export { AttachDarkModeToggleOptions, attachDarkModeToggle, darkModeIcon, isDarkModeEnabled, lightModeIcon, setTheme$1 as setTheme, toggleDarkMode, userPrefersDarkMode };
|
package/dist/lib/theming.js
CHANGED
|
@@ -1,37 +1,41 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
const { matches: userPrefersDarkMode = false } = globalThis.matchMedia?.("(prefers-color-scheme: dark)") ?? {};
|
|
1
|
+
import { effect, sharedSignal } from "./signals.js";
|
|
2
|
+
import { darkModeClass, lightModeClass, setTheme } from "@odx/design-tokens";
|
|
5
3
|
const darkModeIcon = "core::night-mode";
|
|
6
4
|
const lightModeIcon = "core::brightness";
|
|
7
|
-
|
|
5
|
+
const { matches: userPrefersDarkMode = false } = globalThis.matchMedia?.("(prefers-color-scheme: dark)") ?? {};
|
|
6
|
+
globalThis.__ODX_THEME_ROOT__ ??= document.documentElement;
|
|
8
7
|
const hasDarkModeClass = globalThis.__ODX_THEME_ROOT__.classList.contains(darkModeClass);
|
|
9
8
|
const hasLightModeClass = globalThis.__ODX_THEME_ROOT__.classList.contains(lightModeClass);
|
|
10
9
|
const darkModeEnabled = sharedSignal("darkModeEnabled", hasDarkModeClass || hasLightModeClass ? hasDarkModeClass : userPrefersDarkMode);
|
|
11
|
-
function setTheme(config, root = globalThis.__ODX_THEME_ROOT__) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
} else {
|
|
17
|
-
darkModeEnabled.set(config.mode === "dark" ? true : !isDarkModeEnabled());
|
|
18
|
-
}
|
|
10
|
+
function setTheme$1(config, root = globalThis.__ODX_THEME_ROOT__) {
|
|
11
|
+
setTheme(config, root);
|
|
12
|
+
if (!config.mode) return;
|
|
13
|
+
if (config.mode === "auto") darkModeEnabled.set(userPrefersDarkMode);
|
|
14
|
+
else darkModeEnabled.set(config.mode === "dark");
|
|
19
15
|
}
|
|
20
16
|
function isDarkModeEnabled() {
|
|
21
|
-
|
|
17
|
+
return darkModeEnabled.get();
|
|
22
18
|
}
|
|
23
19
|
function toggleDarkMode(enabled, root = globalThis.__ODX_THEME_ROOT__) {
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
enabled ||= !isDarkModeEnabled();
|
|
21
|
+
setTheme$1({ mode: enabled === "auto" ? enabled : enabled ? "dark" : "light" }, root);
|
|
26
22
|
}
|
|
27
23
|
function attachDarkModeToggle(host, options = {}) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
24
|
+
const abortController = new AbortController();
|
|
25
|
+
const cleanup = effect(() => {
|
|
26
|
+
const darkModeEnabled = isDarkModeEnabled();
|
|
27
|
+
const icon = darkModeEnabled ? lightModeIcon : darkModeIcon;
|
|
28
|
+
host.setAttribute("icon", icon);
|
|
29
|
+
options.update?.(host, darkModeEnabled, icon);
|
|
30
|
+
});
|
|
31
|
+
host.addEventListener("click", (event) => {
|
|
32
|
+
if (event.defaultPrevented) return;
|
|
33
|
+
toggleDarkMode(void 0, options.root);
|
|
34
|
+
options.change?.(isDarkModeEnabled());
|
|
35
|
+
}, { signal: abortController.signal });
|
|
36
|
+
return () => {
|
|
37
|
+
abortController.abort();
|
|
38
|
+
cleanup();
|
|
39
|
+
};
|
|
35
40
|
}
|
|
36
|
-
|
|
37
|
-
export { attachDarkModeToggle, darkModeIcon, isDarkModeEnabled, lightModeIcon, setTheme, toggleDarkMode, userPrefersDarkMode };
|
|
41
|
+
export { attachDarkModeToggle, darkModeIcon, isDarkModeEnabled, lightModeIcon, setTheme$1 as setTheme, toggleDarkMode, userPrefersDarkMode };
|
|
@@ -1,43 +1,39 @@
|
|
|
1
1
|
const mediaQueryRegistry = /* @__PURE__ */ new Map();
|
|
2
2
|
const eventListenerRegistry = /* @__PURE__ */ new Map();
|
|
3
3
|
function handleMediaChange(event) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
listenersArray[i]?.(event);
|
|
10
|
-
}
|
|
4
|
+
const listeners = eventListenerRegistry.get(event.media);
|
|
5
|
+
if (!listeners?.size) return;
|
|
6
|
+
const listenersArray = Array.from(listeners);
|
|
7
|
+
let i = listenersArray.length;
|
|
8
|
+
while (i--) listenersArray[i]?.(event);
|
|
11
9
|
}
|
|
12
10
|
function observeMedia(query, listener) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
return () => unobserveMedia(query, listener);
|
|
11
|
+
let listeners = eventListenerRegistry.get(query);
|
|
12
|
+
if (!listeners) {
|
|
13
|
+
listeners = /* @__PURE__ */ new Set();
|
|
14
|
+
eventListenerRegistry.set(query, listeners);
|
|
15
|
+
}
|
|
16
|
+
listeners.add(listener);
|
|
17
|
+
let mediaQueryList = mediaQueryRegistry.get(query);
|
|
18
|
+
if (!mediaQueryList) {
|
|
19
|
+
mediaQueryList = globalThis.matchMedia(query);
|
|
20
|
+
mediaQueryRegistry.set(query, mediaQueryList);
|
|
21
|
+
mediaQueryList.addEventListener("change", handleMediaChange);
|
|
22
|
+
}
|
|
23
|
+
listener(new MediaQueryListEvent("change", {
|
|
24
|
+
media: mediaQueryList.media,
|
|
25
|
+
matches: mediaQueryList.matches
|
|
26
|
+
}));
|
|
27
|
+
return () => unobserveMedia(query, listener);
|
|
31
28
|
}
|
|
32
29
|
function unobserveMedia(query, listener) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
30
|
+
const listeners = eventListenerRegistry.get(query);
|
|
31
|
+
if (!listeners?.delete(listener)) return;
|
|
32
|
+
if (listeners.size > 0) return;
|
|
33
|
+
eventListenerRegistry.delete(query);
|
|
34
|
+
const mediaQueryList = mediaQueryRegistry.get(query);
|
|
35
|
+
if (!mediaQueryList) return;
|
|
36
|
+
mediaQueryList.removeEventListener("change", handleMediaChange);
|
|
37
|
+
mediaQueryRegistry.delete(query);
|
|
41
38
|
}
|
|
42
|
-
|
|
43
|
-
export { observeMedia, unobserveMedia };
|
|
39
|
+
export { observeMedia };
|
package/dist/main.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import { ReadonlySignal, Signal, SignalOptions, computed, effect, sharedSignal, signal } from "./lib/signals.js";
|
|
2
|
+
import { Breakpoint, BreakpointConfig, BreakpointOperator, breakpointAttribute, buildBreakpoint, createBreakpointUpdater, defaultBreakpoints, expandBreakpoints, observeBreakpoint, registeredBreakpoints, setupBreakpoints } from "./lib/breakpoints.js";
|
|
3
|
+
import { UnitIdentifier } from "./lib/models.js";
|
|
4
|
+
import { DateTimeFormatOptions, FormatOptions, ListFormatOptions, NumberFormatOptions, RelativeTimeFormatOptions, formatDate, formatList, formatNumber, formatRelativeTime, parseDate } from "./lib/format.js";
|
|
5
|
+
import { LocalizationOptions, getLocale, getLocalizationOptions, setLocale, setLocalizationOptions } from "./lib/localization.js";
|
|
6
|
+
import { applyScrollLock, removeAllScrollLocks, removeScrollLock } from "./lib/scroll-lock.js";
|
|
7
|
+
import { AttachDarkModeToggleOptions, attachDarkModeToggle, darkModeIcon, isDarkModeEnabled, lightModeIcon, setTheme, toggleDarkMode, userPrefersDarkMode } from "./lib/theming.js";
|
|
8
|
+
export { AttachDarkModeToggleOptions, Breakpoint, BreakpointConfig, BreakpointOperator, DateTimeFormatOptions, FormatOptions, ListFormatOptions, LocalizationOptions, NumberFormatOptions, ReadonlySignal, RelativeTimeFormatOptions, Signal, SignalOptions, type UnitIdentifier, applyScrollLock, attachDarkModeToggle, breakpointAttribute, buildBreakpoint, computed, createBreakpointUpdater, darkModeIcon, defaultBreakpoints, effect, expandBreakpoints, formatDate, formatList, formatNumber, formatRelativeTime, getLocale, getLocalizationOptions, isDarkModeEnabled, lightModeIcon, observeBreakpoint, parseDate, registeredBreakpoints, removeAllScrollLocks, removeScrollLock, setLocale, setLocalizationOptions, setTheme, setupBreakpoints, sharedSignal, signal, toggleDarkMode, userPrefersDarkMode };
|
package/dist/main.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { computed, effect, sharedSignal, signal } from "./lib/signals.js";
|
|
2
|
+
import { breakpointAttribute, buildBreakpoint, createBreakpointUpdater, defaultBreakpoints, expandBreakpoints, observeBreakpoint, registeredBreakpoints, setupBreakpoints } from "./lib/breakpoints.js";
|
|
3
|
+
import { formatDate, formatList, formatNumber, formatRelativeTime, parseDate } from "./lib/format.js";
|
|
4
|
+
import { LocalizationOptions, getLocale, getLocalizationOptions, setLocale, setLocalizationOptions } from "./lib/localization.js";
|
|
5
|
+
import { applyScrollLock, removeAllScrollLocks, removeScrollLock } from "./lib/scroll-lock.js";
|
|
6
|
+
import { attachDarkModeToggle, darkModeIcon, isDarkModeEnabled, lightModeIcon, setTheme, toggleDarkMode, userPrefersDarkMode } from "./lib/theming.js";
|
|
7
|
+
export { LocalizationOptions, applyScrollLock, attachDarkModeToggle, breakpointAttribute, buildBreakpoint, computed, createBreakpointUpdater, darkModeIcon, defaultBreakpoints, effect, expandBreakpoints, formatDate, formatList, formatNumber, formatRelativeTime, getLocale, getLocalizationOptions, isDarkModeEnabled, lightModeIcon, observeBreakpoint, parseDate, registeredBreakpoints, removeAllScrollLocks, removeScrollLock, setLocale, setLocalizationOptions, setTheme, setupBreakpoints, sharedSignal, signal, toggleDarkMode, userPrefersDarkMode };
|