@photon-ai/pho-ui 1.0.0 → 1.0.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/dist/chunks/{menu-COLB_liS.js → menu-Dan0oRvL.js} +79 -76
- package/dist/chunks/menu-Dan0oRvL.js.map +1 -0
- package/dist/chunks/{sidebar-16Pfn7IC.js → sidebar-Buhva5xa.js} +2 -2
- package/dist/chunks/{sidebar-16Pfn7IC.js.map → sidebar-Buhva5xa.js.map} +1 -1
- package/dist/components/autocomplete.js +1 -1
- package/dist/components/autocomplete.js.map +1 -1
- package/dist/components/combobox.js +1 -1
- package/dist/components/combobox.js.map +1 -1
- package/dist/components/context-menu.js +52 -49
- package/dist/components/context-menu.js.map +1 -1
- package/dist/components/menu.js +1 -1
- package/dist/components/select.js +16 -16
- package/dist/components/select.js.map +1 -1
- package/dist/components/theme-toggle.js +22 -18
- package/dist/components/theme-toggle.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/sections/sidebar.js +1 -1
- package/dist/src/components/theme-toggle/theme-toggle.d.ts +4 -0
- package/package.json +1 -1
- package/src/styles/theme.css +2 -2
- package/dist/chunks/menu-COLB_liS.js.map +0 -1
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { t as a } from "./cn-DTiB6ek_.js";
|
|
3
|
-
import { t as
|
|
4
|
-
import { n as
|
|
5
|
-
import { createContext as
|
|
6
|
-
import { jsx as r, jsxs as
|
|
3
|
+
import { t as I } from "./resolve-variant-CcD8iG5l.js";
|
|
4
|
+
import { n as S } from "./spinner-Cy8bkyJf.js";
|
|
5
|
+
import { createContext as E, useCallback as T, useContext as P, useEffect as N, useMemo as G, useRef as b, useState as C } from "react";
|
|
6
|
+
import { Fragment as U, jsx as r, jsxs as x } from "react/jsx-runtime";
|
|
7
7
|
import { Menu as t } from "@base-ui/react/menu";
|
|
8
|
-
import { Separator as
|
|
9
|
-
var y =
|
|
10
|
-
function
|
|
11
|
-
return
|
|
8
|
+
import { Separator as _ } from "@base-ui/react/separator";
|
|
9
|
+
var y = E(null);
|
|
10
|
+
function ce() {
|
|
11
|
+
return P(y)?.pending ?? !1;
|
|
12
12
|
}
|
|
13
|
-
function
|
|
13
|
+
function L(e) {
|
|
14
14
|
return e != null && typeof e.then == "function";
|
|
15
15
|
}
|
|
16
|
-
function
|
|
16
|
+
function O(e) {
|
|
17
17
|
function n({ onOpenChange: i, actionsRef: s, ...u }) {
|
|
18
18
|
const [d, l] = C(!1), c = b(!1), o = b(null);
|
|
19
|
-
|
|
19
|
+
N(() => {
|
|
20
20
|
if (s)
|
|
21
21
|
return s.current = {
|
|
22
22
|
unmount: () => o.current?.unmount(),
|
|
@@ -25,13 +25,13 @@ function L(e) {
|
|
|
25
25
|
s.current = null;
|
|
26
26
|
};
|
|
27
27
|
}, [s]);
|
|
28
|
-
const p =
|
|
28
|
+
const p = T((h, m) => {
|
|
29
29
|
if (!h && c.current) {
|
|
30
30
|
m.cancel();
|
|
31
31
|
return;
|
|
32
32
|
}
|
|
33
33
|
i?.(h, m);
|
|
34
|
-
}, [i]),
|
|
34
|
+
}, [i]), g = G(() => ({
|
|
35
35
|
pending: d,
|
|
36
36
|
beginPending: () => {
|
|
37
37
|
c.current = !0, l(!0);
|
|
@@ -42,7 +42,7 @@ function L(e) {
|
|
|
42
42
|
close: () => o.current?.close()
|
|
43
43
|
}), [d]);
|
|
44
44
|
return /* @__PURE__ */ r(y.Provider, {
|
|
45
|
-
value:
|
|
45
|
+
value: g,
|
|
46
46
|
children: /* @__PURE__ */ r(e, {
|
|
47
47
|
...u,
|
|
48
48
|
actionsRef: o,
|
|
@@ -52,37 +52,37 @@ function L(e) {
|
|
|
52
52
|
}
|
|
53
53
|
return n;
|
|
54
54
|
}
|
|
55
|
-
function
|
|
56
|
-
const u =
|
|
57
|
-
|
|
55
|
+
function w({ onClick: e, closeOnClick: n = !0, loading: i = !1, disabled: s = !1 }) {
|
|
56
|
+
const u = P(y), d = u?.pending ?? !1, [l, c] = C(!1), o = b(!0);
|
|
57
|
+
N(() => (o.current = !0, () => {
|
|
58
58
|
o.current = !1;
|
|
59
59
|
}), []);
|
|
60
|
-
const p = l || i,
|
|
60
|
+
const p = l || i, g = s || d && !l;
|
|
61
61
|
function h(m) {
|
|
62
62
|
if (p || d && !l) {
|
|
63
63
|
m.preventBaseUIHandler?.();
|
|
64
64
|
return;
|
|
65
65
|
}
|
|
66
|
-
const
|
|
67
|
-
|
|
66
|
+
const v = e?.(m);
|
|
67
|
+
L(v) && (m.preventBaseUIHandler?.(), c(!0), u?.beginPending(), v.then(() => {
|
|
68
68
|
u?.endPending(), o.current && c(!1), n && u?.close();
|
|
69
|
-
}, (
|
|
70
|
-
u?.endPending(), o.current && c(!1), typeof process < "u" && process.env.NODE_ENV !== "production" && console.error("Menu.Item: async onClick rejected —",
|
|
69
|
+
}, (k) => {
|
|
70
|
+
u?.endPending(), o.current && c(!1), typeof process < "u" && process.env.NODE_ENV !== "production" && console.error("Menu.Item: async onClick rejected —", k);
|
|
71
71
|
}));
|
|
72
72
|
}
|
|
73
73
|
return {
|
|
74
74
|
inert: p,
|
|
75
|
-
blocked:
|
|
75
|
+
blocked: g,
|
|
76
76
|
handleClick: h
|
|
77
77
|
};
|
|
78
78
|
}
|
|
79
|
-
function
|
|
80
|
-
return /* @__PURE__ */ r(
|
|
79
|
+
function z() {
|
|
80
|
+
return /* @__PURE__ */ r(S, {
|
|
81
81
|
"data-menu-spinner": "",
|
|
82
82
|
size: "md"
|
|
83
83
|
});
|
|
84
84
|
}
|
|
85
|
-
var
|
|
85
|
+
var j = "bg-pho-primary text-pho-primary shadow-pho-lg ring-pho-secondary origin-[var(--transform-origin)] min-w-44 rounded-base p-1.5 ring-1 ring-inset outline-none transition-[transform,opacity] duration-150 ease-out data-[starting-style]:scale-95 data-[starting-style]:opacity-0 data-[ending-style]:scale-95 data-[ending-style]:opacity-0", f = "relative flex cursor-pointer items-center gap-2 rounded-[calc(var(--radius-base)-6px)] py-2 pr-2.5 pl-2.5 text-base text-pho-secondary outline-none select-none data-[highlighted]:bg-pho-ghost-hover data-[highlighted]:text-pho-primary data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-loading:data-[disabled]:opacity-100 data-loading:[&>svg:not([data-menu-spinner])]:hidden [&>svg]:size-4 [&>svg]:text-current", R = {
|
|
86
86
|
default: {
|
|
87
87
|
classes: "",
|
|
88
88
|
description: "Secondary → primary on highlight"
|
|
@@ -91,8 +91,8 @@ var z = "bg-pho-primary text-pho-primary shadow-pho-lg ring-pho-secondary origin
|
|
|
91
91
|
classes: "text-pho-error data-[highlighted]:bg-pho-error-primary data-[highlighted]:text-pho-error",
|
|
92
92
|
description: "Error ink + error wash on highlight"
|
|
93
93
|
}
|
|
94
|
-
},
|
|
95
|
-
function
|
|
94
|
+
}, A = O(t.Root), B = t.Trigger, H = t.Portal, V = t.Group, $ = t.RadioGroup, D = t.SubmenuRoot;
|
|
95
|
+
function F({ className: e, sideOffset: n = 6, ...i }) {
|
|
96
96
|
return /* @__PURE__ */ r(t.Positioner, {
|
|
97
97
|
sideOffset: n,
|
|
98
98
|
className: a("z-50", e),
|
|
@@ -101,105 +101,108 @@ function D({ className: e, sideOffset: n = 6, ...i }) {
|
|
|
101
101
|
}
|
|
102
102
|
function K({ className: e, ...n }) {
|
|
103
103
|
return /* @__PURE__ */ r(t.Popup, {
|
|
104
|
-
className: a(
|
|
104
|
+
className: a(j, e),
|
|
105
105
|
...n
|
|
106
106
|
});
|
|
107
107
|
}
|
|
108
108
|
function q({ className: e, color: n = "default", onClick: i, closeOnClick: s = !0, loading: u = !1, disabled: d = !1, children: l, ...c }) {
|
|
109
|
-
const { inert: o, blocked: p, handleClick:
|
|
109
|
+
const { inert: o, blocked: p, handleClick: g } = w({
|
|
110
110
|
onClick: i,
|
|
111
111
|
closeOnClick: s,
|
|
112
112
|
loading: u,
|
|
113
113
|
disabled: d
|
|
114
114
|
});
|
|
115
|
-
return /* @__PURE__ */
|
|
116
|
-
className: a(
|
|
115
|
+
return /* @__PURE__ */ x(t.Item, {
|
|
116
|
+
className: a(f, I(R, n), e),
|
|
117
117
|
closeOnClick: s,
|
|
118
118
|
disabled: p,
|
|
119
119
|
"data-loading": o || void 0,
|
|
120
120
|
"aria-busy": o || void 0,
|
|
121
|
-
onClick:
|
|
121
|
+
onClick: g,
|
|
122
122
|
...c,
|
|
123
|
-
children: [o ? /* @__PURE__ */ r(
|
|
123
|
+
children: [o ? /* @__PURE__ */ x(U, { children: [/* @__PURE__ */ r(z, {}), /* @__PURE__ */ r("output", {
|
|
124
|
+
className: "sr-only",
|
|
125
|
+
"aria-live": "polite"
|
|
126
|
+
})] }) : null, l]
|
|
124
127
|
});
|
|
125
128
|
}
|
|
126
|
-
function
|
|
129
|
+
function J({ className: e, color: n = "default", ...i }) {
|
|
127
130
|
return /* @__PURE__ */ r(t.LinkItem, {
|
|
128
|
-
className: a(
|
|
131
|
+
className: a(f, I(R, n), e),
|
|
129
132
|
...i
|
|
130
133
|
});
|
|
131
134
|
}
|
|
132
|
-
function
|
|
135
|
+
function Q({ className: e, ...n }) {
|
|
133
136
|
return /* @__PURE__ */ r(t.GroupLabel, {
|
|
134
137
|
className: a("text-pho-secondary px-2.5 py-1.5 text-xs font-medium", e),
|
|
135
138
|
...n
|
|
136
139
|
});
|
|
137
140
|
}
|
|
138
|
-
function
|
|
139
|
-
return /* @__PURE__ */ r(
|
|
140
|
-
className: a("-mx-1 my-1 h-px bg-[var(--border-color-pho-secondary)]", e),
|
|
141
|
+
function W({ className: e, ...n }) {
|
|
142
|
+
return /* @__PURE__ */ r(_, {
|
|
143
|
+
className: a("-mx-1.5 my-1.5 h-px bg-[var(--border-color-pho-secondary)]", e),
|
|
141
144
|
...n
|
|
142
145
|
});
|
|
143
146
|
}
|
|
144
|
-
function
|
|
147
|
+
function X({ className: e, ...n }) {
|
|
145
148
|
return /* @__PURE__ */ r(t.SubmenuTrigger, {
|
|
146
|
-
className: a(
|
|
149
|
+
className: a(f, "data-[popup-open]:bg-pho-ghost-hover", e),
|
|
147
150
|
...n
|
|
148
151
|
});
|
|
149
152
|
}
|
|
150
|
-
function
|
|
153
|
+
function Y({ className: e, ...n }) {
|
|
151
154
|
return /* @__PURE__ */ r(t.CheckboxItem, {
|
|
152
|
-
className: a(
|
|
155
|
+
className: a(f, "pl-8", e),
|
|
153
156
|
...n
|
|
154
157
|
});
|
|
155
158
|
}
|
|
156
|
-
function
|
|
159
|
+
function Z({ className: e, ...n }) {
|
|
157
160
|
return /* @__PURE__ */ r(t.RadioItem, {
|
|
158
|
-
className: a(
|
|
161
|
+
className: a(f, "pl-8", e),
|
|
159
162
|
...n
|
|
160
163
|
});
|
|
161
164
|
}
|
|
162
|
-
var
|
|
163
|
-
function
|
|
165
|
+
var M = "text-pho-brand absolute left-2.5 flex items-center [&>svg]:size-4";
|
|
166
|
+
function ee({ className: e, ...n }) {
|
|
164
167
|
return /* @__PURE__ */ r(t.CheckboxItemIndicator, {
|
|
165
|
-
className: a(
|
|
168
|
+
className: a(M, e),
|
|
166
169
|
...n
|
|
167
170
|
});
|
|
168
171
|
}
|
|
169
|
-
function
|
|
172
|
+
function ne({ className: e, ...n }) {
|
|
170
173
|
return /* @__PURE__ */ r(t.RadioItemIndicator, {
|
|
171
|
-
className: a(
|
|
174
|
+
className: a(M, e),
|
|
172
175
|
...n
|
|
173
176
|
});
|
|
174
177
|
}
|
|
175
|
-
var
|
|
176
|
-
Root:
|
|
177
|
-
Trigger:
|
|
178
|
-
Portal:
|
|
179
|
-
Positioner:
|
|
178
|
+
var le = {
|
|
179
|
+
Root: A,
|
|
180
|
+
Trigger: B,
|
|
181
|
+
Portal: H,
|
|
182
|
+
Positioner: F,
|
|
180
183
|
Popup: K,
|
|
181
184
|
Item: q,
|
|
182
|
-
LinkItem:
|
|
183
|
-
Group:
|
|
184
|
-
GroupLabel:
|
|
185
|
-
Separator:
|
|
186
|
-
SubmenuRoot:
|
|
187
|
-
SubmenuTrigger:
|
|
188
|
-
CheckboxItem:
|
|
189
|
-
CheckboxItemIndicator:
|
|
190
|
-
RadioGroup:
|
|
191
|
-
RadioItem:
|
|
192
|
-
RadioItemIndicator:
|
|
185
|
+
LinkItem: J,
|
|
186
|
+
Group: V,
|
|
187
|
+
GroupLabel: Q,
|
|
188
|
+
Separator: W,
|
|
189
|
+
SubmenuRoot: D,
|
|
190
|
+
SubmenuTrigger: X,
|
|
191
|
+
CheckboxItem: Y,
|
|
192
|
+
CheckboxItemIndicator: ee,
|
|
193
|
+
RadioGroup: $,
|
|
194
|
+
RadioItem: Z,
|
|
195
|
+
RadioItemIndicator: ne
|
|
193
196
|
};
|
|
194
197
|
export {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
198
|
+
z as a,
|
|
199
|
+
O as c,
|
|
200
|
+
le as i,
|
|
201
|
+
R as n,
|
|
202
|
+
w as o,
|
|
203
|
+
j as r,
|
|
204
|
+
ce as s,
|
|
205
|
+
f as t
|
|
203
206
|
};
|
|
204
207
|
|
|
205
|
-
//# sourceMappingURL=menu-
|
|
208
|
+
//# sourceMappingURL=menu-Dan0oRvL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"menu-Dan0oRvL.js","names":[],"sources":["../../src/components/menu/menu-pending.tsx","../../src/components/menu/menu.tsx"],"sourcesContent":["import {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ComponentType,\n type MouseEvent as ReactMouseEvent,\n type ReactNode,\n type RefObject,\n} from \"react\";\nimport { Spinner } from \"../spinner/spinner\";\n\n/** Imperative actions exposed by Base UI menu `actionsRef`. */\ninterface RootActions {\n unmount: () => void;\n close: () => void;\n}\n\ninterface MenuPendingContextValue {\n /** True while a menu item promise is in flight. */\n pending: boolean;\n beginPending: () => void;\n endPending: () => void;\n /** Close the menu imperatively (used by async items on resolve). */\n close: () => void;\n}\n\nconst MenuPendingContext = createContext<MenuPendingContextValue | null>(null);\n\n/**\n * Whether the surrounding menu has an async item promise in flight —\n * use it to disable sibling items while work is pending.\n * Returns `false` outside a `Menu.Root` / `ContextMenu.Root`.\n */\nexport function useMenuPending(): boolean {\n return useContext(MenuPendingContext)?.pending ?? false;\n}\n\nexport function isThenable(value: unknown): value is Promise<unknown> {\n return (\n value != null && typeof (value as { then?: unknown }).then === \"function\"\n );\n}\n\ntype PreventableMouseEvent = ReactMouseEvent<HTMLElement> & {\n preventBaseUIHandler?: () => void;\n};\n\ntype RootWithPendingProps = {\n onOpenChange?: (open: boolean, eventDetails: { cancel: () => void }) => void;\n actionsRef?: RefObject<RootActions | null>;\n children?: ReactNode;\n};\n\n/**\n * Wraps a Base UI menu root so async `Menu.Item` clicks can lock dismissal\n * (outside press, Escape) until the promise settles.\n */\nexport function withMenuPendingRoot<P extends RootWithPendingProps>(\n BaseRoot: ComponentType<P>,\n): ComponentType<P> {\n function PendingRoot({ onOpenChange, actionsRef, ...props }: P) {\n const [pending, setPending] = useState(false);\n // Guard reads a ref so a resolve → close() in the same tick isn't blocked\n // by a not-yet-flushed state update.\n const pendingRef = useRef(false);\n const internalActionsRef = useRef<RootActions | null>(null);\n\n useEffect(() => {\n if (!actionsRef) return;\n // Proxy so callers always hit the live Base UI actions, even if the\n // popup remounts after this effect runs.\n actionsRef.current = {\n unmount: () => internalActionsRef.current?.unmount(),\n close: () => internalActionsRef.current?.close(),\n };\n return () => {\n actionsRef.current = null;\n };\n }, [actionsRef]);\n\n const handleOpenChange = useCallback(\n (open: boolean, eventDetails: { cancel: () => void }) => {\n if (!open && pendingRef.current) {\n eventDetails.cancel();\n return;\n }\n onOpenChange?.(open, eventDetails);\n },\n [onOpenChange],\n );\n\n const contextValue = useMemo<MenuPendingContextValue>(\n () => ({\n pending,\n beginPending: () => {\n pendingRef.current = true;\n setPending(true);\n },\n endPending: () => {\n pendingRef.current = false;\n setPending(false);\n },\n close: () => internalActionsRef.current?.close(),\n }),\n [pending],\n );\n\n return (\n <MenuPendingContext.Provider value={contextValue}>\n <BaseRoot\n {...(props as P)}\n actionsRef={internalActionsRef}\n onOpenChange={handleOpenChange}\n />\n </MenuPendingContext.Provider>\n );\n }\n\n return PendingRoot as ComponentType<P>;\n}\n\nexport type AsyncMenuItemClick = (\n event: ReactMouseEvent<HTMLElement>,\n) => void | Promise<unknown>;\n\n/**\n * Shared click handler for `Menu.Item` / `ContextMenu.Item` promise support.\n * Returns whether the item should show its loading state.\n */\nexport function useAsyncMenuItem({\n onClick,\n closeOnClick = true,\n loading = false,\n disabled = false,\n}: {\n onClick?: AsyncMenuItemClick;\n closeOnClick?: boolean;\n loading?: boolean;\n disabled?: boolean;\n}) {\n const pendingContext = useContext(MenuPendingContext);\n const menuPending = pendingContext?.pending ?? false;\n const [busy, setBusy] = useState(false);\n const mountedRef = useRef(true);\n\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n };\n }, []);\n\n const inert = busy || loading;\n // Disable siblings while any item promise is in flight — not the busy item itself.\n const blocked = disabled || (menuPending && !busy);\n\n function handleClick(event: ReactMouseEvent<HTMLElement>) {\n if (inert || (menuPending && !busy)) {\n (event as PreventableMouseEvent).preventBaseUIHandler?.();\n return;\n }\n const result = onClick?.(event);\n if (!isThenable(result)) {\n return;\n }\n // Stop Base UI's closeOnClick for this press; close on resolve instead.\n (event as PreventableMouseEvent).preventBaseUIHandler?.();\n setBusy(true);\n pendingContext?.beginPending();\n result.then(\n () => {\n pendingContext?.endPending();\n if (mountedRef.current) setBusy(false);\n if (closeOnClick) pendingContext?.close();\n },\n (error: unknown) => {\n pendingContext?.endPending();\n if (mountedRef.current) setBusy(false);\n if (\n typeof process !== \"undefined\" &&\n process.env?.NODE_ENV !== \"production\"\n ) {\n console.error(\"Menu.Item: async onClick rejected —\", error);\n }\n },\n );\n }\n\n return { inert, blocked, handleClick };\n}\n\n/** Menu-row spinner — keeps `data-menu-spinner` for the hide-siblings CSS. */\nexport function MenuItemSpinner() {\n return <Spinner data-menu-spinner=\"\" size=\"md\" />;\n}\n","import {\n type ComponentProps,\n type ElementType,\n type MouseEvent as ReactMouseEvent,\n} from \"react\";\nimport { Menu as BaseMenu } from \"@base-ui/react/menu\";\nimport { Separator as BaseSeparator } from \"@base-ui/react/separator\";\nimport { cn } from \"../../utils/cn\";\nimport { resolveVariant, type VariantMap } from \"../../utils/resolve-variant\";\nimport {\n MenuItemSpinner,\n useAsyncMenuItem,\n useMenuPending,\n withMenuPendingRoot,\n type AsyncMenuItemClick,\n} from \"./menu-pending\";\n\nexport { useMenuPending };\n\n/** Override Base UI's `string | (state) => string` className with plain string. */\ntype StyledProps<T extends ElementType> = Omit<\n ComponentProps<T>,\n \"className\" | \"color\"\n> & {\n className?: string;\n};\n\n/** Shared popup + item styles, reused by `ContextMenu` and `Menubar` menus. */\n// Floating layer: keeps its elevation shadow, sits on the primary surface\n// with the site's hairline (ring-pho-secondary, #eee/#202020) as its edge.\n// `base` radius + p-1.5 inset — the highlight floats 6px clear of the edge.\nexport const MENU_POPUP =\n \"bg-pho-primary text-pho-primary shadow-pho-lg ring-pho-secondary origin-[var(--transform-origin)] min-w-44 rounded-base p-1.5 ring-1 ring-inset outline-none transition-[transform,opacity] duration-150 ease-out data-[starting-style]:scale-95 data-[starting-style]:opacity-0 data-[ending-style]:scale-95 data-[ending-style]:opacity-0\";\n// Rest at secondary; highlighted lifts to primary with the quiet ghost wash.\n// Icons use `text-current` so they follow the row ink (including destructive).\n// While loading, the spinner is first; hide the rest of the leading icons.\n// Concentric correction (see /scale): row radius = popup radius − popup\n// padding (base − 6px). py-2 + 20px line-height lands the 36px row height.\nexport const MENU_ITEM =\n \"relative flex cursor-pointer items-center gap-2 rounded-[calc(var(--radius-base)-6px)] py-2 pr-2.5 pl-2.5 text-base text-pho-secondary outline-none select-none data-[highlighted]:bg-pho-ghost-hover data-[highlighted]:text-pho-primary data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-loading:data-[disabled]:opacity-100 data-loading:[&>svg:not([data-menu-spinner])]:hidden [&>svg]:size-4 [&>svg]:text-current\";\n\n/** Semantic ink for `Menu.Item` / `LinkItem` / `ContextMenu.Item`. */\nexport const MENU_ITEM_COLORS = {\n default: { classes: \"\", description: \"Secondary → primary on highlight\" },\n destructive: {\n classes:\n \"text-pho-error data-[highlighted]:bg-pho-error-primary data-[highlighted]:text-pho-error\",\n description: \"Error ink + error wash on highlight\",\n },\n} satisfies VariantMap;\n\nexport type MenuItemColor = keyof typeof MENU_ITEM_COLORS;\n\ntype ItemColorProps = {\n /** Semantic ink. @default \"default\" */\n color?: MenuItemColor;\n};\n\nexport type MenuItemProps = Omit<StyledProps<typeof BaseMenu.Item>, \"onClick\"> &\n ItemColorProps & {\n /**\n * Action handler. Return a promise to keep the menu open while it runs:\n * the item shows a spinner, dismissal is locked, and the menu closes when\n * the promise resolves (if `closeOnClick`). On rejection the menu stays\n * open — surface errors inside the handler.\n */\n onClick?: AsyncMenuItemClick;\n /**\n * Declarative loading state (same visual as an in-flight promise).\n * @default false\n */\n loading?: boolean;\n };\n\nconst Root = withMenuPendingRoot(BaseMenu.Root);\nconst Trigger = BaseMenu.Trigger;\nconst Portal = BaseMenu.Portal;\nconst Group = BaseMenu.Group;\nconst RadioGroup = BaseMenu.RadioGroup;\n// Don't wrap SubmenuRoot — nested pending context would shadow the parent\n// Root and fail to lock dismissal for async items inside a submenu.\nconst SubmenuRoot = BaseMenu.SubmenuRoot;\n\nfunction Positioner({\n className,\n sideOffset = 6,\n ...props\n}: StyledProps<typeof BaseMenu.Positioner>) {\n return (\n <BaseMenu.Positioner\n sideOffset={sideOffset}\n className={cn(\"z-50\", className)}\n {...props}\n />\n );\n}\n\nfunction Popup({ className, ...props }: StyledProps<typeof BaseMenu.Popup>) {\n return <BaseMenu.Popup className={cn(MENU_POPUP, className)} {...props} />;\n}\n\nfunction Item({\n className,\n color = \"default\",\n onClick,\n closeOnClick = true,\n loading = false,\n disabled = false,\n children,\n ...props\n}: MenuItemProps) {\n const { inert, blocked, handleClick } = useAsyncMenuItem({\n onClick,\n closeOnClick,\n loading,\n disabled,\n });\n\n return (\n <BaseMenu.Item\n className={cn(\n MENU_ITEM,\n resolveVariant(MENU_ITEM_COLORS, color),\n className,\n )}\n closeOnClick={closeOnClick}\n disabled={blocked}\n data-loading={inert || undefined}\n aria-busy={inert || undefined}\n onClick={handleClick as (event: ReactMouseEvent<HTMLElement>) => void}\n {...props}\n >\n {inert ? (\n <>\n <MenuItemSpinner />\n <output className=\"sr-only\" aria-live=\"polite\" />\n </>\n ) : null}\n {children}\n </BaseMenu.Item>\n );\n}\n\nfunction LinkItem({\n className,\n color = \"default\",\n ...props\n}: StyledProps<typeof BaseMenu.LinkItem> & ItemColorProps) {\n return (\n <BaseMenu.LinkItem\n className={cn(\n MENU_ITEM,\n resolveVariant(MENU_ITEM_COLORS, color),\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction GroupLabel({\n className,\n ...props\n}: StyledProps<typeof BaseMenu.GroupLabel>) {\n return (\n <BaseMenu.GroupLabel\n className={cn(\n \"text-pho-secondary px-2.5 py-1.5 text-xs font-medium\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Separator({ className, ...props }: StyledProps<typeof BaseSeparator>) {\n return (\n <BaseSeparator\n className={cn(\n \"-mx-1.5 my-1.5 h-px bg-[var(--border-color-pho-secondary)]\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction SubmenuTrigger({\n className,\n ...props\n}: StyledProps<typeof BaseMenu.SubmenuTrigger>) {\n return (\n <BaseMenu.SubmenuTrigger\n className={cn(\n MENU_ITEM,\n \"data-[popup-open]:bg-pho-ghost-hover\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction CheckboxItem({\n className,\n ...props\n}: StyledProps<typeof BaseMenu.CheckboxItem>) {\n return (\n <BaseMenu.CheckboxItem\n className={cn(MENU_ITEM, \"pl-8\", className)}\n {...props}\n />\n );\n}\n\nfunction RadioItem({\n className,\n ...props\n}: StyledProps<typeof BaseMenu.RadioItem>) {\n return (\n <BaseMenu.RadioItem\n className={cn(MENU_ITEM, \"pl-8\", className)}\n {...props}\n />\n );\n}\n\nconst CHECK_INDICATOR =\n \"text-pho-brand absolute left-2.5 flex items-center [&>svg]:size-4\";\n\nfunction CheckboxItemIndicator({\n className,\n ...props\n}: StyledProps<typeof BaseMenu.CheckboxItemIndicator>) {\n return (\n <BaseMenu.CheckboxItemIndicator\n className={cn(CHECK_INDICATOR, className)}\n {...props}\n />\n );\n}\n\nfunction RadioItemIndicator({\n className,\n ...props\n}: StyledProps<typeof BaseMenu.RadioItemIndicator>) {\n return (\n <BaseMenu.RadioItemIndicator\n className={cn(CHECK_INDICATOR, className)}\n {...props}\n />\n );\n}\n\n/**\n * Dropdown menu built on Base UI `Menu` — a list of actions opened from a\n * trigger. Supports grouped items, separators, submenus\n * (`SubmenuRoot` + `SubmenuTrigger`), and stateful `CheckboxItem` /\n * `RadioItem`s. `Menu.Item` has native promise support (spinner + locked\n * dismissal while pending). For a right-click menu use `ContextMenu`.\n */\nexport const Menu = {\n Root,\n Trigger,\n Portal,\n Positioner,\n Popup,\n Item,\n LinkItem,\n Group,\n GroupLabel,\n Separator,\n SubmenuRoot,\n SubmenuTrigger,\n CheckboxItem,\n CheckboxItemIndicator,\n RadioGroup,\n RadioItem,\n RadioItemIndicator,\n};\n"],"mappings":";;;;;;;;AA8BA,IAAM,IAAqB,EAA8C,IAAI;AAO7E,SAAgB,KAA0B;AACxC,SAAO,EAAW,CAAkB,GAAG,WAAW;AACpD;AAEA,SAAgB,EAAW,GAA2C;AACpE,SACE,KAAS,QAAQ,OAAQ,EAA6B,QAAS;AAEnE;AAgBA,SAAgB,EACd,GACkB;AAClB,WAAS,EAAY,EAAE,cAAA,GAAc,YAAA,GAAY,GAAG,EAAA,GAAY;AAC9D,UAAM,CAAC,GAAS,CAAA,IAAc,EAAS,EAAK,GAGtC,IAAa,EAAO,EAAK,GACzB,IAAqB,EAA2B,IAAI;AAE1D,IAAA,EAAA,MAAgB;AACd,UAAK;AAGL,eAAA,EAAW,UAAU;AAAA,UACnB,SAAA,MAAe,EAAmB,SAAS,QAAQ;AAAA,UACnD,OAAA,MAAa,EAAmB,SAAS,MAAM;AAAA,QACjD,GACA,MAAa;AACX,UAAA,EAAW,UAAU;AAAA,QACvB;AAAA,IACF,GAAG,CAAC,CAAU,CAAC;AAEf,UAAM,IAAmB,EAAA,CACtB,GAAe,MAAyC;AACvD,UAAI,CAAC,KAAQ,EAAW,SAAS;AAC/B,QAAA,EAAa,OAAO;AACpB;AAAA,MACF;AACA,MAAA,IAAe,GAAM,CAAY;AAAA,IACnC,GACA,CAAC,CAAY,CACf,GAEM,IAAe,EAAA,OACZ;AAAA,MACL,SAAA;AAAA,MACA,cAAA,MAAoB;AAClB,QAAA,EAAW,UAAU,IACrB,EAAW,EAAI;AAAA,MACjB;AAAA,MACA,YAAA,MAAkB;AAChB,QAAA,EAAW,UAAU,IACrB,EAAW,EAAK;AAAA,MAClB;AAAA,MACA,OAAA,MAAa,EAAmB,SAAS,MAAM;AAAA,IACjD,IACA,CAAC,CAAO,CACV;AAEA,WACE,gBAAA,EAAC,EAAmB,UAApB;AAAA,MAA6B,OAAO;AAAA,gBAClC,gBAAA,EAAC,GAAD;AAAA,QACE,GAAK;AAAA,QACL,YAAY;AAAA,QACZ,cAAc;AAAA,MACf,CAAA;AAAA,IAC0B,CAAA;AAAA,EAEjC;AAEA,SAAO;AACT;AAUA,SAAgB,EAAiB,EAC/B,SAAA,GACA,cAAA,IAAe,IACf,SAAA,IAAU,IACV,UAAA,IAAW,GAAA,GAMV;AACD,QAAM,IAAiB,EAAW,CAAkB,GAC9C,IAAc,GAAgB,WAAW,IACzC,CAAC,GAAM,CAAA,IAAW,EAAS,EAAK,GAChC,IAAa,EAAO,EAAI;AAE9B,EAAA,EAAA,OACE,EAAW,UAAU,IACrB,MAAa;AACX,IAAA,EAAW,UAAU;AAAA,EACvB,IACC,CAAC,CAAC;AAEL,QAAM,IAAQ,KAAQ,GAEhB,IAAU,KAAa,KAAe,CAAC;AAE7C,WAAS,EAAY,GAAqC;AACxD,QAAI,KAAU,KAAe,CAAC,GAAO;AACnC,MAAA,EAAiC,uBAAuB;AACxD;AAAA,IACF;AACA,UAAM,IAAS,IAAU,CAAK;AAC9B,IAAK,EAAW,CAAM,MAItB,EAAiC,uBAAuB,GACxD,EAAQ,EAAI,GACZ,GAAgB,aAAa,GAC7B,EAAO,KAAA,MACC;AACJ,MAAA,GAAgB,WAAW,GACvB,EAAW,WAAS,EAAQ,EAAK,GACjC,KAAc,GAAgB,MAAM;AAAA,IAC1C,GAAA,CACC,MAAmB;AAClB,MAAA,GAAgB,WAAW,GACvB,EAAW,WAAS,EAAQ,EAAK,GAEnC,OAAO,UAAY,OAAA,QAAA,IAAA,aACO,gBAE1B,QAAQ,MAAM,uCAAuC,CAAK;AAAA,IAE9D,CACF;AAAA,EACF;AAEA,SAAO;AAAA,IAAE,OAAA;AAAA,IAAO,SAAA;AAAA,IAAS,aAAA;AAAA,EAAY;AACvC;AAGA,SAAgB,IAAkB;AAChC,SAAO,gBAAA,EAAC,GAAD;AAAA,IAAS,qBAAkB;AAAA,IAAG,MAAK;AAAA,EAAM,CAAA;AAClD;ACvKA,IAAa,IACX,+UAMW,IACX,8aAGW,IAAmB;AAAA,EAC9B,SAAS;AAAA,IAAE,SAAS;AAAA,IAAI,aAAa;AAAA,EAAmC;AAAA,EACxE,aAAa;AAAA,IACX,SACE;AAAA,IACF,aAAa;AAAA,EACf;AACF,GAyBM,IAAO,EAAoB,EAAS,IAAI,GACxC,IAAU,EAAS,SACnB,IAAS,EAAS,QAClB,IAAQ,EAAS,OACjB,IAAa,EAAS,YAGtB,IAAc,EAAS;AAE7B,SAAS,EAAW,EAClB,WAAA,GACA,YAAA,IAAa,GACb,GAAG,EAAA,GACuC;AAC1C,SACE,gBAAA,EAAC,EAAS,YAAV;AAAA,IACc,YAAA;AAAA,IACZ,WAAW,EAAG,QAAQ,CAAS;AAAA,IAC/B,GAAI;AAAA,EACL,CAAA;AAEL;AAEA,SAAS,EAAM,EAAE,WAAA,GAAW,GAAG,EAAA,GAA6C;AAC1E,SAAO,gBAAA,EAAC,EAAS,OAAV;AAAA,IAAgB,WAAW,EAAG,GAAY,CAAS;AAAA,IAAG,GAAI;AAAA,EAAQ,CAAA;AAC3E;AAEA,SAAS,EAAK,EACZ,WAAA,GACA,OAAA,IAAQ,WACR,SAAA,GACA,cAAA,IAAe,IACf,SAAA,IAAU,IACV,UAAA,IAAW,IACX,UAAA,GACA,GAAG,EAAA,GACa;AAChB,QAAM,EAAE,OAAA,GAAO,SAAA,GAAS,aAAA,EAAA,IAAgB,EAAiB;AAAA,IACvD,SAAA;AAAA,IACA,cAAA;AAAA,IACA,SAAA;AAAA,IACA,UAAA;AAAA,EACF,CAAC;AAED,SACE,gBAAA,EAAC,EAAS,MAAV;AAAA,IACE,WAAW,EACT,GACA,EAAe,GAAkB,CAAK,GACtC,CACF;AAAA,IACc,cAAA;AAAA,IACd,UAAU;AAAA,IACV,gBAAc,KAAS;AAAA,IACvB,aAAW,KAAS;AAAA,IACpB,SAAS;AAAA,IACT,GAAI;AAAA,cAXN,CAaG,IACC,gBAAA,EAAA,GAAA,EAAA,UAAA,CACE,gBAAA,EAAC,GAAD,CAAkB,CAAA,GAClB,gBAAA,EAAC,UAAD;AAAA,MAAQ,WAAU;AAAA,MAAU,aAAU;AAAA,IAAU,CAAA,CAChD,EAAA,CAAA,IACA,MACH,CACY;AAAA;AAEnB;AAEA,SAAS,EAAS,EAChB,WAAA,GACA,OAAA,IAAQ,WACR,GAAG,EAAA,GACsD;AACzD,SACE,gBAAA,EAAC,EAAS,UAAV;AAAA,IACE,WAAW,EACT,GACA,EAAe,GAAkB,CAAK,GACtC,CACF;AAAA,IACA,GAAI;AAAA,EACL,CAAA;AAEL;AAEA,SAAS,EAAW,EAClB,WAAA,GACA,GAAG,EAAA,GACuC;AAC1C,SACE,gBAAA,EAAC,EAAS,YAAV;AAAA,IACE,WAAW,EACT,wDACA,CACF;AAAA,IACA,GAAI;AAAA,EACL,CAAA;AAEL;AAEA,SAAS,EAAU,EAAE,WAAA,GAAW,GAAG,EAAA,GAA4C;AAC7E,SACE,gBAAA,EAAC,GAAD;AAAA,IACE,WAAW,EACT,8DACA,CACF;AAAA,IACA,GAAI;AAAA,EACL,CAAA;AAEL;AAEA,SAAS,EAAe,EACtB,WAAA,GACA,GAAG,EAAA,GAC2C;AAC9C,SACE,gBAAA,EAAC,EAAS,gBAAV;AAAA,IACE,WAAW,EACT,GACA,wCACA,CACF;AAAA,IACA,GAAI;AAAA,EACL,CAAA;AAEL;AAEA,SAAS,EAAa,EACpB,WAAA,GACA,GAAG,EAAA,GACyC;AAC5C,SACE,gBAAA,EAAC,EAAS,cAAV;AAAA,IACE,WAAW,EAAG,GAAW,QAAQ,CAAS;AAAA,IAC1C,GAAI;AAAA,EACL,CAAA;AAEL;AAEA,SAAS,EAAU,EACjB,WAAA,GACA,GAAG,EAAA,GACsC;AACzC,SACE,gBAAA,EAAC,EAAS,WAAV;AAAA,IACE,WAAW,EAAG,GAAW,QAAQ,CAAS;AAAA,IAC1C,GAAI;AAAA,EACL,CAAA;AAEL;AAEA,IAAM,IACJ;AAEF,SAAS,GAAsB,EAC7B,WAAA,GACA,GAAG,EAAA,GACkD;AACrD,SACE,gBAAA,EAAC,EAAS,uBAAV;AAAA,IACE,WAAW,EAAG,GAAiB,CAAS;AAAA,IACxC,GAAI;AAAA,EACL,CAAA;AAEL;AAEA,SAAS,GAAmB,EAC1B,WAAA,GACA,GAAG,EAAA,GAC+C;AAClD,SACE,gBAAA,EAAC,EAAS,oBAAV;AAAA,IACE,WAAW,EAAG,GAAiB,CAAS;AAAA,IACxC,GAAI;AAAA,EACL,CAAA;AAEL;AASA,IAAa,KAAO;AAAA,EAClB,MAAA;AAAA,EACA,SAAA;AAAA,EACA,QAAA;AAAA,EACA,YAAA;AAAA,EACA,OAAA;AAAA,EACA,MAAA;AAAA,EACA,UAAA;AAAA,EACA,OAAA;AAAA,EACA,YAAA;AAAA,EACA,WAAA;AAAA,EACA,aAAA;AAAA,EACA,gBAAA;AAAA,EACA,cAAA;AAAA,EACA,uBAAA;AAAA,EACA,YAAA;AAAA,EACA,WAAA;AAAA,EACA,oBAAA;AACF"}
|
|
@@ -126,7 +126,7 @@ function U({ name: r, avatarSrc: e, initials: n, className: i, ...s }) {
|
|
|
126
126
|
}), /* @__PURE__ */ t(l.Fallback, { children: n ?? S(r) })]
|
|
127
127
|
}),
|
|
128
128
|
/* @__PURE__ */ t("span", {
|
|
129
|
-
className: "text-pho-primary min-w-0 flex-1 truncate text-
|
|
129
|
+
className: "text-pho-primary min-w-0 flex-1 truncate text-base",
|
|
130
130
|
children: r
|
|
131
131
|
}),
|
|
132
132
|
/* @__PURE__ */ t("span", {
|
|
@@ -161,4 +161,4 @@ export {
|
|
|
161
161
|
_ as t
|
|
162
162
|
};
|
|
163
163
|
|
|
164
|
-
//# sourceMappingURL=sidebar-
|
|
164
|
+
//# sourceMappingURL=sidebar-Buhva5xa.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sidebar-16Pfn7IC.js","names":["__iconNode"],"sources":["../../../../node_modules/.pnpm/@tabler+icons-react@3.44.0_react@19.2.7/node_modules/@tabler/icons-react/dist/esm/icons/IconArrowUpRight.mjs","../../../../node_modules/.pnpm/@tabler+icons-react@3.44.0_react@19.2.7/node_modules/@tabler/icons-react/dist/esm/icons/IconDots.mjs","../../src/sections/sidebar/sidebar.tsx"],"sourcesContent":["/**\n * @license @tabler/icons-react v3.44.0 - MIT\n *\n * This source code is licensed under the MIT license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createReactComponent from '../createReactComponent.mjs';\n\nconst __iconNode = [[\"path\", { \"d\": \"M17 7l-10 10\", \"key\": \"svg-0\" }], [\"path\", { \"d\": \"M8 7l9 0l0 9\", \"key\": \"svg-1\" }]];\nconst IconArrowUpRight = createReactComponent(\"outline\", \"arrow-up-right\", \"ArrowUpRight\", __iconNode);\n\nexport { __iconNode, IconArrowUpRight as default };\n//# sourceMappingURL=IconArrowUpRight.mjs.map\n","/**\n * @license @tabler/icons-react v3.44.0 - MIT\n *\n * This source code is licensed under the MIT license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createReactComponent from '../createReactComponent.mjs';\n\nconst __iconNode = [[\"path\", { \"d\": \"M4 12a1 1 0 1 0 2 0a1 1 0 1 0 -2 0\", \"key\": \"svg-0\" }], [\"path\", { \"d\": \"M11 12a1 1 0 1 0 2 0a1 1 0 1 0 -2 0\", \"key\": \"svg-1\" }], [\"path\", { \"d\": \"M18 12a1 1 0 1 0 2 0a1 1 0 1 0 -2 0\", \"key\": \"svg-2\" }]];\nconst IconDots = createReactComponent(\"outline\", \"dots\", \"Dots\", __iconNode);\n\nexport { __iconNode, IconDots as default };\n//# sourceMappingURL=IconDots.mjs.map\n","import {\n isValidElement,\n type AnchorHTMLAttributes,\n type ButtonHTMLAttributes,\n type ComponentProps,\n type FC,\n type ReactNode,\n type Ref,\n} from \"react\";\nimport { IconArrowUpRight, IconDots } from \"@tabler/icons-react\";\nimport { cn } from \"../../utils/cn\";\nimport { isReactComponent } from \"../../utils/is-react-component\";\nimport { useLinkComponent } from \"../../utils/link-provider\";\nimport { Avatar } from \"../../components/avatar\";\nimport { buttonVariants } from \"../../components/button\";\n\n/**\n * Sidebar — Pho's first SECTION: a composed app rail, not a micro component.\n * It encodes the navigation rail used across Photon surfaces (the Pho docs\n * site, the dashboard): a sticky full-height column with a brand header, a\n * scrollable stack of titled nav groups, and a pinned footer that usually\n * carries the account row.\n *\n * Sections stay presentational — no router, no data fetching, no theme\n * plumbing. Links render through the host's `LinkProvider` (same contract as\n * `ButtonLink`), state arrives via props (`active`), and interactive footers\n * compose with other Pho parts (e.g. wrap `Sidebar.AccountRow` in a\n * `Menu.Trigger render={...}` to open an account menu).\n */\n\n/* ------------------------------- class map ------------------------------- */\n\n/** The rail itself — sticky, full-height, hairline right edge. */\nexport const SIDEBAR_ROOT =\n \"border-pho-secondary bg-pho-page sticky top-0 flex h-dvh w-64 shrink-0 flex-col border-r px-4 py-5\";\n\n/** A nav row at rest and on hover. Active/inactive inks split below. */\nexport const SIDEBAR_ITEM =\n \"outline-pho-brand flex w-full cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-left text-base transition-colors focus-visible:outline-2 focus-visible:-outline-offset-1\";\n\n/**\n * Selected row — lifted onto the primary surface with the site hairline.\n * The icon carries the same ink as the label so the pair reads as one unit.\n */\nexport const SIDEBAR_ITEM_ACTIVE =\n \"bg-pho-primary text-pho-primary ring-pho-secondary font-medium ring-1 ring-inset *:data-icon:text-pho-primary\";\n\n/**\n * Resting row — secondary ink (75%), ghost wash on hover. Icon tracks the\n * label's ink at every state.\n */\nexport const SIDEBAR_ITEM_INACTIVE = cn(\n \"text-pho-secondary *:data-icon:text-pho-secondary\",\n \"hover:bg-pho-ghost-hover hover:text-pho-primary hover:*:data-icon:text-pho-primary\",\n);\n\n/* --------------------------------- frame --------------------------------- */\n\ninterface RootProps extends ComponentProps<\"aside\"> {\n ref?: Ref<HTMLElement>;\n}\n\n/** The rail — a sticky, full-height `<aside>` with the hairline right edge. */\nfunction Root({ className, ...props }: RootProps) {\n return <aside className={cn(SIDEBAR_ROOT, className)} {...props} />;\n}\n\n/** Brand slot at the top of the rail — logo, wordmark, workspace switcher. */\nfunction Header({ className, ...props }: ComponentProps<\"div\">) {\n return (\n <div\n className={cn(\"mb-6 flex items-center gap-2.5 px-2\", className)}\n {...props}\n />\n );\n}\n\n/** The scrollable middle — a stack of `Sidebar.Group`s. */\nfunction Nav({ className, ...props }: ComponentProps<\"nav\">) {\n return (\n <nav\n className={cn(\"flex flex-1 flex-col gap-6 overflow-y-auto\", className)}\n {...props}\n />\n );\n}\n\n/** One titled cluster of nav rows: a `GroupLabel` followed by a `List`. */\nfunction Group({ className, ...props }: ComponentProps<\"div\">) {\n return <div className={className} {...props} />;\n}\n\n/** The cluster's caption — description ink, regular weight. */\nfunction GroupLabel({ className, ...props }: ComponentProps<\"div\">) {\n return (\n <div\n className={cn(\n \"text-pho-description mb-2 px-2 text-xs font-normal\",\n className,\n )}\n {...props}\n />\n );\n}\n\ninterface ListProps extends ComponentProps<\"ul\"> {\n /** Lay the rows out in two columns — for long, flat registries. */\n columns?: boolean;\n}\n\n/** The rows of a group. `columns` switches to a two-column grid. */\nfunction List({ className, columns, ...props }: ListProps) {\n return (\n <ul\n className={cn(\n // list-none/m-0/p-0 shield the rail from host prose styles.\n \"m-0 list-none p-0 *:m-0\",\n columns\n ? \"grid grid-cols-2 gap-x-2 gap-y-0.5\"\n : \"flex flex-col gap-0.5\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/** Pinned bottom cluster — docs link, account row, theme toggle. */\nfunction Footer({ className, ...props }: ComponentProps<\"div\">) {\n return (\n <div className={cn(\"mt-4 flex flex-col gap-0.5\", className)} {...props} />\n );\n}\n\n/* --------------------------------- item ---------------------------------- */\n\n/** An icon slot — a component (`IconBook`) or element (`<IconBook />`). */\ntype Slottable = ReactNode | FC<{ className?: string }>;\n\nfunction renderIcon(icon: Slottable): ReactNode {\n if (icon == null || icon === false) return null;\n let content: ReactNode = null;\n if (isReactComponent(icon)) {\n const Icon = icon;\n content = <Icon />;\n } else if (isValidElement(icon)) {\n content = icon;\n }\n if (content == null) return null;\n return (\n <span\n data-icon\n className=\"pointer-events-none inline-flex shrink-0 items-center [&>svg]:size-4 [&>svg]:shrink-0\"\n >\n {content}\n </span>\n );\n}\n\ninterface ItemBaseProps {\n /** Slot before the label — a component (`IconBook`) or element. */\n icon?: Slottable;\n /** Marks the row as the current destination (adds `aria-current=\"page\"`). */\n active?: boolean;\n children?: ReactNode;\n className?: string;\n}\n\nexport interface SidebarItemLinkProps\n extends\n ItemBaseProps,\n Omit<AnchorHTMLAttributes<HTMLAnchorElement>, keyof ItemBaseProps> {\n /** Destination — rendered through the host's `LinkProvider`. */\n href: string;\n /** Leaves the app: opens in a new tab and renders a ↗ cue. */\n external?: boolean;\n}\n\nexport interface SidebarItemButtonProps\n extends\n ItemBaseProps,\n Omit<ButtonHTMLAttributes<HTMLButtonElement>, keyof ItemBaseProps> {\n href?: undefined;\n external?: undefined;\n}\n\nexport type SidebarItemProps = SidebarItemLinkProps | SidebarItemButtonProps;\n\n/**\n * A nav row — a link when `href` is given (rendered through the host's\n * `LinkProvider`), otherwise a button. `active` lifts the row onto the\n * primary surface; `external` opens a new tab and appends a ↗ cue.\n */\nfunction Item({\n icon,\n active,\n className,\n children,\n href,\n external,\n ...rest\n}: SidebarItemProps) {\n const Link = useLinkComponent();\n const rowClass = cn(\n SIDEBAR_ITEM,\n active ? SIDEBAR_ITEM_ACTIVE : SIDEBAR_ITEM_INACTIVE,\n className,\n );\n const label = <span className=\"min-w-0 flex-1 truncate\">{children}</span>;\n\n if (href !== undefined) {\n return (\n <li>\n <Link\n href={href}\n aria-current={active ? \"page\" : undefined}\n {...(external && { target: \"_blank\", rel: \"noopener noreferrer\" })}\n {...(rest as AnchorHTMLAttributes<HTMLAnchorElement>)}\n className={rowClass}\n >\n {renderIcon(icon)}\n {label}\n {external && (\n <>\n {renderIcon(<IconArrowUpRight aria-hidden />)}\n <span className=\"sr-only\">(opens in a new tab)</span>\n </>\n )}\n </Link>\n </li>\n );\n }\n\n return (\n <li>\n <button\n type=\"button\"\n aria-current={active ? \"page\" : undefined}\n {...(rest as ButtonHTMLAttributes<HTMLButtonElement>)}\n className={rowClass}\n >\n {renderIcon(icon)}\n {label}\n </button>\n </li>\n );\n}\n\n/* ------------------------------ account row ------------------------------ */\n\n/**\n * Whole-row account trigger. The row itself stays visually quiet — it only\n * carries the `group` state (hover/press/popup-open) and the focus ring;\n * all visual feedback renders on the ⋯ circle via `group-*` classes.\n */\nconst ACCOUNT_ROW =\n \"group outline-pho-brand flex w-full cursor-pointer items-center gap-2 rounded-base p-2 text-left focus-visible:outline-2 focus-visible:outline-offset-2\";\n\n/** Avatar initials: first + last word initial, else the first character. */\nfunction initialsFrom(name: string): string {\n const words = name.split(/\\s+/).filter(Boolean);\n const first = words[0]?.[0] ?? name[0] ?? \"?\";\n const last = words.length >= 2 ? (words[words.length - 1]?.[0] ?? \"\") : \"\";\n return (first + last).toUpperCase();\n}\n\nexport interface SidebarAccountRowProps extends Omit<\n ButtonHTMLAttributes<HTMLButtonElement>,\n \"children\"\n> {\n /** Display name — also the source for fallback initials. */\n name: string;\n /** Avatar image URL; falls back to initials while loading or on error. */\n avatarSrc?: string;\n /** Override the derived initials. */\n initials?: string;\n ref?: Ref<HTMLButtonElement>;\n}\n\n/**\n * The account chip pinned to the rail's footer — an xs avatar, the name, and\n * a decorative ⋯ circle. The WHOLE row is one button, but the row is only the\n * control — the circle is the indicator: hover, press, and menu-open feedback\n * all render on the ⋯ (a span wearing the stock secondary-circle button\n * classes), driven by the row's `group` state, so it reads as a button\n * without nesting one.\n *\n * It renders a plain `<button>` and forwards every prop, so it slots straight\n * into a menu: `<Menu.Trigger render={<Sidebar.AccountRow name=\"…\" />} />` —\n * Base UI's `data-popup-open` / `data-pressed` states light up the circle.\n */\nfunction AccountRow({\n name,\n avatarSrc,\n initials,\n className,\n ...props\n}: SidebarAccountRowProps) {\n return (\n <button type=\"button\" className={cn(ACCOUNT_ROW, className)} {...props}>\n <Avatar.Root size=\"xs\">\n {avatarSrc && <Avatar.Image src={avatarSrc} alt=\"\" />}\n <Avatar.Fallback>{initials ?? initialsFrom(name)}</Avatar.Fallback>\n </Avatar.Root>\n <span className=\"text-pho-primary min-w-0 flex-1 truncate text-xs\">\n {name}\n </span>\n <span\n aria-hidden\n className={buttonVariants({\n variant: \"outlined\",\n size: \"sm\",\n shape: \"circle\",\n className:\n \"group-hover:bg-pho-primary-hover group-hover:text-pho-secondary-hover group-data-[popup-open]:bg-pho-primary-hover group-data-[popup-open]:text-pho-secondary-hover p-1 group-data-[pressed]:scale-[0.97]\",\n })}\n >\n <IconDots className=\"size-4\" />\n </span>\n </button>\n );\n}\n\n/* -------------------------------- assembly ------------------------------- */\n\n/**\n * The composed sidebar rail. Assemble the frame parts and fill them with\n * rows; wire interactivity by composing other Pho parts around them:\n *\n * ```tsx\n * <Sidebar.Root>\n * <Sidebar.Header>…brand…</Sidebar.Header>\n * <Sidebar.Nav>\n * <Sidebar.Group>\n * <Sidebar.GroupLabel>Pages</Sidebar.GroupLabel>\n * <Sidebar.List>\n * <Sidebar.Item href=\"/\" icon={IconHome} active>\n * Overview\n * </Sidebar.Item>\n * </Sidebar.List>\n * </Sidebar.Group>\n * </Sidebar.Nav>\n * <Sidebar.Footer>\n * <Menu.Root>\n * <Menu.Trigger render={<Sidebar.AccountRow name=\"Ada Lovelace\" />} />\n * …\n * </Menu.Root>\n * </Sidebar.Footer>\n * </Sidebar.Root>\n * ```\n */\nexport const Sidebar = {\n Root,\n Header,\n Nav,\n Group,\n GroupLabel,\n List,\n Item,\n Footer,\n AccountRow,\n};\n"],"x_google_ignoreList":[0,1],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sidebar-Buhva5xa.js","names":["__iconNode"],"sources":["../../../../node_modules/.pnpm/@tabler+icons-react@3.44.0_react@19.2.7/node_modules/@tabler/icons-react/dist/esm/icons/IconArrowUpRight.mjs","../../../../node_modules/.pnpm/@tabler+icons-react@3.44.0_react@19.2.7/node_modules/@tabler/icons-react/dist/esm/icons/IconDots.mjs","../../src/sections/sidebar/sidebar.tsx"],"sourcesContent":["/**\n * @license @tabler/icons-react v3.44.0 - MIT\n *\n * This source code is licensed under the MIT license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createReactComponent from '../createReactComponent.mjs';\n\nconst __iconNode = [[\"path\", { \"d\": \"M17 7l-10 10\", \"key\": \"svg-0\" }], [\"path\", { \"d\": \"M8 7l9 0l0 9\", \"key\": \"svg-1\" }]];\nconst IconArrowUpRight = createReactComponent(\"outline\", \"arrow-up-right\", \"ArrowUpRight\", __iconNode);\n\nexport { __iconNode, IconArrowUpRight as default };\n//# sourceMappingURL=IconArrowUpRight.mjs.map\n","/**\n * @license @tabler/icons-react v3.44.0 - MIT\n *\n * This source code is licensed under the MIT license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createReactComponent from '../createReactComponent.mjs';\n\nconst __iconNode = [[\"path\", { \"d\": \"M4 12a1 1 0 1 0 2 0a1 1 0 1 0 -2 0\", \"key\": \"svg-0\" }], [\"path\", { \"d\": \"M11 12a1 1 0 1 0 2 0a1 1 0 1 0 -2 0\", \"key\": \"svg-1\" }], [\"path\", { \"d\": \"M18 12a1 1 0 1 0 2 0a1 1 0 1 0 -2 0\", \"key\": \"svg-2\" }]];\nconst IconDots = createReactComponent(\"outline\", \"dots\", \"Dots\", __iconNode);\n\nexport { __iconNode, IconDots as default };\n//# sourceMappingURL=IconDots.mjs.map\n","import {\n isValidElement,\n type AnchorHTMLAttributes,\n type ButtonHTMLAttributes,\n type ComponentProps,\n type FC,\n type ReactNode,\n type Ref,\n} from \"react\";\nimport { IconArrowUpRight, IconDots } from \"@tabler/icons-react\";\nimport { cn } from \"../../utils/cn\";\nimport { isReactComponent } from \"../../utils/is-react-component\";\nimport { useLinkComponent } from \"../../utils/link-provider\";\nimport { Avatar } from \"../../components/avatar\";\nimport { buttonVariants } from \"../../components/button\";\n\n/**\n * Sidebar — Pho's first SECTION: a composed app rail, not a micro component.\n * It encodes the navigation rail used across Photon surfaces (the Pho docs\n * site, the dashboard): a sticky full-height column with a brand header, a\n * scrollable stack of titled nav groups, and a pinned footer that usually\n * carries the account row.\n *\n * Sections stay presentational — no router, no data fetching, no theme\n * plumbing. Links render through the host's `LinkProvider` (same contract as\n * `ButtonLink`), state arrives via props (`active`), and interactive footers\n * compose with other Pho parts (e.g. wrap `Sidebar.AccountRow` in a\n * `Menu.Trigger render={...}` to open an account menu).\n */\n\n/* ------------------------------- class map ------------------------------- */\n\n/** The rail itself — sticky, full-height, hairline right edge. */\nexport const SIDEBAR_ROOT =\n \"border-pho-secondary bg-pho-page sticky top-0 flex h-dvh w-64 shrink-0 flex-col border-r px-4 py-5\";\n\n/** A nav row at rest and on hover. Active/inactive inks split below. */\nexport const SIDEBAR_ITEM =\n \"outline-pho-brand flex w-full cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-left text-base transition-colors focus-visible:outline-2 focus-visible:-outline-offset-1\";\n\n/**\n * Selected row — lifted onto the primary surface with the site hairline.\n * The icon carries the same ink as the label so the pair reads as one unit.\n */\nexport const SIDEBAR_ITEM_ACTIVE =\n \"bg-pho-primary text-pho-primary ring-pho-secondary font-medium ring-1 ring-inset *:data-icon:text-pho-primary\";\n\n/**\n * Resting row — secondary ink (75%), ghost wash on hover. Icon tracks the\n * label's ink at every state.\n */\nexport const SIDEBAR_ITEM_INACTIVE = cn(\n \"text-pho-secondary *:data-icon:text-pho-secondary\",\n \"hover:bg-pho-ghost-hover hover:text-pho-primary hover:*:data-icon:text-pho-primary\",\n);\n\n/* --------------------------------- frame --------------------------------- */\n\ninterface RootProps extends ComponentProps<\"aside\"> {\n ref?: Ref<HTMLElement>;\n}\n\n/** The rail — a sticky, full-height `<aside>` with the hairline right edge. */\nfunction Root({ className, ...props }: RootProps) {\n return <aside className={cn(SIDEBAR_ROOT, className)} {...props} />;\n}\n\n/** Brand slot at the top of the rail — logo, wordmark, workspace switcher. */\nfunction Header({ className, ...props }: ComponentProps<\"div\">) {\n return (\n <div\n className={cn(\"mb-6 flex items-center gap-2.5 px-2\", className)}\n {...props}\n />\n );\n}\n\n/** The scrollable middle — a stack of `Sidebar.Group`s. */\nfunction Nav({ className, ...props }: ComponentProps<\"nav\">) {\n return (\n <nav\n className={cn(\"flex flex-1 flex-col gap-6 overflow-y-auto\", className)}\n {...props}\n />\n );\n}\n\n/** One titled cluster of nav rows: a `GroupLabel` followed by a `List`. */\nfunction Group({ className, ...props }: ComponentProps<\"div\">) {\n return <div className={className} {...props} />;\n}\n\n/** The cluster's caption — description ink, regular weight. */\nfunction GroupLabel({ className, ...props }: ComponentProps<\"div\">) {\n return (\n <div\n className={cn(\n \"text-pho-description mb-2 px-2 text-xs font-normal\",\n className,\n )}\n {...props}\n />\n );\n}\n\ninterface ListProps extends ComponentProps<\"ul\"> {\n /** Lay the rows out in two columns — for long, flat registries. */\n columns?: boolean;\n}\n\n/** The rows of a group. `columns` switches to a two-column grid. */\nfunction List({ className, columns, ...props }: ListProps) {\n return (\n <ul\n className={cn(\n // list-none/m-0/p-0 shield the rail from host prose styles.\n \"m-0 list-none p-0 *:m-0\",\n columns\n ? \"grid grid-cols-2 gap-x-2 gap-y-0.5\"\n : \"flex flex-col gap-0.5\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/** Pinned bottom cluster — docs link, account row, theme toggle. */\nfunction Footer({ className, ...props }: ComponentProps<\"div\">) {\n return (\n <div className={cn(\"mt-4 flex flex-col gap-0.5\", className)} {...props} />\n );\n}\n\n/* --------------------------------- item ---------------------------------- */\n\n/** An icon slot — a component (`IconBook`) or element (`<IconBook />`). */\ntype Slottable = ReactNode | FC<{ className?: string }>;\n\nfunction renderIcon(icon: Slottable): ReactNode {\n if (icon == null || icon === false) return null;\n let content: ReactNode = null;\n if (isReactComponent(icon)) {\n const Icon = icon;\n content = <Icon />;\n } else if (isValidElement(icon)) {\n content = icon;\n }\n if (content == null) return null;\n return (\n <span\n data-icon\n className=\"pointer-events-none inline-flex shrink-0 items-center [&>svg]:size-4 [&>svg]:shrink-0\"\n >\n {content}\n </span>\n );\n}\n\ninterface ItemBaseProps {\n /** Slot before the label — a component (`IconBook`) or element. */\n icon?: Slottable;\n /** Marks the row as the current destination (adds `aria-current=\"page\"`). */\n active?: boolean;\n children?: ReactNode;\n className?: string;\n}\n\nexport interface SidebarItemLinkProps\n extends\n ItemBaseProps,\n Omit<AnchorHTMLAttributes<HTMLAnchorElement>, keyof ItemBaseProps> {\n /** Destination — rendered through the host's `LinkProvider`. */\n href: string;\n /** Leaves the app: opens in a new tab and renders a ↗ cue. */\n external?: boolean;\n}\n\nexport interface SidebarItemButtonProps\n extends\n ItemBaseProps,\n Omit<ButtonHTMLAttributes<HTMLButtonElement>, keyof ItemBaseProps> {\n href?: undefined;\n external?: undefined;\n}\n\nexport type SidebarItemProps = SidebarItemLinkProps | SidebarItemButtonProps;\n\n/**\n * A nav row — a link when `href` is given (rendered through the host's\n * `LinkProvider`), otherwise a button. `active` lifts the row onto the\n * primary surface; `external` opens a new tab and appends a ↗ cue.\n */\nfunction Item({\n icon,\n active,\n className,\n children,\n href,\n external,\n ...rest\n}: SidebarItemProps) {\n const Link = useLinkComponent();\n const rowClass = cn(\n SIDEBAR_ITEM,\n active ? SIDEBAR_ITEM_ACTIVE : SIDEBAR_ITEM_INACTIVE,\n className,\n );\n const label = <span className=\"min-w-0 flex-1 truncate\">{children}</span>;\n\n if (href !== undefined) {\n return (\n <li>\n <Link\n href={href}\n aria-current={active ? \"page\" : undefined}\n {...(external && { target: \"_blank\", rel: \"noopener noreferrer\" })}\n {...(rest as AnchorHTMLAttributes<HTMLAnchorElement>)}\n className={rowClass}\n >\n {renderIcon(icon)}\n {label}\n {external && (\n <>\n {renderIcon(<IconArrowUpRight aria-hidden />)}\n <span className=\"sr-only\">(opens in a new tab)</span>\n </>\n )}\n </Link>\n </li>\n );\n }\n\n return (\n <li>\n <button\n type=\"button\"\n aria-current={active ? \"page\" : undefined}\n {...(rest as ButtonHTMLAttributes<HTMLButtonElement>)}\n className={rowClass}\n >\n {renderIcon(icon)}\n {label}\n </button>\n </li>\n );\n}\n\n/* ------------------------------ account row ------------------------------ */\n\n/**\n * Whole-row account trigger. The row itself stays visually quiet — it only\n * carries the `group` state (hover/press/popup-open) and the focus ring;\n * all visual feedback renders on the ⋯ circle via `group-*` classes.\n */\nconst ACCOUNT_ROW =\n \"group outline-pho-brand flex w-full cursor-pointer items-center gap-2 rounded-base p-2 text-left focus-visible:outline-2 focus-visible:outline-offset-2\";\n\n/** Avatar initials: first + last word initial, else the first character. */\nfunction initialsFrom(name: string): string {\n const words = name.split(/\\s+/).filter(Boolean);\n const first = words[0]?.[0] ?? name[0] ?? \"?\";\n const last = words.length >= 2 ? (words[words.length - 1]?.[0] ?? \"\") : \"\";\n return (first + last).toUpperCase();\n}\n\nexport interface SidebarAccountRowProps extends Omit<\n ButtonHTMLAttributes<HTMLButtonElement>,\n \"children\"\n> {\n /** Display name — also the source for fallback initials. */\n name: string;\n /** Avatar image URL; falls back to initials while loading or on error. */\n avatarSrc?: string;\n /** Override the derived initials. */\n initials?: string;\n ref?: Ref<HTMLButtonElement>;\n}\n\n/**\n * The account chip pinned to the rail's footer — an xs avatar, the name, and\n * a decorative ⋯ circle. The WHOLE row is one button, but the row is only the\n * control — the circle is the indicator: hover, press, and menu-open feedback\n * all render on the ⋯ (a span wearing the stock secondary-circle button\n * classes), driven by the row's `group` state, so it reads as a button\n * without nesting one.\n *\n * It renders a plain `<button>` and forwards every prop, so it slots straight\n * into a menu: `<Menu.Trigger render={<Sidebar.AccountRow name=\"…\" />} />` —\n * Base UI's `data-popup-open` / `data-pressed` states light up the circle.\n */\nfunction AccountRow({\n name,\n avatarSrc,\n initials,\n className,\n ...props\n}: SidebarAccountRowProps) {\n return (\n <button type=\"button\" className={cn(ACCOUNT_ROW, className)} {...props}>\n <Avatar.Root size=\"xs\">\n {avatarSrc && <Avatar.Image src={avatarSrc} alt=\"\" />}\n <Avatar.Fallback>{initials ?? initialsFrom(name)}</Avatar.Fallback>\n </Avatar.Root>\n <span className=\"text-pho-primary min-w-0 flex-1 truncate text-base\">\n {name}\n </span>\n <span\n aria-hidden\n className={buttonVariants({\n variant: \"outlined\",\n size: \"sm\",\n shape: \"circle\",\n className:\n \"group-hover:bg-pho-primary-hover group-hover:text-pho-secondary-hover group-data-[popup-open]:bg-pho-primary-hover group-data-[popup-open]:text-pho-secondary-hover p-1 group-data-[pressed]:scale-[0.97]\",\n })}\n >\n <IconDots className=\"size-4\" />\n </span>\n </button>\n );\n}\n\n/* -------------------------------- assembly ------------------------------- */\n\n/**\n * The composed sidebar rail. Assemble the frame parts and fill them with\n * rows; wire interactivity by composing other Pho parts around them:\n *\n * ```tsx\n * <Sidebar.Root>\n * <Sidebar.Header>…brand…</Sidebar.Header>\n * <Sidebar.Nav>\n * <Sidebar.Group>\n * <Sidebar.GroupLabel>Pages</Sidebar.GroupLabel>\n * <Sidebar.List>\n * <Sidebar.Item href=\"/\" icon={IconHome} active>\n * Overview\n * </Sidebar.Item>\n * </Sidebar.List>\n * </Sidebar.Group>\n * </Sidebar.Nav>\n * <Sidebar.Footer>\n * <Menu.Root>\n * <Menu.Trigger render={<Sidebar.AccountRow name=\"Ada Lovelace\" />} />\n * …\n * </Menu.Root>\n * </Sidebar.Footer>\n * </Sidebar.Root>\n * ```\n */\nexport const Sidebar = {\n Root,\n Header,\n Nav,\n Group,\n GroupLabel,\n List,\n Item,\n Footer,\n AccountRow,\n};\n"],"x_google_ignoreList":[0,1],"mappings":"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"}
|
|
@@ -49,7 +49,7 @@ function x({ className: e, ...t }) {
|
|
|
49
49
|
}
|
|
50
50
|
function f({ className: e, ...t }) {
|
|
51
51
|
return /* @__PURE__ */ a(o.Item, {
|
|
52
|
-
className: r("text-pho-secondary
|
|
52
|
+
className: r("text-pho-secondary flex cursor-pointer items-center gap-2 rounded-[calc(var(--radius-base)-4px)] py-1.5 pr-2.5 pl-2 text-base outline-none select-none", "data-[highlighted]:bg-pho-ghost-hover data-[highlighted]:text-pho-primary", e),
|
|
53
53
|
...t
|
|
54
54
|
});
|
|
55
55
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"autocomplete.js","names":[],"sources":["../../src/components/autocomplete/autocomplete.tsx"],"sourcesContent":["import { type ComponentProps, type ElementType } from \"react\";\nimport { Autocomplete as BaseAutocomplete } from \"@base-ui/react/autocomplete\";\nimport { cn } from \"../../utils/cn\";\n\n/** Override Base UI's `string | (state) => string` className with plain string. */\ntype StyledProps<T extends ElementType> = Omit<\n ComponentProps<T>,\n \"className\"\n> & {\n className?: string;\n};\n\nconst Root = BaseAutocomplete.Root;\nconst Value = BaseAutocomplete.Value;\nconst Portal = BaseAutocomplete.Portal;\nconst Group = BaseAutocomplete.Group;\nconst Collection = BaseAutocomplete.Collection;\n\nfunction InputGroup({\n className,\n ...props\n}: StyledProps<typeof BaseAutocomplete.InputGroup>) {\n return (\n <BaseAutocomplete.InputGroup\n className={cn(\"relative flex items-center\", className)}\n {...props}\n />\n );\n}\n\nfunction Input({\n className,\n ...props\n}: StyledProps<typeof BaseAutocomplete.Input>) {\n return (\n <BaseAutocomplete.Input\n className={cn(\n // Flat field surface — the 15% hairline ring carries the edge; shadows\n // are reserved for floating layers.\n // text-md on small viewports — iOS zooms into fields under 16px.\n \"bg-pho-primary ring-pho-primary text-pho-primary placeholder:text-pho-placeholder focus-visible:ring-pho-brand text-md rounded-base w-full px-3 py-2 ring-1 transition-shadow duration-100 ease-linear outline-none ring-inset focus-visible:ring-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-base\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Clear({\n className,\n ...props\n}: StyledProps<typeof BaseAutocomplete.Clear>) {\n return (\n <BaseAutocomplete.Clear\n className={cn(\n \"text-pho-secondary hover:text-pho-secondary-hover absolute right-2.5 flex cursor-pointer items-center [&>svg]:size-4\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Positioner({\n className,\n sideOffset = 6,\n ...props\n}: StyledProps<typeof BaseAutocomplete.Positioner>) {\n return (\n <BaseAutocomplete.Positioner\n sideOffset={sideOffset}\n className={cn(\"z-50 outline-none\", className)}\n {...props}\n />\n );\n}\n\nfunction Popup({\n className,\n ...props\n}: StyledProps<typeof BaseAutocomplete.Popup>) {\n return (\n <BaseAutocomplete.Popup\n className={cn(\n // Floating layer: keeps its elevation shadow, edged with the site\n // hairline (ring-pho-secondary).\n \"bg-pho-primary text-pho-primary shadow-pho-lg ring-pho-secondary rounded-base w-[var(--anchor-width)] max-w-[var(--available-width)] origin-[var(--transform-origin)] p-1 ring-1 transition-[transform,opacity] duration-150 ease-out outline-none ring-inset\",\n \"data-[starting-style]:scale-95 data-[starting-style]:opacity-0\",\n \"data-[ending-style]:scale-95 data-[ending-style]:opacity-0\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction List({\n className,\n ...props\n}: StyledProps<typeof BaseAutocomplete.List>) {\n return (\n <BaseAutocomplete.List\n className={cn(\n \"max-h-[min(20rem,var(--available-height))] overflow-y-auto overscroll-contain\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Empty({\n className,\n ...props\n}: StyledProps<typeof BaseAutocomplete.Empty>) {\n return (\n <BaseAutocomplete.Empty\n className={cn(\n \"text-pho-description px-2.5 py-6 text-center text-base empty:m-0 empty:p-0\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Item({\n className,\n ...props\n}: StyledProps<typeof BaseAutocomplete.Item>) {\n return (\n <BaseAutocomplete.Item\n className={cn(\n \"text-pho-secondary
|
|
1
|
+
{"version":3,"file":"autocomplete.js","names":[],"sources":["../../src/components/autocomplete/autocomplete.tsx"],"sourcesContent":["import { type ComponentProps, type ElementType } from \"react\";\nimport { Autocomplete as BaseAutocomplete } from \"@base-ui/react/autocomplete\";\nimport { cn } from \"../../utils/cn\";\n\n/** Override Base UI's `string | (state) => string` className with plain string. */\ntype StyledProps<T extends ElementType> = Omit<\n ComponentProps<T>,\n \"className\"\n> & {\n className?: string;\n};\n\nconst Root = BaseAutocomplete.Root;\nconst Value = BaseAutocomplete.Value;\nconst Portal = BaseAutocomplete.Portal;\nconst Group = BaseAutocomplete.Group;\nconst Collection = BaseAutocomplete.Collection;\n\nfunction InputGroup({\n className,\n ...props\n}: StyledProps<typeof BaseAutocomplete.InputGroup>) {\n return (\n <BaseAutocomplete.InputGroup\n className={cn(\"relative flex items-center\", className)}\n {...props}\n />\n );\n}\n\nfunction Input({\n className,\n ...props\n}: StyledProps<typeof BaseAutocomplete.Input>) {\n return (\n <BaseAutocomplete.Input\n className={cn(\n // Flat field surface — the 15% hairline ring carries the edge; shadows\n // are reserved for floating layers.\n // text-md on small viewports — iOS zooms into fields under 16px.\n \"bg-pho-primary ring-pho-primary text-pho-primary placeholder:text-pho-placeholder focus-visible:ring-pho-brand text-md rounded-base w-full px-3 py-2 ring-1 transition-shadow duration-100 ease-linear outline-none ring-inset focus-visible:ring-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-base\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Clear({\n className,\n ...props\n}: StyledProps<typeof BaseAutocomplete.Clear>) {\n return (\n <BaseAutocomplete.Clear\n className={cn(\n \"text-pho-secondary hover:text-pho-secondary-hover absolute right-2.5 flex cursor-pointer items-center [&>svg]:size-4\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Positioner({\n className,\n sideOffset = 6,\n ...props\n}: StyledProps<typeof BaseAutocomplete.Positioner>) {\n return (\n <BaseAutocomplete.Positioner\n sideOffset={sideOffset}\n className={cn(\"z-50 outline-none\", className)}\n {...props}\n />\n );\n}\n\nfunction Popup({\n className,\n ...props\n}: StyledProps<typeof BaseAutocomplete.Popup>) {\n return (\n <BaseAutocomplete.Popup\n className={cn(\n // Floating layer: keeps its elevation shadow, edged with the site\n // hairline (ring-pho-secondary).\n \"bg-pho-primary text-pho-primary shadow-pho-lg ring-pho-secondary rounded-base w-[var(--anchor-width)] max-w-[var(--available-width)] origin-[var(--transform-origin)] p-1 ring-1 transition-[transform,opacity] duration-150 ease-out outline-none ring-inset\",\n \"data-[starting-style]:scale-95 data-[starting-style]:opacity-0\",\n \"data-[ending-style]:scale-95 data-[ending-style]:opacity-0\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction List({\n className,\n ...props\n}: StyledProps<typeof BaseAutocomplete.List>) {\n return (\n <BaseAutocomplete.List\n className={cn(\n \"max-h-[min(20rem,var(--available-height))] overflow-y-auto overscroll-contain\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Empty({\n className,\n ...props\n}: StyledProps<typeof BaseAutocomplete.Empty>) {\n return (\n <BaseAutocomplete.Empty\n className={cn(\n \"text-pho-description px-2.5 py-6 text-center text-base empty:m-0 empty:p-0\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Item({\n className,\n ...props\n}: StyledProps<typeof BaseAutocomplete.Item>) {\n return (\n <BaseAutocomplete.Item\n className={cn(\n \"text-pho-secondary flex cursor-pointer items-center gap-2 rounded-[calc(var(--radius-base)-4px)] py-1.5 pr-2.5 pl-2 text-base outline-none select-none\",\n // Secondary at rest; highlight lifts to primary + ghost wash (Menu idiom).\n \"data-[highlighted]:bg-pho-ghost-hover data-[highlighted]:text-pho-primary\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction GroupLabel({\n className,\n ...props\n}: StyledProps<typeof BaseAutocomplete.GroupLabel>) {\n return (\n <BaseAutocomplete.GroupLabel\n className={cn(\n \"text-pho-secondary px-2.5 py-1.5 text-xs font-medium\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/**\n * Autocomplete built on Base UI `Autocomplete` — a free-text input that offers\n * matching suggestions as you type. Unlike `Combobox`, the value isn't\n * constrained to the list: the user can submit text that matches no suggestion.\n * Pass `items` to `Autocomplete.Root` and render an `Item` per suggestion.\n */\nexport const Autocomplete = {\n Root,\n Value,\n InputGroup,\n Input,\n Clear,\n Portal,\n Positioner,\n Popup,\n List,\n Collection,\n Empty,\n Item,\n Group,\n GroupLabel,\n};\n"],"mappings":";;;;;AAYA,IAAM,IAAO,EAAiB,MACxB,IAAQ,EAAiB,OACzB,IAAS,EAAiB,QAC1B,IAAQ,EAAiB,OACzB,IAAa,EAAiB;AAEpC,SAAS,EAAW,EAClB,WAAA,GACA,GAAG,EAAA,GAC+C;AAClD,SACE,gBAAA,EAAC,EAAiB,YAAlB;AAAA,IACE,WAAW,EAAG,8BAA8B,CAAS;AAAA,IACrD,GAAI;AAAA,EACL,CAAA;AAEL;AAEA,SAAS,EAAM,EACb,WAAA,GACA,GAAG,EAAA,GAC0C;AAC7C,SACE,gBAAA,EAAC,EAAiB,OAAlB;AAAA,IACE,WAAW,EAIT,oTACA,CACF;AAAA,IACA,GAAI;AAAA,EACL,CAAA;AAEL;AAEA,SAAS,EAAM,EACb,WAAA,GACA,GAAG,EAAA,GAC0C;AAC7C,SACE,gBAAA,EAAC,EAAiB,OAAlB;AAAA,IACE,WAAW,EACT,wHACA,CACF;AAAA,IACA,GAAI;AAAA,EACL,CAAA;AAEL;AAEA,SAAS,EAAW,EAClB,WAAA,GACA,YAAA,IAAa,GACb,GAAG,EAAA,GAC+C;AAClD,SACE,gBAAA,EAAC,EAAiB,YAAlB;AAAA,IACc,YAAA;AAAA,IACZ,WAAW,EAAG,qBAAqB,CAAS;AAAA,IAC5C,GAAI;AAAA,EACL,CAAA;AAEL;AAEA,SAAS,EAAM,EACb,WAAA,GACA,GAAG,EAAA,GAC0C;AAC7C,SACE,gBAAA,EAAC,EAAiB,OAAlB;AAAA,IACE,WAAW,EAGT,iQACA,kEACA,8DACA,CACF;AAAA,IACA,GAAI;AAAA,EACL,CAAA;AAEL;AAEA,SAAS,EAAK,EACZ,WAAA,GACA,GAAG,EAAA,GACyC;AAC5C,SACE,gBAAA,EAAC,EAAiB,MAAlB;AAAA,IACE,WAAW,EACT,iFACA,CACF;AAAA,IACA,GAAI;AAAA,EACL,CAAA;AAEL;AAEA,SAAS,EAAM,EACb,WAAA,GACA,GAAG,EAAA,GAC0C;AAC7C,SACE,gBAAA,EAAC,EAAiB,OAAlB;AAAA,IACE,WAAW,EACT,8EACA,CACF;AAAA,IACA,GAAI;AAAA,EACL,CAAA;AAEL;AAEA,SAAS,EAAK,EACZ,WAAA,GACA,GAAG,EAAA,GACyC;AAC5C,SACE,gBAAA,EAAC,EAAiB,MAAlB;AAAA,IACE,WAAW,EACT,0JAEA,6EACA,CACF;AAAA,IACA,GAAI;AAAA,EACL,CAAA;AAEL;AAEA,SAAS,EAAW,EAClB,WAAA,GACA,GAAG,EAAA,GAC+C;AAClD,SACE,gBAAA,EAAC,EAAiB,YAAlB;AAAA,IACE,WAAW,EACT,wDACA,CACF;AAAA,IACA,GAAI;AAAA,EACL,CAAA;AAEL;AAQA,IAAa,IAAe;AAAA,EAC1B,MAAA;AAAA,EACA,OAAA;AAAA,EACA,YAAA;AAAA,EACA,OAAA;AAAA,EACA,OAAA;AAAA,EACA,QAAA;AAAA,EACA,YAAA;AAAA,EACA,OAAA;AAAA,EACA,MAAA;AAAA,EACA,YAAA;AAAA,EACA,OAAA;AAAA,EACA,MAAA;AAAA,EACA,OAAA;AAAA,EACA,YAAA;AACF"}
|
|
@@ -55,7 +55,7 @@ function b({ className: e, ...t }) {
|
|
|
55
55
|
}
|
|
56
56
|
function f({ className: e, ...t }) {
|
|
57
57
|
return /* @__PURE__ */ n(r.Item, {
|
|
58
|
-
className: o("text-pho-secondary
|
|
58
|
+
className: o("text-pho-secondary grid cursor-pointer grid-cols-[1rem_1fr] items-center gap-2 rounded-[calc(var(--radius-base)-4px)] py-1.5 pr-2.5 pl-2 text-base outline-none select-none", "data-[highlighted]:bg-pho-ghost-hover data-[highlighted]:text-pho-primary", e),
|
|
59
59
|
...t
|
|
60
60
|
});
|
|
61
61
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"combobox.js","names":[],"sources":["../../src/components/combobox/combobox.tsx"],"sourcesContent":["import { type ComponentProps, type ElementType } from \"react\";\nimport { Combobox as BaseCombobox } from \"@base-ui/react/combobox\";\nimport { cn } from \"../../utils/cn\";\n\n/** Override Base UI's `string | (state) => string` className with plain string. */\ntype StyledProps<T extends ElementType> = Omit<\n ComponentProps<T>,\n \"className\"\n> & {\n className?: string;\n};\n\nconst Root = BaseCombobox.Root;\nconst Value = BaseCombobox.Value;\nconst Portal = BaseCombobox.Portal;\nconst Group = BaseCombobox.Group;\nconst Collection = BaseCombobox.Collection;\n\nfunction InputGroup({\n className,\n ...props\n}: StyledProps<typeof BaseCombobox.InputGroup>) {\n return (\n <BaseCombobox.InputGroup\n className={cn(\"relative flex items-center\", className)}\n {...props}\n />\n );\n}\n\nfunction Input({\n className,\n ...props\n}: StyledProps<typeof BaseCombobox.Input>) {\n return (\n <BaseCombobox.Input\n className={cn(\n // text-md on small viewports — iOS zooms into fields under 16px.\n \"bg-pho-primary ring-pho-primary text-pho-primary placeholder:text-pho-placeholder focus-visible:ring-pho-brand text-md rounded-base w-full px-3 py-2 ring-1 transition-shadow duration-100 ease-linear outline-none ring-inset focus-visible:ring-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-base\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Clear({\n className,\n ...props\n}: StyledProps<typeof BaseCombobox.Clear>) {\n return (\n <BaseCombobox.Clear\n className={cn(\n \"combobox-clear text-pho-secondary hover:text-pho-secondary-hover absolute right-2.5 flex cursor-pointer items-center [&>svg]:size-4\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Trigger({\n className,\n ...props\n}: StyledProps<typeof BaseCombobox.Trigger>) {\n return (\n <BaseCombobox.Trigger\n className={cn(\n \"text-pho-secondary hover:text-pho-secondary-hover absolute right-2.5 flex cursor-pointer items-center [&>svg]:size-4\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Positioner({\n className,\n sideOffset = 6,\n ...props\n}: StyledProps<typeof BaseCombobox.Positioner>) {\n return (\n <BaseCombobox.Positioner\n sideOffset={sideOffset}\n className={cn(\"z-50 outline-none\", className)}\n {...props}\n />\n );\n}\n\nfunction Popup({\n className,\n ...props\n}: StyledProps<typeof BaseCombobox.Popup>) {\n return (\n <BaseCombobox.Popup\n className={cn(\n \"bg-pho-primary text-pho-primary shadow-pho-lg ring-pho-secondary rounded-base w-[var(--anchor-width)] max-w-[var(--available-width)] origin-[var(--transform-origin)] p-1 ring-1 transition-[transform,opacity] duration-150 ease-out outline-none ring-inset\",\n \"data-[starting-style]:scale-95 data-[starting-style]:opacity-0\",\n \"data-[ending-style]:scale-95 data-[ending-style]:opacity-0\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction List({ className, ...props }: StyledProps<typeof BaseCombobox.List>) {\n return (\n <BaseCombobox.List\n className={cn(\n \"max-h-[min(20rem,var(--available-height))] overflow-y-auto overscroll-contain\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Empty({\n className,\n ...props\n}: StyledProps<typeof BaseCombobox.Empty>) {\n return (\n <BaseCombobox.Empty\n className={cn(\n \"text-pho-description px-2.5 py-6 text-center text-base empty:m-0 empty:p-0\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Item({ className, ...props }: StyledProps<typeof BaseCombobox.Item>) {\n return (\n <BaseCombobox.Item\n className={cn(\n \"text-pho-secondary
|
|
1
|
+
{"version":3,"file":"combobox.js","names":[],"sources":["../../src/components/combobox/combobox.tsx"],"sourcesContent":["import { type ComponentProps, type ElementType } from \"react\";\nimport { Combobox as BaseCombobox } from \"@base-ui/react/combobox\";\nimport { cn } from \"../../utils/cn\";\n\n/** Override Base UI's `string | (state) => string` className with plain string. */\ntype StyledProps<T extends ElementType> = Omit<\n ComponentProps<T>,\n \"className\"\n> & {\n className?: string;\n};\n\nconst Root = BaseCombobox.Root;\nconst Value = BaseCombobox.Value;\nconst Portal = BaseCombobox.Portal;\nconst Group = BaseCombobox.Group;\nconst Collection = BaseCombobox.Collection;\n\nfunction InputGroup({\n className,\n ...props\n}: StyledProps<typeof BaseCombobox.InputGroup>) {\n return (\n <BaseCombobox.InputGroup\n className={cn(\"relative flex items-center\", className)}\n {...props}\n />\n );\n}\n\nfunction Input({\n className,\n ...props\n}: StyledProps<typeof BaseCombobox.Input>) {\n return (\n <BaseCombobox.Input\n className={cn(\n // text-md on small viewports — iOS zooms into fields under 16px.\n \"bg-pho-primary ring-pho-primary text-pho-primary placeholder:text-pho-placeholder focus-visible:ring-pho-brand text-md rounded-base w-full px-3 py-2 ring-1 transition-shadow duration-100 ease-linear outline-none ring-inset focus-visible:ring-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-base\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Clear({\n className,\n ...props\n}: StyledProps<typeof BaseCombobox.Clear>) {\n return (\n <BaseCombobox.Clear\n className={cn(\n \"combobox-clear text-pho-secondary hover:text-pho-secondary-hover absolute right-2.5 flex cursor-pointer items-center [&>svg]:size-4\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Trigger({\n className,\n ...props\n}: StyledProps<typeof BaseCombobox.Trigger>) {\n return (\n <BaseCombobox.Trigger\n className={cn(\n \"text-pho-secondary hover:text-pho-secondary-hover absolute right-2.5 flex cursor-pointer items-center [&>svg]:size-4\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Positioner({\n className,\n sideOffset = 6,\n ...props\n}: StyledProps<typeof BaseCombobox.Positioner>) {\n return (\n <BaseCombobox.Positioner\n sideOffset={sideOffset}\n className={cn(\"z-50 outline-none\", className)}\n {...props}\n />\n );\n}\n\nfunction Popup({\n className,\n ...props\n}: StyledProps<typeof BaseCombobox.Popup>) {\n return (\n <BaseCombobox.Popup\n className={cn(\n \"bg-pho-primary text-pho-primary shadow-pho-lg ring-pho-secondary rounded-base w-[var(--anchor-width)] max-w-[var(--available-width)] origin-[var(--transform-origin)] p-1 ring-1 transition-[transform,opacity] duration-150 ease-out outline-none ring-inset\",\n \"data-[starting-style]:scale-95 data-[starting-style]:opacity-0\",\n \"data-[ending-style]:scale-95 data-[ending-style]:opacity-0\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction List({ className, ...props }: StyledProps<typeof BaseCombobox.List>) {\n return (\n <BaseCombobox.List\n className={cn(\n \"max-h-[min(20rem,var(--available-height))] overflow-y-auto overscroll-contain\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Empty({\n className,\n ...props\n}: StyledProps<typeof BaseCombobox.Empty>) {\n return (\n <BaseCombobox.Empty\n className={cn(\n \"text-pho-description px-2.5 py-6 text-center text-base empty:m-0 empty:p-0\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Item({ className, ...props }: StyledProps<typeof BaseCombobox.Item>) {\n return (\n <BaseCombobox.Item\n className={cn(\n \"text-pho-secondary grid cursor-pointer grid-cols-[1rem_1fr] items-center gap-2 rounded-[calc(var(--radius-base)-4px)] py-1.5 pr-2.5 pl-2 text-base outline-none select-none\",\n \"data-[highlighted]:bg-pho-ghost-hover data-[highlighted]:text-pho-primary\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction ItemIndicator({\n className,\n ...props\n}: StyledProps<typeof BaseCombobox.ItemIndicator>) {\n return (\n <BaseCombobox.ItemIndicator\n className={cn(\n \"text-pho-brand col-start-1 flex items-center [&>svg]:size-4\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction GroupLabel({\n className,\n ...props\n}: StyledProps<typeof BaseCombobox.GroupLabel>) {\n return (\n <BaseCombobox.GroupLabel\n className={cn(\n \"text-pho-secondary px-2.5 py-1.5 text-xs font-medium\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Chips({\n className,\n ...props\n}: StyledProps<typeof BaseCombobox.Chips>) {\n return (\n <BaseCombobox.Chips\n className={cn(\n \"bg-pho-primary ring-pho-primary focus-within:ring-pho-brand rounded-base flex flex-wrap items-center gap-1.5 p-1.5 ring-1 ring-inset focus-within:ring-2\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Chip({ className, ...props }: StyledProps<typeof BaseCombobox.Chip>) {\n return (\n <BaseCombobox.Chip\n className={cn(\n // Keyboard-highlighted chip flips to the inverse chip surface.\n \"bg-pho-secondary text-pho-secondary data-[highlighted]:bg-pho-inverse data-[highlighted]:text-pho-inverse flex items-center gap-1 rounded-sm py-0.5 pr-1 pl-2 text-base\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction ChipRemove({\n className,\n ...props\n}: StyledProps<typeof BaseCombobox.ChipRemove>) {\n return (\n <BaseCombobox.ChipRemove\n className={cn(\n \"text-pho-secondary hover:text-pho-secondary-hover in-data-[highlighted]:text-pho-inverse flex cursor-pointer items-center rounded-sm [&>svg]:size-3.5\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/**\n * Combobox built on Base UI `Combobox` — a text input that filters a list as\n * you type and commits to a value from it. Pass `items` to `Combobox.Root`;\n * `Combobox.List` takes a render function mapping each (filtered) item to a\n * `Combobox.Item`. Add `Combobox.Chips` for multi-select. For free-form text\n * with suggestions, use `Autocomplete`; for a small fixed set, use `Select`.\n */\nexport const Combobox = {\n Root,\n Value,\n InputGroup,\n Input,\n Trigger,\n Clear,\n Portal,\n Positioner,\n Popup,\n List,\n Collection,\n Empty,\n Item,\n ItemIndicator,\n Group,\n GroupLabel,\n Chips,\n Chip,\n ChipRemove,\n};\n"],"mappings":"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"}
|
|
@@ -1,73 +1,76 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { t } from "../chunks/cn-DTiB6ek_.js";
|
|
3
|
-
import { t as
|
|
4
|
-
import { a as b, c as
|
|
2
|
+
import { t as a } from "../chunks/cn-DTiB6ek_.js";
|
|
3
|
+
import { t as v } from "../chunks/resolve-variant-CcD8iG5l.js";
|
|
4
|
+
import { a as b, c as x, n as M, o as h, r as N, t as s } from "../chunks/menu-Dan0oRvL.js";
|
|
5
5
|
import "react";
|
|
6
|
-
import { jsx as
|
|
6
|
+
import { Fragment as P, jsx as t, jsxs as i } from "react/jsx-runtime";
|
|
7
7
|
import { ContextMenu as e } from "@base-ui/react/context-menu";
|
|
8
|
-
import { Separator as
|
|
9
|
-
var
|
|
10
|
-
function
|
|
11
|
-
return /* @__PURE__ */
|
|
12
|
-
className:
|
|
13
|
-
...
|
|
8
|
+
import { Separator as S } from "@base-ui/react/separator";
|
|
9
|
+
var R = x(e.Root), y = e.Trigger, G = e.Portal, I = e.Group, T = e.RadioGroup, C = e.SubmenuRoot;
|
|
10
|
+
function E({ className: r, ...o }) {
|
|
11
|
+
return /* @__PURE__ */ t(e.Positioner, {
|
|
12
|
+
className: a("z-50", r),
|
|
13
|
+
...o
|
|
14
14
|
});
|
|
15
15
|
}
|
|
16
|
-
function
|
|
17
|
-
return /* @__PURE__ */
|
|
18
|
-
className:
|
|
19
|
-
...
|
|
16
|
+
function U({ className: r, ...o }) {
|
|
17
|
+
return /* @__PURE__ */ t(e.Popup, {
|
|
18
|
+
className: a(N, r),
|
|
19
|
+
...o
|
|
20
20
|
});
|
|
21
21
|
}
|
|
22
|
-
function
|
|
23
|
-
const { inert: n, blocked:
|
|
24
|
-
onClick:
|
|
22
|
+
function _({ className: r, color: o = "default", onClick: p, closeOnClick: u = !0, loading: m = !1, disabled: l = !1, children: c, ...d }) {
|
|
23
|
+
const { inert: n, blocked: f, handleClick: g } = h({
|
|
24
|
+
onClick: p,
|
|
25
25
|
closeOnClick: u,
|
|
26
|
-
loading:
|
|
27
|
-
disabled:
|
|
26
|
+
loading: m,
|
|
27
|
+
disabled: l
|
|
28
28
|
});
|
|
29
|
-
return /* @__PURE__ */
|
|
30
|
-
className:
|
|
29
|
+
return /* @__PURE__ */ i(e.Item, {
|
|
30
|
+
className: a(s, v(M, o), r),
|
|
31
31
|
closeOnClick: u,
|
|
32
|
-
disabled:
|
|
32
|
+
disabled: f,
|
|
33
33
|
"data-loading": n || void 0,
|
|
34
34
|
"aria-busy": n || void 0,
|
|
35
|
-
onClick:
|
|
36
|
-
...
|
|
37
|
-
children: [n ? /* @__PURE__ */
|
|
35
|
+
onClick: g,
|
|
36
|
+
...d,
|
|
37
|
+
children: [n ? /* @__PURE__ */ i(P, { children: [/* @__PURE__ */ t(b, {}), /* @__PURE__ */ t("output", {
|
|
38
|
+
className: "sr-only",
|
|
39
|
+
"aria-live": "polite"
|
|
40
|
+
})] }) : null, c]
|
|
38
41
|
});
|
|
39
42
|
}
|
|
40
|
-
function
|
|
41
|
-
return /* @__PURE__ */
|
|
42
|
-
className:
|
|
43
|
-
...
|
|
43
|
+
function L({ className: r, ...o }) {
|
|
44
|
+
return /* @__PURE__ */ t(e.GroupLabel, {
|
|
45
|
+
className: a("text-pho-secondary px-2.5 py-1.5 text-xs font-medium", r),
|
|
46
|
+
...o
|
|
44
47
|
});
|
|
45
48
|
}
|
|
46
|
-
function
|
|
47
|
-
return /* @__PURE__ */
|
|
48
|
-
className:
|
|
49
|
-
...
|
|
49
|
+
function j({ className: r, ...o }) {
|
|
50
|
+
return /* @__PURE__ */ t(S, {
|
|
51
|
+
className: a("-mx-1.5 my-1.5 h-px bg-[var(--border-color-pho-secondary)]", r),
|
|
52
|
+
...o
|
|
50
53
|
});
|
|
51
54
|
}
|
|
52
|
-
function
|
|
53
|
-
return /* @__PURE__ */
|
|
54
|
-
className:
|
|
55
|
-
...
|
|
55
|
+
function k({ className: r, ...o }) {
|
|
56
|
+
return /* @__PURE__ */ t(e.SubmenuTrigger, {
|
|
57
|
+
className: a(s, "data-[popup-open]:bg-pho-ghost-hover", r),
|
|
58
|
+
...o
|
|
56
59
|
});
|
|
57
60
|
}
|
|
58
61
|
var q = {
|
|
59
|
-
Root:
|
|
60
|
-
Trigger:
|
|
61
|
-
Portal:
|
|
62
|
-
Positioner:
|
|
63
|
-
Popup:
|
|
64
|
-
Item:
|
|
65
|
-
Group:
|
|
66
|
-
GroupLabel:
|
|
67
|
-
Separator:
|
|
68
|
-
SubmenuRoot:
|
|
69
|
-
SubmenuTrigger:
|
|
70
|
-
RadioGroup:
|
|
62
|
+
Root: R,
|
|
63
|
+
Trigger: y,
|
|
64
|
+
Portal: G,
|
|
65
|
+
Positioner: E,
|
|
66
|
+
Popup: U,
|
|
67
|
+
Item: _,
|
|
68
|
+
Group: I,
|
|
69
|
+
GroupLabel: L,
|
|
70
|
+
Separator: j,
|
|
71
|
+
SubmenuRoot: C,
|
|
72
|
+
SubmenuTrigger: k,
|
|
73
|
+
RadioGroup: T
|
|
71
74
|
};
|
|
72
75
|
export {
|
|
73
76
|
q as ContextMenu
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-menu.js","names":[],"sources":["../../src/components/context-menu/context-menu.tsx"],"sourcesContent":["import {\n type ComponentProps,\n type ElementType,\n type MouseEvent as ReactMouseEvent,\n} from \"react\";\nimport { ContextMenu as BaseContextMenu } from \"@base-ui/react/context-menu\";\nimport { Separator as BaseSeparator } from \"@base-ui/react/separator\";\nimport { cn } from \"../../utils/cn\";\nimport { resolveVariant } from \"../../utils/resolve-variant\";\nimport {\n MENU_POPUP,\n MENU_ITEM,\n MENU_ITEM_COLORS,\n type MenuItemColor,\n} from \"../menu/menu\";\nimport {\n MenuItemSpinner,\n useAsyncMenuItem,\n withMenuPendingRoot,\n type AsyncMenuItemClick,\n} from \"../menu/menu-pending\";\n\n/** Override Base UI's `string | (state) => string` className with plain string. */\ntype StyledProps<T extends ElementType> = Omit<\n ComponentProps<T>,\n \"className\" | \"color\"\n> & {\n className?: string;\n};\n\ntype ContextMenuItemProps = Omit<\n StyledProps<typeof BaseContextMenu.Item>,\n \"onClick\"\n> & {\n /** Semantic ink. @default \"default\" */\n color?: MenuItemColor;\n /**\n * Action handler. Return a promise to keep the menu open while it runs —\n * same behavior as `Menu.Item`.\n */\n onClick?: AsyncMenuItemClick;\n /** Declarative loading state. @default false */\n loading?: boolean;\n};\n\nconst Root = withMenuPendingRoot(BaseContextMenu.Root);\nconst Trigger = BaseContextMenu.Trigger;\nconst Portal = BaseContextMenu.Portal;\nconst Group = BaseContextMenu.Group;\nconst RadioGroup = BaseContextMenu.RadioGroup;\n// Don't wrap SubmenuRoot — nested pending context would shadow the parent\n// Root and fail to lock dismissal for async items inside a submenu.\nconst SubmenuRoot = BaseContextMenu.SubmenuRoot;\n\nfunction Positioner({\n className,\n ...props\n}: StyledProps<typeof BaseContextMenu.Positioner>) {\n return (\n <BaseContextMenu.Positioner className={cn(\"z-50\", className)} {...props} />\n );\n}\n\nfunction Popup({\n className,\n ...props\n}: StyledProps<typeof BaseContextMenu.Popup>) {\n return (\n <BaseContextMenu.Popup className={cn(MENU_POPUP, className)} {...props} />\n );\n}\n\nfunction Item({\n className,\n color = \"default\",\n onClick,\n closeOnClick = true,\n loading = false,\n disabled = false,\n children,\n ...props\n}: ContextMenuItemProps) {\n const { inert, blocked, handleClick } = useAsyncMenuItem({\n onClick,\n closeOnClick,\n loading,\n disabled,\n });\n\n return (\n <BaseContextMenu.Item\n className={cn(\n MENU_ITEM,\n resolveVariant(MENU_ITEM_COLORS, color),\n className,\n )}\n closeOnClick={closeOnClick}\n disabled={blocked}\n data-loading={inert || undefined}\n aria-busy={inert || undefined}\n onClick={handleClick as (event: ReactMouseEvent<HTMLElement>) => void}\n {...props}\n >\n {inert ? <MenuItemSpinner
|
|
1
|
+
{"version":3,"file":"context-menu.js","names":[],"sources":["../../src/components/context-menu/context-menu.tsx"],"sourcesContent":["import {\n type ComponentProps,\n type ElementType,\n type MouseEvent as ReactMouseEvent,\n} from \"react\";\nimport { ContextMenu as BaseContextMenu } from \"@base-ui/react/context-menu\";\nimport { Separator as BaseSeparator } from \"@base-ui/react/separator\";\nimport { cn } from \"../../utils/cn\";\nimport { resolveVariant } from \"../../utils/resolve-variant\";\nimport {\n MENU_POPUP,\n MENU_ITEM,\n MENU_ITEM_COLORS,\n type MenuItemColor,\n} from \"../menu/menu\";\nimport {\n MenuItemSpinner,\n useAsyncMenuItem,\n withMenuPendingRoot,\n type AsyncMenuItemClick,\n} from \"../menu/menu-pending\";\n\n/** Override Base UI's `string | (state) => string` className with plain string. */\ntype StyledProps<T extends ElementType> = Omit<\n ComponentProps<T>,\n \"className\" | \"color\"\n> & {\n className?: string;\n};\n\ntype ContextMenuItemProps = Omit<\n StyledProps<typeof BaseContextMenu.Item>,\n \"onClick\"\n> & {\n /** Semantic ink. @default \"default\" */\n color?: MenuItemColor;\n /**\n * Action handler. Return a promise to keep the menu open while it runs —\n * same behavior as `Menu.Item`.\n */\n onClick?: AsyncMenuItemClick;\n /** Declarative loading state. @default false */\n loading?: boolean;\n};\n\nconst Root = withMenuPendingRoot(BaseContextMenu.Root);\nconst Trigger = BaseContextMenu.Trigger;\nconst Portal = BaseContextMenu.Portal;\nconst Group = BaseContextMenu.Group;\nconst RadioGroup = BaseContextMenu.RadioGroup;\n// Don't wrap SubmenuRoot — nested pending context would shadow the parent\n// Root and fail to lock dismissal for async items inside a submenu.\nconst SubmenuRoot = BaseContextMenu.SubmenuRoot;\n\nfunction Positioner({\n className,\n ...props\n}: StyledProps<typeof BaseContextMenu.Positioner>) {\n return (\n <BaseContextMenu.Positioner className={cn(\"z-50\", className)} {...props} />\n );\n}\n\nfunction Popup({\n className,\n ...props\n}: StyledProps<typeof BaseContextMenu.Popup>) {\n return (\n <BaseContextMenu.Popup className={cn(MENU_POPUP, className)} {...props} />\n );\n}\n\nfunction Item({\n className,\n color = \"default\",\n onClick,\n closeOnClick = true,\n loading = false,\n disabled = false,\n children,\n ...props\n}: ContextMenuItemProps) {\n const { inert, blocked, handleClick } = useAsyncMenuItem({\n onClick,\n closeOnClick,\n loading,\n disabled,\n });\n\n return (\n <BaseContextMenu.Item\n className={cn(\n MENU_ITEM,\n resolveVariant(MENU_ITEM_COLORS, color),\n className,\n )}\n closeOnClick={closeOnClick}\n disabled={blocked}\n data-loading={inert || undefined}\n aria-busy={inert || undefined}\n onClick={handleClick as (event: ReactMouseEvent<HTMLElement>) => void}\n {...props}\n >\n {inert ? (\n <>\n <MenuItemSpinner />\n <output className=\"sr-only\" aria-live=\"polite\" />\n </>\n ) : null}\n {children}\n </BaseContextMenu.Item>\n );\n}\n\nfunction GroupLabel({\n className,\n ...props\n}: StyledProps<typeof BaseContextMenu.GroupLabel>) {\n return (\n <BaseContextMenu.GroupLabel\n className={cn(\n \"text-pho-secondary px-2.5 py-1.5 text-xs font-medium\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Separator({ className, ...props }: StyledProps<typeof BaseSeparator>) {\n return (\n <BaseSeparator\n className={cn(\n \"-mx-1.5 my-1.5 h-px bg-[var(--border-color-pho-secondary)]\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction SubmenuTrigger({\n className,\n ...props\n}: StyledProps<typeof BaseContextMenu.SubmenuTrigger>) {\n return (\n <BaseContextMenu.SubmenuTrigger\n className={cn(\n MENU_ITEM,\n \"data-[popup-open]:bg-pho-ghost-hover\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/**\n * Right-click (context) menu built on Base UI `ContextMenu`. `ContextMenu.Trigger`\n * wraps the area that opens the menu on right-click / long-press; the popup\n * shares its look with `Menu`. `ContextMenu.Item` has the same native promise\n * support as `Menu.Item`. Always mirror these actions somewhere visible —\n * a context menu must not be the only way to reach them.\n */\nexport const ContextMenu = {\n Root,\n Trigger,\n Portal,\n Positioner,\n Popup,\n Item,\n Group,\n GroupLabel,\n Separator,\n SubmenuRoot,\n SubmenuTrigger,\n RadioGroup,\n};\n"],"mappings":";;;;;;;;AA6CA,IAAM,IAAO,EAAoB,EAAgB,IAAI,GAC/C,IAAU,EAAgB,SAC1B,IAAS,EAAgB,QACzB,IAAQ,EAAgB,OACxB,IAAa,EAAgB,YAG7B,IAAc,EAAgB;AAEpC,SAAS,EAAW,EAClB,WAAA,GACA,GAAG,EAAA,GAC8C;AACjD,SACE,gBAAA,EAAC,EAAgB,YAAjB;AAAA,IAA4B,WAAW,EAAG,QAAQ,CAAS;AAAA,IAAG,GAAI;AAAA,EAAQ,CAAA;AAE9E;AAEA,SAAS,EAAM,EACb,WAAA,GACA,GAAG,EAAA,GACyC;AAC5C,SACE,gBAAA,EAAC,EAAgB,OAAjB;AAAA,IAAuB,WAAW,EAAG,GAAY,CAAS;AAAA,IAAG,GAAI;AAAA,EAAQ,CAAA;AAE7E;AAEA,SAAS,EAAK,EACZ,WAAA,GACA,OAAA,IAAQ,WACR,SAAA,GACA,cAAA,IAAe,IACf,SAAA,IAAU,IACV,UAAA,IAAW,IACX,UAAA,GACA,GAAG,EAAA,GACoB;AACvB,QAAM,EAAE,OAAA,GAAO,SAAA,GAAS,aAAA,EAAA,IAAgB,EAAiB;AAAA,IACvD,SAAA;AAAA,IACA,cAAA;AAAA,IACA,SAAA;AAAA,IACA,UAAA;AAAA,EACF,CAAC;AAED,SACE,gBAAA,EAAC,EAAgB,MAAjB;AAAA,IACE,WAAW,EACT,GACA,EAAe,GAAkB,CAAK,GACtC,CACF;AAAA,IACc,cAAA;AAAA,IACd,UAAU;AAAA,IACV,gBAAc,KAAS;AAAA,IACvB,aAAW,KAAS;AAAA,IACpB,SAAS;AAAA,IACT,GAAI;AAAA,cAXN,CAaG,IACC,gBAAA,EAAA,GAAA,EAAA,UAAA,CACE,gBAAA,EAAC,GAAD,CAAkB,CAAA,GAClB,gBAAA,EAAC,UAAD;AAAA,MAAQ,WAAU;AAAA,MAAU,aAAU;AAAA,IAAU,CAAA,CAChD,EAAA,CAAA,IACA,MACH,CACmB;AAAA;AAE1B;AAEA,SAAS,EAAW,EAClB,WAAA,GACA,GAAG,EAAA,GAC8C;AACjD,SACE,gBAAA,EAAC,EAAgB,YAAjB;AAAA,IACE,WAAW,EACT,wDACA,CACF;AAAA,IACA,GAAI;AAAA,EACL,CAAA;AAEL;AAEA,SAAS,EAAU,EAAE,WAAA,GAAW,GAAG,EAAA,GAA4C;AAC7E,SACE,gBAAA,EAAC,GAAD;AAAA,IACE,WAAW,EACT,8DACA,CACF;AAAA,IACA,GAAI;AAAA,EACL,CAAA;AAEL;AAEA,SAAS,EAAe,EACtB,WAAA,GACA,GAAG,EAAA,GACkD;AACrD,SACE,gBAAA,EAAC,EAAgB,gBAAjB;AAAA,IACE,WAAW,EACT,GACA,wCACA,CACF;AAAA,IACA,GAAI;AAAA,EACL,CAAA;AAEL;AASA,IAAa,IAAc;AAAA,EACzB,MAAA;AAAA,EACA,SAAA;AAAA,EACA,QAAA;AAAA,EACA,YAAA;AAAA,EACA,OAAA;AAAA,EACA,MAAA;AAAA,EACA,OAAA;AAAA,EACA,YAAA;AAAA,EACA,WAAA;AAAA,EACA,aAAA;AAAA,EACA,gBAAA;AAAA,EACA,YAAA;AACF"}
|
package/dist/components/menu.js
CHANGED
|
@@ -1,49 +1,49 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { t as
|
|
2
|
+
import { t as a } from "../chunks/cn-DTiB6ek_.js";
|
|
3
3
|
import "react";
|
|
4
|
-
import { jsx as
|
|
4
|
+
import { jsx as o } from "react/jsx-runtime";
|
|
5
5
|
import { Select as r } from "@base-ui/react/select";
|
|
6
6
|
var i = r.Root, s = r.Value, p = r.Portal, l = r.List, c = r.Group, u = r.ItemText;
|
|
7
7
|
function d({ className: e, ...t }) {
|
|
8
|
-
return /* @__PURE__ */
|
|
9
|
-
className:
|
|
8
|
+
return /* @__PURE__ */ o(r.Trigger, {
|
|
9
|
+
className: a("bg-pho-primary ring-pho-primary text-pho-primary outline-pho-brand rounded-base flex min-w-44 cursor-pointer items-center justify-between gap-2 px-3 py-2 text-base ring-1 transition select-none ring-inset", "data-[popup-open]:ring-pho-brand focus-visible:outline-2 focus-visible:-outline-offset-1", "data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50", "[&_svg]:text-pho-secondary [&_svg]:size-4", e),
|
|
10
10
|
...t
|
|
11
11
|
});
|
|
12
12
|
}
|
|
13
13
|
function m({ className: e, ...t }) {
|
|
14
|
-
return /* @__PURE__ */
|
|
15
|
-
className:
|
|
14
|
+
return /* @__PURE__ */ o(r.Icon, {
|
|
15
|
+
className: a("flex shrink-0 items-center", e),
|
|
16
16
|
...t
|
|
17
17
|
});
|
|
18
18
|
}
|
|
19
19
|
function g({ className: e, sideOffset: t = 6, ...n }) {
|
|
20
|
-
return /* @__PURE__ */
|
|
20
|
+
return /* @__PURE__ */ o(r.Positioner, {
|
|
21
21
|
sideOffset: t,
|
|
22
|
-
className:
|
|
22
|
+
className: a("z-50 outline-none", e),
|
|
23
23
|
...n
|
|
24
24
|
});
|
|
25
25
|
}
|
|
26
26
|
function h({ className: e, ...t }) {
|
|
27
|
-
return /* @__PURE__ */
|
|
28
|
-
className:
|
|
27
|
+
return /* @__PURE__ */ o(r.Popup, {
|
|
28
|
+
className: a("bg-pho-primary text-pho-primary shadow-pho-lg ring-pho-secondary rounded-base max-h-[var(--available-height)] min-w-[var(--anchor-width)] origin-[var(--transform-origin)] overflow-y-auto p-1 ring-1 transition-[transform,opacity] duration-150 ease-out outline-none ring-inset", "data-[starting-style]:scale-95 data-[starting-style]:opacity-0", "data-[ending-style]:scale-95 data-[ending-style]:opacity-0", e),
|
|
29
29
|
...t
|
|
30
30
|
});
|
|
31
31
|
}
|
|
32
32
|
function y({ className: e, ...t }) {
|
|
33
|
-
return /* @__PURE__ */
|
|
34
|
-
className:
|
|
33
|
+
return /* @__PURE__ */ o(r.Item, {
|
|
34
|
+
className: a("text-pho-secondary grid cursor-pointer grid-cols-[1rem_1fr] items-center gap-2 rounded-[calc(var(--radius-base)-4px)] py-1.5 pr-2.5 pl-2 text-base outline-none select-none", "data-[highlighted]:bg-pho-ghost-hover data-[highlighted]:text-pho-primary data-[disabled]:opacity-50", e),
|
|
35
35
|
...t
|
|
36
36
|
});
|
|
37
37
|
}
|
|
38
38
|
function f({ className: e, ...t }) {
|
|
39
|
-
return /* @__PURE__ */
|
|
40
|
-
className:
|
|
39
|
+
return /* @__PURE__ */ o(r.ItemIndicator, {
|
|
40
|
+
className: a("text-pho-brand col-start-1 flex items-center [&>svg]:size-4", e),
|
|
41
41
|
...t
|
|
42
42
|
});
|
|
43
43
|
}
|
|
44
44
|
function x({ className: e, ...t }) {
|
|
45
|
-
return /* @__PURE__ */
|
|
46
|
-
className:
|
|
45
|
+
return /* @__PURE__ */ o(r.GroupLabel, {
|
|
46
|
+
className: a("text-pho-secondary px-2.5 py-1.5 text-xs font-medium", e),
|
|
47
47
|
...t
|
|
48
48
|
});
|
|
49
49
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"select.js","names":[],"sources":["../../src/components/select/select.tsx"],"sourcesContent":["import { type ComponentProps, type ElementType } from \"react\";\nimport { Select as BaseSelect } from \"@base-ui/react/select\";\nimport { cn } from \"../../utils/cn\";\n\n/** Override Base UI's `string | (state) => string` className with plain string. */\ntype StyledProps<T extends ElementType> = Omit<\n ComponentProps<T>,\n \"className\"\n> & {\n className?: string;\n};\n\nconst Root = BaseSelect.Root;\nconst Value = BaseSelect.Value;\nconst Portal = BaseSelect.Portal;\nconst List = BaseSelect.List;\nconst Group = BaseSelect.Group;\nconst ItemText = BaseSelect.ItemText;\n\nfunction Trigger({\n className,\n ...props\n}: StyledProps<typeof BaseSelect.Trigger>) {\n return (\n <BaseSelect.Trigger\n className={cn(\n // Flat field surface — shadows are reserved for floating layers;\n // the 15% ring-pho-primary hairline is the input edge.\n \"bg-pho-primary ring-pho-primary text-pho-primary outline-pho-brand rounded-base flex min-w-44 cursor-pointer items-center justify-between gap-2 px-3 py-2 text-base ring-1 transition select-none ring-inset\",\n \"data-[popup-open]:ring-pho-brand focus-visible:outline-2 focus-visible:-outline-offset-1\",\n \"data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50\",\n \"[&_svg]:text-pho-secondary [&_svg]:size-4\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Icon({ className, ...props }: StyledProps<typeof BaseSelect.Icon>) {\n return (\n <BaseSelect.Icon\n className={cn(\"flex shrink-0 items-center\", className)}\n {...props}\n />\n );\n}\n\nfunction Positioner({\n className,\n sideOffset = 6,\n ...props\n}: StyledProps<typeof BaseSelect.Positioner>) {\n return (\n <BaseSelect.Positioner\n sideOffset={sideOffset}\n className={cn(\"z-50 outline-none\", className)}\n {...props}\n />\n );\n}\n\nfunction Popup({ className, ...props }: StyledProps<typeof BaseSelect.Popup>) {\n return (\n <BaseSelect.Popup\n className={cn(\n // Floating layer: keeps its elevation shadow, edged with the site\n // hairline (ring-pho-secondary, #eee/#202020).\n \"bg-pho-primary text-pho-primary shadow-pho-lg ring-pho-secondary rounded-base max-h-[var(--available-height)] min-w-[var(--anchor-width)] origin-[var(--transform-origin)] overflow-y-auto p-1 ring-1 transition-[transform,opacity] duration-150 ease-out outline-none ring-inset\",\n \"data-[starting-style]:scale-95 data-[starting-style]:opacity-0\",\n \"data-[ending-style]:scale-95 data-[ending-style]:opacity-0\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Item({ className, ...props }: StyledProps<typeof BaseSelect.Item>) {\n return (\n <BaseSelect.Item\n className={cn(\n \"text-pho-secondary
|
|
1
|
+
{"version":3,"file":"select.js","names":[],"sources":["../../src/components/select/select.tsx"],"sourcesContent":["import { type ComponentProps, type ElementType } from \"react\";\nimport { Select as BaseSelect } from \"@base-ui/react/select\";\nimport { cn } from \"../../utils/cn\";\n\n/** Override Base UI's `string | (state) => string` className with plain string. */\ntype StyledProps<T extends ElementType> = Omit<\n ComponentProps<T>,\n \"className\"\n> & {\n className?: string;\n};\n\nconst Root = BaseSelect.Root;\nconst Value = BaseSelect.Value;\nconst Portal = BaseSelect.Portal;\nconst List = BaseSelect.List;\nconst Group = BaseSelect.Group;\nconst ItemText = BaseSelect.ItemText;\n\nfunction Trigger({\n className,\n ...props\n}: StyledProps<typeof BaseSelect.Trigger>) {\n return (\n <BaseSelect.Trigger\n className={cn(\n // Flat field surface — shadows are reserved for floating layers;\n // the 15% ring-pho-primary hairline is the input edge.\n \"bg-pho-primary ring-pho-primary text-pho-primary outline-pho-brand rounded-base flex min-w-44 cursor-pointer items-center justify-between gap-2 px-3 py-2 text-base ring-1 transition select-none ring-inset\",\n \"data-[popup-open]:ring-pho-brand focus-visible:outline-2 focus-visible:-outline-offset-1\",\n \"data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50\",\n \"[&_svg]:text-pho-secondary [&_svg]:size-4\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Icon({ className, ...props }: StyledProps<typeof BaseSelect.Icon>) {\n return (\n <BaseSelect.Icon\n className={cn(\"flex shrink-0 items-center\", className)}\n {...props}\n />\n );\n}\n\nfunction Positioner({\n className,\n sideOffset = 6,\n ...props\n}: StyledProps<typeof BaseSelect.Positioner>) {\n return (\n <BaseSelect.Positioner\n sideOffset={sideOffset}\n className={cn(\"z-50 outline-none\", className)}\n {...props}\n />\n );\n}\n\nfunction Popup({ className, ...props }: StyledProps<typeof BaseSelect.Popup>) {\n return (\n <BaseSelect.Popup\n className={cn(\n // Floating layer: keeps its elevation shadow, edged with the site\n // hairline (ring-pho-secondary, #eee/#202020).\n \"bg-pho-primary text-pho-primary shadow-pho-lg ring-pho-secondary rounded-base max-h-[var(--available-height)] min-w-[var(--anchor-width)] origin-[var(--transform-origin)] overflow-y-auto p-1 ring-1 transition-[transform,opacity] duration-150 ease-out outline-none ring-inset\",\n \"data-[starting-style]:scale-95 data-[starting-style]:opacity-0\",\n \"data-[ending-style]:scale-95 data-[ending-style]:opacity-0\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Item({ className, ...props }: StyledProps<typeof BaseSelect.Item>) {\n return (\n <BaseSelect.Item\n className={cn(\n \"text-pho-secondary grid cursor-pointer grid-cols-[1rem_1fr] items-center gap-2 rounded-[calc(var(--radius-base)-4px)] py-1.5 pr-2.5 pl-2 text-base outline-none select-none\",\n // Secondary at rest; highlight lifts to primary + ghost wash (Menu idiom).\n \"data-[highlighted]:bg-pho-ghost-hover data-[highlighted]:text-pho-primary data-[disabled]:opacity-50\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction ItemIndicator({\n className,\n ...props\n}: StyledProps<typeof BaseSelect.ItemIndicator>) {\n return (\n <BaseSelect.ItemIndicator\n className={cn(\n \"text-pho-brand col-start-1 flex items-center [&>svg]:size-4\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction GroupLabel({\n className,\n ...props\n}: StyledProps<typeof BaseSelect.GroupLabel>) {\n return (\n <BaseSelect.GroupLabel\n className={cn(\n \"text-pho-secondary px-2.5 py-1.5 text-xs font-medium\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/**\n * Select built on Base UI `Select` — pick one option (or several with\n * `multiple`) from a list that opens on click. Pass `items` to `Select.Root`,\n * render an `Item` per option, and show the selection with `Select.Value`. For\n * a short, always-visible set use `RadioGroup`; to filter a long list by typing\n * use `Combobox`.\n */\nexport const Select = {\n Root,\n Trigger,\n Value,\n Icon,\n Portal,\n Positioner,\n Popup,\n List,\n Item,\n ItemText,\n ItemIndicator,\n Group,\n GroupLabel,\n};\n"],"mappings":";;;;;AAYA,IAAM,IAAO,EAAW,MAClB,IAAQ,EAAW,OACnB,IAAS,EAAW,QACpB,IAAO,EAAW,MAClB,IAAQ,EAAW,OACnB,IAAW,EAAW;AAE5B,SAAS,EAAQ,EACf,WAAA,GACA,GAAG,EAAA,GACsC;AACzC,SACE,gBAAA,EAAC,EAAW,SAAZ;AAAA,IACE,WAAW,EAGT,gNACA,4FACA,iEACA,6CACA,CACF;AAAA,IACA,GAAI;AAAA,EACL,CAAA;AAEL;AAEA,SAAS,EAAK,EAAE,WAAA,GAAW,GAAG,EAAA,GAA8C;AAC1E,SACE,gBAAA,EAAC,EAAW,MAAZ;AAAA,IACE,WAAW,EAAG,8BAA8B,CAAS;AAAA,IACrD,GAAI;AAAA,EACL,CAAA;AAEL;AAEA,SAAS,EAAW,EAClB,WAAA,GACA,YAAA,IAAa,GACb,GAAG,EAAA,GACyC;AAC5C,SACE,gBAAA,EAAC,EAAW,YAAZ;AAAA,IACc,YAAA;AAAA,IACZ,WAAW,EAAG,qBAAqB,CAAS;AAAA,IAC5C,GAAI;AAAA,EACL,CAAA;AAEL;AAEA,SAAS,EAAM,EAAE,WAAA,GAAW,GAAG,EAAA,GAA+C;AAC5E,SACE,gBAAA,EAAC,EAAW,OAAZ;AAAA,IACE,WAAW,EAGT,sRACA,kEACA,8DACA,CACF;AAAA,IACA,GAAI;AAAA,EACL,CAAA;AAEL;AAEA,SAAS,EAAK,EAAE,WAAA,GAAW,GAAG,EAAA,GAA8C;AAC1E,SACE,gBAAA,EAAC,EAAW,MAAZ;AAAA,IACE,WAAW,EACT,+KAEA,wGACA,CACF;AAAA,IACA,GAAI;AAAA,EACL,CAAA;AAEL;AAEA,SAAS,EAAc,EACrB,WAAA,GACA,GAAG,EAAA,GAC4C;AAC/C,SACE,gBAAA,EAAC,EAAW,eAAZ;AAAA,IACE,WAAW,EACT,+DACA,CACF;AAAA,IACA,GAAI;AAAA,EACL,CAAA;AAEL;AAEA,SAAS,EAAW,EAClB,WAAA,GACA,GAAG,EAAA,GACyC;AAC5C,SACE,gBAAA,EAAC,EAAW,YAAZ;AAAA,IACE,WAAW,EACT,wDACA,CACF;AAAA,IACA,GAAI;AAAA,EACL,CAAA;AAEL;AASA,IAAa,IAAS;AAAA,EACpB,MAAA;AAAA,EACA,SAAA;AAAA,EACA,OAAA;AAAA,EACA,MAAA;AAAA,EACA,QAAA;AAAA,EACA,YAAA;AAAA,EACA,OAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,UAAA;AAAA,EACA,eAAA;AAAA,EACA,OAAA;AAAA,EACA,YAAA;AACF"}
|
|
@@ -29,7 +29,7 @@ var j = [
|
|
|
29
29
|
}], ["path", {
|
|
30
30
|
d: "M3 12h1m8 -9v1m8 8h1m-9 8v1m-6.4 -15.4l.7 .7m12.1 -.7l-.7 .7m0 11.4l.7 .7m-12.1 -.7l-.7 .7",
|
|
31
31
|
key: "svg-1"
|
|
32
|
-
}]], Z = y("outline", "sun", "Sun", Y), b = "pho-mode",
|
|
32
|
+
}]], Z = y("outline", "sun", "Sun", Y), b = "pho-mode", s = "pho-themechange", p = [
|
|
33
33
|
{
|
|
34
34
|
value: "device",
|
|
35
35
|
label: "Device",
|
|
@@ -46,6 +46,10 @@ var j = [
|
|
|
46
46
|
Icon: V
|
|
47
47
|
}
|
|
48
48
|
], B = {
|
|
49
|
+
xs: {
|
|
50
|
+
track: "gap-px rounded-base p-0.5",
|
|
51
|
+
item: "size-5.5 rounded-[calc(var(--radius-base)-2px)] [&>svg]:size-3"
|
|
52
|
+
},
|
|
49
53
|
sm: {
|
|
50
54
|
track: "gap-0.5 rounded-base p-0.5",
|
|
51
55
|
item: "size-7 rounded-[calc(var(--radius-base)-2px)] [&>svg]:size-3.5"
|
|
@@ -68,14 +72,14 @@ function M(e, n = typeof window < "u" ? window.matchMedia("(prefers-color-scheme
|
|
|
68
72
|
function l(e) {
|
|
69
73
|
return typeof e == "function" ? e() : e !== void 0 ? e : typeof document > "u" ? null : document.documentElement;
|
|
70
74
|
}
|
|
71
|
-
var
|
|
75
|
+
var u = null, g = null, k = /* @__PURE__ */ new Map();
|
|
72
76
|
function w(e) {
|
|
73
77
|
if (e == null || typeof localStorage > "u") return null;
|
|
74
78
|
const n = localStorage.getItem(e);
|
|
75
79
|
return n == null ? null : F(n);
|
|
76
80
|
}
|
|
77
81
|
function J(e = b) {
|
|
78
|
-
return
|
|
82
|
+
return u ?? w(e) ?? "device";
|
|
79
83
|
}
|
|
80
84
|
function re(e = typeof document > "u" ? null : document.documentElement) {
|
|
81
85
|
return e?.dataset.mode === "dark" ? "dark" : "light";
|
|
@@ -86,7 +90,7 @@ function T(e, n) {
|
|
|
86
90
|
function Q(e) {
|
|
87
91
|
if (g?.(), g = null, typeof window > "u" || J(e) !== "device") return;
|
|
88
92
|
const n = window.matchMedia("(prefers-color-scheme: dark)"), r = () => {
|
|
89
|
-
T(M("device", n), document.documentElement), window.dispatchEvent(new Event(
|
|
93
|
+
T(M("device", n), document.documentElement), window.dispatchEvent(new Event(s));
|
|
90
94
|
};
|
|
91
95
|
n.addEventListener("change", r), g = () => n.removeEventListener("change", r);
|
|
92
96
|
}
|
|
@@ -106,11 +110,11 @@ function E(e, n) {
|
|
|
106
110
|
t && W(t, e);
|
|
107
111
|
return;
|
|
108
112
|
}
|
|
109
|
-
|
|
113
|
+
u = e, r != null && typeof localStorage < "u" && localStorage.setItem(r, e), Q(r ?? null), typeof window < "u" && window.dispatchEvent(new Event(s));
|
|
110
114
|
}
|
|
111
115
|
function X(e) {
|
|
112
116
|
return typeof window > "u" ? () => {
|
|
113
|
-
} : (window.addEventListener(
|
|
117
|
+
} : (window.addEventListener(s, e), () => window.removeEventListener(s, e));
|
|
114
118
|
}
|
|
115
119
|
function D(e, n) {
|
|
116
120
|
n.modeProp === void 0 && E(e, {
|
|
@@ -119,9 +123,9 @@ function D(e, n) {
|
|
|
119
123
|
}), n.onModeChange?.(e);
|
|
120
124
|
}
|
|
121
125
|
function K({ mode: e, defaultMode: n = "device", onModeChange: r, storageKey: t = b, target: i, size: z = "md", className: A, "aria-label": C = "Theme", ...H }) {
|
|
122
|
-
const O = $(X, () =>
|
|
126
|
+
const O = $(X, () => u ?? w(t) ?? n, () => n);
|
|
123
127
|
v(() => {
|
|
124
|
-
e === void 0 && E(
|
|
128
|
+
e === void 0 && E(u ?? w(t) ?? n, {
|
|
125
129
|
target: l(i),
|
|
126
130
|
storageKey: t
|
|
127
131
|
});
|
|
@@ -140,8 +144,8 @@ function K({ mode: e, defaultMode: n = "device", onModeChange: r, storageKey: t
|
|
|
140
144
|
t,
|
|
141
145
|
i
|
|
142
146
|
]), v(() => () => {
|
|
143
|
-
const
|
|
144
|
-
|
|
147
|
+
const d = l(i);
|
|
148
|
+
d && d !== document.documentElement && N(d);
|
|
145
149
|
}, [i]);
|
|
146
150
|
const x = e ?? O, S = B[z];
|
|
147
151
|
return /* @__PURE__ */ h("div", {
|
|
@@ -149,31 +153,31 @@ function K({ mode: e, defaultMode: n = "device", onModeChange: r, storageKey: t
|
|
|
149
153
|
"aria-label": C,
|
|
150
154
|
...H,
|
|
151
155
|
className: _("ring-pho-interactive inline-flex items-center ring-1 ring-inset", S.track, A),
|
|
152
|
-
children: p.map(({ value:
|
|
153
|
-
const f = x ===
|
|
156
|
+
children: p.map(({ value: d, label: R, Icon: q }) => {
|
|
157
|
+
const f = x === d;
|
|
154
158
|
return /* @__PURE__ */ h("button", {
|
|
155
159
|
type: "button",
|
|
156
160
|
role: "radio",
|
|
157
161
|
"aria-checked": f,
|
|
158
162
|
"aria-label": R,
|
|
159
163
|
tabIndex: f ? 0 : -1,
|
|
160
|
-
onClick: () => D(
|
|
164
|
+
onClick: () => D(d, {
|
|
161
165
|
modeProp: e,
|
|
162
166
|
storageKey: t,
|
|
163
167
|
target: i,
|
|
164
168
|
onModeChange: r
|
|
165
169
|
}),
|
|
166
|
-
onKeyDown: (
|
|
170
|
+
onKeyDown: (a) => {
|
|
167
171
|
const o = p.map((m) => m.value), L = o.indexOf(x);
|
|
168
172
|
let c;
|
|
169
|
-
if (
|
|
170
|
-
|
|
173
|
+
if (a.key === "ArrowRight" || a.key === "ArrowDown" ? c = o[(L + 1) % o.length] : a.key === "ArrowLeft" || a.key === "ArrowUp" ? c = o[(L - 1 + o.length) % o.length] : a.key === "Home" ? c = o[0] : a.key === "End" && (c = o[o.length - 1]), !c) return;
|
|
174
|
+
a.preventDefault(), D(c, {
|
|
171
175
|
modeProp: e,
|
|
172
176
|
storageKey: t,
|
|
173
177
|
target: i,
|
|
174
178
|
onModeChange: r
|
|
175
179
|
});
|
|
176
|
-
const I =
|
|
180
|
+
const I = a.currentTarget.parentElement?.querySelector(`[aria-label="${p.find((m) => m.value === c)?.label}"]`);
|
|
177
181
|
I instanceof HTMLElement && I.focus();
|
|
178
182
|
},
|
|
179
183
|
className: _("outline-pho-brand inline-flex flex-1 cursor-pointer items-center justify-center transition duration-100 ease-linear focus-visible:outline-2 focus-visible:outline-offset-2", f ? "bg-pho-inverse text-pho-inverse" : "text-pho-description hover:text-pho-primary", S.item),
|
|
@@ -181,7 +185,7 @@ function K({ mode: e, defaultMode: n = "device", onModeChange: r, storageKey: t
|
|
|
181
185
|
"aria-hidden": "true",
|
|
182
186
|
className: "shrink-0"
|
|
183
187
|
})
|
|
184
|
-
},
|
|
188
|
+
}, d);
|
|
185
189
|
})
|
|
186
190
|
});
|
|
187
191
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme-toggle.js","names":["__iconNode","__iconNode"],"sources":["../../../../node_modules/.pnpm/@tabler+icons-react@3.44.0_react@19.2.7/node_modules/@tabler/icons-react/dist/esm/icons/IconDeviceDesktop.mjs","../../../../node_modules/.pnpm/@tabler+icons-react@3.44.0_react@19.2.7/node_modules/@tabler/icons-react/dist/esm/icons/IconMoon.mjs","../../../../node_modules/.pnpm/@tabler+icons-react@3.44.0_react@19.2.7/node_modules/@tabler/icons-react/dist/esm/icons/IconSun.mjs","../../src/components/theme-toggle/theme-toggle.tsx"],"sourcesContent":["/**\n * @license @tabler/icons-react v3.44.0 - MIT\n *\n * This source code is licensed under the MIT license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createReactComponent from '../createReactComponent.mjs';\n\nconst __iconNode = [[\"path\", { \"d\": \"M3 5a1 1 0 0 1 1 -1h16a1 1 0 0 1 1 1v10a1 1 0 0 1 -1 1h-16a1 1 0 0 1 -1 -1v-10\", \"key\": \"svg-0\" }], [\"path\", { \"d\": \"M7 20h10\", \"key\": \"svg-1\" }], [\"path\", { \"d\": \"M9 16v4\", \"key\": \"svg-2\" }], [\"path\", { \"d\": \"M15 16v4\", \"key\": \"svg-3\" }]];\nconst IconDeviceDesktop = createReactComponent(\"outline\", \"device-desktop\", \"DeviceDesktop\", __iconNode);\n\nexport { __iconNode, IconDeviceDesktop as default };\n//# sourceMappingURL=IconDeviceDesktop.mjs.map\n","/**\n * @license @tabler/icons-react v3.44.0 - MIT\n *\n * This source code is licensed under the MIT license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createReactComponent from '../createReactComponent.mjs';\n\nconst __iconNode = [[\"path\", { \"d\": \"M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454l0 .008\", \"key\": \"svg-0\" }]];\nconst IconMoon = createReactComponent(\"outline\", \"moon\", \"Moon\", __iconNode);\n\nexport { __iconNode, IconMoon as default };\n//# sourceMappingURL=IconMoon.mjs.map\n","/**\n * @license @tabler/icons-react v3.44.0 - MIT\n *\n * This source code is licensed under the MIT license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createReactComponent from '../createReactComponent.mjs';\n\nconst __iconNode = [[\"path\", { \"d\": \"M8 12a4 4 0 1 0 8 0a4 4 0 1 0 -8 0\", \"key\": \"svg-0\" }], [\"path\", { \"d\": \"M3 12h1m8 -9v1m8 8h1m-9 8v1m-6.4 -15.4l.7 .7m12.1 -.7l-.7 .7m0 11.4l.7 .7m-12.1 -.7l-.7 .7\", \"key\": \"svg-1\" }]];\nconst IconSun = createReactComponent(\"outline\", \"sun\", \"Sun\", __iconNode);\n\nexport { __iconNode, IconSun as default };\n//# sourceMappingURL=IconSun.mjs.map\n","import { useEffect, useSyncExternalStore, type HTMLAttributes } from \"react\";\nimport { IconDeviceDesktop, IconMoon, IconSun } from \"@tabler/icons-react\";\nimport { cn } from \"../../utils/cn\";\n\n/**\n * Appearance preference — `device` follows `prefers-color-scheme`; `light` /\n * `dark` force the scheme via `data-mode`.\n */\nexport type ThemeMode = \"device\" | \"light\" | \"dark\";\n\n/** Resolved color-scheme after applying a preference. */\nexport type ResolvedTheme = \"light\" | \"dark\";\n\n/** Default `localStorage` key used by the docs site and this component. */\nexport const THEME_STORAGE_KEY = \"pho-mode\";\n\nconst THEME_CHANGE_EVENT = \"pho-themechange\";\n\nconst OPTIONS = [\n { value: \"device\" as const, label: \"Device\", Icon: IconDeviceDesktop },\n { value: \"light\" as const, label: \"Light\", Icon: IconSun },\n { value: \"dark\" as const, label: \"Dark\", Icon: IconMoon },\n];\n\n// Concentric correction (see /scale): inner = outer − gap, derived from the\n// radius token with calc so it tracks theme changes. Track is `base`; the gap\n// is the track padding (sm/md p-0.5 = 2px, lg p-1 = 4px). Plain round, no\n// squircle (the track carries a ring-inset).\nconst THEME_SIZES = {\n sm: {\n track: \"gap-0.5 rounded-base p-0.5\",\n item: \"size-7 rounded-[calc(var(--radius-base)-2px)] [&>svg]:size-3.5\",\n },\n md: {\n track: \"gap-0.5 rounded-base p-0.5\",\n item: \"size-8 rounded-[calc(var(--radius-base)-2px)] [&>svg]:size-4\",\n },\n lg: {\n track: \"gap-1 rounded-base p-1\",\n item: \"size-9 rounded-[calc(var(--radius-base)-4px)] [&>svg]:size-5\",\n },\n} as const;\n\nexport type ThemeToggleSize = keyof typeof THEME_SIZES;\n\nexport interface ThemeToggleProps extends Omit<\n HTMLAttributes<HTMLDivElement>,\n \"children\" | \"color\" | \"onChange\" | \"defaultValue\"\n> {\n /** Controlled preference. */\n mode?: ThemeMode;\n /** Uncontrolled initial preference. @default \"device\" */\n defaultMode?: ThemeMode;\n /** Fired when the user picks a segment. */\n onModeChange?: (mode: ThemeMode) => void;\n /**\n * Persist the preference under this `localStorage` key. Pass `null` to skip\n * persistence. @default \"pho-mode\"\n */\n storageKey?: string | null;\n /**\n * Element that receives `data-mode=\"dark\"`. Defaults to\n * `document.documentElement`.\n */\n target?: HTMLElement | null | (() => HTMLElement | null);\n /** Size variant. @default \"md\" */\n size?: ThemeToggleSize;\n}\n\n/** Parse a stored preference; unknown / missing values fall back to `device`. */\nexport function parseThemeMode(value: string | null | undefined): ThemeMode {\n if (value === \"light\" || value === \"dark\" || value === \"device\") return value;\n return \"device\";\n}\n\n/** Resolve a preference against the OS color-scheme. */\nexport function resolveThemeMode(\n mode: ThemeMode,\n query: { matches: boolean } = typeof window !== \"undefined\"\n ? window.matchMedia(\"(prefers-color-scheme: dark)\")\n : { matches: false },\n): ResolvedTheme {\n if (mode === \"light\" || mode === \"dark\") return mode;\n return query.matches ? \"dark\" : \"light\";\n}\n\nfunction resolveTarget(\n target?: ThemeToggleProps[\"target\"],\n): HTMLElement | null {\n if (typeof target === \"function\") return target();\n if (target !== undefined) return target;\n return typeof document === \"undefined\" ? null : document.documentElement;\n}\n\n/** Preference mirrored across document-level ThemeToggle instances. */\nlet storedPreference: ThemeMode | null = null;\nlet mediaCleanup: (() => void) | null = null;\n/** Per-target `prefers-color-scheme` listeners (scoped `target` instances). */\nconst targetMediaCleanups = new Map<HTMLElement, () => void>();\n\n/** Drop in-memory preference + media listener (tests / full remounts). */\nexport function clearThemePreference() {\n storedPreference = null;\n mediaCleanup?.();\n mediaCleanup = null;\n for (const cleanup of targetMediaCleanups.values()) cleanup();\n targetMediaCleanups.clear();\n}\n\n/** Read a persisted preference, or `null` when nothing is stored. */\nfunction readStoredPreference(storageKey: string | null): ThemeMode | null {\n if (storageKey == null || typeof localStorage === \"undefined\") return null;\n const raw = localStorage.getItem(storageKey);\n if (raw == null) return null;\n return parseThemeMode(raw);\n}\n\n/** Current document preference (memory, then storage, else `device`). */\nexport function getThemePreference(\n storageKey: string | null = THEME_STORAGE_KEY,\n): ThemeMode {\n return storedPreference ?? readStoredPreference(storageKey) ?? \"device\";\n}\n\n/** Read the resolved light/dark mode from an element (or `<html>`). */\nexport function getThemeMode(\n target: HTMLElement | null = typeof document === \"undefined\"\n ? null\n : document.documentElement,\n): ResolvedTheme {\n return target?.dataset.mode === \"dark\" ? \"dark\" : \"light\";\n}\n\nfunction applyResolved(resolved: ResolvedTheme, target: HTMLElement | null) {\n if (!target) return;\n if (resolved === \"dark\") target.dataset.mode = \"dark\";\n else delete target.dataset.mode;\n}\n\nfunction bindMediaListener(storageKey: string | null) {\n mediaCleanup?.();\n mediaCleanup = null;\n if (typeof window === \"undefined\") return;\n if (getThemePreference(storageKey) !== \"device\") return;\n\n const mql = window.matchMedia(\"(prefers-color-scheme: dark)\");\n const onChange = () => {\n applyResolved(resolveThemeMode(\"device\", mql), document.documentElement);\n window.dispatchEvent(new Event(THEME_CHANGE_EVENT));\n };\n mql.addEventListener(\"change\", onChange);\n mediaCleanup = () => mql.removeEventListener(\"change\", onChange);\n}\n\n/** Track OS scheme changes for a scoped target (docs previews, etc.). */\nfunction bindTargetMediaListener(target: HTMLElement, mode: ThemeMode) {\n unbindTargetMediaListener(target);\n if (typeof window === \"undefined\" || mode !== \"device\") return;\n\n const mql = window.matchMedia(\"(prefers-color-scheme: dark)\");\n const onChange = () => {\n applyResolved(resolveThemeMode(\"device\", mql), target);\n };\n mql.addEventListener(\"change\", onChange);\n targetMediaCleanups.set(target, () =>\n mql.removeEventListener(\"change\", onChange),\n );\n}\n\nfunction unbindTargetMediaListener(target: HTMLElement | null) {\n if (!target) return;\n targetMediaCleanups.get(target)?.();\n targetMediaCleanups.delete(target);\n}\n\n/**\n * Apply an appearance preference: persist it, resolve against the OS when\n * `device`, set `data-mode` on the target, and notify document-level toggles.\n */\nexport function setThemeMode(\n mode: ThemeMode,\n options?: {\n target?: HTMLElement | null;\n storageKey?: string | null;\n },\n): void {\n const storageKey =\n options && \"storageKey\" in options ? options.storageKey : THEME_STORAGE_KEY;\n const target =\n options?.target ??\n (typeof document === \"undefined\" ? null : document.documentElement);\n const syncDocument =\n typeof document === \"undefined\" ||\n target == null ||\n target === document.documentElement;\n\n applyResolved(resolveThemeMode(mode), target);\n\n if (!syncDocument) {\n if (target) bindTargetMediaListener(target, mode);\n return;\n }\n\n storedPreference = mode;\n if (storageKey != null && typeof localStorage !== \"undefined\") {\n localStorage.setItem(storageKey, mode);\n }\n bindMediaListener(storageKey ?? null);\n\n if (typeof window !== \"undefined\") {\n window.dispatchEvent(new Event(THEME_CHANGE_EVENT));\n }\n}\n\nfunction subscribeTheme(onChange: () => void) {\n if (typeof window === \"undefined\") return () => {};\n window.addEventListener(THEME_CHANGE_EVENT, onChange);\n return () => window.removeEventListener(THEME_CHANGE_EVENT, onChange);\n}\n\nfunction selectMode(\n value: ThemeMode,\n options: {\n modeProp?: ThemeMode;\n storageKey: string | null;\n target: ThemeToggleProps[\"target\"];\n onModeChange?: (mode: ThemeMode) => void;\n },\n) {\n if (options.modeProp === undefined) {\n setThemeMode(value, {\n target: resolveTarget(options.target),\n storageKey: options.storageKey,\n });\n }\n options.onModeChange?.(value);\n}\n\n/**\n * Segmented appearance control — Device / Light / Dark. Forces\n * `data-mode=\"dark\"` (or clears it) so Pho's `light-dark()` tokens follow\n * `color-scheme`. `device` tracks `prefers-color-scheme`. Persists under\n * `pho-mode` by default; pair with a blocking `<head>` script to avoid a\n * flash (see docs).\n */\nexport function ThemeToggle({\n mode: modeProp,\n defaultMode = \"device\",\n onModeChange,\n storageKey = THEME_STORAGE_KEY,\n target,\n size = \"md\",\n className,\n \"aria-label\": ariaLabel = \"Theme\",\n ...props\n}: ThemeToggleProps) {\n const storeMode = useSyncExternalStore(\n subscribeTheme,\n () => storedPreference ?? readStoredPreference(storageKey) ?? defaultMode,\n () => defaultMode,\n );\n\n // Uncontrolled — hydrate from storage (or `defaultMode`) on mount.\n useEffect(() => {\n if (modeProp !== undefined) return;\n const initial =\n storedPreference ?? readStoredPreference(storageKey) ?? defaultMode;\n setThemeMode(initial, {\n target: resolveTarget(target),\n storageKey,\n });\n }, [modeProp, storageKey, target, defaultMode]);\n\n // Controlled — keep the target in sync with the prop.\n useEffect(() => {\n if (modeProp === undefined) return;\n setThemeMode(modeProp, {\n target: resolveTarget(target),\n storageKey,\n });\n }, [modeProp, storageKey, target]);\n\n // Drop scoped-target media listeners on unmount (document listener is shared).\n useEffect(() => {\n return () => {\n const el = resolveTarget(target);\n if (el && el !== document.documentElement) {\n unbindTargetMediaListener(el);\n }\n };\n }, [target]);\n\n const mode = modeProp ?? storeMode;\n const sizes = THEME_SIZES[size];\n\n return (\n // Segmented control: styled buttons with radiogroup semantics. Native\n // `<input type=\"radio\">` cannot express the inverse-chip track layout.\n // oxlint-disable-next-line jsx-a11y/prefer-tag-over-role\n <div\n role=\"radiogroup\"\n aria-label={ariaLabel}\n {...props}\n className={cn(\n \"ring-pho-interactive inline-flex items-center ring-1 ring-inset\",\n sizes.track,\n className,\n )}\n >\n {OPTIONS.map(({ value, label, Icon }) => {\n const selected = mode === value;\n return (\n <button\n key={value}\n type=\"button\"\n role=\"radio\" // oxlint-disable-line jsx-a11y/prefer-tag-over-role -- segment needs button chrome\n aria-checked={selected}\n aria-label={label}\n tabIndex={selected ? 0 : -1}\n onClick={() =>\n selectMode(value, { modeProp, storageKey, target, onModeChange })\n }\n onKeyDown={(event) => {\n const order = OPTIONS.map((o) => o.value);\n const index = order.indexOf(mode);\n let next: ThemeMode | undefined;\n if (event.key === \"ArrowRight\" || event.key === \"ArrowDown\") {\n next = order[(index + 1) % order.length];\n } else if (event.key === \"ArrowLeft\" || event.key === \"ArrowUp\") {\n next = order[(index - 1 + order.length) % order.length];\n } else if (event.key === \"Home\") {\n next = order[0];\n } else if (event.key === \"End\") {\n next = order[order.length - 1];\n }\n if (!next) return;\n event.preventDefault();\n selectMode(next, { modeProp, storageKey, target, onModeChange });\n const el = event.currentTarget.parentElement?.querySelector(\n `[aria-label=\"${OPTIONS.find((o) => o.value === next)?.label}\"]`,\n );\n if (el instanceof HTMLElement) el.focus();\n }}\n className={cn(\n \"outline-pho-brand inline-flex flex-1 cursor-pointer items-center justify-center transition duration-100 ease-linear focus-visible:outline-2 focus-visible:outline-offset-2\",\n // No hover wash — in a segmented control the only filled element\n // is the selected chip. Unselected segments rest at the dim\n // description ink and jump to primary on hover for a clear cue.\n selected\n ? \"bg-pho-inverse text-pho-inverse\"\n : \"text-pho-description hover:text-pho-primary\",\n sizes.item,\n )}\n >\n <Icon aria-hidden=\"true\" className=\"shrink-0\" />\n </button>\n );\n })}\n </div>\n );\n}\n\nThemeToggle.displayName = \"ThemeToggle\";\n"],"x_google_ignoreList":[0,1,2],"mappings":";;;;;AASA,IAAMA,IAAa;AAAA,EAAC,CAAC,QAAQ;AAAA,IAAE,GAAK;AAAA,IAAkF,KAAO;AAAA,EAAQ,CAAC;AAAA,EAAG,CAAC,QAAQ;AAAA,IAAE,GAAK;AAAA,IAAY,KAAO;AAAA,EAAQ,CAAC;AAAA,EAAG,CAAC,QAAQ;AAAA,IAAE,GAAK;AAAA,IAAW,KAAO;AAAA,EAAQ,CAAC;AAAA,EAAG,CAAC,QAAQ;AAAA,IAAE,GAAK;AAAA,IAAY,KAAO;AAAA,EAAQ,CAAC;AAAC,GAC7Q,IAAoB,EAAqB,WAAW,kBAAkB,iBAAiBA,CAAU,GCDjGC,IAAa,CAAC,CAAC,QAAQ;AAAA,EAAE,GAAK;AAAA,EAAwF,KAAO;AAAQ,CAAC,CAAC,GACvI,IAAW,EAAqB,WAAW,QAAQ,QAAQA,CAAU,GCDrE,IAAa,CAAC,CAAC,QAAQ;AAAA,EAAE,GAAK;AAAA,EAAsC,KAAO;AAAQ,CAAC,GAAG,CAAC,QAAQ;AAAA,EAAE,GAAK;AAAA,EAA8F,KAAO;AAAQ,CAAC,CAAC,GACtN,IAAU,EAAqB,WAAW,OAAO,OAAO,CAAU,GCI3D,IAAoB,YAE3B,IAAqB,mBAErB,IAAU;AAAA,EACd;AAAA,IAAE,OAAO;AAAA,IAAmB,OAAO;AAAA,IAAU,MAAM;AAAA,EAAkB;AAAA,EACrE;AAAA,IAAE,OAAO;AAAA,IAAkB,OAAO;AAAA,IAAS,MAAM;AAAA,EAAQ;AAAA,EACzD;AAAA,IAAE,OAAO;AAAA,IAAiB,OAAO;AAAA,IAAQ,MAAM;AAAA,EAAS;AAC1D,GAMM,IAAc;AAAA,EAClB,IAAI;AAAA,IACF,OAAO;AAAA,IACP,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,OAAO;AAAA,IACP,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,OAAO;AAAA,IACP,MAAM;AAAA,EACR;AACF;AA6BA,SAAgB,EAAe,GAA6C;AAC1E,SAAI,MAAU,WAAW,MAAU,UAAU,MAAU,WAAiB,IACjE;AACT;AAGA,SAAgB,EACd,GACA,IAA8B,OAAO,SAAW,MAC5C,OAAO,WAAW,8BAA8B,IAChD,EAAE,SAAS,GAAM,GACN;AACf,SAAI,MAAS,WAAW,MAAS,SAAe,IACzC,EAAM,UAAU,SAAS;AAClC;AAEA,SAAS,EACP,GACoB;AACpB,SAAI,OAAO,KAAW,aAAmB,EAAO,IAC5C,MAAW,SAAkB,IAC1B,OAAO,WAAa,MAAc,OAAO,SAAS;AAC3D;AAGA,IAAI,IAAqC,MACrC,IAAoC,MAElC,IAAsB,oBAAI,IAA6B;AAY7D,SAAS,EAAqB,GAA6C;AACzE,MAAI,KAAc,QAAQ,OAAO,eAAiB,IAAa,QAAO;AACtE,QAAM,IAAM,aAAa,QAAQ,CAAU;AAC3C,SAAI,KAAO,OAAa,OACjB,EAAe,CAAG;AAC3B;AAGA,SAAgB,EACd,IAA4B,GACjB;AACX,SAAO,KAAoB,EAAqB,CAAU,KAAK;AACjE;AAGA,SAAgB,GACd,IAA6B,OAAO,WAAa,MAC7C,OACA,SAAS,iBACE;AACf,SAAO,GAAQ,QAAQ,SAAS,SAAS,SAAS;AACpD;AAEA,SAAS,EAAc,GAAyB,GAA4B;AAC1E,EAAK,MACD,MAAa,SAAQ,EAAO,QAAQ,OAAO,SAC1C,OAAO,EAAO,QAAQ;AAC7B;AAEA,SAAS,EAAkB,GAA2B;AAIpD,MAHA,IAAe,GACf,IAAe,MACX,OAAO,SAAW,OAClB,EAAmB,CAAU,MAAM,SAAU;AAEjD,QAAM,IAAM,OAAO,WAAW,8BAA8B,GACtD,IAAA,MAAiB;AACrB,IAAA,EAAc,EAAiB,UAAU,CAAG,GAAG,SAAS,eAAe,GACvE,OAAO,cAAc,IAAI,MAAM,CAAkB,CAAC;AAAA,EACpD;AACA,EAAA,EAAI,iBAAiB,UAAU,CAAQ,GACvC,IAAA,MAAqB,EAAI,oBAAoB,UAAU,CAAQ;AACjE;AAGA,SAAS,EAAwB,GAAqB,GAAiB;AAErE,MADA,EAA0B,CAAM,GAC5B,OAAO,SAAW,OAAe,MAAS,SAAU;AAExD,QAAM,IAAM,OAAO,WAAW,8BAA8B,GACtD,IAAA,MAAiB;AACrB,IAAA,EAAc,EAAiB,UAAU,CAAG,GAAG,CAAM;AAAA,EACvD;AACA,EAAA,EAAI,iBAAiB,UAAU,CAAQ,GACvC,EAAoB,IAAI,GAAA,MACtB,EAAI,oBAAoB,UAAU,CAAQ,CAC5C;AACF;AAEA,SAAS,EAA0B,GAA4B;AAC7D,EAAK,MACL,EAAoB,IAAI,CAAM,IAAI,GAClC,EAAoB,OAAO,CAAM;AACnC;AAMA,SAAgB,EACd,GACA,GAIM;AACN,QAAM,IACJ,KAAW,gBAAgB,IAAU,EAAQ,aAAa,GACtD,IACJ,GAAS,WACR,OAAO,WAAa,MAAc,OAAO,SAAS,kBAC/C,IACJ,OAAO,WAAa,OACpB,KAAU,QACV,MAAW,SAAS;AAItB,MAFA,EAAc,EAAiB,CAAI,GAAG,CAAM,GAExC,CAAC,GAAc;AACjB,IAAI,KAAQ,EAAwB,GAAQ,CAAI;AAChD;AAAA,EACF;AAEA,EAAA,IAAmB,GACf,KAAc,QAAQ,OAAO,eAAiB,OAChD,aAAa,QAAQ,GAAY,CAAI,GAEvC,EAAkB,KAAc,IAAI,GAEhC,OAAO,SAAW,OACpB,OAAO,cAAc,IAAI,MAAM,CAAkB,CAAC;AAEtD;AAEA,SAAS,EAAe,GAAsB;AAC5C,SAAI,OAAO,SAAW,MAAa,MAAa;AAAA,EAAC,KACjD,OAAO,iBAAiB,GAAoB,CAAQ,GACpD,MAAa,OAAO,oBAAoB,GAAoB,CAAQ;AACtE;AAEA,SAAS,EACP,GACA,GAMA;AACA,EAAI,EAAQ,aAAa,UACvB,EAAa,GAAO;AAAA,IAClB,QAAQ,EAAc,EAAQ,MAAM;AAAA,IACpC,YAAY,EAAQ;AAAA,EACtB,CAAC,GAEH,EAAQ,eAAe,CAAK;AAC9B;AASA,SAAgB,EAAY,EAC1B,MAAM,GACN,aAAA,IAAc,UACd,cAAA,GACA,YAAA,IAAa,GACb,QAAA,GACA,MAAA,IAAO,MACP,WAAA,GACA,cAAc,IAAY,SAC1B,GAAG,EAAA,GACgB;AACnB,QAAM,IAAY,EAChB,GAAA,MACM,KAAoB,EAAqB,CAAU,KAAK,GAAA,MACxD,CACR;AAGA,EAAA,EAAA,MAAgB;AACd,IAAI,MAAa,UAGjB,EADE,KAAoB,EAAqB,CAAU,KAAK,GACpC;AAAA,MACpB,QAAQ,EAAc,CAAM;AAAA,MAC5B,YAAA;AAAA,IACF,CAAC;AAAA,EACH,GAAG;AAAA,IAAC;AAAA,IAAU;AAAA,IAAY;AAAA,IAAQ;AAAA,EAAW,CAAC,GAG9C,EAAA,MAAgB;AACd,IAAI,MAAa,UACjB,EAAa,GAAU;AAAA,MACrB,QAAQ,EAAc,CAAM;AAAA,MAC5B,YAAA;AAAA,IACF,CAAC;AAAA,EACH,GAAG;AAAA,IAAC;AAAA,IAAU;AAAA,IAAY;AAAA,EAAM,CAAC,GAGjC,EAAA,MACE,MAAa;AACX,UAAM,IAAK,EAAc,CAAM;AAC/B,IAAI,KAAM,MAAO,SAAS,mBACxB,EAA0B,CAAE;AAAA,EAEhC,GACC,CAAC,CAAM,CAAC;AAEX,QAAM,IAAO,KAAY,GACnB,IAAQ,EAAY,CAAA;AAE1B,SAIE,gBAAA,EAAC,OAAD;AAAA,IACE,MAAK;AAAA,IACL,cAAY;AAAA,IACZ,GAAI;AAAA,IACJ,WAAW,EACT,mEACA,EAAM,OACN,CACF;AAAA,cAEC,EAAQ,IAAA,CAAK,EAAE,OAAA,GAAO,OAAA,GAAO,MAAA,EAAA,MAAW;AACvC,YAAM,IAAW,MAAS;AAC1B,aACE,gBAAA,EAAC,UAAD;AAAA,QAEE,MAAK;AAAA,QACL,MAAK;AAAA,QACL,gBAAc;AAAA,QACd,cAAY;AAAA,QACZ,UAAU,IAAW,IAAI;AAAA,QACzB,SAAA,MACE,EAAW,GAAO;AAAA,UAAE,UAAA;AAAA,UAAU,YAAA;AAAA,UAAY,QAAA;AAAA,UAAQ,cAAA;AAAA,QAAa,CAAC;AAAA,QAElE,WAAA,CAAY,MAAU;AACpB,gBAAM,IAAQ,EAAQ,IAAA,CAAK,MAAM,EAAE,KAAK,GAClC,IAAQ,EAAM,QAAQ,CAAI;AAChC,cAAI;AAUJ,cATI,EAAM,QAAQ,gBAAgB,EAAM,QAAQ,cAC9C,IAAO,GAAO,IAAQ,KAAK,EAAM,MAAA,IACxB,EAAM,QAAQ,eAAe,EAAM,QAAQ,YACpD,IAAO,GAAO,IAAQ,IAAI,EAAM,UAAU,EAAM,MAAA,IACvC,EAAM,QAAQ,SACvB,IAAO,EAAM,CAAA,IACJ,EAAM,QAAQ,UACvB,IAAO,EAAM,EAAM,SAAS,CAAA,IAE1B,CAAC,EAAM;AACX,UAAA,EAAM,eAAe,GACrB,EAAW,GAAM;AAAA,YAAE,UAAA;AAAA,YAAU,YAAA;AAAA,YAAY,QAAA;AAAA,YAAQ,cAAA;AAAA,UAAa,CAAC;AAC/D,gBAAM,IAAK,EAAM,cAAc,eAAe,cAC5C,gBAAgB,EAAQ,KAAA,CAAM,MAAM,EAAE,UAAU,CAAI,GAAG,KAAA,IACzD;AACA,UAAI,aAAc,eAAa,EAAG,MAAM;AAAA,QAC1C;AAAA,QACA,WAAW,EACT,8KAIA,IACI,oCACA,+CACJ,EAAM,IACR;AAAA,kBAEA,gBAAA,EAAC,GAAD;AAAA,UAAM,eAAY;AAAA,UAAO,WAAU;AAAA,QAAY,CAAA;AAAA,MACzC,GA1CD,CA0CC;AAAA,IAEZ,CAAC;AAAA,EACE,CAAA;AAET;AAEA,EAAY,cAAc"}
|
|
1
|
+
{"version":3,"file":"theme-toggle.js","names":["__iconNode","__iconNode"],"sources":["../../../../node_modules/.pnpm/@tabler+icons-react@3.44.0_react@19.2.7/node_modules/@tabler/icons-react/dist/esm/icons/IconDeviceDesktop.mjs","../../../../node_modules/.pnpm/@tabler+icons-react@3.44.0_react@19.2.7/node_modules/@tabler/icons-react/dist/esm/icons/IconMoon.mjs","../../../../node_modules/.pnpm/@tabler+icons-react@3.44.0_react@19.2.7/node_modules/@tabler/icons-react/dist/esm/icons/IconSun.mjs","../../src/components/theme-toggle/theme-toggle.tsx"],"sourcesContent":["/**\n * @license @tabler/icons-react v3.44.0 - MIT\n *\n * This source code is licensed under the MIT license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createReactComponent from '../createReactComponent.mjs';\n\nconst __iconNode = [[\"path\", { \"d\": \"M3 5a1 1 0 0 1 1 -1h16a1 1 0 0 1 1 1v10a1 1 0 0 1 -1 1h-16a1 1 0 0 1 -1 -1v-10\", \"key\": \"svg-0\" }], [\"path\", { \"d\": \"M7 20h10\", \"key\": \"svg-1\" }], [\"path\", { \"d\": \"M9 16v4\", \"key\": \"svg-2\" }], [\"path\", { \"d\": \"M15 16v4\", \"key\": \"svg-3\" }]];\nconst IconDeviceDesktop = createReactComponent(\"outline\", \"device-desktop\", \"DeviceDesktop\", __iconNode);\n\nexport { __iconNode, IconDeviceDesktop as default };\n//# sourceMappingURL=IconDeviceDesktop.mjs.map\n","/**\n * @license @tabler/icons-react v3.44.0 - MIT\n *\n * This source code is licensed under the MIT license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createReactComponent from '../createReactComponent.mjs';\n\nconst __iconNode = [[\"path\", { \"d\": \"M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454l0 .008\", \"key\": \"svg-0\" }]];\nconst IconMoon = createReactComponent(\"outline\", \"moon\", \"Moon\", __iconNode);\n\nexport { __iconNode, IconMoon as default };\n//# sourceMappingURL=IconMoon.mjs.map\n","/**\n * @license @tabler/icons-react v3.44.0 - MIT\n *\n * This source code is licensed under the MIT license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createReactComponent from '../createReactComponent.mjs';\n\nconst __iconNode = [[\"path\", { \"d\": \"M8 12a4 4 0 1 0 8 0a4 4 0 1 0 -8 0\", \"key\": \"svg-0\" }], [\"path\", { \"d\": \"M3 12h1m8 -9v1m8 8h1m-9 8v1m-6.4 -15.4l.7 .7m12.1 -.7l-.7 .7m0 11.4l.7 .7m-12.1 -.7l-.7 .7\", \"key\": \"svg-1\" }]];\nconst IconSun = createReactComponent(\"outline\", \"sun\", \"Sun\", __iconNode);\n\nexport { __iconNode, IconSun as default };\n//# sourceMappingURL=IconSun.mjs.map\n","import { useEffect, useSyncExternalStore, type HTMLAttributes } from \"react\";\nimport { IconDeviceDesktop, IconMoon, IconSun } from \"@tabler/icons-react\";\nimport { cn } from \"../../utils/cn\";\n\n/**\n * Appearance preference — `device` follows `prefers-color-scheme`; `light` /\n * `dark` force the scheme via `data-mode`.\n */\nexport type ThemeMode = \"device\" | \"light\" | \"dark\";\n\n/** Resolved color-scheme after applying a preference. */\nexport type ResolvedTheme = \"light\" | \"dark\";\n\n/** Default `localStorage` key used by the docs site and this component. */\nexport const THEME_STORAGE_KEY = \"pho-mode\";\n\nconst THEME_CHANGE_EVENT = \"pho-themechange\";\n\nconst OPTIONS = [\n { value: \"device\" as const, label: \"Device\", Icon: IconDeviceDesktop },\n { value: \"light\" as const, label: \"Light\", Icon: IconSun },\n { value: \"dark\" as const, label: \"Dark\", Icon: IconMoon },\n];\n\n// Concentric correction (see /scale): inner = outer − gap, derived from the\n// radius token with calc so it tracks theme changes. Track is `base`; the gap\n// is the track padding (xs–md p-0.5 = 2px, lg p-1 = 4px). Plain round, no\n// squircle (the track carries a ring-inset).\nconst THEME_SIZES = {\n xs: {\n track: \"gap-px rounded-base p-0.5\",\n item: \"size-5.5 rounded-[calc(var(--radius-base)-2px)] [&>svg]:size-3\",\n },\n sm: {\n track: \"gap-0.5 rounded-base p-0.5\",\n item: \"size-7 rounded-[calc(var(--radius-base)-2px)] [&>svg]:size-3.5\",\n },\n md: {\n track: \"gap-0.5 rounded-base p-0.5\",\n item: \"size-8 rounded-[calc(var(--radius-base)-2px)] [&>svg]:size-4\",\n },\n lg: {\n track: \"gap-1 rounded-base p-1\",\n item: \"size-9 rounded-[calc(var(--radius-base)-4px)] [&>svg]:size-5\",\n },\n} as const;\n\nexport type ThemeToggleSize = keyof typeof THEME_SIZES;\n\nexport interface ThemeToggleProps extends Omit<\n HTMLAttributes<HTMLDivElement>,\n \"children\" | \"color\" | \"onChange\" | \"defaultValue\"\n> {\n /** Controlled preference. */\n mode?: ThemeMode;\n /** Uncontrolled initial preference. @default \"device\" */\n defaultMode?: ThemeMode;\n /** Fired when the user picks a segment. */\n onModeChange?: (mode: ThemeMode) => void;\n /**\n * Persist the preference under this `localStorage` key. Pass `null` to skip\n * persistence. @default \"pho-mode\"\n */\n storageKey?: string | null;\n /**\n * Element that receives `data-mode=\"dark\"`. Defaults to\n * `document.documentElement`.\n */\n target?: HTMLElement | null | (() => HTMLElement | null);\n /** Size variant. @default \"md\" */\n size?: ThemeToggleSize;\n}\n\n/** Parse a stored preference; unknown / missing values fall back to `device`. */\nexport function parseThemeMode(value: string | null | undefined): ThemeMode {\n if (value === \"light\" || value === \"dark\" || value === \"device\") return value;\n return \"device\";\n}\n\n/** Resolve a preference against the OS color-scheme. */\nexport function resolveThemeMode(\n mode: ThemeMode,\n query: { matches: boolean } = typeof window !== \"undefined\"\n ? window.matchMedia(\"(prefers-color-scheme: dark)\")\n : { matches: false },\n): ResolvedTheme {\n if (mode === \"light\" || mode === \"dark\") return mode;\n return query.matches ? \"dark\" : \"light\";\n}\n\nfunction resolveTarget(\n target?: ThemeToggleProps[\"target\"],\n): HTMLElement | null {\n if (typeof target === \"function\") return target();\n if (target !== undefined) return target;\n return typeof document === \"undefined\" ? null : document.documentElement;\n}\n\n/** Preference mirrored across document-level ThemeToggle instances. */\nlet storedPreference: ThemeMode | null = null;\nlet mediaCleanup: (() => void) | null = null;\n/** Per-target `prefers-color-scheme` listeners (scoped `target` instances). */\nconst targetMediaCleanups = new Map<HTMLElement, () => void>();\n\n/** Drop in-memory preference + media listener (tests / full remounts). */\nexport function clearThemePreference() {\n storedPreference = null;\n mediaCleanup?.();\n mediaCleanup = null;\n for (const cleanup of targetMediaCleanups.values()) cleanup();\n targetMediaCleanups.clear();\n}\n\n/** Read a persisted preference, or `null` when nothing is stored. */\nfunction readStoredPreference(storageKey: string | null): ThemeMode | null {\n if (storageKey == null || typeof localStorage === \"undefined\") return null;\n const raw = localStorage.getItem(storageKey);\n if (raw == null) return null;\n return parseThemeMode(raw);\n}\n\n/** Current document preference (memory, then storage, else `device`). */\nexport function getThemePreference(\n storageKey: string | null = THEME_STORAGE_KEY,\n): ThemeMode {\n return storedPreference ?? readStoredPreference(storageKey) ?? \"device\";\n}\n\n/** Read the resolved light/dark mode from an element (or `<html>`). */\nexport function getThemeMode(\n target: HTMLElement | null = typeof document === \"undefined\"\n ? null\n : document.documentElement,\n): ResolvedTheme {\n return target?.dataset.mode === \"dark\" ? \"dark\" : \"light\";\n}\n\nfunction applyResolved(resolved: ResolvedTheme, target: HTMLElement | null) {\n if (!target) return;\n if (resolved === \"dark\") target.dataset.mode = \"dark\";\n else delete target.dataset.mode;\n}\n\nfunction bindMediaListener(storageKey: string | null) {\n mediaCleanup?.();\n mediaCleanup = null;\n if (typeof window === \"undefined\") return;\n if (getThemePreference(storageKey) !== \"device\") return;\n\n const mql = window.matchMedia(\"(prefers-color-scheme: dark)\");\n const onChange = () => {\n applyResolved(resolveThemeMode(\"device\", mql), document.documentElement);\n window.dispatchEvent(new Event(THEME_CHANGE_EVENT));\n };\n mql.addEventListener(\"change\", onChange);\n mediaCleanup = () => mql.removeEventListener(\"change\", onChange);\n}\n\n/** Track OS scheme changes for a scoped target (docs previews, etc.). */\nfunction bindTargetMediaListener(target: HTMLElement, mode: ThemeMode) {\n unbindTargetMediaListener(target);\n if (typeof window === \"undefined\" || mode !== \"device\") return;\n\n const mql = window.matchMedia(\"(prefers-color-scheme: dark)\");\n const onChange = () => {\n applyResolved(resolveThemeMode(\"device\", mql), target);\n };\n mql.addEventListener(\"change\", onChange);\n targetMediaCleanups.set(target, () =>\n mql.removeEventListener(\"change\", onChange),\n );\n}\n\nfunction unbindTargetMediaListener(target: HTMLElement | null) {\n if (!target) return;\n targetMediaCleanups.get(target)?.();\n targetMediaCleanups.delete(target);\n}\n\n/**\n * Apply an appearance preference: persist it, resolve against the OS when\n * `device`, set `data-mode` on the target, and notify document-level toggles.\n */\nexport function setThemeMode(\n mode: ThemeMode,\n options?: {\n target?: HTMLElement | null;\n storageKey?: string | null;\n },\n): void {\n const storageKey =\n options && \"storageKey\" in options ? options.storageKey : THEME_STORAGE_KEY;\n const target =\n options?.target ??\n (typeof document === \"undefined\" ? null : document.documentElement);\n const syncDocument =\n typeof document === \"undefined\" ||\n target == null ||\n target === document.documentElement;\n\n applyResolved(resolveThemeMode(mode), target);\n\n if (!syncDocument) {\n if (target) bindTargetMediaListener(target, mode);\n return;\n }\n\n storedPreference = mode;\n if (storageKey != null && typeof localStorage !== \"undefined\") {\n localStorage.setItem(storageKey, mode);\n }\n bindMediaListener(storageKey ?? null);\n\n if (typeof window !== \"undefined\") {\n window.dispatchEvent(new Event(THEME_CHANGE_EVENT));\n }\n}\n\nfunction subscribeTheme(onChange: () => void) {\n if (typeof window === \"undefined\") return () => {};\n window.addEventListener(THEME_CHANGE_EVENT, onChange);\n return () => window.removeEventListener(THEME_CHANGE_EVENT, onChange);\n}\n\nfunction selectMode(\n value: ThemeMode,\n options: {\n modeProp?: ThemeMode;\n storageKey: string | null;\n target: ThemeToggleProps[\"target\"];\n onModeChange?: (mode: ThemeMode) => void;\n },\n) {\n if (options.modeProp === undefined) {\n setThemeMode(value, {\n target: resolveTarget(options.target),\n storageKey: options.storageKey,\n });\n }\n options.onModeChange?.(value);\n}\n\n/**\n * Segmented appearance control — Device / Light / Dark. Forces\n * `data-mode=\"dark\"` (or clears it) so Pho's `light-dark()` tokens follow\n * `color-scheme`. `device` tracks `prefers-color-scheme`. Persists under\n * `pho-mode` by default; pair with a blocking `<head>` script to avoid a\n * flash (see docs).\n */\nexport function ThemeToggle({\n mode: modeProp,\n defaultMode = \"device\",\n onModeChange,\n storageKey = THEME_STORAGE_KEY,\n target,\n size = \"md\",\n className,\n \"aria-label\": ariaLabel = \"Theme\",\n ...props\n}: ThemeToggleProps) {\n const storeMode = useSyncExternalStore(\n subscribeTheme,\n () => storedPreference ?? readStoredPreference(storageKey) ?? defaultMode,\n () => defaultMode,\n );\n\n // Uncontrolled — hydrate from storage (or `defaultMode`) on mount.\n useEffect(() => {\n if (modeProp !== undefined) return;\n const initial =\n storedPreference ?? readStoredPreference(storageKey) ?? defaultMode;\n setThemeMode(initial, {\n target: resolveTarget(target),\n storageKey,\n });\n }, [modeProp, storageKey, target, defaultMode]);\n\n // Controlled — keep the target in sync with the prop.\n useEffect(() => {\n if (modeProp === undefined) return;\n setThemeMode(modeProp, {\n target: resolveTarget(target),\n storageKey,\n });\n }, [modeProp, storageKey, target]);\n\n // Drop scoped-target media listeners on unmount (document listener is shared).\n useEffect(() => {\n return () => {\n const el = resolveTarget(target);\n if (el && el !== document.documentElement) {\n unbindTargetMediaListener(el);\n }\n };\n }, [target]);\n\n const mode = modeProp ?? storeMode;\n const sizes = THEME_SIZES[size];\n\n return (\n // Segmented control: styled buttons with radiogroup semantics. Native\n // `<input type=\"radio\">` cannot express the inverse-chip track layout.\n // oxlint-disable-next-line jsx-a11y/prefer-tag-over-role\n <div\n role=\"radiogroup\"\n aria-label={ariaLabel}\n {...props}\n className={cn(\n \"ring-pho-interactive inline-flex items-center ring-1 ring-inset\",\n sizes.track,\n className,\n )}\n >\n {OPTIONS.map(({ value, label, Icon }) => {\n const selected = mode === value;\n return (\n <button\n key={value}\n type=\"button\"\n role=\"radio\" // oxlint-disable-line jsx-a11y/prefer-tag-over-role -- segment needs button chrome\n aria-checked={selected}\n aria-label={label}\n tabIndex={selected ? 0 : -1}\n onClick={() =>\n selectMode(value, { modeProp, storageKey, target, onModeChange })\n }\n onKeyDown={(event) => {\n const order = OPTIONS.map((o) => o.value);\n const index = order.indexOf(mode);\n let next: ThemeMode | undefined;\n if (event.key === \"ArrowRight\" || event.key === \"ArrowDown\") {\n next = order[(index + 1) % order.length];\n } else if (event.key === \"ArrowLeft\" || event.key === \"ArrowUp\") {\n next = order[(index - 1 + order.length) % order.length];\n } else if (event.key === \"Home\") {\n next = order[0];\n } else if (event.key === \"End\") {\n next = order[order.length - 1];\n }\n if (!next) return;\n event.preventDefault();\n selectMode(next, { modeProp, storageKey, target, onModeChange });\n const el = event.currentTarget.parentElement?.querySelector(\n `[aria-label=\"${OPTIONS.find((o) => o.value === next)?.label}\"]`,\n );\n if (el instanceof HTMLElement) el.focus();\n }}\n className={cn(\n \"outline-pho-brand inline-flex flex-1 cursor-pointer items-center justify-center transition duration-100 ease-linear focus-visible:outline-2 focus-visible:outline-offset-2\",\n // No hover wash — in a segmented control the only filled element\n // is the selected chip. Unselected segments rest at the dim\n // description ink and jump to primary on hover for a clear cue.\n selected\n ? \"bg-pho-inverse text-pho-inverse\"\n : \"text-pho-description hover:text-pho-primary\",\n sizes.item,\n )}\n >\n <Icon aria-hidden=\"true\" className=\"shrink-0\" />\n </button>\n );\n })}\n </div>\n );\n}\n\nThemeToggle.displayName = \"ThemeToggle\";\n"],"x_google_ignoreList":[0,1,2],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { n as o, r as n, t as r } from "./chunks/link-provider-9TFNyDqO.js";
|
|
|
4
4
|
import { t as e } from "./chunks/resolve-variant-CcD8iG5l.js";
|
|
5
5
|
import "./utils.js";
|
|
6
6
|
import { a as E, c as B, d as f, f as I, i as S, l as p, n as u, o as _, r as A, s as O, t as R, u as c } from "./chunks/close-button-8f-oRJXt.js";
|
|
7
|
-
import { a as N, i as l, n as D, r as V, t as L } from "./chunks/sidebar-
|
|
7
|
+
import { a as N, i as l, n as D, r as V, t as L } from "./chunks/sidebar-Buhva5xa.js";
|
|
8
8
|
import { t as d } from "./chunks/input-BSJGBUbf.js";
|
|
9
9
|
import { n as g, t as M } from "./chunks/dialog-Bgb2Z1_v.js";
|
|
10
10
|
export {
|
package/dist/sections/sidebar.js
CHANGED
|
@@ -9,6 +9,10 @@ export type ResolvedTheme = "light" | "dark";
|
|
|
9
9
|
/** Default `localStorage` key used by the docs site and this component. */
|
|
10
10
|
export declare const THEME_STORAGE_KEY = "pho-mode";
|
|
11
11
|
declare const THEME_SIZES: {
|
|
12
|
+
readonly xs: {
|
|
13
|
+
readonly track: "gap-px rounded-base p-0.5";
|
|
14
|
+
readonly item: "size-5.5 rounded-[calc(var(--radius-base)-2px)] [&>svg]:size-3";
|
|
15
|
+
};
|
|
12
16
|
readonly sm: {
|
|
13
17
|
readonly track: "gap-0.5 rounded-base p-0.5";
|
|
14
18
|
readonly item: "size-7 rounded-[calc(var(--radius-base)-2px)] [&>svg]:size-3.5";
|
package/package.json
CHANGED
package/src/styles/theme.css
CHANGED
|
@@ -58,12 +58,12 @@
|
|
|
58
58
|
/* =========================== Type scale =========================== */
|
|
59
59
|
/* CLOSED scale — the reset removes Tailwind's default sizes (text-2xl, …)
|
|
60
60
|
so only these steps generate utilities. Body: xs/base/md/lg/xl =
|
|
61
|
-
|
|
61
|
+
13/14/16/18/20 (Pho `text-base` is 14px, not Tailwind's 16px default).
|
|
62
62
|
Display: xs/sm/base/md/lg/xl/2xl = 18/20/24/32/40/48/60.
|
|
63
63
|
NOTE: the reset wipes the whole --text-* prefix; every --text-color-pho-*
|
|
64
64
|
token is declared AFTER this point in the file, so it survives. */
|
|
65
65
|
--text-*: initial;
|
|
66
|
-
--text-xs: 0.
|
|
66
|
+
--text-xs: 0.8125rem;
|
|
67
67
|
--text-xs--line-height: 1.125rem;
|
|
68
68
|
--text-base: 0.875rem;
|
|
69
69
|
--text-base--line-height: 1.25rem;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"menu-COLB_liS.js","names":[],"sources":["../../src/components/menu/menu-pending.tsx","../../src/components/menu/menu.tsx"],"sourcesContent":["import {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ComponentType,\n type MouseEvent as ReactMouseEvent,\n type ReactNode,\n type RefObject,\n} from \"react\";\nimport { Spinner } from \"../spinner/spinner\";\n\n/** Imperative actions exposed by Base UI menu `actionsRef`. */\ninterface RootActions {\n unmount: () => void;\n close: () => void;\n}\n\ninterface MenuPendingContextValue {\n /** True while a menu item promise is in flight. */\n pending: boolean;\n beginPending: () => void;\n endPending: () => void;\n /** Close the menu imperatively (used by async items on resolve). */\n close: () => void;\n}\n\nconst MenuPendingContext = createContext<MenuPendingContextValue | null>(null);\n\n/**\n * Whether the surrounding menu has an async item promise in flight —\n * use it to disable sibling items while work is pending.\n * Returns `false` outside a `Menu.Root` / `ContextMenu.Root`.\n */\nexport function useMenuPending(): boolean {\n return useContext(MenuPendingContext)?.pending ?? false;\n}\n\nexport function isThenable(value: unknown): value is Promise<unknown> {\n return (\n value != null && typeof (value as { then?: unknown }).then === \"function\"\n );\n}\n\ntype PreventableMouseEvent = ReactMouseEvent<HTMLElement> & {\n preventBaseUIHandler?: () => void;\n};\n\ntype RootWithPendingProps = {\n onOpenChange?: (open: boolean, eventDetails: { cancel: () => void }) => void;\n actionsRef?: RefObject<RootActions | null>;\n children?: ReactNode;\n};\n\n/**\n * Wraps a Base UI menu root so async `Menu.Item` clicks can lock dismissal\n * (outside press, Escape) until the promise settles.\n */\nexport function withMenuPendingRoot<P extends RootWithPendingProps>(\n BaseRoot: ComponentType<P>,\n): ComponentType<P> {\n function PendingRoot({ onOpenChange, actionsRef, ...props }: P) {\n const [pending, setPending] = useState(false);\n // Guard reads a ref so a resolve → close() in the same tick isn't blocked\n // by a not-yet-flushed state update.\n const pendingRef = useRef(false);\n const internalActionsRef = useRef<RootActions | null>(null);\n\n useEffect(() => {\n if (!actionsRef) return;\n // Proxy so callers always hit the live Base UI actions, even if the\n // popup remounts after this effect runs.\n actionsRef.current = {\n unmount: () => internalActionsRef.current?.unmount(),\n close: () => internalActionsRef.current?.close(),\n };\n return () => {\n actionsRef.current = null;\n };\n }, [actionsRef]);\n\n const handleOpenChange = useCallback(\n (open: boolean, eventDetails: { cancel: () => void }) => {\n if (!open && pendingRef.current) {\n eventDetails.cancel();\n return;\n }\n onOpenChange?.(open, eventDetails);\n },\n [onOpenChange],\n );\n\n const contextValue = useMemo<MenuPendingContextValue>(\n () => ({\n pending,\n beginPending: () => {\n pendingRef.current = true;\n setPending(true);\n },\n endPending: () => {\n pendingRef.current = false;\n setPending(false);\n },\n close: () => internalActionsRef.current?.close(),\n }),\n [pending],\n );\n\n return (\n <MenuPendingContext.Provider value={contextValue}>\n <BaseRoot\n {...(props as P)}\n actionsRef={internalActionsRef}\n onOpenChange={handleOpenChange}\n />\n </MenuPendingContext.Provider>\n );\n }\n\n return PendingRoot as ComponentType<P>;\n}\n\nexport type AsyncMenuItemClick = (\n event: ReactMouseEvent<HTMLElement>,\n) => void | Promise<unknown>;\n\n/**\n * Shared click handler for `Menu.Item` / `ContextMenu.Item` promise support.\n * Returns whether the item should show its loading state.\n */\nexport function useAsyncMenuItem({\n onClick,\n closeOnClick = true,\n loading = false,\n disabled = false,\n}: {\n onClick?: AsyncMenuItemClick;\n closeOnClick?: boolean;\n loading?: boolean;\n disabled?: boolean;\n}) {\n const pendingContext = useContext(MenuPendingContext);\n const menuPending = pendingContext?.pending ?? false;\n const [busy, setBusy] = useState(false);\n const mountedRef = useRef(true);\n\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n };\n }, []);\n\n const inert = busy || loading;\n // Disable siblings while any item promise is in flight.\n const blocked = disabled || inert || menuPending;\n\n function handleClick(event: ReactMouseEvent<HTMLElement>) {\n if (inert || (menuPending && !busy)) {\n (event as PreventableMouseEvent).preventBaseUIHandler?.();\n return;\n }\n const result = onClick?.(event);\n if (!isThenable(result)) {\n return;\n }\n // Stop Base UI's closeOnClick for this press; close on resolve instead.\n (event as PreventableMouseEvent).preventBaseUIHandler?.();\n setBusy(true);\n pendingContext?.beginPending();\n result.then(\n () => {\n pendingContext?.endPending();\n if (mountedRef.current) setBusy(false);\n if (closeOnClick) pendingContext?.close();\n },\n (error: unknown) => {\n pendingContext?.endPending();\n if (mountedRef.current) setBusy(false);\n if (\n typeof process !== \"undefined\" &&\n process.env?.NODE_ENV !== \"production\"\n ) {\n console.error(\"Menu.Item: async onClick rejected —\", error);\n }\n },\n );\n }\n\n return { inert, blocked, handleClick };\n}\n\n/** Menu-row spinner — keeps `data-menu-spinner` for the hide-siblings CSS. */\nexport function MenuItemSpinner() {\n return <Spinner data-menu-spinner=\"\" size=\"md\" />;\n}\n","import {\n type ComponentProps,\n type ElementType,\n type MouseEvent as ReactMouseEvent,\n} from \"react\";\nimport { Menu as BaseMenu } from \"@base-ui/react/menu\";\nimport { Separator as BaseSeparator } from \"@base-ui/react/separator\";\nimport { cn } from \"../../utils/cn\";\nimport { resolveVariant, type VariantMap } from \"../../utils/resolve-variant\";\nimport {\n MenuItemSpinner,\n useAsyncMenuItem,\n useMenuPending,\n withMenuPendingRoot,\n type AsyncMenuItemClick,\n} from \"./menu-pending\";\n\nexport { useMenuPending };\n\n/** Override Base UI's `string | (state) => string` className with plain string. */\ntype StyledProps<T extends ElementType> = Omit<\n ComponentProps<T>,\n \"className\" | \"color\"\n> & {\n className?: string;\n};\n\n/** Shared popup + item styles, reused by `ContextMenu` and `Menubar` menus. */\n// Floating layer: keeps its elevation shadow, sits on the primary surface\n// with the site's hairline (ring-pho-secondary, #eee/#202020) as its edge.\nexport const MENU_POPUP =\n \"bg-pho-primary text-pho-primary shadow-pho-lg ring-pho-secondary origin-[var(--transform-origin)] min-w-44 rounded-base p-1 ring-1 ring-inset outline-none transition-[transform,opacity] duration-150 ease-out data-[starting-style]:scale-95 data-[starting-style]:opacity-0 data-[ending-style]:scale-95 data-[ending-style]:opacity-0\";\n// Rest at secondary; highlighted lifts to primary with the quiet ghost wash.\n// Icons use `text-current` so they follow the row ink (including destructive).\n// While loading, the spinner is first; hide the rest of the leading icons.\nexport const MENU_ITEM =\n \"relative flex cursor-pointer items-center gap-2 rounded-base py-1.5 pr-2.5 pl-2.5 text-base text-pho-secondary outline-none select-none data-[highlighted]:bg-pho-ghost-hover data-[highlighted]:text-pho-primary data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-loading:data-[disabled]:opacity-100 data-loading:[&>svg:not([data-menu-spinner])]:hidden [&>svg]:size-4 [&>svg]:text-current\";\n\n/** Semantic ink for `Menu.Item` / `LinkItem` / `ContextMenu.Item`. */\nexport const MENU_ITEM_COLORS = {\n default: { classes: \"\", description: \"Secondary → primary on highlight\" },\n destructive: {\n classes:\n \"text-pho-error data-[highlighted]:bg-pho-error-primary data-[highlighted]:text-pho-error\",\n description: \"Error ink + error wash on highlight\",\n },\n} satisfies VariantMap;\n\nexport type MenuItemColor = keyof typeof MENU_ITEM_COLORS;\n\ntype ItemColorProps = {\n /** Semantic ink. @default \"default\" */\n color?: MenuItemColor;\n};\n\nexport type MenuItemProps = Omit<StyledProps<typeof BaseMenu.Item>, \"onClick\"> &\n ItemColorProps & {\n /**\n * Action handler. Return a promise to keep the menu open while it runs:\n * the item shows a spinner, dismissal is locked, and the menu closes when\n * the promise resolves (if `closeOnClick`). On rejection the menu stays\n * open — surface errors inside the handler.\n */\n onClick?: AsyncMenuItemClick;\n /**\n * Declarative loading state (same visual as an in-flight promise).\n * @default false\n */\n loading?: boolean;\n };\n\nconst Root = withMenuPendingRoot(BaseMenu.Root);\nconst Trigger = BaseMenu.Trigger;\nconst Portal = BaseMenu.Portal;\nconst Group = BaseMenu.Group;\nconst RadioGroup = BaseMenu.RadioGroup;\n// Don't wrap SubmenuRoot — nested pending context would shadow the parent\n// Root and fail to lock dismissal for async items inside a submenu.\nconst SubmenuRoot = BaseMenu.SubmenuRoot;\n\nfunction Positioner({\n className,\n sideOffset = 6,\n ...props\n}: StyledProps<typeof BaseMenu.Positioner>) {\n return (\n <BaseMenu.Positioner\n sideOffset={sideOffset}\n className={cn(\"z-50\", className)}\n {...props}\n />\n );\n}\n\nfunction Popup({ className, ...props }: StyledProps<typeof BaseMenu.Popup>) {\n return <BaseMenu.Popup className={cn(MENU_POPUP, className)} {...props} />;\n}\n\nfunction Item({\n className,\n color = \"default\",\n onClick,\n closeOnClick = true,\n loading = false,\n disabled = false,\n children,\n ...props\n}: MenuItemProps) {\n const { inert, blocked, handleClick } = useAsyncMenuItem({\n onClick,\n closeOnClick,\n loading,\n disabled,\n });\n\n return (\n <BaseMenu.Item\n className={cn(\n MENU_ITEM,\n resolveVariant(MENU_ITEM_COLORS, color),\n className,\n )}\n closeOnClick={closeOnClick}\n disabled={blocked}\n data-loading={inert || undefined}\n aria-busy={inert || undefined}\n onClick={handleClick as (event: ReactMouseEvent<HTMLElement>) => void}\n {...props}\n >\n {inert ? <MenuItemSpinner /> : null}\n {children}\n </BaseMenu.Item>\n );\n}\n\nfunction LinkItem({\n className,\n color = \"default\",\n ...props\n}: StyledProps<typeof BaseMenu.LinkItem> & ItemColorProps) {\n return (\n <BaseMenu.LinkItem\n className={cn(\n MENU_ITEM,\n resolveVariant(MENU_ITEM_COLORS, color),\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction GroupLabel({\n className,\n ...props\n}: StyledProps<typeof BaseMenu.GroupLabel>) {\n return (\n <BaseMenu.GroupLabel\n className={cn(\n \"text-pho-secondary px-2.5 py-1.5 text-xs font-medium\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Separator({ className, ...props }: StyledProps<typeof BaseSeparator>) {\n return (\n <BaseSeparator\n className={cn(\n \"-mx-1 my-1 h-px bg-[var(--border-color-pho-secondary)]\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction SubmenuTrigger({\n className,\n ...props\n}: StyledProps<typeof BaseMenu.SubmenuTrigger>) {\n return (\n <BaseMenu.SubmenuTrigger\n className={cn(\n MENU_ITEM,\n \"data-[popup-open]:bg-pho-ghost-hover\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction CheckboxItem({\n className,\n ...props\n}: StyledProps<typeof BaseMenu.CheckboxItem>) {\n return (\n <BaseMenu.CheckboxItem\n className={cn(MENU_ITEM, \"pl-8\", className)}\n {...props}\n />\n );\n}\n\nfunction RadioItem({\n className,\n ...props\n}: StyledProps<typeof BaseMenu.RadioItem>) {\n return (\n <BaseMenu.RadioItem\n className={cn(MENU_ITEM, \"pl-8\", className)}\n {...props}\n />\n );\n}\n\nconst CHECK_INDICATOR =\n \"text-pho-brand absolute left-2.5 flex items-center [&>svg]:size-4\";\n\nfunction CheckboxItemIndicator({\n className,\n ...props\n}: StyledProps<typeof BaseMenu.CheckboxItemIndicator>) {\n return (\n <BaseMenu.CheckboxItemIndicator\n className={cn(CHECK_INDICATOR, className)}\n {...props}\n />\n );\n}\n\nfunction RadioItemIndicator({\n className,\n ...props\n}: StyledProps<typeof BaseMenu.RadioItemIndicator>) {\n return (\n <BaseMenu.RadioItemIndicator\n className={cn(CHECK_INDICATOR, className)}\n {...props}\n />\n );\n}\n\n/**\n * Dropdown menu built on Base UI `Menu` — a list of actions opened from a\n * trigger. Supports grouped items, separators, submenus\n * (`SubmenuRoot` + `SubmenuTrigger`), and stateful `CheckboxItem` /\n * `RadioItem`s. `Menu.Item` has native promise support (spinner + locked\n * dismissal while pending). For a right-click menu use `ContextMenu`.\n */\nexport const Menu = {\n Root,\n Trigger,\n Portal,\n Positioner,\n Popup,\n Item,\n LinkItem,\n Group,\n GroupLabel,\n Separator,\n SubmenuRoot,\n SubmenuTrigger,\n CheckboxItem,\n CheckboxItemIndicator,\n RadioGroup,\n RadioItem,\n RadioItemIndicator,\n};\n"],"mappings":"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"}
|