@togo-framework/ui 0.1.10 → 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-KD4MPGYQ.js → chunk-7B6OKTGY.js} +80 -4
- package/dist/chunk-7B6OKTGY.js.map +1 -0
- package/dist/chunk-NRF3KNQX.js +117 -0
- package/dist/chunk-NRF3KNQX.js.map +1 -0
- package/dist/{chunk-XXP2ZYPY.js → chunk-YYV7ECKZ.js} +468 -580
- package/dist/chunk-YYV7ECKZ.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +25 -21
- package/dist/index.js.map +1 -1
- package/dist/shadcn.js +20 -18
- package/dist/theme/index.d.ts +25 -1
- package/dist/theme/index.js +4 -1
- package/dist/theme/tokens.semantic.css +102 -0
- package/package.json +1 -1
- package/dist/chunk-KD4MPGYQ.js.map +0 -1
- package/dist/chunk-XXP2ZYPY.js.map +0 -1
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Button,
|
|
3
|
+
DropdownMenu,
|
|
4
|
+
DropdownMenuContent,
|
|
5
|
+
DropdownMenuItem,
|
|
6
|
+
DropdownMenuSeparator,
|
|
7
|
+
DropdownMenuTrigger,
|
|
8
|
+
cn
|
|
9
|
+
} from "./chunk-NRF3KNQX.js";
|
|
10
|
+
|
|
1
11
|
// src/theme/brand.ts
|
|
2
12
|
function isHSL(value) {
|
|
3
13
|
return /^\d+(\.\d+)?\s+\d+(\.\d+)?%\s+\d+(\.\d+)?%$/.test(value.trim());
|
|
@@ -111,8 +121,14 @@ import * as React from "react";
|
|
|
111
121
|
|
|
112
122
|
// src/theme/themes.ts
|
|
113
123
|
var themes = [
|
|
114
|
-
{ id: "dark", label: "Dark", base: "dark" },
|
|
115
|
-
{ id: "light", label: "Light", base: "light" }
|
|
124
|
+
{ id: "dark", label: "Dark", base: "dark", accent: "#1FC7DC" },
|
|
125
|
+
{ id: "light", label: "Light", base: "light", accent: "#1659C8" },
|
|
126
|
+
{ id: "purple", label: "Purple", base: "dark", accent: "#9B6DF5" },
|
|
127
|
+
{ id: "rose", label: "Rose", base: "dark", accent: "#F5427B" },
|
|
128
|
+
{ id: "emerald", label: "Emerald", base: "dark", accent: "#10B981" },
|
|
129
|
+
{ id: "purple-light", label: "Purple Light", base: "light", accent: "#7C3AED" },
|
|
130
|
+
{ id: "rose-light", label: "Rose Light", base: "light", accent: "#E11D48" },
|
|
131
|
+
{ id: "emerald-light", label: "Emerald Light", base: "light", accent: "#059669" }
|
|
116
132
|
];
|
|
117
133
|
function themeBase(id) {
|
|
118
134
|
return themes.find((t) => t.id === id)?.base ?? "dark";
|
|
@@ -191,6 +207,65 @@ function useTheme() {
|
|
|
191
207
|
return ctx;
|
|
192
208
|
}
|
|
193
209
|
|
|
210
|
+
// src/theme/ThemePicker.tsx
|
|
211
|
+
import { Palette } from "lucide-react";
|
|
212
|
+
import { jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
213
|
+
function Swatch({ color, className }) {
|
|
214
|
+
if (!color) return null;
|
|
215
|
+
return /* @__PURE__ */ jsx3(
|
|
216
|
+
"span",
|
|
217
|
+
{
|
|
218
|
+
className: cn("inline-block h-3.5 w-3.5 shrink-0 rounded-full border border-white/20", className),
|
|
219
|
+
style: { backgroundColor: color }
|
|
220
|
+
}
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
function ThemePicker({ themes: themes2 = themes, size = "default", className, label }) {
|
|
224
|
+
const { theme, setTheme } = useTheme();
|
|
225
|
+
const current = themes2.find((t) => t.id === theme) ?? themes2[0];
|
|
226
|
+
const iconCls = size === "sm" ? "h-3.5 w-3.5" : "h-4 w-4";
|
|
227
|
+
const btnCls = size === "sm" ? "h-7 w-7" : "h-8 w-8";
|
|
228
|
+
const dark = themes2.filter((t) => t.base === "dark");
|
|
229
|
+
const light = themes2.filter((t) => t.base === "light");
|
|
230
|
+
return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
231
|
+
/* @__PURE__ */ jsx3(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx3(
|
|
232
|
+
Button,
|
|
233
|
+
{
|
|
234
|
+
variant: "ghost",
|
|
235
|
+
size: "icon",
|
|
236
|
+
className: cn(btnCls, "text-muted-foreground", className),
|
|
237
|
+
"aria-label": "Switch theme",
|
|
238
|
+
children: current?.accent ? /* @__PURE__ */ jsx3(Swatch, { color: current.accent, className: "h-4 w-4" }) : /* @__PURE__ */ jsx3(Palette, { className: iconCls })
|
|
239
|
+
}
|
|
240
|
+
) }),
|
|
241
|
+
/* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", className: "w-44", children: [
|
|
242
|
+
label && /* @__PURE__ */ jsx3("div", { className: "px-2 py-1.5 text-xs font-medium text-muted-foreground", children: label }),
|
|
243
|
+
/* @__PURE__ */ jsx3("div", { className: "px-2 py-1 text-[10px] uppercase tracking-wider text-muted-foreground/70", children: "Dark" }),
|
|
244
|
+
dark.map((t) => /* @__PURE__ */ jsx3(ThemeItem, { def: t, active: theme === t.id, onSelect: () => setTheme(t.id) }, t.id)),
|
|
245
|
+
/* @__PURE__ */ jsx3(DropdownMenuSeparator, {}),
|
|
246
|
+
/* @__PURE__ */ jsx3("div", { className: "px-2 py-1 text-[10px] uppercase tracking-wider text-muted-foreground/70", children: "Light" }),
|
|
247
|
+
light.map((t) => /* @__PURE__ */ jsx3(ThemeItem, { def: t, active: theme === t.id, onSelect: () => setTheme(t.id) }, t.id))
|
|
248
|
+
] })
|
|
249
|
+
] });
|
|
250
|
+
}
|
|
251
|
+
function ThemeItem({ def, active, onSelect }) {
|
|
252
|
+
return /* @__PURE__ */ jsxs(
|
|
253
|
+
DropdownMenuItem,
|
|
254
|
+
{
|
|
255
|
+
role: "menuitemradio",
|
|
256
|
+
"aria-checked": active,
|
|
257
|
+
onClick: onSelect,
|
|
258
|
+
className: cn("flex items-center gap-2", active && "font-medium text-foreground"),
|
|
259
|
+
children: [
|
|
260
|
+
/* @__PURE__ */ jsx3(Swatch, { color: def.accent }),
|
|
261
|
+
/* @__PURE__ */ jsx3("span", { className: "flex-1", children: def.label }),
|
|
262
|
+
active && /* @__PURE__ */ jsx3("span", { className: "text-xs text-muted-foreground", children: "\u2713" })
|
|
263
|
+
]
|
|
264
|
+
}
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
ThemePicker.displayName = "ThemePicker";
|
|
268
|
+
|
|
194
269
|
export {
|
|
195
270
|
isHSL,
|
|
196
271
|
isValidColor,
|
|
@@ -206,6 +281,7 @@ export {
|
|
|
206
281
|
STORAGE_KEY,
|
|
207
282
|
themeInitScript,
|
|
208
283
|
ThemeProvider,
|
|
209
|
-
useTheme
|
|
284
|
+
useTheme,
|
|
285
|
+
ThemePicker
|
|
210
286
|
};
|
|
211
|
-
//# sourceMappingURL=chunk-
|
|
287
|
+
//# sourceMappingURL=chunk-7B6OKTGY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/theme/brand.ts","../src/theme/BrandingProvider.tsx","../src/theme/ThemeProvider.tsx","../src/theme/themes.ts","../src/theme/ThemePicker.tsx"],"sourcesContent":["'use client'\n\n/**\n * brand.ts — Sentra dynamic theming primitives.\n *\n * Pure utilities: no React, no app context, no bridge dependency.\n * A product imports these and wires its own org-settings fetch,\n * then calls applyBrand() to override the CSS var baseline at runtime.\n *\n * CSS variables written (same set as app/src/components/BrandingProvider.tsx):\n * --primary HSL \"H S% L%\" — buttons, rings, active states\n * --brand-primary HSL \"H S% L%\" — alias kept for Situation Room glow\n * --brand-primary-glow HSL with +7 lightness — glow variant\n * --ring same as --primary\n * --sidebar-primary same as --primary\n * --sidebar-ring same as --primary\n * --ai-glow same as --primary\n * --accent-muted accent HSL with -13 lightness\n * --logo-url CSS url(\"…\") string for background-image consumers\n */\n\n// ── Colour helpers ─────────────────────────────────────────────────────────\n\n/** Returns true for the HSL string form \"H S% L%\". */\nexport function isHSL(value: string): boolean {\n return /^\\d+(\\.\\d+)?\\s+\\d+(\\.\\d+)?%\\s+\\d+(\\.\\d+)?%$/.test(value.trim());\n}\n\n/** Returns true for \"#RRGGBB\" or \"#RGB\". */\nexport function isValidColor(value: string): boolean {\n const t = value.trim();\n return (\n isHSL(t) || /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(t)\n );\n}\n\n/**\n * Converts \"#RRGGBB\" or \"#RGB\" to the HSL string form \"H S% L%\".\n * Returns an empty string when the input is not a valid hex color.\n */\nexport function hexToHSL(hex: string): string {\n let h = hex.replace(\"#\", \"\").trim();\n if (h.length === 3) h = h.split(\"\").map((c) => c + c).join(\"\");\n if (h.length !== 6) return \"\";\n\n const r = parseInt(h.substring(0, 2), 16) / 255;\n const g = parseInt(h.substring(2, 4), 16) / 255;\n const b = parseInt(h.substring(4, 6), 16) / 255;\n\n const max = Math.max(r, g, b);\n const min = Math.min(r, g, b);\n const l = (max + min) / 2;\n\n if (max === min) return `0 0% ${Math.round(l * 100)}%`;\n\n const d = max - min;\n const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n let hue = 0;\n if (max === r) hue = ((g - b) / d + (g < b ? 6 : 0)) / 6;\n else if (max === g) hue = ((b - r) / d + 2) / 6;\n else hue = ((r - g) / d + 4) / 6;\n\n return `${Math.round(hue * 360)} ${Math.round(s * 100)}% ${Math.round(l * 100)}%`;\n}\n\n/**\n * Normalises a hex or HSL value to the \"H S% L%\" form.\n * Returns null when the value is unrecognised — callers should skip setting\n * the var rather than writing a broken value.\n */\nexport function toHSLSafe(color: string): string | null {\n if (!color) return null;\n const t = color.trim();\n if (isHSL(t)) return t;\n const result = hexToHSL(t);\n return result !== \"\" ? result : null;\n}\n\n/**\n * Nudges the lightness of an \"H S% L%\" string by `delta` percentage points,\n * clamped to [0, 100].\n */\nexport function nudgeL(hsl: string, delta: number): string {\n const parts = hsl.trim().split(/\\s+/);\n if (parts.length < 3) return hsl;\n const l = parseFloat(parts[2] ?? \"0\");\n const newL = Math.max(0, Math.min(100, l + delta));\n return `${parts[0]} ${parts[1]} ${Math.round(newL)}%`;\n}\n\n// ── Sentra platform defaults ───────────────────────────────────────────────\n\n/**\n * SENTRA_BRAND — the platform's own brand tokens.\n *\n * These are the values used when no tenant branding is configured.\n * BrandingProvider applies them on first render so the first paint is always\n * branded; a tenant override writes over them once org-settings resolves.\n */\nexport const SENTRA_BRAND = {\n /** Brand primary: Sentra crimson (--primary 345 75% 33%). */\n primaryHex: \"#931535\",\n /** Brand accent: Tailwind violet-500. */\n accentHex: \"#daab4e\",\n /** Logo path — products serve this from their own /public directory. */\n logoUrl: \"/sentra-logo-full.png\",\n} as const;\n\n// ── Pre-computed HSL values for the defaults ──────────────────────────────\n\nconst SENTRA_PRIMARY_HSL = toHSLSafe(SENTRA_BRAND.primaryHex)!; // \"160 84% 39%\"\nconst SENTRA_ACCENT_HSL = toHSLSafe(SENTRA_BRAND.accentHex)!; // \"263 70% 66%\"\n\n// ── Brand application ──────────────────────────────────────────────────────\n\nexport interface BrandTokens {\n /** Hex string (\"#RRGGBB\") or HSL string (\"H S% L%\") for the primary color. */\n primaryHex?: string;\n /** Hex string (\"#RRGGBB\") or HSL string (\"H S% L%\") for the accent color. */\n accentHex?: string;\n /** Absolute URL or relative path to the org logo image. */\n logoUrl?: string;\n}\n\n/**\n * applyBrand — writes brand CSS custom properties directly onto `root`\n * (typically `document.documentElement`).\n *\n * Call this inside a useEffect whenever org-settings data changes.\n * When a field is absent or invalid, the corresponding Sentra default fills\n * the gap — the product always has a styled baseline.\n *\n * @param root The element to set properties on (usually document.documentElement).\n * @param tokens The brand tokens from org-settings; all fields are optional.\n */\nexport function applyBrand(root: HTMLElement, tokens: BrandTokens = {}): void {\n // ── Primary ──────────────────────────────────────────────────────────────\n const primaryHSL =\n (tokens.primaryHex ? toHSLSafe(tokens.primaryHex) : null) ?? SENTRA_PRIMARY_HSL;\n\n root.style.setProperty(\"--primary\", primaryHSL);\n root.style.setProperty(\"--brand-primary\", primaryHSL);\n root.style.setProperty(\"--brand-primary-glow\", nudgeL(primaryHSL, 7));\n root.style.setProperty(\"--ring\", primaryHSL);\n root.style.setProperty(\"--sidebar-primary\", primaryHSL);\n root.style.setProperty(\"--sidebar-ring\", primaryHSL);\n root.style.setProperty(\"--ai-glow\", primaryHSL);\n\n // ── Accent ───────────────────────────────────────────────────────────────\n const accentHSL =\n (tokens.accentHex ? toHSLSafe(tokens.accentHex) : null) ?? SENTRA_ACCENT_HSL;\n\n root.style.setProperty(\"--accent-muted\", nudgeL(accentHSL, -13));\n\n // ── Logo ─────────────────────────────────────────────────────────────────\n // Only set --logo-url when the tenant actually has a logo. Do NOT fall back to\n // the Sentra default PNG (operator 2026-06-05: empty DB logo was rendering\n // /sentra-logo-full.png everywhere instead of the platform icon). When there's\n // no logo, set --logo-url: none so background-image consumers show nothing and\n // icon-based marks (AuthCard crest, AdminLayout brand mark) take over.\n const rawLogo = tokens.logoUrl;\n if (rawLogo && rawLogo.trim() !== \"\") {\n root.style.setProperty(\"--logo-url\", `url(\"${rawLogo}\")`);\n } else {\n root.style.setProperty(\"--logo-url\", \"none\");\n }\n}","'use client'\n\n/**\n * BrandingProvider.tsx — React wrapper for dynamic Sentra branding.\n *\n * Design contract (prop-driven, no app context):\n * A product fetches its own org-settings and passes the values as props.\n * BrandingProvider calls applyBrand() in a useEffect whenever the values\n * change, writing the CSS custom properties onto document.documentElement.\n *\n * The tokens.css vars (--primary, --brand-primary, etc.) are the static\n * fallback baseline. applyBrand() overrides them at runtime with the org's\n * palette, making the UI theme dynamic per tenant.\n *\n * Placement: wrap the root of your product's component tree AFTER your\n * ThemeProvider (light/dark), so the dark-class is already on <html> when\n * the effect fires.\n *\n * Usage:\n * import { BrandingProvider } from '@prism/ui'\n *\n * // In your product's root layout / providers component:\n * const { data: org } = useOrgSettings() // your own fetch\n *\n * return (\n * <BrandingProvider\n * primaryHex={org?.primaryColor}\n * accentHex={org?.accentColor}\n * logoUrl={org?.logoUrl}\n * >\n * {children}\n * </BrandingProvider>\n * )\n *\n * SSR note: applyBrand() only runs inside useEffect (client-side). On the\n * server the CSS var defaults from tokens.css are used — no flash for the\n * initial paint because the default palette is set in the stylesheet.\n */\nimport { createContext, useContext, useEffect, type ReactNode } from \"react\";\nimport { applyBrand, SENTRA_BRAND, type BrandTokens } from \"./brand\";\n\n// ── BrandContext (optional — lets deeply-nested components read the current tokens) ──\n\ninterface BrandContextValue extends Omit<BrandTokens, 'logoUrl'> {\n /** The resolved primary hex/HSL that is currently active (may be the Sentra default). */\n primaryHex: string;\n /** The resolved accent hex/HSL that is currently active (may be the Sentra default). */\n accentHex: string;\n /**\n * The RAW logo URL the tenant set, or null when none is configured.\n * Intentionally NOT defaulted to the Sentra logo: consumers (AdminLayout,\n * AuthCard) use null to decide \"no logo → render the icon mark instead\".\n * (operator 2026-06-05: everything was showing /sentra-logo-full.png — the\n * default — instead of the platform icon when no DB logo exists.)\n * The `--logo-url` CSS var (set by applyBrand) still falls back to the Sentra\n * default for pure background-image consumers; this context value does not.\n */\n logoUrl: string | null;\n /** Lucide icon name (e.g. 'ShieldCheck') for the platform mark. Null if unset. */\n iconName: string | null;\n /** Resolved product/platform name (for the sidebar title). Empty if unset. */\n productName: string;\n}\n\nconst BrandContext = createContext<BrandContextValue>({\n primaryHex: SENTRA_BRAND.primaryHex,\n accentHex: SENTRA_BRAND.accentHex,\n logoUrl: null,\n iconName: null,\n productName: \"\",\n});\n\n/**\n * useBrand — reads the currently-active brand tokens from context.\n *\n * Returns the Sentra defaults when no BrandingProvider is in the tree.\n * Only use this when a component genuinely needs to read the color values\n * (e.g. to pass them to a canvas API). For standard CSS theming the CSS\n * vars (hsl(var(--primary)) etc.) are always preferred.\n */\nexport function useBrand(): BrandContextValue {\n return useContext(BrandContext);\n}\n\n// ── BrandingProvider ───────────────────────────────────────────────────────\n\ninterface BrandingProviderProps extends BrandTokens {\n /** Lucide icon name for the platform mark (from Fort branding.icon). */\n iconName?: string | null;\n /** Product/platform display name (from Fort branding.product_name_*). */\n productName?: string;\n children: ReactNode;\n}\n\n/**\n * BrandingProvider — hot-applies org branding CSS vars and exposes the\n * active tokens via BrandContext.\n *\n * Renders no additional DOM nodes — it is a pure side-effect + context provider.\n *\n * Props (all optional — Sentra defaults fill any missing value):\n * primaryHex Hex \"#RRGGBB\" or HSL \"H S% L%\" for the brand primary color.\n * accentHex Hex \"#RRGGBB\" or HSL \"H S% L%\" for the brand accent color.\n * logoUrl Absolute URL or relative path to the org logo.\n */\nconst BrandingProvider = ({\n primaryHex,\n accentHex,\n logoUrl,\n iconName,\n productName,\n children,\n}: BrandingProviderProps) => {\n // Apply CSS vars on mount and whenever the brand tokens change.\n useEffect(() => {\n if (typeof document === \"undefined\") return; // SSR guard\n applyBrand(document.documentElement, { primaryHex, accentHex, logoUrl });\n }, [primaryHex, accentHex, logoUrl]);\n\n const contextValue: BrandContextValue = {\n primaryHex: primaryHex ?? SENTRA_BRAND.primaryHex,\n accentHex: accentHex ?? SENTRA_BRAND.accentHex,\n // RAW logo: null when the tenant has none (empty/whitespace counts as none),\n // so consumers fall back to the icon mark instead of the Sentra default PNG.\n logoUrl: logoUrl && logoUrl.trim() !== '' ? logoUrl : null,\n iconName: iconName ?? null,\n productName: productName ?? \"\",\n };\n\n return (\n <BrandContext.Provider value={contextValue}>\n {children}\n </BrandContext.Provider>\n );\n};\n\nBrandingProvider.displayName = \"BrandingProvider\";\n\nexport { BrandingProvider };\nexport type { BrandingProviderProps, BrandContextValue };","\"use client\";\n\nimport * as React from \"react\";\nimport { themes as defaultThemes, themeBase, STORAGE_KEY, type ThemeDef } from \"./themes\";\n\nexport type TogoTheme = \"dark\" | \"light\" | (string & {});\nexport type Dir = \"ltr\" | \"rtl\";\n\n/** Per-app brand overrides: any `--togo-*` (or bridged) custom property → value. */\nexport type ThemeOverrides = Record<string, string>;\n\nexport interface ThemeContextValue {\n theme: TogoTheme;\n setTheme: (t: TogoTheme) => void;\n themes: ThemeDef[];\n dir: Dir;\n setDir: (d: Dir) => void;\n}\n\nconst ThemeContext = React.createContext<ThemeContextValue | null>(null);\n\nexport interface ThemeProviderProps {\n theme?: TogoTheme;\n /** Per-app brand overrides applied as inline custom properties on the scope element. */\n overrides?: ThemeOverrides;\n dir?: Dir;\n /** \"html\" (default) themes <html>; \"self\" themes a wrapper div (so themes can coexist on one page). */\n scope?: \"html\" | \"self\";\n themes?: ThemeDef[];\n /** Persist theme/dir choice to localStorage and read it on first mount. */\n persist?: boolean;\n className?: string;\n children: React.ReactNode;\n}\n\nfunction applyToElement(el: HTMLElement, theme: string, dir: Dir, overrides?: ThemeOverrides) {\n el.setAttribute(\"data-theme\", theme);\n el.classList.toggle(\"dark\", themeBase(theme) === \"dark\");\n el.setAttribute(\"dir\", dir);\n if (overrides) for (const [k, v] of Object.entries(overrides)) el.style.setProperty(k, v);\n}\n\n/**\n * ThemeProvider — runtime theming. Sets `data-theme` + toggles `.dark` + `dir` on its\n * scope (the <html> element, or a wrapper when scope=\"self\"), applies per-app `overrides`\n * as inline custom properties, and exposes `useTheme()`. SSR-safe (no DOM access at module\n * top level; all mutations run in effects). For no-flash, also inline `themeInitScript`.\n */\nexport function ThemeProvider({\n theme: themeProp,\n overrides,\n dir: dirProp,\n scope = \"html\",\n themes = defaultThemes,\n persist = true,\n className,\n children,\n}: ThemeProviderProps) {\n const [theme, setThemeState] = React.useState<TogoTheme>(themeProp ?? \"dark\");\n const [dir, setDirState] = React.useState<Dir>(dirProp ?? \"ltr\");\n const selfRef = React.useRef<HTMLDivElement>(null);\n\n // First mount: hydrate from localStorage / prefers-color-scheme (only when uncontrolled).\n React.useEffect(() => {\n if (themeProp != null || !persist || typeof window === \"undefined\") return;\n const stored = window.localStorage.getItem(STORAGE_KEY);\n if (stored) setThemeState(stored);\n else if (window.matchMedia?.(\"(prefers-color-scheme: light)\").matches) setThemeState(\"light\");\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Keep state in sync when controlled.\n React.useEffect(() => { if (themeProp != null) setThemeState(themeProp); }, [themeProp]);\n React.useEffect(() => { if (dirProp != null) setDirState(dirProp); }, [dirProp]);\n\n const setTheme = React.useCallback((t: TogoTheme) => {\n setThemeState(t);\n if (persist && typeof window !== \"undefined\") window.localStorage.setItem(STORAGE_KEY, String(t));\n }, [persist]);\n\n const setDir = React.useCallback((d: Dir) => setDirState(d), []);\n\n // Apply to the chosen scope.\n React.useEffect(() => {\n if (typeof document === \"undefined\") return;\n const el = scope === \"self\" ? selfRef.current : document.documentElement;\n if (el) applyToElement(el, String(theme), dir, overrides);\n }, [theme, dir, overrides, scope]);\n\n const value = React.useMemo<ThemeContextValue>(() => ({ theme, setTheme, themes, dir, setDir }), [theme, setTheme, themes, dir, setDir]);\n\n return (\n <ThemeContext.Provider value={value}>\n {scope === \"self\" ? (\n <div\n ref={selfRef}\n data-theme={theme}\n dir={dir}\n className={[\"tg-root\", themeBase(String(theme)) === \"dark\" ? \"dark\" : \"\", \"bg-background text-foreground\", className].filter(Boolean).join(\" \")}\n style={overrides as React.CSSProperties}\n >\n {children}\n </div>\n ) : (\n children\n )}\n </ThemeContext.Provider>\n );\n}\nThemeProvider.displayName = \"ThemeProvider\";\n\nexport function useTheme(): ThemeContextValue {\n const ctx = React.useContext(ThemeContext);\n if (!ctx) throw new Error(\"useTheme must be used within a <ThemeProvider>\");\n return ctx;\n}\n","// ToGO theme registry. A theme is a `data-theme` value + a dark/light base (so the\n// existing `.dark`-driven utilities stay in sync). Add a tenant/brand theme by adding\n// one block to tokens.semantic.css and one entry here — no component changes.\n\nexport type ThemeBase = \"dark\" | \"light\";\n\nexport interface ThemeDef {\n id: string;\n label: string;\n /** Whether this theme toggles the `.dark` class (keeps `dark:` utilities in sync). */\n base: ThemeBase;\n /** Optional accent hex for swatch display (not used by ThemeProvider itself). */\n accent?: string;\n}\n\nexport const themes: ThemeDef[] = [\n { id: \"dark\", label: \"Dark\", base: \"dark\", accent: \"#1FC7DC\" },\n { id: \"light\", label: \"Light\", base: \"light\", accent: \"#1659C8\" },\n { id: \"purple\", label: \"Purple\", base: \"dark\", accent: \"#9B6DF5\" },\n { id: \"rose\", label: \"Rose\", base: \"dark\", accent: \"#F5427B\" },\n { id: \"emerald\", label: \"Emerald\", base: \"dark\", accent: \"#10B981\" },\n { id: \"purple-light\", label: \"Purple Light\", base: \"light\", accent: \"#7C3AED\" },\n { id: \"rose-light\", label: \"Rose Light\", base: \"light\", accent: \"#E11D48\" },\n { id: \"emerald-light\", label: \"Emerald Light\", base: \"light\", accent: \"#059669\" },\n];\n\nexport function themeBase(id: string): ThemeBase {\n return themes.find((t) => t.id === id)?.base ?? \"dark\";\n}\n\nexport const STORAGE_KEY = \"togo-theme\";\n\n/**\n * Inline this string in a <script> in <head> to set the theme before first paint\n * (no flash of the wrong theme). The framework injects it server-side.\n *\n * <script dangerouslySetInnerHTML={{ __html: themeInitScript }} />\n */\nexport const themeInitScript = `(function(){try{\nvar k=${JSON.stringify(STORAGE_KEY)};\nvar t=localStorage.getItem(k);\nif(!t){t=window.matchMedia&&window.matchMedia('(prefers-color-scheme: light)').matches?'light':'dark';}\nvar d=document.documentElement;\nd.setAttribute('data-theme',t);\nd.classList.toggle('dark', t!=='light');\n}catch(e){}})();`;\n","\"use client\";\n\n/**\n * ThemePicker — a compact dropdown that lists every registered theme with a colour\n * swatch and checks the currently active one. Wires directly to useTheme(); no\n * external props needed unless you want to pass a custom theme list.\n *\n * Design: semantic tokens only, RTL-safe, accessible (role=\"menuitemradio\").\n */\n\nimport * as React from \"react\";\nimport { Palette } from \"lucide-react\";\nimport { Button } from \"../components/ui/button\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"../components/ui/dropdown-menu\";\nimport { cn } from \"../lib/utils\";\nimport { useTheme } from \"./ThemeProvider\";\nimport { themes as defaultThemes, type ThemeDef } from \"./themes\";\n\nexport interface ThemePickerProps {\n /** Override the list of themes shown (defaults to the kit's built-in presets). */\n themes?: ThemeDef[];\n /** Button size */\n size?: \"sm\" | \"default\";\n className?: string;\n /** Label shown in the dropdown header (defaults to no header). */\n label?: string;\n}\n\n/** Colour swatch chip — 14 × 14 px circle with the theme's accent colour. */\nfunction Swatch({ color, className }: { color?: string; className?: string }) {\n if (!color) return null;\n return (\n <span\n className={cn(\"inline-block h-3.5 w-3.5 shrink-0 rounded-full border border-white/20\", className)}\n style={{ backgroundColor: color }}\n />\n );\n}\n\nexport function ThemePicker({ themes = defaultThemes, size = \"default\", className, label }: ThemePickerProps) {\n const { theme, setTheme } = useTheme();\n const current = themes.find((t) => t.id === theme) ?? themes[0];\n const iconCls = size === \"sm\" ? \"h-3.5 w-3.5\" : \"h-4 w-4\";\n const btnCls = size === \"sm\" ? \"h-7 w-7\" : \"h-8 w-8\";\n\n // Separate into dark-base and light-base groups.\n const dark = themes.filter((t) => t.base === \"dark\");\n const light = themes.filter((t) => t.base === \"light\");\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className={cn(btnCls, \"text-muted-foreground\", className)}\n aria-label=\"Switch theme\"\n >\n {current?.accent ? (\n <Swatch color={current.accent} className=\"h-4 w-4\" />\n ) : (\n <Palette className={iconCls} />\n )}\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-44\">\n {label && (\n <div className=\"px-2 py-1.5 text-xs font-medium text-muted-foreground\">{label}</div>\n )}\n <div className=\"px-2 py-1 text-[10px] uppercase tracking-wider text-muted-foreground/70\">Dark</div>\n {dark.map((t) => (\n <ThemeItem key={t.id} def={t} active={theme === t.id} onSelect={() => setTheme(t.id)} />\n ))}\n <DropdownMenuSeparator />\n <div className=\"px-2 py-1 text-[10px] uppercase tracking-wider text-muted-foreground/70\">Light</div>\n {light.map((t) => (\n <ThemeItem key={t.id} def={t} active={theme === t.id} onSelect={() => setTheme(t.id)} />\n ))}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\nfunction ThemeItem({ def, active, onSelect }: { def: ThemeDef; active: boolean; onSelect: () => void }) {\n return (\n <DropdownMenuItem\n role=\"menuitemradio\"\n aria-checked={active}\n onClick={onSelect}\n className={cn(\"flex items-center gap-2\", active && \"font-medium text-foreground\")}\n >\n <Swatch color={def.accent} />\n <span className=\"flex-1\">{def.label}</span>\n {active && (\n <span className=\"text-xs text-muted-foreground\">✓</span>\n )}\n </DropdownMenuItem>\n );\n}\n\nThemePicker.displayName = \"ThemePicker\";\n"],"mappings":"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","names":["jsx","themes","jsx","themes"]}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// src/lib/utils.ts
|
|
2
|
+
import { clsx } from "clsx";
|
|
3
|
+
import { twMerge } from "tailwind-merge";
|
|
4
|
+
function cn(...inputs) {
|
|
5
|
+
return twMerge(clsx(inputs));
|
|
6
|
+
}
|
|
7
|
+
function formatRelativeTime(isoString) {
|
|
8
|
+
const diff = Date.now() - new Date(isoString).getTime();
|
|
9
|
+
const mins = Math.floor(diff / 6e4);
|
|
10
|
+
if (mins < 1) return "just now";
|
|
11
|
+
if (mins < 60) return `${mins}m ago`;
|
|
12
|
+
const hours = Math.floor(mins / 60);
|
|
13
|
+
if (hours < 24) return `${hours}h ago`;
|
|
14
|
+
return `${Math.floor(hours / 24)}d ago`;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// src/components/ui/button.tsx
|
|
18
|
+
import * as React from "react";
|
|
19
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
20
|
+
import { cva } from "class-variance-authority";
|
|
21
|
+
import { jsx } from "react/jsx-runtime";
|
|
22
|
+
var buttonVariants = cva(
|
|
23
|
+
// Prism v2: token-driven motion (duration-fast/ease-standard), tactile press
|
|
24
|
+
// feedback (active:scale), elevation on solid variants, token focus ring.
|
|
25
|
+
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-all duration-fast ease-standard active:scale-[0.98] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
|
26
|
+
{
|
|
27
|
+
variants: {
|
|
28
|
+
variant: {
|
|
29
|
+
default: "bg-primary text-primary-foreground shadow-sm hover:bg-primary/90 hover:shadow-md",
|
|
30
|
+
destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90 hover:shadow-md",
|
|
31
|
+
outline: "border border-input bg-background shadow-xs hover:bg-primary/10 hover:text-primary hover:border-primary/40",
|
|
32
|
+
secondary: "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
|
|
33
|
+
ghost: "hover:bg-primary/10 hover:text-primary",
|
|
34
|
+
link: "text-primary underline-offset-4 hover:underline"
|
|
35
|
+
},
|
|
36
|
+
size: {
|
|
37
|
+
default: "h-10 px-4 py-2",
|
|
38
|
+
sm: "h-9 rounded-md px-3",
|
|
39
|
+
lg: "h-11 rounded-md px-8",
|
|
40
|
+
icon: "h-10 w-10"
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
defaultVariants: {
|
|
44
|
+
variant: "default",
|
|
45
|
+
size: "default"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
);
|
|
49
|
+
var Button = React.forwardRef(
|
|
50
|
+
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
51
|
+
const Comp = asChild ? Slot : "button";
|
|
52
|
+
return /* @__PURE__ */ jsx(Comp, { className: cn(buttonVariants({ variant, size, className })), ref, ...props });
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
Button.displayName = "Button";
|
|
56
|
+
|
|
57
|
+
// src/components/ui/dropdown-menu.tsx
|
|
58
|
+
import * as React2 from "react";
|
|
59
|
+
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
|
60
|
+
import { Check, ChevronRight, Circle } from "lucide-react";
|
|
61
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
62
|
+
var DropdownMenu = DropdownMenuPrimitive.Root;
|
|
63
|
+
var DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
|
|
64
|
+
var DropdownMenuGroup = DropdownMenuPrimitive.Group;
|
|
65
|
+
var DropdownMenuPortal = DropdownMenuPrimitive.Portal;
|
|
66
|
+
var DropdownMenuSub = DropdownMenuPrimitive.Sub;
|
|
67
|
+
var DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
|
|
68
|
+
var DropdownMenuSubTrigger = React2.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ jsxs(DropdownMenuPrimitive.SubTrigger, { ref, className: cn("flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[state=open]:bg-primary/10 focus:bg-primary/10", inset && "ps-8", className), ...props, children: [
|
|
69
|
+
children,
|
|
70
|
+
/* @__PURE__ */ jsx2(ChevronRight, { className: "ms-auto h-4 w-4 rtl:rotate-180" })
|
|
71
|
+
] }));
|
|
72
|
+
DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;
|
|
73
|
+
var DropdownMenuSubContent = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx2(DropdownMenuPrimitive.SubContent, { ref, className: cn("z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", className), ...props }));
|
|
74
|
+
DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;
|
|
75
|
+
var DropdownMenuContent = React2.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx2(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsx2(DropdownMenuPrimitive.Content, { ref, sideOffset, className: cn("z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", className), ...props }) }));
|
|
76
|
+
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
|
|
77
|
+
var DropdownMenuItem = React2.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx2(DropdownMenuPrimitive.Item, { ref, className: cn("relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors duration-fast ease-standard data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-primary/10 focus:text-primary", inset && "ps-8", className), ...props }));
|
|
78
|
+
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
|
|
79
|
+
var DropdownMenuCheckboxItem = React2.forwardRef(({ className, children, checked, ...props }, ref) => /* @__PURE__ */ jsxs(DropdownMenuPrimitive.CheckboxItem, { ref, className: cn("relative flex cursor-default select-none items-center rounded-sm py-1.5 ps-8 pe-2 text-sm outline-none transition-colors duration-fast ease-standard data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-primary/10 focus:text-primary", className), checked, ...props, children: [
|
|
80
|
+
/* @__PURE__ */ jsx2("span", { className: "absolute start-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx2(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx2(Check, { className: "h-4 w-4" }) }) }),
|
|
81
|
+
children
|
|
82
|
+
] }));
|
|
83
|
+
DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;
|
|
84
|
+
var DropdownMenuRadioItem = React2.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(DropdownMenuPrimitive.RadioItem, { ref, className: cn("relative flex cursor-default select-none items-center rounded-sm py-1.5 ps-8 pe-2 text-sm outline-none transition-colors duration-fast ease-standard data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-primary/10 focus:text-primary", className), ...props, children: [
|
|
85
|
+
/* @__PURE__ */ jsx2("span", { className: "absolute start-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx2(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx2(Circle, { className: "h-2 w-2 fill-current" }) }) }),
|
|
86
|
+
children
|
|
87
|
+
] }));
|
|
88
|
+
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
|
|
89
|
+
var DropdownMenuLabel = React2.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx2(DropdownMenuPrimitive.Label, { ref, className: cn("px-2 py-1.5 text-sm font-semibold", inset && "ps-8", className), ...props }));
|
|
90
|
+
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
|
|
91
|
+
var DropdownMenuSeparator = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx2(DropdownMenuPrimitive.Separator, { ref, className: cn("-mx-1 my-1 h-px bg-muted", className), ...props }));
|
|
92
|
+
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
|
|
93
|
+
var DropdownMenuShortcut = ({ className, ...props }) => /* @__PURE__ */ jsx2("span", { className: cn("ms-auto text-xs tracking-widest opacity-60", className), ...props });
|
|
94
|
+
DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
|
|
95
|
+
|
|
96
|
+
export {
|
|
97
|
+
cn,
|
|
98
|
+
formatRelativeTime,
|
|
99
|
+
buttonVariants,
|
|
100
|
+
Button,
|
|
101
|
+
DropdownMenu,
|
|
102
|
+
DropdownMenuTrigger,
|
|
103
|
+
DropdownMenuGroup,
|
|
104
|
+
DropdownMenuPortal,
|
|
105
|
+
DropdownMenuSub,
|
|
106
|
+
DropdownMenuRadioGroup,
|
|
107
|
+
DropdownMenuSubTrigger,
|
|
108
|
+
DropdownMenuSubContent,
|
|
109
|
+
DropdownMenuContent,
|
|
110
|
+
DropdownMenuItem,
|
|
111
|
+
DropdownMenuCheckboxItem,
|
|
112
|
+
DropdownMenuRadioItem,
|
|
113
|
+
DropdownMenuLabel,
|
|
114
|
+
DropdownMenuSeparator,
|
|
115
|
+
DropdownMenuShortcut
|
|
116
|
+
};
|
|
117
|
+
//# sourceMappingURL=chunk-NRF3KNQX.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/components/ui/button.tsx","../src/components/ui/dropdown-menu.tsx"],"sourcesContent":["import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\n/**\n * Format an ISO date string as a human-readable relative time string.\n * Identical behaviour to the app's formatRelativeTime util — kept here\n * so notification/profile components have no runtime dependency on the\n * app's lib.\n */\nexport function formatRelativeTime(isoString: string): string {\n const diff = Date.now() - new Date(isoString).getTime();\n const mins = Math.floor(diff / 60_000);\n if (mins < 1) return \"just now\";\n if (mins < 60) return `${mins}m ago`;\n const hours = Math.floor(mins / 60);\n if (hours < 24) return `${hours}h ago`;\n return `${Math.floor(hours / 24)}d ago`;\n}\n","'use client'\n\nimport * as React from \"react\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\nimport { cn } from \"../../lib/utils\";\n\nconst buttonVariants = cva(\n // Prism v2: token-driven motion (duration-fast/ease-standard), tactile press\n // feedback (active:scale), elevation on solid variants, token focus ring.\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-all duration-fast ease-standard active:scale-[0.98] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground shadow-sm hover:bg-primary/90 hover:shadow-md\",\n destructive: \"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90 hover:shadow-md\",\n outline: \"border border-input bg-background shadow-xs hover:bg-primary/10 hover:text-primary hover:border-primary/40\",\n secondary: \"bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80\",\n ghost: \"hover:bg-primary/10 hover:text-primary\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default: \"h-10 px-4 py-2\",\n sm: \"h-9 rounded-md px-3\",\n lg: \"h-11 rounded-md px-8\",\n icon: \"h-10 w-10\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n },\n);\n\nexport interface ButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof buttonVariants> {\n asChild?: boolean;\n}\n\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : \"button\";\n return <Comp className={cn(buttonVariants({ variant, size, className }))} ref={ref} {...props} />;\n },\n);\nButton.displayName = \"Button\";\n\nexport { Button, buttonVariants };\n","'use client'\n\nimport * as React from \"react\";\nimport * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport { Check, ChevronRight, Circle } from \"lucide-react\";\n\nimport { cn } from \"../../lib/utils\";\n\nconst DropdownMenu = DropdownMenuPrimitive.Root;\nconst DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;\nconst DropdownMenuGroup = DropdownMenuPrimitive.Group;\nconst DropdownMenuPortal = DropdownMenuPrimitive.Portal;\nconst DropdownMenuSub = DropdownMenuPrimitive.Sub;\nconst DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;\n\nconst DropdownMenuSubTrigger = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & { inset?: boolean }\n>(({ className, inset, children, ...props }, ref) => (\n <DropdownMenuPrimitive.SubTrigger ref={ref} className={cn(\"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[state=open]:bg-primary/10 focus:bg-primary/10\", inset && \"ps-8\", className)} {...props}>\n {children}\n <ChevronRight className=\"ms-auto h-4 w-4 rtl:rotate-180\" />\n </DropdownMenuPrimitive.SubTrigger>\n));\nDropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;\n\nconst DropdownMenuSubContent = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.SubContent ref={ref} className={cn(\"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\", className)} {...props} />\n));\nDropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;\n\nconst DropdownMenuContent = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>\n>(({ className, sideOffset = 4, ...props }, ref) => (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content ref={ref} sideOffset={sideOffset} className={cn(\"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\", className)} {...props} />\n </DropdownMenuPrimitive.Portal>\n));\nDropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;\n\nconst DropdownMenuItem = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & { inset?: boolean }\n>(({ className, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.Item ref={ref} className={cn(\"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors duration-fast ease-standard data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-primary/10 focus:text-primary\", inset && \"ps-8\", className)} {...props} />\n));\nDropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;\n\nconst DropdownMenuCheckboxItem = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>\n>(({ className, children, checked, ...props }, ref) => (\n <DropdownMenuPrimitive.CheckboxItem ref={ref} className={cn(\"relative flex cursor-default select-none items-center rounded-sm py-1.5 ps-8 pe-2 text-sm outline-none transition-colors duration-fast ease-standard data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-primary/10 focus:text-primary\", className)} checked={checked} {...props}>\n <span className=\"absolute start-2 flex h-3.5 w-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator><Check className=\"h-4 w-4\" /></DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.CheckboxItem>\n));\nDropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;\n\nconst DropdownMenuRadioItem = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>\n>(({ className, children, ...props }, ref) => (\n <DropdownMenuPrimitive.RadioItem ref={ref} className={cn(\"relative flex cursor-default select-none items-center rounded-sm py-1.5 ps-8 pe-2 text-sm outline-none transition-colors duration-fast ease-standard data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-primary/10 focus:text-primary\", className)} {...props}>\n <span className=\"absolute start-2 flex h-3.5 w-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator><Circle className=\"h-2 w-2 fill-current\" /></DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.RadioItem>\n));\nDropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;\n\nconst DropdownMenuLabel = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Label>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & { inset?: boolean }\n>(({ className, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.Label ref={ref} className={cn(\"px-2 py-1.5 text-sm font-semibold\", inset && \"ps-8\", className)} {...props} />\n));\nDropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;\n\nconst DropdownMenuSeparator = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Separator>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.Separator ref={ref} className={cn(\"-mx-1 my-1 h-px bg-muted\", className)} {...props} />\n));\nDropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;\n\nconst DropdownMenuShortcut = ({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) => (\n <span className={cn(\"ms-auto text-xs tracking-widest opacity-60\", className)} {...props} />\n);\nDropdownMenuShortcut.displayName = \"DropdownMenuShortcut\";\n\nexport { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuCheckboxItem, DropdownMenuRadioItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuGroup, DropdownMenuPortal, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuRadioGroup };\n"],"mappings":"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","names":["React","jsx"]}
|