@twentyfirstmedia/ui-core 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/admin.d.ts.map +1 -1
- package/dist/components/admin.js +95 -71
- package/dist/components/admin.js.map +1 -1
- package/dist/components/agents.d.ts.map +1 -1
- package/dist/components/agents.js +49 -35
- package/dist/components/agents.js.map +1 -1
- package/dist/components/app-chrome.d.ts.map +1 -1
- package/dist/components/app-chrome.js +6 -2
- package/dist/components/app-chrome.js.map +1 -1
- package/dist/components/approvals.d.ts.map +1 -1
- package/dist/components/approvals.js +22 -18
- package/dist/components/approvals.js.map +1 -1
- package/dist/components/building-blocks.d.ts.map +1 -1
- package/dist/components/building-blocks.js +6 -2
- package/dist/components/building-blocks.js.map +1 -1
- package/dist/components/charts.d.ts.map +1 -1
- package/dist/components/charts.js +20 -10
- package/dist/components/charts.js.map +1 -1
- package/dist/components/chat.d.ts.map +1 -1
- package/dist/components/chat.js +31 -19
- package/dist/components/chat.js.map +1 -1
- package/dist/components/commerce.d.ts +2 -2
- package/dist/components/commerce.d.ts.map +1 -1
- package/dist/components/commerce.js +45 -31
- package/dist/components/commerce.js.map +1 -1
- package/dist/components/data-display.d.ts +5 -9
- package/dist/components/data-display.d.ts.map +1 -1
- package/dist/components/data-display.js +34 -35
- package/dist/components/data-display.js.map +1 -1
- package/dist/components/data-table.d.ts.map +1 -1
- package/dist/components/data-table.js +15 -10
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/developer.d.ts.map +1 -1
- package/dist/components/developer.js +20 -11
- package/dist/components/developer.js.map +1 -1
- package/dist/components/feedback.d.ts.map +1 -1
- package/dist/components/feedback.js +12 -6
- package/dist/components/feedback.js.map +1 -1
- package/dist/components/form.d.ts +2 -1
- package/dist/components/form.d.ts.map +1 -1
- package/dist/components/form.js +12 -9
- package/dist/components/form.js.map +1 -1
- package/dist/components/forms.d.ts +2 -1
- package/dist/components/forms.d.ts.map +1 -1
- package/dist/components/forms.js +92 -42
- package/dist/components/forms.js.map +1 -1
- package/dist/components/foundation.d.ts +5 -2
- package/dist/components/foundation.d.ts.map +1 -1
- package/dist/components/foundation.js +15 -12
- package/dist/components/foundation.js.map +1 -1
- package/dist/components/inputs.d.ts.map +1 -1
- package/dist/components/inputs.js +3 -1
- package/dist/components/inputs.js.map +1 -1
- package/dist/components/mail.d.ts.map +1 -1
- package/dist/components/mail.js +15 -10
- package/dist/components/mail.js.map +1 -1
- package/dist/components/media.d.ts.map +1 -1
- package/dist/components/media.js +39 -18
- package/dist/components/media.js.map +1 -1
- package/dist/components/navigation.d.ts.map +1 -1
- package/dist/components/navigation.js +21 -9
- package/dist/components/navigation.js.map +1 -1
- package/dist/components/operations.d.ts.map +1 -1
- package/dist/components/operations.js +37 -27
- package/dist/components/operations.js.map +1 -1
- package/dist/components/previews.d.ts.map +1 -1
- package/dist/components/previews.js +14 -10
- package/dist/components/previews.js.map +1 -1
- package/dist/components/primitives.d.ts.map +1 -1
- package/dist/components/primitives.js +4 -1
- package/dist/components/primitives.js.map +1 -1
- package/dist/components/real-estate.d.ts.map +1 -1
- package/dist/components/real-estate.js +43 -28
- package/dist/components/real-estate.js.map +1 -1
- package/dist/components/rich-text-editor.d.ts.map +1 -1
- package/dist/components/rich-text-editor.js +18 -15
- package/dist/components/rich-text-editor.js.map +1 -1
- package/dist/components/select-menu.d.ts.map +1 -1
- package/dist/components/select-menu.js +4 -1
- package/dist/components/select-menu.js.map +1 -1
- package/dist/components/shell.d.ts.map +1 -1
- package/dist/components/shell.js +8 -3
- package/dist/components/shell.js.map +1 -1
- package/dist/components/site.d.ts.map +1 -1
- package/dist/components/site.js +17 -13
- package/dist/components/site.js.map +1 -1
- package/dist/components/types.d.ts +102 -3
- package/dist/components/types.d.ts.map +1 -1
- package/dist/components/workspace.d.ts.map +1 -1
- package/dist/components/workspace.js +50 -34
- package/dist/components/workspace.js.map +1 -1
- package/dist/context.d.ts +39 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +76 -0
- package/dist/context.js.map +1 -0
- package/dist/format.d.ts +33 -6
- package/dist/format.d.ts.map +1 -1
- package/dist/format.js +75 -10
- package/dist/format.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/provider.d.ts +18 -11
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +11 -18
- package/dist/provider.js.map +1 -1
- package/dist/strings.d.ts +503 -0
- package/dist/strings.d.ts.map +1 -0
- package/dist/strings.js +537 -0
- package/dist/strings.js.map +1 -0
- package/package.json +1 -1
- package/src/components/admin.tsx +117 -93
- package/src/components/agents.tsx +55 -41
- package/src/components/app-chrome.tsx +6 -2
- package/src/components/approvals.tsx +26 -22
- package/src/components/building-blocks.tsx +6 -2
- package/src/components/charts.tsx +21 -11
- package/src/components/chat.tsx +45 -35
- package/src/components/commerce.tsx +61 -53
- package/src/components/data-display.tsx +38 -45
- package/src/components/data-table.tsx +20 -15
- package/src/components/developer.tsx +26 -15
- package/src/components/feedback.tsx +19 -7
- package/src/components/form.tsx +17 -9
- package/src/components/forms.tsx +131 -53
- package/src/components/foundation.tsx +23 -36
- package/src/components/inputs.tsx +4 -2
- package/src/components/mail.tsx +16 -11
- package/src/components/media.tsx +64 -21
- package/src/components/navigation.tsx +25 -13
- package/src/components/operations.tsx +40 -32
- package/src/components/previews.tsx +17 -15
- package/src/components/primitives.tsx +8 -5
- package/src/components/real-estate.tsx +55 -35
- package/src/components/rich-text-editor.tsx +20 -17
- package/src/components/select-menu.tsx +5 -2
- package/src/components/shell.tsx +8 -3
- package/src/components/site.tsx +18 -14
- package/src/components/types.ts +111 -3
- package/src/components/workspace.tsx +79 -60
- package/src/context.ts +112 -0
- package/src/format.ts +108 -15
- package/src/index.ts +43 -0
- package/src/provider.tsx +36 -40
- package/src/strings.ts +1500 -0
package/src/format.ts
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Numbers, money, percentages and dates, formatted with Intl
|
|
3
|
-
*
|
|
2
|
+
* Numbers, money, percentages and dates, formatted with Intl. English (en-US) by default; every
|
|
3
|
+
* helper takes an optional BCP 47 locale as its last argument, and components use the locale of
|
|
4
|
+
* the nearest `UIProvider` (see `useFormat`). Money defaults to euros; calendars start on Monday.
|
|
4
5
|
*/
|
|
5
6
|
export const LOCALE = "en-US";
|
|
6
7
|
export const CURRENCY = "EUR";
|
|
7
8
|
/** First day of the week in calendars: 0 Sunday … 6 Saturday. */
|
|
8
9
|
export const WEEK_START = 1;
|
|
9
10
|
|
|
10
|
-
export function formatNumber(v: number, o?: Intl.NumberFormatOptions): string {
|
|
11
|
+
export function formatNumber(v: number, o?: Intl.NumberFormatOptions, locale?: string): string {
|
|
11
12
|
try {
|
|
12
|
-
return new Intl.NumberFormat(LOCALE, o).format(v);
|
|
13
|
+
return new Intl.NumberFormat(locale || LOCALE, o).format(v);
|
|
13
14
|
} catch {
|
|
14
15
|
return String(v);
|
|
15
16
|
}
|
|
@@ -19,29 +20,121 @@ export function formatMoney(
|
|
|
19
20
|
v: number,
|
|
20
21
|
currency?: string | null,
|
|
21
22
|
o?: Intl.NumberFormatOptions,
|
|
23
|
+
locale?: string,
|
|
22
24
|
): string {
|
|
23
|
-
return formatNumber(
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
return formatNumber(
|
|
26
|
+
v,
|
|
27
|
+
{
|
|
28
|
+
style: "currency",
|
|
29
|
+
currency: currency || CURRENCY,
|
|
30
|
+
minimumFractionDigits: v % 1 ? 2 : 0,
|
|
31
|
+
maximumFractionDigits: 2,
|
|
32
|
+
...o,
|
|
33
|
+
},
|
|
34
|
+
locale,
|
|
35
|
+
);
|
|
30
36
|
}
|
|
31
37
|
|
|
32
38
|
/** A share in percent: `19` → "19%". */
|
|
33
|
-
export function formatPercent(v: number, o?: Intl.NumberFormatOptions): string {
|
|
34
|
-
return formatNumber(v / 100, { style: "percent", maximumFractionDigits: 0, ...o });
|
|
39
|
+
export function formatPercent(v: number, o?: Intl.NumberFormatOptions, locale?: string): string {
|
|
40
|
+
return formatNumber(v / 100, { style: "percent", maximumFractionDigits: 0, ...o }, locale);
|
|
35
41
|
}
|
|
36
42
|
|
|
37
|
-
export function formatDate(
|
|
43
|
+
export function formatDate(
|
|
44
|
+
input: Date | string | number,
|
|
45
|
+
o?: Intl.DateTimeFormatOptions,
|
|
46
|
+
locale?: string,
|
|
47
|
+
): string {
|
|
38
48
|
const d = input instanceof Date ? input : new Date(input);
|
|
39
49
|
try {
|
|
40
50
|
return new Intl.DateTimeFormat(
|
|
41
|
-
LOCALE,
|
|
51
|
+
locale || LOCALE,
|
|
42
52
|
o || { day: "2-digit", month: "2-digit", year: "numeric" },
|
|
43
53
|
).format(d);
|
|
44
54
|
} catch {
|
|
45
55
|
return d.toDateString();
|
|
46
56
|
}
|
|
47
57
|
}
|
|
58
|
+
|
|
59
|
+
/** The group and decimal separators of a locale: `en-US` → `{ group: ",", decimal: "." }`. */
|
|
60
|
+
export function numberSeparators(locale?: string): { group: string; decimal: string } {
|
|
61
|
+
let group = ",",
|
|
62
|
+
decimal = ".";
|
|
63
|
+
try {
|
|
64
|
+
for (const part of new Intl.NumberFormat(locale || LOCALE).formatToParts(12345.6)) {
|
|
65
|
+
if (part.type === "group") group = part.value;
|
|
66
|
+
else if (part.type === "decimal") decimal = part.value;
|
|
67
|
+
}
|
|
68
|
+
} catch {
|
|
69
|
+
// keep the English separators
|
|
70
|
+
}
|
|
71
|
+
return { group, decimal };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const escape = (s: string) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
75
|
+
|
|
76
|
+
/** A number inside a formatted string, as `parseFormatted` finds it. */
|
|
77
|
+
export interface FormattedNumber {
|
|
78
|
+
/** Text before the number ("€", "+"). */
|
|
79
|
+
prefix: string;
|
|
80
|
+
value: number;
|
|
81
|
+
/** Digits after the decimal separator. */
|
|
82
|
+
decimals: number;
|
|
83
|
+
/** Whether the number used group separators ("1,305"). */
|
|
84
|
+
grouped: boolean;
|
|
85
|
+
/** Text after the number (" €/m²", "%"). */
|
|
86
|
+
suffix: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Finds the first number in a string formatted for `locale` and returns it with the text around
|
|
91
|
+
* it: `parseFormatted("13,05 €/m²", "de-DE")` → `{ prefix: "", value: 13.05, decimals: 2, … }`.
|
|
92
|
+
* Group separators are only taken between digits; a space or no-break space counts as a group
|
|
93
|
+
* separator for locales that group with one.
|
|
94
|
+
*/
|
|
95
|
+
export function parseFormatted(input: string | number, locale?: string): FormattedNumber | null {
|
|
96
|
+
if (typeof input === "number") {
|
|
97
|
+
if (!Number.isFinite(input)) return null;
|
|
98
|
+
const s = String(input);
|
|
99
|
+
if (/e/i.test(s)) return null;
|
|
100
|
+
return {
|
|
101
|
+
prefix: "",
|
|
102
|
+
value: input,
|
|
103
|
+
decimals: (s.split(".")[1] || "").length,
|
|
104
|
+
grouped: false,
|
|
105
|
+
suffix: "",
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
const { group, decimal } = numberSeparators(locale);
|
|
109
|
+
// narrow and regular no-break spaces both appear as group separators (fr, de-CH …)
|
|
110
|
+
const groups = /^\s$/.test(group) ? "[\\s\\u00a0\\u202f]" : escape(group);
|
|
111
|
+
const re = new RegExp(
|
|
112
|
+
`^([^0-9-]*)(-?[0-9](?:[0-9]|${groups}(?=[0-9]))*)(?:${escape(decimal)}([0-9]+))?(.*)$`,
|
|
113
|
+
"s",
|
|
114
|
+
);
|
|
115
|
+
const m = re.exec(input);
|
|
116
|
+
if (!m) return null;
|
|
117
|
+
const int = (m[2] as string).replace(new RegExp(groups, "g"), "");
|
|
118
|
+
const frac = m[3] ?? "";
|
|
119
|
+
return {
|
|
120
|
+
prefix: m[1] ?? "",
|
|
121
|
+
value: parseFloat(frac ? `${int}.${frac}` : int),
|
|
122
|
+
decimals: frac.length,
|
|
123
|
+
grouped: int.length !== (m[2] as string).length,
|
|
124
|
+
suffix: m[4] ?? "",
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Writes a number back in the shape `parseFormatted` found it in (same decimals, grouping, text). */
|
|
129
|
+
export function formatLike(v: number, shape: FormattedNumber, locale?: string): string {
|
|
130
|
+
const s = formatNumber(
|
|
131
|
+
v,
|
|
132
|
+
{
|
|
133
|
+
minimumFractionDigits: shape.decimals,
|
|
134
|
+
maximumFractionDigits: shape.decimals,
|
|
135
|
+
useGrouping: shape.grouped,
|
|
136
|
+
},
|
|
137
|
+
locale,
|
|
138
|
+
);
|
|
139
|
+
return shape.prefix + s + shape.suffix;
|
|
140
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -4,13 +4,56 @@ export {
|
|
|
4
4
|
formatPercent,
|
|
5
5
|
formatMoney,
|
|
6
6
|
formatDate,
|
|
7
|
+
formatLike,
|
|
8
|
+
parseFormatted,
|
|
9
|
+
numberSeparators,
|
|
7
10
|
LOCALE,
|
|
8
11
|
CURRENCY,
|
|
9
12
|
WEEK_START,
|
|
13
|
+
type FormattedNumber,
|
|
10
14
|
} from "./format.js";
|
|
15
|
+
export {
|
|
16
|
+
DEFAULT_STRINGS,
|
|
17
|
+
SHARED_STRINGS,
|
|
18
|
+
ADMIN_STRINGS,
|
|
19
|
+
AGENTS_STRINGS,
|
|
20
|
+
APP_CHROME_STRINGS,
|
|
21
|
+
APPROVALS_STRINGS,
|
|
22
|
+
BUILDING_BLOCKS_STRINGS,
|
|
23
|
+
CHARTS_STRINGS,
|
|
24
|
+
CHAT_STRINGS,
|
|
25
|
+
COMMERCE_STRINGS,
|
|
26
|
+
DATA_DISPLAY_STRINGS,
|
|
27
|
+
DATA_TABLE_STRINGS,
|
|
28
|
+
DEVELOPER_STRINGS,
|
|
29
|
+
FEEDBACK_STRINGS,
|
|
30
|
+
FORM_STRINGS,
|
|
31
|
+
FORMS_STRINGS,
|
|
32
|
+
MAIL_STRINGS,
|
|
33
|
+
MEDIA_STRINGS,
|
|
34
|
+
NAVIGATION_STRINGS,
|
|
35
|
+
OPERATIONS_STRINGS,
|
|
36
|
+
PREVIEWS_STRINGS,
|
|
37
|
+
PRIMITIVES_STRINGS,
|
|
38
|
+
REAL_ESTATE_STRINGS,
|
|
39
|
+
RICH_TEXT_EDITOR_STRINGS,
|
|
40
|
+
SELECT_MENU_STRINGS,
|
|
41
|
+
SHELL_STRINGS,
|
|
42
|
+
SITE_STRINGS,
|
|
43
|
+
WORKSPACE_STRINGS,
|
|
44
|
+
mergeStrings,
|
|
45
|
+
mergeMessages,
|
|
46
|
+
type UIStrings,
|
|
47
|
+
type UIMessages,
|
|
48
|
+
} from "./strings.js";
|
|
11
49
|
export {
|
|
12
50
|
UIProvider,
|
|
13
51
|
useUI,
|
|
52
|
+
useUIStrings,
|
|
53
|
+
useStrings,
|
|
54
|
+
useFormat,
|
|
55
|
+
formattersFor,
|
|
56
|
+
type Formatters,
|
|
14
57
|
type UIProviderProps,
|
|
15
58
|
type UIContextValue,
|
|
16
59
|
type Kit,
|
package/src/provider.tsx
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
useEffect,
|
|
6
|
-
useMemo,
|
|
7
|
-
useRef,
|
|
8
|
-
useState,
|
|
9
|
-
type CSSProperties,
|
|
10
|
-
type ReactNode,
|
|
11
|
-
} from "react";
|
|
2
|
+
import { useEffect, useMemo, useRef, useState, type CSSProperties, type ReactNode } from "react";
|
|
3
|
+
import { UIContext, useUI, type UIContextValue } from "./context.js";
|
|
4
|
+
import { mergeMessages, type UIMessages } from "./strings.js";
|
|
12
5
|
import { themeStyle, type ThemeInput, type ThemeValues } from "./theme.js";
|
|
6
|
+
|
|
7
|
+
export {
|
|
8
|
+
useUI,
|
|
9
|
+
useUIStrings,
|
|
10
|
+
useStrings,
|
|
11
|
+
useFormat,
|
|
12
|
+
formattersFor,
|
|
13
|
+
type UIContextValue,
|
|
14
|
+
type Formatters,
|
|
15
|
+
} from "./context.js";
|
|
13
16
|
export type Kit = "halo" | "pro";
|
|
14
17
|
export type Theme = "light" | "dark" | "system";
|
|
15
18
|
export type Density = "compact" | "comfortable";
|
|
@@ -53,39 +56,23 @@ export interface UIProviderProps {
|
|
|
53
56
|
* reduced-motion setting always turns motion off.
|
|
54
57
|
*/
|
|
55
58
|
motion?: Motion;
|
|
59
|
+
/**
|
|
60
|
+
* BCP 47 locale for the numbers, money, percentages and dates components show (`"de-DE"`).
|
|
61
|
+
* Default `"en-US"`; a nested provider keeps its parent's locale unless it sets its own.
|
|
62
|
+
*/
|
|
63
|
+
locale?: string;
|
|
64
|
+
/**
|
|
65
|
+
* Your own text for any built-in string: accessible names, button texts, placeholders, status
|
|
66
|
+
* words (`{ close: "Schließen", selectedCount: (n) => \`${n} ausgewählt\` }`). Partial: what you
|
|
67
|
+
* leave out stays English (or what an outer provider set). Props such as `title` or `label` on a
|
|
68
|
+
* component still win. See `DEFAULT_STRINGS` for every key.
|
|
69
|
+
*/
|
|
70
|
+
messages?: UIMessages;
|
|
56
71
|
className?: string;
|
|
57
72
|
style?: CSSProperties;
|
|
58
73
|
children?: ReactNode;
|
|
59
74
|
}
|
|
60
75
|
|
|
61
|
-
export interface UIContextValue {
|
|
62
|
-
kit: Kit | undefined;
|
|
63
|
-
theme: Theme | undefined;
|
|
64
|
-
density: Density | undefined;
|
|
65
|
-
surface: Surface | undefined;
|
|
66
|
-
motion: Motion | undefined;
|
|
67
|
-
/** Element portals render into (null: document.body). */
|
|
68
|
-
portalRoot: HTMLElement | null;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const UIContext = createContext<UIContextValue>({
|
|
72
|
-
kit: undefined,
|
|
73
|
-
theme: undefined,
|
|
74
|
-
density: undefined,
|
|
75
|
-
surface: undefined,
|
|
76
|
-
motion: undefined,
|
|
77
|
-
portalRoot: null,
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
/** Current kit, theme, density and portal target. */
|
|
81
|
-
export function useUI(): UIContextValue {
|
|
82
|
-
return useContext(UIContext);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Sets kit, theme and density for everything inside (they only change attributes, so switching
|
|
87
|
-
* never re-mounts the subtree).
|
|
88
|
-
*/
|
|
89
76
|
/** True while the colour scheme the page shows is dark (theme prop, kit default, system). */
|
|
90
77
|
function useDarkMode(theme: Theme | undefined, kit: Kit | undefined, enabled: boolean): boolean {
|
|
91
78
|
const [systemDark, setSystemDark] = useState(false);
|
|
@@ -106,6 +93,10 @@ function useDarkMode(theme: Theme | undefined, kit: Kit | undefined, enabled: bo
|
|
|
106
93
|
const isThemeInput = (t: ThemeValues | ThemeInput): t is ThemeInput =>
|
|
107
94
|
"light" in t || "dark" in t || "radius" in t;
|
|
108
95
|
|
|
96
|
+
/**
|
|
97
|
+
* Sets kit, theme, density, locale and strings for everything inside (switching never re-mounts
|
|
98
|
+
* the subtree: kit, theme and density only change attributes, locale and strings re-render).
|
|
99
|
+
*/
|
|
109
100
|
export function UIProvider(p: UIProviderProps) {
|
|
110
101
|
const parent = useUI();
|
|
111
102
|
const scope = p.scope ?? "document";
|
|
@@ -115,6 +106,11 @@ export function UIProvider(p: UIProviderProps) {
|
|
|
115
106
|
const density = p.density ?? parent.density;
|
|
116
107
|
const surface = p.surface ?? parent.surface;
|
|
117
108
|
const motion = p.motion ?? parent.motion;
|
|
109
|
+
const locale = p.locale || parent.locale;
|
|
110
|
+
const messages = useMemo(
|
|
111
|
+
() => (p.messages ? mergeMessages(parent.messages, p.messages) : parent.messages),
|
|
112
|
+
[parent.messages, p.messages],
|
|
113
|
+
);
|
|
118
114
|
const perMode = !!p.tokens && isThemeInput(p.tokens);
|
|
119
115
|
const dark = useDarkMode(theme, kit, perMode);
|
|
120
116
|
const vars = useMemo(() => {
|
|
@@ -155,8 +151,8 @@ export function UIProvider(p: UIProviderProps) {
|
|
|
155
151
|
|
|
156
152
|
const [portalRoot, setPortalRoot] = useState<HTMLElement | null>(null);
|
|
157
153
|
const ctx = useMemo<UIContextValue>(
|
|
158
|
-
() => ({ kit, theme, density, surface, motion, portalRoot }),
|
|
159
|
-
[kit, theme, density, surface, motion, portalRoot],
|
|
154
|
+
() => ({ kit, theme, density, surface, motion, locale, messages, portalRoot }),
|
|
155
|
+
[kit, theme, density, surface, motion, locale, messages, portalRoot],
|
|
160
156
|
);
|
|
161
157
|
// Derived colours (glass, hover shades, Pro's scale) are worked out where data-theme sits. A
|
|
162
158
|
// subtree with its own tokens needs data-theme too, or they would keep the outer values.
|