@jbpark/ui-kit 4.1.0 → 5.1.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/Button.d.mts.map +1 -1
- package/dist/Button.mjs +7 -2
- package/dist/Button.mjs.map +1 -1
- package/dist/Space.mjs +2 -0
- package/dist/Space.mjs.map +1 -1
- package/dist/components/atoms/skeleton/skeleton.mjs +1 -1
- package/dist/components/atoms/skeleton/skeleton.mjs.map +1 -1
- package/dist/components/molecules/dropdown.mjs +1 -1
- package/dist/components/molecules/dropdown.mjs.map +1 -1
- package/dist/components/organisms/imperative-stack.mjs +6 -4
- package/dist/components/organisms/imperative-stack.mjs.map +1 -1
- package/dist/components/organisms/modal.d.mts.map +1 -1
- package/dist/components/organisms/modal.mjs +12 -7
- package/dist/components/organisms/modal.mjs.map +1 -1
- package/dist/components/organisms/toast.d.mts.map +1 -1
- package/dist/components/organisms/toast.mjs +3 -1
- package/dist/components/organisms/toast.mjs.map +1 -1
- package/dist/components/templates/grid/col.d.mts.map +1 -1
- package/dist/components/templates/grid/col.mjs +35 -15
- package/dist/components/templates/grid/col.mjs.map +1 -1
- package/dist/components/templates/grid/row-context.mjs +1 -2
- package/dist/components/templates/grid/row-context.mjs.map +1 -1
- package/dist/components/templates/grid/row.d.mts.map +1 -1
- package/dist/components/templates/grid/row.mjs +2 -9
- package/dist/components/templates/grid/row.mjs.map +1 -1
- package/dist/components/templates/layout/content.d.mts.map +1 -1
- package/dist/components/templates/layout/content.mjs +5 -1
- package/dist/components/templates/layout/content.mjs.map +1 -1
- package/dist/components/templates/layout/sider.mjs +22 -7
- package/dist/components/templates/layout/sider.mjs.map +1 -1
- package/dist/components/templates/page-header.d.mts.map +1 -1
- package/dist/components/templates/page-header.mjs +3 -1
- package/dist/components/templates/page-header.mjs.map +1 -1
- package/dist/core/badge.d.mts +1 -1
- package/dist/core/button.d.mts +1 -1
- package/dist/index.d.mts +3 -2
- package/dist/index.mjs +2 -1
- package/dist/providers/config/config.d.mts +9 -1
- package/dist/providers/config/config.d.mts.map +1 -1
- package/dist/providers/config/config.mjs +79 -9
- package/dist/providers/config/config.mjs.map +1 -1
- package/dist/providers/config/context.d.mts.map +1 -1
- package/dist/providers/config/context.mjs +6 -2
- package/dist/providers/config/context.mjs.map +1 -1
- package/dist/providers/config/index.d.mts +3 -2
- package/dist/providers/config/registry.d.mts +14 -0
- package/dist/providers/config/registry.d.mts.map +1 -0
- package/dist/providers/config/registry.mjs +26 -0
- package/dist/providers/config/registry.mjs.map +1 -0
- package/dist/providers/config/types.d.mts +32 -2
- package/dist/providers/config/types.d.mts.map +1 -1
- package/dist/providers.d.mts +3 -2
- package/dist/providers.mjs +2 -1
- package/dist/style.css +47 -0
- package/package.json +2 -1
|
@@ -4,7 +4,6 @@ import { cn } from "../../../utils.mjs";
|
|
|
4
4
|
import { RowContext } from "./row-context.mjs";
|
|
5
5
|
import { useMemo } from "react";
|
|
6
6
|
import { jsx } from "react/jsx-runtime";
|
|
7
|
-
import { useResponsiveSize } from "@jbpark/use-hooks";
|
|
8
7
|
|
|
9
8
|
//#region src/components/templates/grid/row.tsx
|
|
10
9
|
const ALIGN_CLASSES = {
|
|
@@ -23,16 +22,10 @@ const JUSTIFY_CLASSES = {
|
|
|
23
22
|
};
|
|
24
23
|
const Row = ({ gutter = 0, align, justify, wrap = true, className, style, children, ...props }) => {
|
|
25
24
|
const [gutterX, gutterY] = Array.isArray(gutter) ? gutter : [gutter, 0];
|
|
26
|
-
const { breakpoint } = useResponsiveSize({ viewport: true });
|
|
27
25
|
const contextValue = useMemo(() => ({
|
|
28
26
|
gutterX,
|
|
29
|
-
gutterY
|
|
30
|
-
|
|
31
|
-
}), [
|
|
32
|
-
gutterX,
|
|
33
|
-
gutterY,
|
|
34
|
-
breakpoint
|
|
35
|
-
]);
|
|
27
|
+
gutterY
|
|
28
|
+
}), [gutterX, gutterY]);
|
|
36
29
|
return /* @__PURE__ */ jsx(RowContext.Provider, {
|
|
37
30
|
value: contextValue,
|
|
38
31
|
children: /* @__PURE__ */ jsx("div", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"row.mjs","names":[],"sources":["../../../../src/components/templates/grid/row.tsx"],"sourcesContent":["'use client';\n\nimport { useMemo } from 'react';\n\nimport {
|
|
1
|
+
{"version":3,"file":"row.mjs","names":[],"sources":["../../../../src/components/templates/grid/row.tsx"],"sourcesContent":["'use client';\n\nimport { useMemo } from 'react';\n\nimport { cn } from '@repo/ui/utils';\n\nimport { RowContext } from './row-context';\n\nconst ALIGN_CLASSES = {\n top: 'items-start',\n middle: 'items-center',\n bottom: 'items-end',\n stretch: 'items-stretch',\n};\n\nconst JUSTIFY_CLASSES = {\n start: 'justify-start',\n end: 'justify-end',\n center: 'justify-center',\n 'space-around': 'justify-around',\n 'space-between': 'justify-between',\n 'space-evenly': 'justify-evenly',\n};\n\nexport interface Props extends React.ComponentProps<'div'> {\n gutter?: number | [number, number];\n align?: keyof typeof ALIGN_CLASSES;\n justify?: keyof typeof JUSTIFY_CLASSES;\n wrap?: boolean;\n}\n\nconst Row = ({\n gutter = 0,\n align,\n justify,\n wrap = true,\n className,\n style,\n children,\n ...props\n}: Props) => {\n const [gutterX, gutterY] = Array.isArray(gutter) ? gutter : [gutter, 0];\n\n const contextValue = useMemo(\n () => ({ gutterX, gutterY }),\n [gutterX, gutterY],\n );\n\n return (\n <RowContext.Provider value={contextValue}>\n <div\n className={cn(\n 'flex',\n wrap && 'flex-wrap',\n align && ALIGN_CLASSES[align],\n justify && JUSTIFY_CLASSES[justify],\n className,\n //\n )}\n style={{\n // Negative margin + Col's matching padding is the classic\n // gutter technique — unlike a plain `gap`, it doesn't break the\n // percentage-width math when several Cols are meant to sum to\n // exactly 100% of the row. Vertical gutter has no such\n // constraint (it only affects spacing *between* wrapped rows),\n // so it uses native `row-gap` directly.\n marginLeft: gutterX ? -gutterX / 2 : undefined,\n marginRight: gutterX ? -gutterX / 2 : undefined,\n rowGap: gutterY || undefined,\n ...style,\n }}\n {...props}\n >\n {children}\n </div>\n </RowContext.Provider>\n );\n};\n\nexport default Row;\n"],"mappings":";;;;;;;;AAQA,MAAM,gBAAgB;CACpB,KAAK;CACL,QAAQ;CACR,QAAQ;CACR,SAAS;CACV;AAED,MAAM,kBAAkB;CACtB,OAAO;CACP,KAAK;CACL,QAAQ;CACR,gBAAgB;CAChB,iBAAiB;CACjB,gBAAgB;CACjB;AASD,MAAM,OAAO,EACX,SAAS,GACT,OACA,SACA,OAAO,MACP,WACA,OACA,UACA,GAAG,YACQ;CACX,MAAM,CAAC,SAAS,WAAW,MAAM,QAAQ,OAAO,GAAG,SAAS,CAAC,QAAQ,EAAE;CAEvE,MAAM,eAAe,eACZ;EAAE;EAAS;EAAS,GAC3B,CAAC,SAAS,QAAQ,CACnB;AAED,QACE,oBAAC,WAAW;EAAS,OAAO;YAC1B,oBAAC;GACC,WAAW,GACT,QACA,QAAQ,aACR,SAAS,cAAc,QACvB,WAAW,gBAAgB,UAC3B,UAED;GACD,OAAO;IAOL,YAAY,UAAU,CAAC,UAAU,IAAI;IACrC,aAAa,UAAU,CAAC,UAAU,IAAI;IACtC,QAAQ,WAAW;IACnB,GAAG;IACJ;GACD,GAAI;GAEH;IACG;GACc"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"content.d.mts","names":[],"sources":["../../../../src/components/templates/layout/content.tsx"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"content.d.mts","names":[],"sources":["../../../../src/components/templates/layout/content.tsx"],"mappings":";;;UAMiB,KAAA,SAAc,KAAA,CAAM,cAAA;EACnC,OAAA;AAAA;AAAA,cAGI,OAAA;EAAW,QAAA;EAAA,SAAA;EAAA,OAAA;EAAA,GAAA;AAAA,GAAoD,KAAA,KAAK,kBAAA,CAAA,GAAA,CAAA,OAAA"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { cn } from "../../../utils.mjs";
|
|
2
|
+
import { SiderRegistryContext } from "./sider-context.mjs";
|
|
2
3
|
import { jsx } from "react/jsx-runtime";
|
|
3
4
|
import { Slot } from "@radix-ui/react-slot";
|
|
4
5
|
|
|
@@ -7,7 +8,10 @@ const Content = ({ children, className, asChild = false, ...props }) => {
|
|
|
7
8
|
return /* @__PURE__ */ jsx(asChild ? Slot : "main", {
|
|
8
9
|
className: cn("min-w-0 shrink grow basis-auto", className),
|
|
9
10
|
...props,
|
|
10
|
-
children
|
|
11
|
+
children: /* @__PURE__ */ jsx(SiderRegistryContext.Provider, {
|
|
12
|
+
value: null,
|
|
13
|
+
children
|
|
14
|
+
})
|
|
11
15
|
});
|
|
12
16
|
};
|
|
13
17
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"content.mjs","names":[],"sources":["../../../../src/components/templates/layout/content.tsx"],"sourcesContent":["import { Slot } from '@radix-ui/react-slot';\n\nimport { cn } from '@repo/ui/utils';\n\nexport interface Props extends React.ComponentProps<'main'> {\n asChild?: boolean;\n}\n\nconst Content = ({ children, className, asChild = false, ...props }: Props) => {\n // Only one <main> landmark should exist per page — a Layout nested\n // inside a page that already has its own <main> (or a Content nested\n // inside another Content) needs a way to opt out of rendering a second\n // one. asChild + Slot (same pattern as core/button.tsx and\n // core/badge.tsx) merges these props/classes onto the caller's own\n // element instead.\n const Comp = asChild ? Slot : 'main';\n\n return (\n <Comp\n className={cn(\n 'min-w-0 shrink grow basis-auto',\n // basis-auto (not basis-0) sizes Content from its actual content\n // height first, so flex-grow only adds extra space when content is\n // shorter than the viewport — when content is taller, Content\n // keeps its natural (larger) height instead of clipping to\n // available space and pushes Footer below it. min-h-0 is\n // intentionally omitted here: with basis-auto, the default\n // min-height:auto (content-based) is what makes that possible; on\n // the Sider row's cross axis it's harmless since min-height there\n // governs stretch, not main-axis growth.\n className,\n )}\n {...props}\n >\n {children}\n </Comp>\n );\n};\n\nexport default Content;\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"content.mjs","names":[],"sources":["../../../../src/components/templates/layout/content.tsx"],"sourcesContent":["import { Slot } from '@radix-ui/react-slot';\n\nimport { cn } from '@repo/ui/utils';\n\nimport { SiderRegistryContext } from './sider-context';\n\nexport interface Props extends React.ComponentProps<'main'> {\n asChild?: boolean;\n}\n\nconst Content = ({ children, className, asChild = false, ...props }: Props) => {\n // Only one <main> landmark should exist per page — a Layout nested\n // inside a page that already has its own <main> (or a Content nested\n // inside another Content) needs a way to opt out of rendering a second\n // one. asChild + Slot (same pattern as core/button.tsx and\n // core/badge.tsx) merges these props/classes onto the caller's own\n // element instead.\n const Comp = asChild ? Slot : 'main';\n\n return (\n <Comp\n className={cn(\n 'min-w-0 shrink grow basis-auto',\n // basis-auto (not basis-0) sizes Content from its actual content\n // height first, so flex-grow only adds extra space when content is\n // shorter than the viewport — when content is taller, Content\n // keeps its natural (larger) height instead of clipping to\n // available space and pushes Footer below it. min-h-0 is\n // intentionally omitted here: with basis-auto, the default\n // min-height:auto (content-based) is what makes that possible; on\n // the Sider row's cross axis it's harmless since min-height there\n // governs stretch, not main-axis growth.\n className,\n )}\n {...props}\n >\n {/* Reset the registry to null so a `Sider` used inside `Content`\n (e.g. a detail page's own sub-navigation) doesn't register\n against the ancestor `Layout` and flip its axis to flex-row —\n a genuinely nested `Layout` already gets its own fresh registry,\n this only guards the \"Sider with no intervening Layout\" case. */}\n <SiderRegistryContext.Provider value={null}>\n {children}\n </SiderRegistryContext.Provider>\n </Comp>\n );\n};\n\nexport default Content;\n"],"mappings":";;;;;;AAUA,MAAM,WAAW,EAAE,UAAU,WAAW,UAAU,OAAO,GAAG,YAAmB;AAS7E,QACE,oBAHW,UAAU,OAAO;EAI1B,WAAW,GACT,kCAUA,UACD;EACD,GAAI;YAOJ,oBAAC,qBAAqB;GAAS,OAAO;GACnC;IAC6B;GAC3B"}
|
|
@@ -4,7 +4,7 @@ import { cn } from "../../../utils.mjs";
|
|
|
4
4
|
import { DEFAULT_LOCALE, useConfig } from "../../../providers/config/context.mjs";
|
|
5
5
|
import { useRegisterSider } from "./sider-context.mjs";
|
|
6
6
|
import { PanelLeftClose, PanelLeftOpen } from "lucide-react";
|
|
7
|
-
import { useId,
|
|
7
|
+
import { useEffect, useId, useRef } from "react";
|
|
8
8
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
9
|
import { useControllableState, useResponsiveSize } from "@jbpark/use-hooks";
|
|
10
10
|
|
|
@@ -29,15 +29,30 @@ const Sider = ({ children, className, classNames, style, width = 200, collapsedW
|
|
|
29
29
|
});
|
|
30
30
|
const { breakpoint: viewportBreakpoint } = useResponsiveSize({ viewport: true });
|
|
31
31
|
const broken = breakpoint ? BREAKPOINT_ORDER.indexOf(viewportBreakpoint.current) < BREAKPOINT_ORDER.indexOf(breakpoint) : false;
|
|
32
|
-
|
|
32
|
+
const latestBrokenRef = useRef(broken);
|
|
33
|
+
const previousBrokenRef = useRef(null);
|
|
34
|
+
const microtaskScheduledRef = useRef(false);
|
|
35
|
+
const onBreakpointRef = useRef(onBreakpoint);
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
onBreakpointRef.current = onBreakpoint;
|
|
38
|
+
});
|
|
39
|
+
useEffect(() => {
|
|
33
40
|
if (!breakpoint) return;
|
|
34
|
-
|
|
35
|
-
|
|
41
|
+
latestBrokenRef.current = broken;
|
|
42
|
+
if (microtaskScheduledRef.current) return;
|
|
43
|
+
microtaskScheduledRef.current = true;
|
|
44
|
+
queueMicrotask(() => {
|
|
45
|
+
microtaskScheduledRef.current = false;
|
|
46
|
+
const settledBroken = latestBrokenRef.current;
|
|
47
|
+
if (previousBrokenRef.current === settledBroken) return;
|
|
48
|
+
previousBrokenRef.current = settledBroken;
|
|
49
|
+
setCollapsed(settledBroken);
|
|
50
|
+
onBreakpointRef.current?.(settledBroken);
|
|
51
|
+
});
|
|
36
52
|
}, [
|
|
37
53
|
broken,
|
|
38
54
|
breakpoint,
|
|
39
|
-
setCollapsed
|
|
40
|
-
onBreakpoint
|
|
55
|
+
setCollapsed
|
|
41
56
|
]);
|
|
42
57
|
const onTriggerClick = () => {
|
|
43
58
|
setCollapsed(!collapsed);
|
|
@@ -54,7 +69,7 @@ const Sider = ({ children, className, classNames, style, width = 200, collapsedW
|
|
|
54
69
|
id: contentId,
|
|
55
70
|
className: "min-h-0 flex-1 overflow-auto",
|
|
56
71
|
children
|
|
57
|
-
}), collapsible && /* @__PURE__ */ jsx("button", {
|
|
72
|
+
}), collapsible && trigger !== null && /* @__PURE__ */ jsx("button", {
|
|
58
73
|
type: "button",
|
|
59
74
|
"aria-label": collapsed ? locale.expand ?? DEFAULT_LOCALE.expand : locale.collapse ?? DEFAULT_LOCALE.collapse,
|
|
60
75
|
"aria-expanded": !collapsed,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sider.mjs","names":[],"sources":["../../../../src/components/templates/layout/sider.tsx"],"sourcesContent":["'use client';\n\nimport { useId,
|
|
1
|
+
{"version":3,"file":"sider.mjs","names":[],"sources":["../../../../src/components/templates/layout/sider.tsx"],"sourcesContent":["'use client';\n\nimport { useEffect, useId, useRef } from 'react';\n\nimport { useControllableState, useResponsiveSize } from '@jbpark/use-hooks';\nimport { PanelLeftClose, PanelLeftOpen } from 'lucide-react';\n\nimport { DEFAULT_LOCALE, useConfig } from '@repo/ui/providers';\nimport { cn } from '@repo/ui/utils';\n\nimport { useRegisterSider } from './sider-context';\n\ntype Breakpoint = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';\n\n// Order matters here, not the values — used to compare the current\n// viewport tier against the configured `breakpoint` ordinally, since\n// `useResponsiveSize` reports which named tier the viewport is currently\n// in rather than a raw pixel width.\nconst BREAKPOINT_ORDER: Breakpoint[] = ['xs', 'sm', 'md', 'lg', 'xl', '2xl'];\n\nexport interface Props extends Omit<\n React.ComponentProps<'aside'>,\n 'onCollapse'\n> {\n width?: number | string;\n collapsedWidth?: number | string;\n collapsible?: boolean;\n defaultCollapsed?: boolean;\n collapsed?: boolean;\n placement?: 'left' | 'right';\n reverseArrow?: boolean;\n trigger?: React.ReactNode;\n classNames?: {\n trigger?: string;\n };\n breakpoint?: Breakpoint;\n onCollapse?: (collapsed: boolean) => void;\n onBreakpoint?: (broken: boolean) => void;\n}\n\nconst toCssSize = (value: number | string) =>\n typeof value === 'number' ? `${value}px` : value;\n\nconst Sider = ({\n children,\n className,\n classNames,\n style,\n width = 200,\n collapsedWidth = 80,\n collapsible = false,\n defaultCollapsed = false,\n collapsed: _collapsed,\n placement = 'left',\n reverseArrow = false,\n trigger,\n breakpoint,\n onCollapse,\n onBreakpoint,\n ...props\n}: Props) => {\n useRegisterSider();\n\n const { locale } = useConfig();\n const contentId = useId();\n const [collapsed, setCollapsed] = useControllableState<boolean>({\n value: _collapsed,\n defaultValue: defaultCollapsed,\n onChange: onCollapse,\n });\n\n const { breakpoint: viewportBreakpoint } = useResponsiveSize({\n viewport: true,\n });\n const broken = breakpoint\n ? BREAKPOINT_ORDER.indexOf(viewportBreakpoint.current) <\n BREAKPOINT_ORDER.indexOf(breakpoint)\n : false;\n\n const latestBrokenRef = useRef(broken);\n const previousBrokenRef = useRef<boolean | null>(null);\n const microtaskScheduledRef = useRef(false);\n const onBreakpointRef = useRef(onBreakpoint);\n\n useEffect(() => {\n onBreakpointRef.current = onBreakpoint;\n });\n\n // `useResponsiveSize`'s own initial measurement resolves through its own\n // layout effect, which (since it's called earlier in this component)\n // commits and — if the real viewport differs from its SSR-safe 'xs'\n // placeholder default — triggers a synchronous corrective re-render, all\n // before the browser paints. Both the placeholder-derived render and the\n // corrected one get their own effect pass (React doesn't coalesce\n // same-tick synchronous re-commits into a single effect flush), so\n // reacting to `broken` directly — in a layout or passive effect either\n // way — fires once with the wrong placeholder value, then again with the\n // corrected one.\n //\n // Coalescing through a microtask sidesteps that: every effect pass just\n // records its `broken` into a ref and schedules (at most once) a\n // microtask that reads whatever ended up latest once the synchronous\n // cascade has fully settled, and acts on that single, correct value.\n //\n // The `previousBrokenRef` guard is the separate fix for #227 point 3:\n // without it, an inline `onCollapse`/`onBreakpoint` (a fresh identity\n // every render) would change `setCollapsed`'s own identity and re-run\n // this effect on every unrelated parent re-render, reapplying `broken`\n // and undoing a user's manual toggle. Only a genuine change should act.\n useEffect(() => {\n if (!breakpoint) {\n return;\n }\n\n latestBrokenRef.current = broken;\n\n if (microtaskScheduledRef.current) {\n return;\n }\n microtaskScheduledRef.current = true;\n\n queueMicrotask(() => {\n microtaskScheduledRef.current = false;\n\n const settledBroken = latestBrokenRef.current;\n\n if (previousBrokenRef.current === settledBroken) {\n return;\n }\n\n previousBrokenRef.current = settledBroken;\n setCollapsed(settledBroken);\n onBreakpointRef.current?.(settledBroken);\n });\n }, [broken, breakpoint, setCollapsed]);\n\n const onTriggerClick = () => {\n setCollapsed(!collapsed);\n };\n\n // A right-placed Sider's collapse icon should default to pointing the\n // opposite way from a left-placed one (it's opening/closing a panel on\n // the other side of the content), so `placement` flips the effective\n // direction on top of whatever `reverseArrow` already requests —\n // `reverseArrow` still layers on as a manual override either way.\n const effectiveReverseArrow = reverseArrow !== (placement === 'right');\n const TriggerIcon =\n collapsed !== effectiveReverseArrow ? PanelLeftOpen : PanelLeftClose;\n\n return (\n <aside\n className={cn(\n // Below Header's z-50 (and every other floating/overlay primitive\n // in this library, which all use z-50) — Sider is a static layout\n // column, not floating chrome, and previously outranked Header\n // with an arbitrary z-100, covering it once Header stuck to the\n // viewport top on scroll.\n 'z-10 flex h-full shrink-0 flex-col overflow-hidden',\n 'transition-[width] duration-200',\n // Lets a Sider visually sit on the right without needing to\n // reorder JSX/children — useful since Sider's presence is\n // detected via context (sider-context.ts) rather than requiring\n // it to be a specific direct child in a specific position.\n placement === 'right' && 'order-last',\n className,\n //\n )}\n style={{\n width: toCssSize(collapsed ? collapsedWidth : width),\n ...style,\n }}\n {...props}\n >\n <div id={contentId} className=\"min-h-0 flex-1 overflow-auto\">\n {children}\n </div>\n {collapsible && trigger !== null && (\n <button\n type=\"button\"\n aria-label={\n collapsed\n ? (locale.expand ?? DEFAULT_LOCALE.expand)\n : (locale.collapse ?? DEFAULT_LOCALE.collapse)\n }\n aria-expanded={!collapsed}\n aria-controls={contentId}\n onClick={onTriggerClick}\n className={cn(\n 'flex w-full shrink-0 items-center justify-center py-2',\n 'cursor-pointer transition-colors hover:bg-black/5',\n classNames?.trigger,\n //\n )}\n >\n {trigger === undefined ? <TriggerIcon className=\"size-4\" /> : trigger}\n </button>\n )}\n </aside>\n );\n};\n\nexport default Sider;\n"],"mappings":";;;;;;;;;;;AAkBA,MAAM,mBAAiC;CAAC;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;AAsB5E,MAAM,aAAa,UACjB,OAAO,UAAU,WAAW,GAAG,MAAM,MAAM;AAE7C,MAAM,SAAS,EACb,UACA,WACA,YACA,OACA,QAAQ,KACR,iBAAiB,IACjB,cAAc,OACd,mBAAmB,OACnB,WAAW,YACX,YAAY,QACZ,eAAe,OACf,SACA,YACA,YACA,cACA,GAAG,YACQ;AACX,mBAAkB;CAElB,MAAM,EAAE,WAAW,WAAW;CAC9B,MAAM,YAAY,OAAO;CACzB,MAAM,CAAC,WAAW,gBAAgB,qBAA8B;EAC9D,OAAO;EACP,cAAc;EACd,UAAU;EACX,CAAC;CAEF,MAAM,EAAE,YAAY,uBAAuB,kBAAkB,EAC3D,UAAU,MACX,CAAC;CACF,MAAM,SAAS,aACX,iBAAiB,QAAQ,mBAAmB,QAAQ,GACpD,iBAAiB,QAAQ,WAAW,GACpC;CAEJ,MAAM,kBAAkB,OAAO,OAAO;CACtC,MAAM,oBAAoB,OAAuB,KAAK;CACtD,MAAM,wBAAwB,OAAO,MAAM;CAC3C,MAAM,kBAAkB,OAAO,aAAa;AAE5C,iBAAgB;AACd,kBAAgB,UAAU;GAC1B;AAuBF,iBAAgB;AACd,MAAI,CAAC,WACH;AAGF,kBAAgB,UAAU;AAE1B,MAAI,sBAAsB,QACxB;AAEF,wBAAsB,UAAU;AAEhC,uBAAqB;AACnB,yBAAsB,UAAU;GAEhC,MAAM,gBAAgB,gBAAgB;AAEtC,OAAI,kBAAkB,YAAY,cAChC;AAGF,qBAAkB,UAAU;AAC5B,gBAAa,cAAc;AAC3B,mBAAgB,UAAU,cAAc;IACxC;IACD;EAAC;EAAQ;EAAY;EAAa,CAAC;CAEtC,MAAM,uBAAuB;AAC3B,eAAa,CAAC,UAAU;;CAS1B,MAAM,cACJ,eAF4B,kBAAkB,cAAc,YAEtB,gBAAgB;AAExD,QACE,qBAAC;EACC,WAAW,GAMT,sDACA,mCAKA,cAAc,WAAW,cACzB,UAED;EACD,OAAO;GACL,OAAO,UAAU,YAAY,iBAAiB,MAAM;GACpD,GAAG;GACJ;EACD,GAAI;aAEJ,oBAAC;GAAI,IAAI;GAAW,WAAU;GAC3B;IACG,EACL,eAAe,YAAY,QAC1B,oBAAC;GACC,MAAK;GACL,cACE,YACK,OAAO,UAAU,eAAe,SAChC,OAAO,YAAY,eAAe;GAEzC,iBAAe,CAAC;GAChB,iBAAe;GACf,SAAS;GACT,WAAW,GACT,yDACA,qDACA,YAAY,QAEb;aAEA,YAAY,SAAY,oBAAC,eAAY,WAAU,WAAW,GAAG;IACvD;GAEL"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page-header.d.mts","names":[],"sources":["../../../src/components/templates/page-header.tsx"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"page-header.d.mts","names":[],"sources":["../../../src/components/templates/page-header.tsx"],"mappings":";;;UASiB,KAAA,SAAc,IAAA,CAAK,KAAA,CAAM,cAAA;EACxC,KAAA,GAAQ,KAAA,CAAM,SAAA;EACd,QAAA,GAAW,KAAA,CAAM,SAAA;EACjB,KAAA,GAAQ,KAAA,CAAM,SAAA;EACd,QAAA,GAAW,KAAA,CAAM,SAAA;EACjB,MAAA;EACA,UAAA;IACE,IAAA;IACA,KAAA;IACA,QAAA;IACA,KAAA;EAAA;AAAA;AAAA,cAOE,UAAA;EAAc,KAAA;EAAA,QAAA;EAAA,KAAA;EAAA,QAAA;EAAA,MAAA;EAAA,SAAA;EAAA,UAAA;EAAA,QAAA;EAAA,GAAA;AAAA,GAUjB,KAAA,KAAK,kBAAA,CAAA,GAAA,CAAA,OAAA"}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { cn, renderConditional } from "../../utils.mjs";
|
|
4
|
+
import { DEFAULT_LOCALE, useConfig } from "../../providers/config/context.mjs";
|
|
4
5
|
import Button from "../../Button.mjs";
|
|
5
6
|
import { ArrowLeft } from "lucide-react";
|
|
6
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
8
|
|
|
8
9
|
//#region src/components/templates/page-header.tsx
|
|
9
10
|
const PageHeader = ({ title, subTitle, extra, backIcon, onBack, className, classNames, children, ...props }) => {
|
|
11
|
+
const { locale } = useConfig();
|
|
10
12
|
return /* @__PURE__ */ jsxs("div", {
|
|
11
13
|
className: cn("flex flex-col gap-2", className),
|
|
12
14
|
...props,
|
|
@@ -16,7 +18,7 @@ const PageHeader = ({ title, subTitle, extra, backIcon, onBack, className, class
|
|
|
16
18
|
type: "text",
|
|
17
19
|
shape: "circle",
|
|
18
20
|
size: "small",
|
|
19
|
-
"aria-label":
|
|
21
|
+
"aria-label": locale.back ?? DEFAULT_LOCALE.back,
|
|
20
22
|
icon: backIcon || /* @__PURE__ */ jsx(ArrowLeft, {}),
|
|
21
23
|
onClick: onBack,
|
|
22
24
|
className: cn(classNames?.back)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page-header.mjs","names":[],"sources":["../../../src/components/templates/page-header.tsx"],"sourcesContent":["'use client';\n\nimport { ArrowLeft } from 'lucide-react';\n\nimport { cn, renderConditional } from '@repo/ui/utils';\n\nimport Button from '../atoms/button';\n\nexport interface Props extends Omit<React.ComponentProps<'div'>, 'title'> {\n title?: React.ReactNode;\n subTitle?: React.ReactNode;\n extra?: React.ReactNode;\n backIcon?: React.ReactNode;\n onBack?: () => void;\n classNames?: {\n back?: string;\n title?: string;\n subTitle?: string;\n extra?: string;\n };\n}\n\n// Title + back button + extra action area — same shape as Drawer's header\n// (title/extra/closable), which this borrows the layout from wholesale;\n// PageHeader just swaps Drawer's close button for a back button.\
|
|
1
|
+
{"version":3,"file":"page-header.mjs","names":[],"sources":["../../../src/components/templates/page-header.tsx"],"sourcesContent":["'use client';\n\nimport { ArrowLeft } from 'lucide-react';\n\nimport { DEFAULT_LOCALE, useConfig } from '@repo/ui/providers';\nimport { cn, renderConditional } from '@repo/ui/utils';\n\nimport Button from '../atoms/button';\n\nexport interface Props extends Omit<React.ComponentProps<'div'>, 'title'> {\n title?: React.ReactNode;\n subTitle?: React.ReactNode;\n extra?: React.ReactNode;\n backIcon?: React.ReactNode;\n onBack?: () => void;\n classNames?: {\n back?: string;\n title?: string;\n subTitle?: string;\n extra?: string;\n };\n}\n\n// Title + back button + extra action area — same shape as Drawer's header\n// (title/extra/closable), which this borrows the layout from wholesale;\n// PageHeader just swaps Drawer's close button for a back button.\nconst PageHeader = ({\n title,\n subTitle,\n extra,\n backIcon,\n onBack,\n className,\n classNames,\n children,\n ...props\n}: Props) => {\n const { locale } = useConfig();\n\n return (\n <div className={cn('flex flex-col gap-2', className)} {...props}>\n <div className=\"flex items-start gap-2\">\n {onBack && (\n <Button\n type=\"text\"\n shape=\"circle\"\n size=\"small\"\n aria-label={locale.back ?? DEFAULT_LOCALE.back}\n icon={backIcon || <ArrowLeft />}\n onClick={onBack}\n className={cn(classNames?.back)}\n />\n )}\n <div className=\"flex flex-1 items-start justify-between gap-2\">\n <div className=\"flex flex-col gap-0.5\">\n {title && (\n <p className={cn('text-lg font-medium', classNames?.title)}>\n {title}\n </p>\n )}\n {subTitle && (\n <p\n className={cn(\n 'text-muted-foreground text-sm',\n classNames?.subTitle,\n )}\n >\n {subTitle}\n </p>\n )}\n </div>\n {renderConditional(extra, v => (\n <div className={cn('shrink-0', classNames?.extra)}>{v}</div>\n ))}\n </div>\n </div>\n {children}\n </div>\n );\n};\n\nexport default PageHeader;\n"],"mappings":";;;;;;;;;AA0BA,MAAM,cAAc,EAClB,OACA,UACA,OACA,UACA,QACA,WACA,YACA,UACA,GAAG,YACQ;CACX,MAAM,EAAE,WAAW,WAAW;AAE9B,QACE,qBAAC;EAAI,WAAW,GAAG,uBAAuB,UAAU;EAAE,GAAI;aACxD,qBAAC;GAAI,WAAU;cACZ,UACC,oBAAC;IACC,MAAK;IACL,OAAM;IACN,MAAK;IACL,cAAY,OAAO,QAAQ,eAAe;IAC1C,MAAM,YAAY,oBAAC,cAAY;IAC/B,SAAS;IACT,WAAW,GAAG,YAAY,KAAK;KAC/B,EAEJ,qBAAC;IAAI,WAAU;eACb,qBAAC;KAAI,WAAU;gBACZ,SACC,oBAAC;MAAE,WAAW,GAAG,uBAAuB,YAAY,MAAM;gBACvD;OACC,EAEL,YACC,oBAAC;MACC,WAAW,GACT,iCACA,YAAY,SACb;gBAEA;OACC;MAEF,EACL,kBAAkB,QAAO,MACxB,oBAAC;KAAI,WAAW,GAAG,YAAY,YAAY,MAAM;eAAG;MAAQ,CAC5D;KACE;IACF,EACL;GACG"}
|
package/dist/core/badge.d.mts
CHANGED
|
@@ -8,7 +8,7 @@ declare namespace badge_d_exports {
|
|
|
8
8
|
export { Badge, Props, badgeVariants };
|
|
9
9
|
}
|
|
10
10
|
declare const badgeVariants: (props?: ({
|
|
11
|
-
variant?: "
|
|
11
|
+
variant?: "default" | "destructive" | "outline" | "secondary" | null | undefined;
|
|
12
12
|
} & class_variance_authority_types0.ClassProp) | undefined) => string;
|
|
13
13
|
type Props = React$1.ComponentProps<'span'> & VariantProps<typeof badgeVariants> & {
|
|
14
14
|
asChild?: boolean;
|
package/dist/core/button.d.mts
CHANGED
|
@@ -8,7 +8,7 @@ declare namespace button_d_exports {
|
|
|
8
8
|
export { Button, Props, buttonVariants };
|
|
9
9
|
}
|
|
10
10
|
declare const buttonVariants: (props?: ({
|
|
11
|
-
variant?: "link" | "
|
|
11
|
+
variant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | null | undefined;
|
|
12
12
|
size?: "default" | "icon" | "xs" | "sm" | "lg" | "icon-xs" | "icon-sm" | "icon-lg" | null | undefined;
|
|
13
13
|
} & class_variance_authority_types0.ClassProp) | undefined) => string;
|
|
14
14
|
type Props = React$1.ComponentProps<'button'> & VariantProps<typeof buttonVariants> & {
|
package/dist/index.d.mts
CHANGED
|
@@ -48,8 +48,9 @@ import { PageHeader, Props as Props$16 } from "./components/templates/page-heade
|
|
|
48
48
|
import { Props as Props$19, Row } from "./components/templates/grid/row.mjs";
|
|
49
49
|
import { Col, Props as Props$1 } from "./components/templates/grid/col.mjs";
|
|
50
50
|
import "./components/templates/index.mjs";
|
|
51
|
-
import { Locale, ThemeConfig, ThemeToken } from "./providers/config/types.mjs";
|
|
51
|
+
import { ComponentSize, DefaultProps, Locale, ThemeConfig, ThemeToken } from "./providers/config/types.mjs";
|
|
52
52
|
import { DEFAULT_LOCALE, useConfig } from "./providers/config/context.mjs";
|
|
53
53
|
import { Config, Props as Props$3 } from "./providers/config/config.mjs";
|
|
54
|
+
import { ConfigSnapshotProvider, getRootConfigValue } from "./providers/config/registry.mjs";
|
|
54
55
|
import "./providers.mjs";
|
|
55
|
-
export { Button, Card, Props as CardProps, Checkbox, Col, Props$1 as ColProps, Collapse, Props$2 as CollapseProps, ColorPicker, Config, Props$3 as ConfigProps, Container, Props$4 as ContainerProps, Props$5 as ContentProps, DEFAULT_LOCALE, DatePicker, Drawer, Props$6 as DrawerProps, Dropdown, Props$7 as DropdownProps, Empty, Props$8 as EmptyProps, FloatButton, Props$9 as FooterProps, Props$10 as HeaderProps, Input, Layout, Props$11 as LayoutProps, List, Props$12 as ListProps, Locale, Marquees, Props$13 as MarqueesProps, Menu, Props$14 as MenuProps, Modal, Props$15 as ModalProps, PageHeader, Props$16 as PageHeaderProps, Popover, Progress, Radio, Result, Props$17 as ResultProps, Reveals, Props$18 as RevealsProps, Row, Props$19 as RowProps, Select, Props$20 as SiderProps, Skeleton, Space, Props$21 as SpaceProps, Spin, Splitter, Props$22 as SplitterProps, Swiper, Props$23 as SwiperProps, Switch, Tag, ThemeConfig, ThemeToken, Toast, StaticProps as ToastOptions, Typography, Upload, UploadFile, Props$24 as UploadProps, useConfig };
|
|
56
|
+
export { Button, Card, Props as CardProps, Checkbox, Col, Props$1 as ColProps, Collapse, Props$2 as CollapseProps, ColorPicker, ComponentSize, Config, Props$3 as ConfigProps, ConfigSnapshotProvider, Container, Props$4 as ContainerProps, Props$5 as ContentProps, DEFAULT_LOCALE, DatePicker, DefaultProps, Drawer, Props$6 as DrawerProps, Dropdown, Props$7 as DropdownProps, Empty, Props$8 as EmptyProps, FloatButton, Props$9 as FooterProps, Props$10 as HeaderProps, Input, Layout, Props$11 as LayoutProps, List, Props$12 as ListProps, Locale, Marquees, Props$13 as MarqueesProps, Menu, Props$14 as MenuProps, Modal, Props$15 as ModalProps, PageHeader, Props$16 as PageHeaderProps, Popover, Progress, Radio, Result, Props$17 as ResultProps, Reveals, Props$18 as RevealsProps, Row, Props$19 as RowProps, Select, Props$20 as SiderProps, Skeleton, Space, Props$21 as SpaceProps, Spin, Splitter, Props$22 as SplitterProps, Swiper, Props$23 as SwiperProps, Switch, Tag, ThemeConfig, ThemeToken, Toast, StaticProps as ToastOptions, Typography, Upload, UploadFile, Props$24 as UploadProps, getRootConfigValue, useConfig };
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import "./style.mjs";
|
|
2
2
|
import { DEFAULT_LOCALE, useConfig } from "./providers/config/context.mjs";
|
|
3
|
+
import { ConfigSnapshotProvider, getRootConfigValue } from "./providers/config/registry.mjs";
|
|
3
4
|
import Config from "./providers/config/config.mjs";
|
|
4
5
|
import Button from "./Button.mjs";
|
|
5
6
|
import Checkbox from "./components/atoms/checkbox/index.mjs";
|
|
@@ -38,4 +39,4 @@ import PageHeader from "./components/templates/page-header.mjs";
|
|
|
38
39
|
import Row from "./components/templates/grid/row.mjs";
|
|
39
40
|
import Col from "./components/templates/grid/col.mjs";
|
|
40
41
|
|
|
41
|
-
export { Button, Card, Checkbox, Col, Collapse, ColorPicker, Config, Container, DEFAULT_LOCALE, DatePicker, Drawer, Dropdown, Empty, FloatButton, Input, Layout, List, Marquees, Menu, Modal, PageHeader, Popover, Progress, Radio, Result, Reveals, Row, Select, Skeleton, Space, Spin, Splitter, Swiper, Switch, Tag, Toast, Typography, Upload, useConfig };
|
|
42
|
+
export { Button, Card, Checkbox, Col, Collapse, ColorPicker, Config, ConfigSnapshotProvider, Container, DEFAULT_LOCALE, DatePicker, Drawer, Dropdown, Empty, FloatButton, Input, Layout, List, Marquees, Menu, Modal, PageHeader, Popover, Progress, Radio, Result, Reveals, Row, Select, Skeleton, Space, Spin, Splitter, Swiper, Switch, Tag, Toast, Typography, Upload, getRootConfigValue, useConfig };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Locale, ThemeConfig, ThemeToken } from "./types.mjs";
|
|
1
|
+
import { ComponentSize, DefaultProps, Locale, ThemeConfig, ThemeToken } from "./types.mjs";
|
|
2
2
|
import { DEFAULT_LOCALE, useConfig } from "./context.mjs";
|
|
3
3
|
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
4
4
|
|
|
@@ -7,14 +7,22 @@ interface Props {
|
|
|
7
7
|
theme?: ThemeConfig;
|
|
8
8
|
locale?: Locale;
|
|
9
9
|
getContainer?: () => HTMLElement;
|
|
10
|
+
componentSize?: ComponentSize;
|
|
11
|
+
direction?: 'ltr' | 'rtl';
|
|
12
|
+
defaultProps?: DefaultProps;
|
|
10
13
|
className?: string;
|
|
14
|
+
style?: React.CSSProperties;
|
|
11
15
|
children: React.ReactNode;
|
|
12
16
|
}
|
|
13
17
|
declare const Config: ({
|
|
14
18
|
theme,
|
|
15
19
|
locale,
|
|
16
20
|
getContainer,
|
|
21
|
+
componentSize,
|
|
22
|
+
direction,
|
|
23
|
+
defaultProps,
|
|
17
24
|
className,
|
|
25
|
+
style,
|
|
18
26
|
children
|
|
19
27
|
}: Props) => react_jsx_runtime0.JSX.Element;
|
|
20
28
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.mts","names":[],"sources":["../../../src/providers/config/config.tsx"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"config.d.mts","names":[],"sources":["../../../src/providers/config/config.tsx"],"mappings":";;;;;UAuHU,KAAA;EACR,KAAA,GAAQ,WAAA;EACR,MAAA,GAAS,MAAA;EACT,YAAA,SAAqB,WAAA;EACrB,aAAA,GAAgB,aAAA;EAChB,SAAA;EACA,YAAA,GAAe,YAAA;EACf,SAAA;EACA,KAAA,GAAQ,KAAA,CAAM,aAAA;EACd,QAAA,EAAU,KAAA,CAAM,SAAA;AAAA;AAAA,cAGZ,MAAA;EAAU,KAAA;EAAA,MAAA;EAAA,YAAA;EAAA,aAAA;EAAA,SAAA;EAAA,YAAA;EAAA,SAAA;EAAA,KAAA;EAAA;AAAA,GAUb,KAAA,KAAK,kBAAA,CAAA,GAAA,CAAA,OAAA"}
|
|
@@ -2,10 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
import { cn } from "../../utils.mjs";
|
|
4
4
|
import { Context, DEFAULT_LOCALE, useConfig } from "./context.mjs";
|
|
5
|
-
import {
|
|
5
|
+
import { registerRootConfig } from "./registry.mjs";
|
|
6
|
+
import { useCallback, useEffect, useMemo, useState, useSyncExternalStore } from "react";
|
|
6
7
|
import { jsx } from "react/jsx-runtime";
|
|
8
|
+
import { DirectionProvider } from "@radix-ui/react-direction";
|
|
7
9
|
|
|
8
10
|
//#region src/providers/config/config.tsx
|
|
11
|
+
const DARK_MEDIA_QUERY = "(prefers-color-scheme: dark)";
|
|
12
|
+
const subscribeToSystemColorScheme = (callback) => {
|
|
13
|
+
if (typeof window === "undefined") return () => {};
|
|
14
|
+
const mql = window.matchMedia(DARK_MEDIA_QUERY);
|
|
15
|
+
mql.addEventListener("change", callback);
|
|
16
|
+
return () => mql.removeEventListener("change", callback);
|
|
17
|
+
};
|
|
18
|
+
const getSystemPrefersDark = () => typeof window !== "undefined" && window.matchMedia(DARK_MEDIA_QUERY).matches;
|
|
19
|
+
const getServerSnapshot = () => false;
|
|
20
|
+
const useSystemPrefersDark = () => useSyncExternalStore(subscribeToSystemColorScheme, getSystemPrefersDark, getServerSnapshot);
|
|
9
21
|
const tokenToCssVar = {
|
|
10
22
|
colorPrimary: "--primary",
|
|
11
23
|
colorPrimaryForeground: "--primary-foreground",
|
|
@@ -25,7 +37,27 @@ const tokenToCssVar = {
|
|
|
25
37
|
colorBorder: "--border",
|
|
26
38
|
colorInput: "--input",
|
|
27
39
|
colorRing: "--ring",
|
|
28
|
-
borderRadius: "--radius"
|
|
40
|
+
borderRadius: "--radius",
|
|
41
|
+
btnBackground: "--btn-bg",
|
|
42
|
+
btnBackgroundHover: "--btn-bg-hover",
|
|
43
|
+
btnBackgroundActive: "--btn-bg-active",
|
|
44
|
+
btnBorder: "--btn-border",
|
|
45
|
+
btnForeground: "--btn-fg",
|
|
46
|
+
sidebar: "--sidebar",
|
|
47
|
+
sidebarForeground: "--sidebar-foreground",
|
|
48
|
+
sidebarPrimary: "--sidebar-primary",
|
|
49
|
+
sidebarPrimaryForeground: "--sidebar-primary-foreground",
|
|
50
|
+
sidebarAccent: "--sidebar-accent",
|
|
51
|
+
sidebarAccentForeground: "--sidebar-accent-foreground",
|
|
52
|
+
sidebarBorder: "--sidebar-border",
|
|
53
|
+
sidebarRing: "--sidebar-ring",
|
|
54
|
+
chart1: "--chart-1",
|
|
55
|
+
chart2: "--chart-2",
|
|
56
|
+
chart3: "--chart-3",
|
|
57
|
+
chart4: "--chart-4",
|
|
58
|
+
chart5: "--chart-5",
|
|
59
|
+
fontSans: "--font-sans",
|
|
60
|
+
fontMono: "--font-mono"
|
|
29
61
|
};
|
|
30
62
|
const buildCssVars = (token) => {
|
|
31
63
|
if (!token) return {};
|
|
@@ -37,9 +69,10 @@ const buildCssVars = (token) => {
|
|
|
37
69
|
}
|
|
38
70
|
return vars;
|
|
39
71
|
};
|
|
40
|
-
const Config = ({ theme = {}, locale = {}, getContainer, className, children }) => {
|
|
72
|
+
const Config = ({ theme = {}, locale = {}, getContainer, componentSize, direction, defaultProps, className, style, children }) => {
|
|
41
73
|
const parent = useConfig();
|
|
42
74
|
const [wrapperEl, setWrapperEl] = useState(null);
|
|
75
|
+
const isRoot = !parent.isConfigured;
|
|
43
76
|
const themeKey = JSON.stringify(theme);
|
|
44
77
|
const parentThemeKey = JSON.stringify(parent.theme);
|
|
45
78
|
const localeKey = JSON.stringify(locale);
|
|
@@ -50,16 +83,29 @@ const Config = ({ theme = {}, locale = {}, getContainer, className, children })
|
|
|
50
83
|
token: {
|
|
51
84
|
...parent.theme.token,
|
|
52
85
|
...theme.token
|
|
86
|
+
},
|
|
87
|
+
darkToken: {
|
|
88
|
+
...parent.theme.darkToken,
|
|
89
|
+
...theme.darkToken
|
|
53
90
|
}
|
|
54
91
|
}), [parentThemeKey, themeKey]);
|
|
55
92
|
const mergedLocale = useMemo(() => ({
|
|
56
93
|
...parent.locale,
|
|
57
94
|
...locale
|
|
58
95
|
}), [parentLocaleKey, localeKey]);
|
|
59
|
-
const
|
|
96
|
+
const systemPrefersDark = useSystemPrefersDark();
|
|
97
|
+
const isDarkActive = mergedTheme.dark === "system" ? systemPrefersDark : mergedTheme.dark === "dark";
|
|
98
|
+
const cssVars = useMemo(() => buildCssVars(isDarkActive ? {
|
|
99
|
+
...mergedTheme.token,
|
|
100
|
+
...mergedTheme.darkToken
|
|
101
|
+
} : mergedTheme.token), [
|
|
102
|
+
mergedTheme.token,
|
|
103
|
+
mergedTheme.darkToken,
|
|
104
|
+
isDarkActive
|
|
105
|
+
]);
|
|
60
106
|
const hasCssVars = Object.keys(cssVars).length > 0;
|
|
61
107
|
const hasDarkMode = mergedTheme.dark !== void 0;
|
|
62
|
-
const needsWrapper = hasCssVars || hasDarkMode || className;
|
|
108
|
+
const needsWrapper = hasCssVars || hasDarkMode || !!className || !!style || !!direction;
|
|
63
109
|
const resolvedGetContainer = useCallback(() => {
|
|
64
110
|
if (getContainer) return getContainer();
|
|
65
111
|
if (needsWrapper && wrapperEl) return wrapperEl;
|
|
@@ -70,27 +116,51 @@ const Config = ({ theme = {}, locale = {}, getContainer, className, children })
|
|
|
70
116
|
wrapperEl,
|
|
71
117
|
parent
|
|
72
118
|
]);
|
|
119
|
+
const resolvedComponentSize = componentSize ?? parent.componentSize;
|
|
120
|
+
const resolvedDirection = direction ?? parent.direction;
|
|
121
|
+
const defaultPropsKey = JSON.stringify(defaultProps);
|
|
122
|
+
const mergedDefaultProps = useMemo(() => parent.defaultProps || defaultProps ? {
|
|
123
|
+
...parent.defaultProps,
|
|
124
|
+
...defaultProps
|
|
125
|
+
} : void 0, [JSON.stringify(parent.defaultProps), defaultPropsKey]);
|
|
73
126
|
const contextValue = useMemo(() => ({
|
|
74
127
|
theme: mergedTheme,
|
|
75
128
|
locale: mergedLocale,
|
|
76
|
-
getContainer: resolvedGetContainer
|
|
129
|
+
getContainer: resolvedGetContainer,
|
|
130
|
+
componentSize: resolvedComponentSize,
|
|
131
|
+
direction: resolvedDirection,
|
|
132
|
+
defaultProps: mergedDefaultProps,
|
|
133
|
+
isConfigured: true
|
|
77
134
|
}), [
|
|
78
135
|
mergedTheme,
|
|
79
136
|
mergedLocale,
|
|
80
|
-
resolvedGetContainer
|
|
137
|
+
resolvedGetContainer,
|
|
138
|
+
resolvedComponentSize,
|
|
139
|
+
resolvedDirection,
|
|
140
|
+
mergedDefaultProps
|
|
81
141
|
]);
|
|
82
|
-
|
|
142
|
+
useEffect(() => {
|
|
143
|
+
if (!isRoot) return;
|
|
144
|
+
return registerRootConfig(contextValue);
|
|
145
|
+
}, [isRoot, contextValue]);
|
|
146
|
+
const content = /* @__PURE__ */ jsx(Context.Provider, {
|
|
83
147
|
value: contextValue,
|
|
84
148
|
children: needsWrapper ? /* @__PURE__ */ jsx("div", {
|
|
85
149
|
ref: setWrapperEl,
|
|
86
|
-
|
|
150
|
+
dir: direction,
|
|
151
|
+
className: cn(isDarkActive && "dark", className),
|
|
87
152
|
style: {
|
|
88
153
|
...hasCssVars ? cssVars : void 0,
|
|
154
|
+
...style,
|
|
89
155
|
display: "contents"
|
|
90
156
|
},
|
|
91
157
|
children
|
|
92
158
|
}) : children
|
|
93
159
|
});
|
|
160
|
+
return direction ? /* @__PURE__ */ jsx(DirectionProvider, {
|
|
161
|
+
dir: direction,
|
|
162
|
+
children: content
|
|
163
|
+
}) : content;
|
|
94
164
|
};
|
|
95
165
|
|
|
96
166
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.mjs","names":[],"sources":["../../../src/providers/config/config.tsx"],"sourcesContent":["'use client';\n\nimport { useCallback, useMemo, useState } from 'react';\n\nimport { cn } from '@repo/ui/utils';\n\nimport { Context, DEFAULT_LOCALE, useConfig } from './context';\nimport type { Locale, ThemeConfig, ThemeToken } from './types';\n\nconst tokenToCssVar: Record<keyof ThemeToken, string> = {\n colorPrimary: '--primary',\n colorPrimaryForeground: '--primary-foreground',\n colorBackground: '--background',\n colorForeground: '--foreground',\n colorCard: '--card',\n colorCardForeground: '--card-foreground',\n colorPopover: '--popover',\n colorPopoverForeground: '--popover-foreground',\n colorSecondary: '--secondary',\n colorSecondaryForeground: '--secondary-foreground',\n colorMuted: '--muted',\n colorMutedForeground: '--muted-foreground',\n colorAccent: '--accent',\n colorAccentForeground: '--accent-foreground',\n colorDestructive: '--destructive',\n colorBorder: '--border',\n colorInput: '--input',\n colorRing: '--ring',\n borderRadius: '--radius',\n};\n\nconst buildCssVars = (token?: ThemeToken): React.CSSProperties => {\n if (!token) {\n return {};\n }\n\n const vars: Record<string, string> = {};\n\n for (const [key, value] of Object.entries(token)) {\n if (value === undefined) {\n continue;\n }\n const cssVar = tokenToCssVar[key as keyof ThemeToken];\n if (cssVar) {\n vars[cssVar] = value;\n }\n }\n\n return vars as React.CSSProperties;\n};\n\ninterface Props {\n theme?: ThemeConfig;\n locale?: Locale;\n getContainer?: () => HTMLElement;\n className?: string;\n children: React.ReactNode;\n}\n\nconst Config = ({\n theme = {},\n locale = {},\n getContainer,\n className,\n children,\n}: Props) => {\n const parent = useConfig();\n const [wrapperEl, setWrapperEl] = useState<HTMLDivElement | null>(null);\n\n // `theme` is typically a fresh inline object literal at the call site\n // (and `parent.theme` inherits the same problem from its own Config\n // ancestor), so depending on them directly meant mergedTheme/contextValue\n // got a new identity on every render regardless of whether the actual\n // values changed — every useConfig() consumer in the tree re-rendered on\n // every render of whatever's above this Config, which for the common\n // app-root usage is everything. Depend on a serialized key instead so\n // the memo only invalidates when the content actually changes; these\n // are small, string/boolean-only objects, so JSON.stringify is cheap.\n const themeKey = JSON.stringify(theme);\n const parentThemeKey = JSON.stringify(parent.theme);\n const localeKey = JSON.stringify(locale);\n const parentLocaleKey = JSON.stringify(parent.locale);\n\n const mergedTheme = useMemo<ThemeConfig>(\n () => ({\n ...parent.theme,\n ...theme,\n token: {\n ...parent.theme.token,\n ...theme.token,\n },\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [parentThemeKey, themeKey],\n );\n\n const mergedLocale = useMemo<Locale>(\n () => ({\n ...parent.locale,\n ...locale,\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [parentLocaleKey, localeKey],\n );\n\n const cssVars = useMemo(\n () => buildCssVars(mergedTheme.token),\n [mergedTheme.token],\n );\n\n const hasCssVars = Object.keys(cssVars).length > 0;\n const hasDarkMode = mergedTheme.dark !== undefined;\n const needsWrapper = hasCssVars || hasDarkMode || className;\n\n // Resolution order: an explicit `getContainer` prop on this Config wins;\n // otherwise, if this Config renders its own themed wrapper below, that's\n // the default (portaled content appended into it still inherits its CSS\n // custom properties and matches the `.dark` selector — `display:\n // contents` only removes the element from the layout box tree, not from\n // the DOM/cascade); otherwise defer to the parent Config's resolution,\n // so an inner Config that only sets e.g. `locale` doesn't shadow an\n // outer one's theme container.\n const resolvedGetContainer = useCallback((): HTMLElement | undefined => {\n if (getContainer) {\n return getContainer();\n }\n if (needsWrapper && wrapperEl) {\n return wrapperEl;\n }\n return parent.getContainer();\n }, [getContainer, needsWrapper, wrapperEl, parent]);\n\n const contextValue = useMemo(\n () => ({\n theme: mergedTheme,\n locale: mergedLocale,\n getContainer: resolvedGetContainer,\n }),\n [mergedTheme, mergedLocale, resolvedGetContainer],\n );\n\n return (\n <Context.Provider value={contextValue}>\n {needsWrapper ? (\n <div\n ref={setWrapperEl}\n className={cn(mergedTheme.dark && 'dark', className)}\n style={{\n ...(hasCssVars ? cssVars : undefined),\n // Keeps this element out of the layout box tree — so it\n // doesn't intercept flex/grid child relationships or break\n // height chains like min-h-screen — while custom properties\n // and the `dark` class selector still cascade to children\n // normally (inheritance and box generation are separate\n // mechanisms in CSS). Note this means className shouldn't be\n // used here for anything that needs a real box (padding,\n // background, borders); Config's className is meant for\n // theming hooks (the `dark` class, arbitrary selector hooks),\n // not layout.\n display: 'contents',\n }}\n >\n {children}\n </div>\n ) : (\n children\n )}\n </Context.Provider>\n );\n};\n\nexport default Config;\nexport { useConfig, DEFAULT_LOCALE };\nexport type { Props, Locale, ThemeConfig, ThemeToken };\n"],"mappings":";;;;;;;;AASA,MAAM,gBAAkD;CACtD,cAAc;CACd,wBAAwB;CACxB,iBAAiB;CACjB,iBAAiB;CACjB,WAAW;CACX,qBAAqB;CACrB,cAAc;CACd,wBAAwB;CACxB,gBAAgB;CAChB,0BAA0B;CAC1B,YAAY;CACZ,sBAAsB;CACtB,aAAa;CACb,uBAAuB;CACvB,kBAAkB;CAClB,aAAa;CACb,YAAY;CACZ,WAAW;CACX,cAAc;CACf;AAED,MAAM,gBAAgB,UAA4C;AAChE,KAAI,CAAC,MACH,QAAO,EAAE;CAGX,MAAM,OAA+B,EAAE;AAEvC,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,MAAM,EAAE;AAChD,MAAI,UAAU,OACZ;EAEF,MAAM,SAAS,cAAc;AAC7B,MAAI,OACF,MAAK,UAAU;;AAInB,QAAO;;AAWT,MAAM,UAAU,EACd,QAAQ,EAAE,EACV,SAAS,EAAE,EACX,cACA,WACA,eACW;CACX,MAAM,SAAS,WAAW;CAC1B,MAAM,CAAC,WAAW,gBAAgB,SAAgC,KAAK;CAWvE,MAAM,WAAW,KAAK,UAAU,MAAM;CACtC,MAAM,iBAAiB,KAAK,UAAU,OAAO,MAAM;CACnD,MAAM,YAAY,KAAK,UAAU,OAAO;CACxC,MAAM,kBAAkB,KAAK,UAAU,OAAO,OAAO;CAErD,MAAM,cAAc,eACX;EACL,GAAG,OAAO;EACV,GAAG;EACH,OAAO;GACL,GAAG,OAAO,MAAM;GAChB,GAAG,MAAM;GACV;EACF,GAED,CAAC,gBAAgB,SAAS,CAC3B;CAED,MAAM,eAAe,eACZ;EACL,GAAG,OAAO;EACV,GAAG;EACJ,GAED,CAAC,iBAAiB,UAAU,CAC7B;CAED,MAAM,UAAU,cACR,aAAa,YAAY,MAAM,EACrC,CAAC,YAAY,MAAM,CACpB;CAED,MAAM,aAAa,OAAO,KAAK,QAAQ,CAAC,SAAS;CACjD,MAAM,cAAc,YAAY,SAAS;CACzC,MAAM,eAAe,cAAc,eAAe;CAUlD,MAAM,uBAAuB,kBAA2C;AACtE,MAAI,aACF,QAAO,cAAc;AAEvB,MAAI,gBAAgB,UAClB,QAAO;AAET,SAAO,OAAO,cAAc;IAC3B;EAAC;EAAc;EAAc;EAAW;EAAO,CAAC;CAEnD,MAAM,eAAe,eACZ;EACL,OAAO;EACP,QAAQ;EACR,cAAc;EACf,GACD;EAAC;EAAa;EAAc;EAAqB,CAClD;AAED,QACE,oBAAC,QAAQ;EAAS,OAAO;YACtB,eACC,oBAAC;GACC,KAAK;GACL,WAAW,GAAG,YAAY,QAAQ,QAAQ,UAAU;GACpD,OAAO;IACL,GAAI,aAAa,UAAU;IAW3B,SAAS;IACV;GAEA;IACG,GAEN;GAEe"}
|
|
1
|
+
{"version":3,"file":"config.mjs","names":[],"sources":["../../../src/providers/config/config.tsx"],"sourcesContent":["'use client';\n\nimport {\n useCallback,\n useEffect,\n useMemo,\n useState,\n useSyncExternalStore,\n} from 'react';\n\nimport { DirectionProvider } from '@radix-ui/react-direction';\n\nimport { cn } from '@repo/ui/utils';\n\nimport { Context, DEFAULT_LOCALE, useConfig } from './context';\nimport { registerRootConfig } from './registry';\nimport type {\n ComponentSize,\n DefaultProps,\n Locale,\n ThemeConfig,\n ThemeToken,\n} from './types';\n\nconst DARK_MEDIA_QUERY = '(prefers-color-scheme: dark)';\n\nconst subscribeToSystemColorScheme = (callback: () => void) => {\n if (typeof window === 'undefined') {\n return () => {};\n }\n\n const mql = window.matchMedia(DARK_MEDIA_QUERY);\n mql.addEventListener('change', callback);\n return () => mql.removeEventListener('change', callback);\n};\n\nconst getSystemPrefersDark = () =>\n typeof window !== 'undefined' && window.matchMedia(DARK_MEDIA_QUERY).matches;\n\n// No `window` during SSR, so there's no way to know the visitor's actual\n// preference before hydration — assume light (the conservative default)\n// and let useSyncExternalStore correct it client-side once matchMedia is\n// available, same flash-of-incorrect-guess tradeoff already accepted for\n// Sider's breakpoint prop elsewhere in this library.\nconst getServerSnapshot = () => false;\n\nconst useSystemPrefersDark = () =>\n useSyncExternalStore(\n subscribeToSystemColorScheme,\n getSystemPrefersDark,\n getServerSnapshot,\n );\n\nconst tokenToCssVar: Record<keyof ThemeToken, string> = {\n colorPrimary: '--primary',\n colorPrimaryForeground: '--primary-foreground',\n colorBackground: '--background',\n colorForeground: '--foreground',\n colorCard: '--card',\n colorCardForeground: '--card-foreground',\n colorPopover: '--popover',\n colorPopoverForeground: '--popover-foreground',\n colorSecondary: '--secondary',\n colorSecondaryForeground: '--secondary-foreground',\n colorMuted: '--muted',\n colorMutedForeground: '--muted-foreground',\n colorAccent: '--accent',\n colorAccentForeground: '--accent-foreground',\n colorDestructive: '--destructive',\n colorBorder: '--border',\n colorInput: '--input',\n colorRing: '--ring',\n borderRadius: '--radius',\n\n btnBackground: '--btn-bg',\n btnBackgroundHover: '--btn-bg-hover',\n btnBackgroundActive: '--btn-bg-active',\n btnBorder: '--btn-border',\n btnForeground: '--btn-fg',\n\n sidebar: '--sidebar',\n sidebarForeground: '--sidebar-foreground',\n sidebarPrimary: '--sidebar-primary',\n sidebarPrimaryForeground: '--sidebar-primary-foreground',\n sidebarAccent: '--sidebar-accent',\n sidebarAccentForeground: '--sidebar-accent-foreground',\n sidebarBorder: '--sidebar-border',\n sidebarRing: '--sidebar-ring',\n\n chart1: '--chart-1',\n chart2: '--chart-2',\n chart3: '--chart-3',\n chart4: '--chart-4',\n chart5: '--chart-5',\n\n fontSans: '--font-sans',\n fontMono: '--font-mono',\n};\n\nconst buildCssVars = (token?: ThemeToken): React.CSSProperties => {\n if (!token) {\n return {};\n }\n\n const vars: Record<string, string> = {};\n\n for (const [key, value] of Object.entries(token)) {\n if (value === undefined) {\n continue;\n }\n const cssVar = tokenToCssVar[key as keyof ThemeToken];\n if (cssVar) {\n vars[cssVar] = value;\n }\n }\n\n return vars as React.CSSProperties;\n};\n\ninterface Props {\n theme?: ThemeConfig;\n locale?: Locale;\n getContainer?: () => HTMLElement;\n componentSize?: ComponentSize;\n direction?: 'ltr' | 'rtl';\n defaultProps?: DefaultProps;\n className?: string;\n style?: React.CSSProperties;\n children: React.ReactNode;\n}\n\nconst Config = ({\n theme = {},\n locale = {},\n getContainer,\n componentSize,\n direction,\n defaultProps,\n className,\n style,\n children,\n}: Props) => {\n const parent = useConfig();\n const [wrapperEl, setWrapperEl] = useState<HTMLDivElement | null>(null);\n\n // Only a Config with no Config ancestor of its own registers for the\n // imperative stack (Modal.*/Toast.*) to inherit — see registry.tsx.\n const isRoot = !parent.isConfigured;\n\n // `theme` is typically a fresh inline object literal at the call site\n // (and `parent.theme` inherits the same problem from its own Config\n // ancestor), so depending on them directly meant mergedTheme/contextValue\n // got a new identity on every render regardless of whether the actual\n // values changed — every useConfig() consumer in the tree re-rendered on\n // every render of whatever's above this Config, which for the common\n // app-root usage is everything. Depend on a serialized key instead so\n // the memo only invalidates when the content actually changes; these\n // are small, string/boolean-only objects, so JSON.stringify is cheap.\n const themeKey = JSON.stringify(theme);\n const parentThemeKey = JSON.stringify(parent.theme);\n const localeKey = JSON.stringify(locale);\n const parentLocaleKey = JSON.stringify(parent.locale);\n\n const mergedTheme = useMemo<ThemeConfig>(\n () => ({\n ...parent.theme,\n ...theme,\n token: {\n ...parent.theme.token,\n ...theme.token,\n },\n darkToken: {\n ...parent.theme.darkToken,\n ...theme.darkToken,\n },\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [parentThemeKey, themeKey],\n );\n\n const mergedLocale = useMemo<Locale>(\n () => ({\n ...parent.locale,\n ...locale,\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [parentLocaleKey, localeKey],\n );\n\n const systemPrefersDark = useSystemPrefersDark();\n const isDarkActive =\n mergedTheme.dark === 'system'\n ? systemPrefersDark\n : mergedTheme.dark === 'dark';\n\n // `darkToken` overrides individual keys of `token` (not a full swap)\n // only while dark mode is actually active.\n const cssVars = useMemo(\n () =>\n buildCssVars(\n isDarkActive\n ? { ...mergedTheme.token, ...mergedTheme.darkToken }\n : mergedTheme.token,\n ),\n [mergedTheme.token, mergedTheme.darkToken, isDarkActive],\n );\n\n const hasCssVars = Object.keys(cssVars).length > 0;\n const hasDarkMode = mergedTheme.dark !== undefined;\n const needsWrapper =\n hasCssVars || hasDarkMode || !!className || !!style || !!direction;\n\n // Resolution order: an explicit `getContainer` prop on this Config wins;\n // otherwise, if this Config renders its own themed wrapper below, that's\n // the default (portaled content appended into it still inherits its CSS\n // custom properties and matches the `.dark` selector — `display:\n // contents` only removes the element from the layout box tree, not from\n // the DOM/cascade); otherwise defer to the parent Config's resolution,\n // so an inner Config that only sets e.g. `locale` doesn't shadow an\n // outer one's theme container.\n const resolvedGetContainer = useCallback((): HTMLElement | undefined => {\n if (getContainer) {\n return getContainer();\n }\n if (needsWrapper && wrapperEl) {\n return wrapperEl;\n }\n return parent.getContainer();\n }, [getContainer, needsWrapper, wrapperEl, parent]);\n\n const resolvedComponentSize = componentSize ?? parent.componentSize;\n const resolvedDirection = direction ?? parent.direction;\n\n const defaultPropsKey = JSON.stringify(defaultProps);\n const parentDefaultPropsKey = JSON.stringify(parent.defaultProps);\n\n const mergedDefaultProps = useMemo<DefaultProps | undefined>(\n () =>\n parent.defaultProps || defaultProps\n ? { ...parent.defaultProps, ...defaultProps }\n : undefined,\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [parentDefaultPropsKey, defaultPropsKey],\n );\n\n const contextValue = useMemo(\n () => ({\n theme: mergedTheme,\n locale: mergedLocale,\n getContainer: resolvedGetContainer,\n componentSize: resolvedComponentSize,\n direction: resolvedDirection,\n defaultProps: mergedDefaultProps,\n isConfigured: true,\n }),\n [\n mergedTheme,\n mergedLocale,\n resolvedGetContainer,\n resolvedComponentSize,\n resolvedDirection,\n mergedDefaultProps,\n ],\n );\n\n useEffect(() => {\n if (!isRoot) {\n return;\n }\n return registerRootConfig(contextValue);\n }, [isRoot, contextValue]);\n\n const content = (\n <Context.Provider value={contextValue}>\n {needsWrapper ? (\n <div\n ref={setWrapperEl}\n dir={direction}\n className={cn(isDarkActive && 'dark', className)}\n style={{\n ...(hasCssVars ? cssVars : undefined),\n ...style,\n // Keeps this element out of the layout box tree — so it\n // doesn't intercept flex/grid child relationships or break\n // height chains like min-h-screen — while custom properties\n // and the `dark` class selector still cascade to children\n // normally (inheritance and box generation are separate\n // mechanisms in CSS). Note this means className/style\n // shouldn't be used here for anything that needs a real box\n // (padding, background, borders); Config's className/style are\n // meant for theming hooks (the `dark` class, arbitrary\n // selector hooks, custom properties), not layout — spread\n // after the caller's `style` so it can't be overridden into\n // something that reintroduces the layout-breaking wrapper this\n // was added to fix in the first place.\n display: 'contents',\n }}\n >\n {children}\n </div>\n ) : (\n children\n )}\n </Context.Provider>\n );\n\n // DirectionProvider is Radix's own mechanism (@radix-ui/react-direction)\n // for propagating `dir` to every primitive that calls its useDirection()\n // internally — Select, Menu (Dropdown/Menu), Accordion (Collapse),\n // RadioGroup, ScrollArea all pick up RTL automatically this way, no\n // per-component wiring needed. Only wraps when this Config's own\n // `direction` prop is set (not the merely-inherited resolved value) —\n // context already cascades on its own, so re-wrapping at every nested\n // Config that doesn't override direction would just be redundant.\n // Components with hardcoded LTR-only layout logic that Radix's Direction\n // context doesn't reach (Popover placement, Splitter, Sider, Drawer)\n // aren't covered by this and would need dedicated follow-up work.\n return direction ? (\n <DirectionProvider dir={direction}>{content}</DirectionProvider>\n ) : (\n content\n );\n};\n\nexport default Config;\nexport { useConfig, DEFAULT_LOCALE };\nexport type {\n Props,\n ComponentSize,\n DefaultProps,\n Locale,\n ThemeConfig,\n ThemeToken,\n};\n"],"mappings":";;;;;;;;;;AAwBA,MAAM,mBAAmB;AAEzB,MAAM,gCAAgC,aAAyB;AAC7D,KAAI,OAAO,WAAW,YACpB,cAAa;CAGf,MAAM,MAAM,OAAO,WAAW,iBAAiB;AAC/C,KAAI,iBAAiB,UAAU,SAAS;AACxC,cAAa,IAAI,oBAAoB,UAAU,SAAS;;AAG1D,MAAM,6BACJ,OAAO,WAAW,eAAe,OAAO,WAAW,iBAAiB,CAAC;AAOvE,MAAM,0BAA0B;AAEhC,MAAM,6BACJ,qBACE,8BACA,sBACA,kBACD;AAEH,MAAM,gBAAkD;CACtD,cAAc;CACd,wBAAwB;CACxB,iBAAiB;CACjB,iBAAiB;CACjB,WAAW;CACX,qBAAqB;CACrB,cAAc;CACd,wBAAwB;CACxB,gBAAgB;CAChB,0BAA0B;CAC1B,YAAY;CACZ,sBAAsB;CACtB,aAAa;CACb,uBAAuB;CACvB,kBAAkB;CAClB,aAAa;CACb,YAAY;CACZ,WAAW;CACX,cAAc;CAEd,eAAe;CACf,oBAAoB;CACpB,qBAAqB;CACrB,WAAW;CACX,eAAe;CAEf,SAAS;CACT,mBAAmB;CACnB,gBAAgB;CAChB,0BAA0B;CAC1B,eAAe;CACf,yBAAyB;CACzB,eAAe;CACf,aAAa;CAEb,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CAER,UAAU;CACV,UAAU;CACX;AAED,MAAM,gBAAgB,UAA4C;AAChE,KAAI,CAAC,MACH,QAAO,EAAE;CAGX,MAAM,OAA+B,EAAE;AAEvC,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,MAAM,EAAE;AAChD,MAAI,UAAU,OACZ;EAEF,MAAM,SAAS,cAAc;AAC7B,MAAI,OACF,MAAK,UAAU;;AAInB,QAAO;;AAeT,MAAM,UAAU,EACd,QAAQ,EAAE,EACV,SAAS,EAAE,EACX,cACA,eACA,WACA,cACA,WACA,OACA,eACW;CACX,MAAM,SAAS,WAAW;CAC1B,MAAM,CAAC,WAAW,gBAAgB,SAAgC,KAAK;CAIvE,MAAM,SAAS,CAAC,OAAO;CAWvB,MAAM,WAAW,KAAK,UAAU,MAAM;CACtC,MAAM,iBAAiB,KAAK,UAAU,OAAO,MAAM;CACnD,MAAM,YAAY,KAAK,UAAU,OAAO;CACxC,MAAM,kBAAkB,KAAK,UAAU,OAAO,OAAO;CAErD,MAAM,cAAc,eACX;EACL,GAAG,OAAO;EACV,GAAG;EACH,OAAO;GACL,GAAG,OAAO,MAAM;GAChB,GAAG,MAAM;GACV;EACD,WAAW;GACT,GAAG,OAAO,MAAM;GAChB,GAAG,MAAM;GACV;EACF,GAED,CAAC,gBAAgB,SAAS,CAC3B;CAED,MAAM,eAAe,eACZ;EACL,GAAG,OAAO;EACV,GAAG;EACJ,GAED,CAAC,iBAAiB,UAAU,CAC7B;CAED,MAAM,oBAAoB,sBAAsB;CAChD,MAAM,eACJ,YAAY,SAAS,WACjB,oBACA,YAAY,SAAS;CAI3B,MAAM,UAAU,cAEZ,aACE,eACI;EAAE,GAAG,YAAY;EAAO,GAAG,YAAY;EAAW,GAClD,YAAY,MACjB,EACH;EAAC,YAAY;EAAO,YAAY;EAAW;EAAa,CACzD;CAED,MAAM,aAAa,OAAO,KAAK,QAAQ,CAAC,SAAS;CACjD,MAAM,cAAc,YAAY,SAAS;CACzC,MAAM,eACJ,cAAc,eAAe,CAAC,CAAC,aAAa,CAAC,CAAC,SAAS,CAAC,CAAC;CAU3D,MAAM,uBAAuB,kBAA2C;AACtE,MAAI,aACF,QAAO,cAAc;AAEvB,MAAI,gBAAgB,UAClB,QAAO;AAET,SAAO,OAAO,cAAc;IAC3B;EAAC;EAAc;EAAc;EAAW;EAAO,CAAC;CAEnD,MAAM,wBAAwB,iBAAiB,OAAO;CACtD,MAAM,oBAAoB,aAAa,OAAO;CAE9C,MAAM,kBAAkB,KAAK,UAAU,aAAa;CAGpD,MAAM,qBAAqB,cAEvB,OAAO,gBAAgB,eACnB;EAAE,GAAG,OAAO;EAAc,GAAG;EAAc,GAC3C,QAEN,CAR4B,KAAK,UAAU,OAAO,aAAa,EAQvC,gBAAgB,CACzC;CAED,MAAM,eAAe,eACZ;EACL,OAAO;EACP,QAAQ;EACR,cAAc;EACd,eAAe;EACf,WAAW;EACX,cAAc;EACd,cAAc;EACf,GACD;EACE;EACA;EACA;EACA;EACA;EACA;EACD,CACF;AAED,iBAAgB;AACd,MAAI,CAAC,OACH;AAEF,SAAO,mBAAmB,aAAa;IACtC,CAAC,QAAQ,aAAa,CAAC;CAE1B,MAAM,UACJ,oBAAC,QAAQ;EAAS,OAAO;YACtB,eACC,oBAAC;GACC,KAAK;GACL,KAAK;GACL,WAAW,GAAG,gBAAgB,QAAQ,UAAU;GAChD,OAAO;IACL,GAAI,aAAa,UAAU;IAC3B,GAAG;IAcH,SAAS;IACV;GAEA;IACG,GAEN;GAEe;AAcrB,QAAO,YACL,oBAAC;EAAkB,KAAK;YAAY;GAA4B,GAEhE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.mts","names":[],"sources":["../../../src/providers/config/context.ts"],"mappings":";;;;cAMa,cAAA,EAAgB,QAAA,CAAS,MAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"context.d.mts","names":[],"sources":["../../../src/providers/config/context.ts"],"mappings":";;;;cAMa,cAAA,EAAgB,QAAA,CAAS,MAAA;AAAA,cAmBzB,SAAA,QAAS,YAAA"}
|
|
@@ -9,12 +9,16 @@ const DEFAULT_LOCALE = {
|
|
|
9
9
|
backToTop: "맨 위로",
|
|
10
10
|
loading: "로딩 중",
|
|
11
11
|
expand: "펼치기",
|
|
12
|
-
collapse: "접기"
|
|
12
|
+
collapse: "접기",
|
|
13
|
+
back: "뒤로가기",
|
|
14
|
+
ok: "OK",
|
|
15
|
+
cancel: "Cancel"
|
|
13
16
|
};
|
|
14
17
|
const Context = createContext({
|
|
15
18
|
theme: {},
|
|
16
19
|
locale: DEFAULT_LOCALE,
|
|
17
|
-
getContainer: () => void 0
|
|
20
|
+
getContainer: () => void 0,
|
|
21
|
+
isConfigured: false
|
|
18
22
|
});
|
|
19
23
|
const useConfig = () => useContext(Context);
|
|
20
24
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.mjs","names":[],"sources":["../../../src/providers/config/context.ts"],"sourcesContent":["'use client';\n\nimport { createContext, useContext } from 'react';\n\nimport type { ContextValue, Locale } from './types';\n\nexport const DEFAULT_LOCALE: Required<Locale> = {\n close: '닫기',\n clear: '지우기',\n backToTop: '맨 위로',\n loading: '로딩 중',\n expand: '펼치기',\n collapse: '접기',\n};\n\nexport const Context = createContext<ContextValue>({\n theme: {},\n locale: DEFAULT_LOCALE,\n getContainer: () => undefined,\n});\n\nexport const useConfig = () => useContext(Context);\n"],"mappings":";;;;;AAMA,MAAa,iBAAmC;CAC9C,OAAO;CACP,OAAO;CACP,WAAW;CACX,SAAS;CACT,QAAQ;CACR,UAAU;
|
|
1
|
+
{"version":3,"file":"context.mjs","names":[],"sources":["../../../src/providers/config/context.ts"],"sourcesContent":["'use client';\n\nimport { createContext, useContext } from 'react';\n\nimport type { ContextValue, Locale } from './types';\n\nexport const DEFAULT_LOCALE: Required<Locale> = {\n close: '닫기',\n clear: '지우기',\n backToTop: '맨 위로',\n loading: '로딩 중',\n expand: '펼치기',\n collapse: '접기',\n back: '뒤로가기',\n ok: 'OK',\n cancel: 'Cancel',\n};\n\nexport const Context = createContext<ContextValue>({\n theme: {},\n locale: DEFAULT_LOCALE,\n getContainer: () => undefined,\n isConfigured: false,\n});\n\nexport const useConfig = () => useContext(Context);\n"],"mappings":";;;;;AAMA,MAAa,iBAAmC;CAC9C,OAAO;CACP,OAAO;CACP,WAAW;CACX,SAAS;CACT,QAAQ;CACR,UAAU;CACV,MAAM;CACN,IAAI;CACJ,QAAQ;CACT;AAED,MAAa,UAAU,cAA4B;CACjD,OAAO,EAAE;CACT,QAAQ;CACR,oBAAoB;CACpB,cAAc;CACf,CAAC;AAEF,MAAa,kBAAkB,WAAW,QAAQ"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import { Locale, ThemeConfig, ThemeToken } from "./types.mjs";
|
|
1
|
+
import { ComponentSize, DefaultProps, Locale, ThemeConfig, ThemeToken } from "./types.mjs";
|
|
2
2
|
import { DEFAULT_LOCALE, useConfig } from "./context.mjs";
|
|
3
|
-
import { Config, Props } from "./config.mjs";
|
|
3
|
+
import { Config, Props } from "./config.mjs";
|
|
4
|
+
import { ConfigSnapshotProvider, getRootConfigValue } from "./registry.mjs";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ContextValue } from "./types.mjs";
|
|
2
|
+
import * as react from "react";
|
|
3
|
+
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
4
|
+
|
|
5
|
+
//#region src/providers/config/registry.d.ts
|
|
6
|
+
declare const getRootConfigValue: () => ContextValue | null;
|
|
7
|
+
declare const ConfigSnapshotProvider: ({
|
|
8
|
+
children
|
|
9
|
+
}: {
|
|
10
|
+
children: React.ReactNode;
|
|
11
|
+
}) => string | number | bigint | boolean | Iterable<react.ReactNode> | Promise<string | number | bigint | boolean | react.ReactPortal | react.ReactElement<unknown, string | react.JSXElementConstructor<any>> | Iterable<react.ReactNode> | null | undefined> | react_jsx_runtime0.JSX.Element | null | undefined;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { ConfigSnapshotProvider, getRootConfigValue };
|
|
14
|
+
//# sourceMappingURL=registry.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.mts","names":[],"sources":["../../../src/providers/config/registry.tsx"],"mappings":";;;;;cAkCa,kBAAA,QAAyB,YAAA;AAAA,cAOzB,sBAAA;EAA0B;AAAA;EAGrC,QAAA,EAAU,KAAA,CAAM,SAAA;AAAA,2CACjB,QAAA,CAD0B,KAAA,CAC1B,SAAA,IAAA,OAAA,sCAAA,KAAA,CAAA,WAAA,GAAA,KAAA,CAAA,YAAA,mBAAA,KAAA,CAAA,qBAAA,SAAA,QAAA,CAAA,KAAA,CAAA,SAAA,wBAAA,kBAAA,CAAA,GAAA,CAAA,OAAA"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Context } from "./context.mjs";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
|
|
6
|
+
//#region src/providers/config/registry.tsx
|
|
7
|
+
let currentValue = null;
|
|
8
|
+
const registerRootConfig = (value) => {
|
|
9
|
+
currentValue = value;
|
|
10
|
+
return () => {
|
|
11
|
+
if (currentValue === value) currentValue = null;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
const getRootConfigValue = () => currentValue;
|
|
15
|
+
const ConfigSnapshotProvider = ({ children }) => {
|
|
16
|
+
const value = getRootConfigValue();
|
|
17
|
+
if (!value) return children;
|
|
18
|
+
return /* @__PURE__ */ jsx(Context.Provider, {
|
|
19
|
+
value,
|
|
20
|
+
children
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
//#endregion
|
|
25
|
+
export { ConfigSnapshotProvider, getRootConfigValue, registerRootConfig };
|
|
26
|
+
//# sourceMappingURL=registry.mjs.map
|