@bug-on/m3-expressive 1.1.0 → 1.2.1
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 +18 -0
- package/dist/buttons.d.mts +3 -3
- package/dist/buttons.d.ts +3 -3
- package/dist/buttons.js +708 -606
- package/dist/buttons.js.map +1 -1
- package/dist/buttons.mjs +707 -605
- package/dist/buttons.mjs.map +1 -1
- package/dist/core-Bc5Wj_pc.d.ts +497 -0
- package/dist/core-D4048_K5.d.mts +497 -0
- package/dist/core.d.mts +6 -422
- package/dist/core.d.ts +6 -422
- package/dist/core.js +223 -129
- package/dist/core.js.map +1 -1
- package/dist/core.mjs +224 -130
- package/dist/core.mjs.map +1 -1
- package/dist/feedback.js +85 -61
- package/dist/feedback.js.map +1 -1
- package/dist/feedback.mjs +85 -61
- package/dist/feedback.mjs.map +1 -1
- package/dist/forms.d.mts +2 -2
- package/dist/forms.d.ts +2 -2
- package/dist/forms.js +70 -8
- package/dist/forms.js.map +1 -1
- package/dist/forms.mjs +70 -8
- package/dist/forms.mjs.map +1 -1
- package/dist/{icon-button-D-gs0gfj.d.mts → icon-button-sSt6PPLg.d.mts} +6 -0
- package/dist/{icon-button-D-gs0gfj.d.ts → icon-button-sSt6PPLg.d.ts} +6 -0
- package/dist/index.css +6 -1
- package/dist/index.d.mts +68 -6
- package/dist/index.d.ts +68 -6
- package/dist/index.js +1177 -580
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1172 -583
- package/dist/index.mjs.map +1 -1
- package/dist/layout.d.mts +18 -1
- package/dist/layout.d.ts +18 -1
- package/dist/layout.js +94 -8
- package/dist/layout.js.map +1 -1
- package/dist/layout.mjs +94 -8
- package/dist/layout.mjs.map +1 -1
- package/dist/{md3-DFhj-NZj.d.mts → md3-Dty-Qcad.d.mts} +7 -1
- package/dist/{md3-DFhj-NZj.d.ts → md3-Dty-Qcad.d.ts} +7 -1
- package/dist/navigation.d.mts +134 -9
- package/dist/navigation.d.ts +134 -9
- package/dist/navigation.js +403 -93
- package/dist/navigation.js.map +1 -1
- package/dist/navigation.mjs +397 -94
- package/dist/navigation.mjs.map +1 -1
- package/dist/overlays.js +214 -189
- package/dist/overlays.js.map +1 -1
- package/dist/overlays.mjs +176 -151
- package/dist/overlays.mjs.map +1 -1
- package/dist/pickers.js +222 -197
- package/dist/pickers.js.map +1 -1
- package/dist/pickers.mjs +189 -164
- package/dist/pickers.mjs.map +1 -1
- package/dist/{split-button-trailing-uncheckable-BRPuTqi1.d.mts → split-button-trailing-uncheckable-BcPD_7uK.d.ts} +73 -7
- package/dist/{split-button-trailing-uncheckable-CjOFCoyW.d.ts → split-button-trailing-uncheckable-DtFJkTFr.d.mts} +73 -7
- package/dist/{text-field-eAIpz9z1.d.mts → text-field-T4Rg-9Bw.d.mts} +7 -0
- package/dist/{text-field-eAIpz9z1.d.ts → text-field-T4Rg-9Bw.d.ts} +7 -0
- package/package.json +4 -4
package/dist/core.mjs
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
import * as React11 from 'react';
|
|
3
3
|
import { createContext, useState, useEffect, useRef, useCallback, useMemo, useContext } from 'react';
|
|
4
4
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
5
|
-
import {
|
|
5
|
+
import { hexFromArgb, Hct, SchemeExpressive, SchemeNeutral, SchemeMonochrome, SchemeContent, SchemeFidelity, SchemeVibrant, SchemeTonalSpot } from '@material/material-color-utilities';
|
|
6
6
|
import { clsx } from 'clsx';
|
|
7
7
|
import { twMerge } from 'tailwind-merge';
|
|
8
8
|
import { LazyMotion, domMax, m, useMotionValue, animate, useAnimationFrame, AnimatePresence, useReducedMotion } from 'motion/react';
|
|
9
|
+
import { Slot } from '@radix-ui/react-slot';
|
|
9
10
|
|
|
10
11
|
var __defProp = Object.defineProperty;
|
|
11
12
|
var __defProps = Object.defineProperties;
|
|
@@ -151,66 +152,110 @@ function resolveMode(mode) {
|
|
|
151
152
|
if (typeof window === "undefined") return "light";
|
|
152
153
|
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
153
154
|
}
|
|
154
|
-
function
|
|
155
|
-
const
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
155
|
+
function createDynamicScheme(sourceColorHex, isDark, variant = "expressive", contrastLevel = 0) {
|
|
156
|
+
const hct = Hct.fromInt(argbFromHex(sourceColorHex));
|
|
157
|
+
const spec = "2025";
|
|
158
|
+
switch (variant) {
|
|
159
|
+
case "tonal_spot":
|
|
160
|
+
return new SchemeTonalSpot(hct, isDark, contrastLevel, spec);
|
|
161
|
+
case "vibrant":
|
|
162
|
+
return new SchemeVibrant(hct, isDark, contrastLevel, spec);
|
|
163
|
+
case "fidelity":
|
|
164
|
+
return new SchemeFidelity(hct, isDark, contrastLevel, spec);
|
|
165
|
+
case "content":
|
|
166
|
+
return new SchemeContent(hct, isDark, contrastLevel, spec);
|
|
167
|
+
case "monochrome":
|
|
168
|
+
return new SchemeMonochrome(hct, isDark, contrastLevel, spec);
|
|
169
|
+
case "neutral":
|
|
170
|
+
return new SchemeNeutral(hct, isDark, contrastLevel, spec);
|
|
171
|
+
default:
|
|
172
|
+
return new SchemeExpressive(hct, isDark, contrastLevel, spec);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
function argbFromHex(hex) {
|
|
176
|
+
const sanitized = hex.replace(/^#/, "");
|
|
177
|
+
const r = Number.parseInt(sanitized.substring(0, 2), 16);
|
|
178
|
+
const g = Number.parseInt(sanitized.substring(2, 4), 16);
|
|
179
|
+
const b = Number.parseInt(sanitized.substring(4, 6), 16);
|
|
180
|
+
return (4278190080 | r << 16 | g << 8 | b) >>> 0;
|
|
181
|
+
}
|
|
182
|
+
function generateM3Theme(sourceColorHex, mode = "light", options = {}) {
|
|
183
|
+
const { variant = "expressive", contrastLevel = 0 } = options;
|
|
184
|
+
const isDark = mode === "dark";
|
|
185
|
+
const scheme = createDynamicScheme(
|
|
186
|
+
sourceColorHex,
|
|
187
|
+
isDark,
|
|
188
|
+
variant,
|
|
189
|
+
contrastLevel
|
|
190
|
+
);
|
|
191
|
+
const hex = (argb) => hexFromArgb(argb);
|
|
160
192
|
return {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
193
|
+
// Primary
|
|
194
|
+
primary: hex(scheme.primary),
|
|
195
|
+
onPrimary: hex(scheme.onPrimary),
|
|
196
|
+
primaryContainer: hex(scheme.primaryContainer),
|
|
197
|
+
onPrimaryContainer: hex(scheme.onPrimaryContainer),
|
|
198
|
+
inversePrimary: hex(scheme.inversePrimary),
|
|
199
|
+
primaryFixed: hex(scheme.primaryFixed),
|
|
200
|
+
primaryFixedDim: hex(scheme.primaryFixedDim),
|
|
201
|
+
onPrimaryFixed: hex(scheme.onPrimaryFixed),
|
|
202
|
+
onPrimaryFixedVariant: hex(scheme.onPrimaryFixedVariant),
|
|
203
|
+
primaryDim: hex(scheme.primaryDim),
|
|
204
|
+
// Secondary
|
|
205
|
+
secondary: hex(scheme.secondary),
|
|
206
|
+
onSecondary: hex(scheme.onSecondary),
|
|
207
|
+
secondaryContainer: hex(scheme.secondaryContainer),
|
|
208
|
+
onSecondaryContainer: hex(scheme.onSecondaryContainer),
|
|
209
|
+
secondaryFixed: hex(scheme.secondaryFixed),
|
|
210
|
+
secondaryFixedDim: hex(scheme.secondaryFixedDim),
|
|
211
|
+
onSecondaryFixed: hex(scheme.onSecondaryFixed),
|
|
212
|
+
onSecondaryFixedVariant: hex(scheme.onSecondaryFixedVariant),
|
|
213
|
+
secondaryDim: hex(scheme.secondaryDim),
|
|
214
|
+
// Tertiary
|
|
215
|
+
tertiary: hex(scheme.tertiary),
|
|
216
|
+
onTertiary: hex(scheme.onTertiary),
|
|
217
|
+
tertiaryContainer: hex(scheme.tertiaryContainer),
|
|
218
|
+
onTertiaryContainer: hex(scheme.onTertiaryContainer),
|
|
219
|
+
tertiaryFixed: hex(scheme.tertiaryFixed),
|
|
220
|
+
tertiaryFixedDim: hex(scheme.tertiaryFixedDim),
|
|
221
|
+
onTertiaryFixed: hex(scheme.onTertiaryFixed),
|
|
222
|
+
onTertiaryFixedVariant: hex(scheme.onTertiaryFixedVariant),
|
|
223
|
+
tertiaryDim: hex(scheme.tertiaryDim),
|
|
224
|
+
// Error
|
|
225
|
+
error: hex(scheme.error),
|
|
226
|
+
onError: hex(scheme.onError),
|
|
227
|
+
errorContainer: hex(scheme.errorContainer),
|
|
228
|
+
onErrorContainer: hex(scheme.onErrorContainer),
|
|
229
|
+
// Surface
|
|
230
|
+
surface: hex(scheme.surface),
|
|
231
|
+
onSurface: hex(scheme.onSurface),
|
|
232
|
+
surfaceVariant: hex(scheme.surfaceVariant),
|
|
233
|
+
onSurfaceVariant: hex(scheme.onSurfaceVariant),
|
|
234
|
+
surfaceTint: hex(scheme.surfaceTint),
|
|
235
|
+
surfaceDim: hex(scheme.surfaceDim),
|
|
236
|
+
surfaceBright: hex(scheme.surfaceBright),
|
|
237
|
+
surfaceContainerLowest: hex(scheme.surfaceContainerLowest),
|
|
238
|
+
surfaceContainerLow: hex(scheme.surfaceContainerLow),
|
|
239
|
+
surfaceContainer: hex(scheme.surfaceContainer),
|
|
240
|
+
surfaceContainerHigh: hex(scheme.surfaceContainerHigh),
|
|
241
|
+
surfaceContainerHighest: hex(scheme.surfaceContainerHighest),
|
|
242
|
+
// Inverse
|
|
243
|
+
inverseSurface: hex(scheme.inverseSurface),
|
|
244
|
+
inverseOnSurface: hex(scheme.inverseOnSurface),
|
|
245
|
+
// Background
|
|
246
|
+
background: hex(scheme.background),
|
|
247
|
+
onBackground: hex(scheme.onBackground),
|
|
248
|
+
// Outline
|
|
249
|
+
outline: hex(scheme.outline),
|
|
250
|
+
outlineVariant: hex(scheme.outlineVariant),
|
|
251
|
+
// Utility
|
|
252
|
+
shadow: hex(scheme.shadow),
|
|
253
|
+
scrim: hex(scheme.scrim)
|
|
209
254
|
};
|
|
210
255
|
}
|
|
211
|
-
function applyTheme(sourceColorHex, mode = "light", root = document.documentElement) {
|
|
256
|
+
function applyTheme(sourceColorHex, mode = "light", root = document.documentElement, options = {}) {
|
|
212
257
|
const resolved = resolveMode(mode);
|
|
213
|
-
const colors = generateM3Theme(sourceColorHex, resolved);
|
|
258
|
+
const colors = generateM3Theme(sourceColorHex, resolved, options);
|
|
214
259
|
for (const [key, value] of Object.entries(colors)) {
|
|
215
260
|
const kebabKey = key.replace(/[A-Z]/g, (m7) => `-${m7.toLowerCase()}`);
|
|
216
261
|
root.style.setProperty(`--md-sys-color-${kebabKey}`, value);
|
|
@@ -1436,6 +1481,7 @@ var IconButtonComponent = React11.forwardRef(
|
|
|
1436
1481
|
loading = false,
|
|
1437
1482
|
loadingVariant = "loading-indicator",
|
|
1438
1483
|
iconSize,
|
|
1484
|
+
asChild = false,
|
|
1439
1485
|
children,
|
|
1440
1486
|
onClick,
|
|
1441
1487
|
onKeyDown,
|
|
@@ -1451,6 +1497,7 @@ var IconButtonComponent = React11.forwardRef(
|
|
|
1451
1497
|
"loading",
|
|
1452
1498
|
"loadingVariant",
|
|
1453
1499
|
"iconSize",
|
|
1500
|
+
"asChild",
|
|
1454
1501
|
"children",
|
|
1455
1502
|
"onClick",
|
|
1456
1503
|
"onKeyDown",
|
|
@@ -1512,7 +1559,87 @@ var IconButtonComponent = React11.forwardRef(
|
|
|
1512
1559
|
},
|
|
1513
1560
|
[loading, onClick, onKeyDown]
|
|
1514
1561
|
);
|
|
1515
|
-
|
|
1562
|
+
const innerContent = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1563
|
+
needsTouchTarget && /* @__PURE__ */ jsx(TouchTarget, {}),
|
|
1564
|
+
/* @__PURE__ */ jsx(Ripple, { ripples, onRippleDone: removeRipple }),
|
|
1565
|
+
/* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", initial: false, children: loading ? /* @__PURE__ */ jsx(
|
|
1566
|
+
m.span,
|
|
1567
|
+
__spreadProps(__spreadValues({}, ICON_SPAN_VARIANTS), {
|
|
1568
|
+
transition: SPRING_TRANSITION,
|
|
1569
|
+
className: cn(
|
|
1570
|
+
"flex items-center justify-center shrink-0",
|
|
1571
|
+
iconSize != null ? void 0 : iconClass
|
|
1572
|
+
),
|
|
1573
|
+
style: isCustomSize ? { width: `${iconSize}px`, height: `${iconSize}px` } : void 0,
|
|
1574
|
+
children: loadingVariant === "loading-indicator" ? /* @__PURE__ */ jsx(
|
|
1575
|
+
LoadingIndicator,
|
|
1576
|
+
{
|
|
1577
|
+
size: typeof iconPx === "number" ? iconPx : defaultIconPx,
|
|
1578
|
+
color: "currentColor",
|
|
1579
|
+
"aria-label": "Loading"
|
|
1580
|
+
}
|
|
1581
|
+
) : /* @__PURE__ */ jsx(
|
|
1582
|
+
ProgressIndicator,
|
|
1583
|
+
{
|
|
1584
|
+
variant: "circular",
|
|
1585
|
+
size: typeof iconPx === "number" ? iconPx : defaultIconPx,
|
|
1586
|
+
color: "currentColor",
|
|
1587
|
+
trackColor: "transparent",
|
|
1588
|
+
"aria-label": "Loading"
|
|
1589
|
+
}
|
|
1590
|
+
)
|
|
1591
|
+
}),
|
|
1592
|
+
"loading"
|
|
1593
|
+
) : /* @__PURE__ */ jsx(
|
|
1594
|
+
m.span,
|
|
1595
|
+
__spreadProps(__spreadValues({}, ICON_SPAN_VARIANTS), {
|
|
1596
|
+
transition: SPRING_TRANSITION,
|
|
1597
|
+
"aria-hidden": "true",
|
|
1598
|
+
className: cn(
|
|
1599
|
+
"flex items-center justify-center shrink-0 [&_svg]:w-full [&_svg]:h-full [&_.md-icon]:text-[length:inherit]!",
|
|
1600
|
+
iconSize != null ? void 0 : iconClass
|
|
1601
|
+
),
|
|
1602
|
+
style: {
|
|
1603
|
+
fontSize: typeof iconPx === "number" ? `${iconPx}px` : iconPx,
|
|
1604
|
+
width: isCustomSize ? `${iconSize}px` : void 0,
|
|
1605
|
+
height: isCustomSize ? `${iconSize}px` : void 0
|
|
1606
|
+
},
|
|
1607
|
+
children: asChild ? React11.Children.only(children).props.children : children
|
|
1608
|
+
}),
|
|
1609
|
+
"content"
|
|
1610
|
+
) })
|
|
1611
|
+
] });
|
|
1612
|
+
const containerClassName = cn(
|
|
1613
|
+
baseIconButtonClasses,
|
|
1614
|
+
resolvedColorClass,
|
|
1615
|
+
outlineWidthClass,
|
|
1616
|
+
disabledBgClass,
|
|
1617
|
+
"overflow-hidden",
|
|
1618
|
+
SIZE_STYLES[size],
|
|
1619
|
+
loading && "pointer-events-none opacity-75 cursor-not-allowed",
|
|
1620
|
+
className
|
|
1621
|
+
);
|
|
1622
|
+
if (asChild) {
|
|
1623
|
+
const child = React11.Children.only(children);
|
|
1624
|
+
return /* @__PURE__ */ jsx(LazyMotion, { features: domMax, strict: true, children: /* @__PURE__ */ jsx(
|
|
1625
|
+
Slot,
|
|
1626
|
+
__spreadProps(__spreadValues({
|
|
1627
|
+
ref,
|
|
1628
|
+
"aria-pressed": isToggle ? isSelected : void 0,
|
|
1629
|
+
"aria-label": ariaLabel,
|
|
1630
|
+
"aria-busy": loading || void 0,
|
|
1631
|
+
"aria-disabled": loading || restProps.disabled,
|
|
1632
|
+
onClick: handleClick,
|
|
1633
|
+
onPointerDown,
|
|
1634
|
+
onKeyDown: handleKeyDown,
|
|
1635
|
+
style: __spreadProps(__spreadValues({}, style), { borderRadius: `${animateRadius}px` }),
|
|
1636
|
+
className: containerClassName
|
|
1637
|
+
}, restProps), {
|
|
1638
|
+
children: React11.cloneElement(child, { children: innerContent })
|
|
1639
|
+
})
|
|
1640
|
+
) });
|
|
1641
|
+
}
|
|
1642
|
+
return /* @__PURE__ */ jsx(LazyMotion, { features: domMax, strict: true, children: /* @__PURE__ */ jsx(
|
|
1516
1643
|
m.button,
|
|
1517
1644
|
__spreadProps(__spreadValues({
|
|
1518
1645
|
ref,
|
|
@@ -1528,67 +1655,9 @@ var IconButtonComponent = React11.forwardRef(
|
|
|
1528
1655
|
animate: { borderRadius: animateRadius },
|
|
1529
1656
|
whileTap: { borderRadius: pressedRadius },
|
|
1530
1657
|
transition: { borderRadius: SPRING_TRANSITION_FAST },
|
|
1531
|
-
className:
|
|
1532
|
-
baseIconButtonClasses,
|
|
1533
|
-
resolvedColorClass,
|
|
1534
|
-
outlineWidthClass,
|
|
1535
|
-
disabledBgClass,
|
|
1536
|
-
"overflow-hidden",
|
|
1537
|
-
SIZE_STYLES[size],
|
|
1538
|
-
loading && "pointer-events-none opacity-75 cursor-not-allowed",
|
|
1539
|
-
className
|
|
1540
|
-
)
|
|
1658
|
+
className: containerClassName
|
|
1541
1659
|
}, restProps), {
|
|
1542
|
-
children:
|
|
1543
|
-
needsTouchTarget && /* @__PURE__ */ jsx(TouchTarget, {}),
|
|
1544
|
-
/* @__PURE__ */ jsx(Ripple, { ripples, onRippleDone: removeRipple }),
|
|
1545
|
-
/* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", initial: false, children: loading ? /* @__PURE__ */ jsx(
|
|
1546
|
-
m.span,
|
|
1547
|
-
__spreadProps(__spreadValues({}, ICON_SPAN_VARIANTS), {
|
|
1548
|
-
transition: SPRING_TRANSITION,
|
|
1549
|
-
className: cn(
|
|
1550
|
-
"flex items-center justify-center shrink-0",
|
|
1551
|
-
iconSize != null ? void 0 : iconClass
|
|
1552
|
-
),
|
|
1553
|
-
style: isCustomSize ? { width: `${iconSize}px`, height: `${iconSize}px` } : void 0,
|
|
1554
|
-
children: loadingVariant === "loading-indicator" ? /* @__PURE__ */ jsx(
|
|
1555
|
-
LoadingIndicator,
|
|
1556
|
-
{
|
|
1557
|
-
size: typeof iconPx === "number" ? iconPx : defaultIconPx,
|
|
1558
|
-
color: "currentColor",
|
|
1559
|
-
"aria-label": "Loading"
|
|
1560
|
-
}
|
|
1561
|
-
) : /* @__PURE__ */ jsx(
|
|
1562
|
-
ProgressIndicator,
|
|
1563
|
-
{
|
|
1564
|
-
variant: "circular",
|
|
1565
|
-
size: typeof iconPx === "number" ? iconPx : defaultIconPx,
|
|
1566
|
-
color: "currentColor",
|
|
1567
|
-
trackColor: "transparent",
|
|
1568
|
-
"aria-label": "Loading"
|
|
1569
|
-
}
|
|
1570
|
-
)
|
|
1571
|
-
}),
|
|
1572
|
-
"loading"
|
|
1573
|
-
) : /* @__PURE__ */ jsx(
|
|
1574
|
-
m.span,
|
|
1575
|
-
__spreadProps(__spreadValues({}, ICON_SPAN_VARIANTS), {
|
|
1576
|
-
transition: SPRING_TRANSITION,
|
|
1577
|
-
"aria-hidden": "true",
|
|
1578
|
-
className: cn(
|
|
1579
|
-
"flex items-center justify-center shrink-0 [&_svg]:w-full [&_svg]:h-full [&_.md-icon]:text-[length:inherit]!",
|
|
1580
|
-
iconSize != null ? void 0 : iconClass
|
|
1581
|
-
),
|
|
1582
|
-
style: {
|
|
1583
|
-
fontSize: typeof iconPx === "number" ? `${iconPx}px` : iconPx,
|
|
1584
|
-
width: isCustomSize ? `${iconSize}px` : void 0,
|
|
1585
|
-
height: isCustomSize ? `${iconSize}px` : void 0
|
|
1586
|
-
},
|
|
1587
|
-
children
|
|
1588
|
-
}),
|
|
1589
|
-
"content"
|
|
1590
|
-
) })
|
|
1591
|
-
]
|
|
1660
|
+
children: innerContent
|
|
1592
1661
|
})
|
|
1593
1662
|
) });
|
|
1594
1663
|
}
|
|
@@ -2469,6 +2538,8 @@ function MD3ThemeProvider({
|
|
|
2469
2538
|
sourceColor: initialSourceColor = "#6750A4",
|
|
2470
2539
|
defaultMode = "light",
|
|
2471
2540
|
persistToLocalStorage = false,
|
|
2541
|
+
variant = "expressive",
|
|
2542
|
+
contrastLevel = 0,
|
|
2472
2543
|
typography: typographyProp,
|
|
2473
2544
|
fontFamily,
|
|
2474
2545
|
fontVariationAxes,
|
|
@@ -2477,6 +2548,17 @@ function MD3ThemeProvider({
|
|
|
2477
2548
|
const [sourceColor, setSourceColor] = useState(initialSourceColor);
|
|
2478
2549
|
const [mode, setMode] = useState(defaultMode);
|
|
2479
2550
|
const [isHydrated, setIsHydrated] = useState(!persistToLocalStorage);
|
|
2551
|
+
const [systemMode, setSystemMode] = useState("light");
|
|
2552
|
+
useEffect(() => {
|
|
2553
|
+
if (typeof window === "undefined") return;
|
|
2554
|
+
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
|
2555
|
+
const updateSystemMode = () => {
|
|
2556
|
+
setSystemMode(mediaQuery.matches ? "dark" : "light");
|
|
2557
|
+
};
|
|
2558
|
+
updateSystemMode();
|
|
2559
|
+
mediaQuery.addEventListener("change", updateSystemMode);
|
|
2560
|
+
return () => mediaQuery.removeEventListener("change", updateSystemMode);
|
|
2561
|
+
}, []);
|
|
2480
2562
|
useEffect(() => {
|
|
2481
2563
|
if (!persistToLocalStorage) return;
|
|
2482
2564
|
const savedColor = localStorage.getItem(STORAGE_KEY_COLOR);
|
|
@@ -2488,25 +2570,37 @@ function MD3ThemeProvider({
|
|
|
2488
2570
|
setMode(savedMode);
|
|
2489
2571
|
setIsHydrated(true);
|
|
2490
2572
|
}, [persistToLocalStorage]);
|
|
2573
|
+
const effectiveMode = mode === "system" ? systemMode : mode;
|
|
2491
2574
|
useEffect(() => {
|
|
2492
2575
|
if (!isHydrated) return;
|
|
2493
|
-
applyTheme(sourceColor,
|
|
2576
|
+
applyTheme(sourceColor, effectiveMode, document.documentElement, {
|
|
2577
|
+
variant,
|
|
2578
|
+
contrastLevel
|
|
2579
|
+
});
|
|
2494
2580
|
if (persistToLocalStorage) {
|
|
2495
2581
|
localStorage.setItem(STORAGE_KEY_COLOR, sourceColor);
|
|
2496
2582
|
localStorage.setItem(STORAGE_KEY_MODE, mode);
|
|
2497
2583
|
}
|
|
2498
|
-
}, [
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2584
|
+
}, [
|
|
2585
|
+
sourceColor,
|
|
2586
|
+
mode,
|
|
2587
|
+
effectiveMode,
|
|
2588
|
+
persistToLocalStorage,
|
|
2589
|
+
isHydrated,
|
|
2590
|
+
variant,
|
|
2591
|
+
contrastLevel
|
|
2592
|
+
]);
|
|
2507
2593
|
const themeValue = useMemo(
|
|
2508
|
-
() => ({
|
|
2509
|
-
|
|
2594
|
+
() => ({
|
|
2595
|
+
sourceColor,
|
|
2596
|
+
setSourceColor,
|
|
2597
|
+
mode,
|
|
2598
|
+
setMode,
|
|
2599
|
+
effectiveMode,
|
|
2600
|
+
variant,
|
|
2601
|
+
contrastLevel
|
|
2602
|
+
}),
|
|
2603
|
+
[sourceColor, mode, effectiveMode, variant, contrastLevel]
|
|
2510
2604
|
);
|
|
2511
2605
|
const typographyValue = useMemo(() => {
|
|
2512
2606
|
if (typographyProp) return typographyProp;
|