@refraction-ui/react 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/theme.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../../theme/src/theme-machine.ts","../../theme/src/theme-script.ts","../../theme/src/dom-adapters.ts","../../react-theme/src/theme-provider.tsx","../../react-theme/src/theme-toggle.tsx","../../react-theme/src/theme-script-component.tsx"],"names":["React","React3"],"mappings":"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","file":"theme.js","sourcesContent":["/**\n * Headless theme state machine — pure TypeScript, zero DOM dependencies.\n * Manages light/dark/system mode with system preference tracking.\n */\n\nexport type ThemeMode = 'light' | 'dark' | 'system'\nexport type ResolvedTheme = 'light' | 'dark'\n\nexport interface ThemeState {\n /** User's chosen mode */\n mode: ThemeMode\n /** Resolved theme after system preference detection */\n resolved: ResolvedTheme\n}\n\nexport interface ThemeConfig {\n /** Initial mode. Default: 'system' */\n defaultMode?: ThemeMode\n /** localStorage key. Default: 'rfr-theme' */\n storageKey?: string\n /** HTML attribute to set. Default: 'class' */\n attribute?: 'class' | 'data-theme'\n}\n\nexport interface StorageAdapter {\n get(key: string): string | null\n set(key: string, value: string): void\n}\n\nexport interface MediaQueryAdapter {\n matches(query: string): boolean\n subscribe(query: string, callback: (matches: boolean) => void): () => void\n}\n\nexport interface ThemeAPI {\n /** Get current state */\n getState(): ThemeState\n /** Set mode (light/dark/system) */\n setMode(mode: ThemeMode): void\n /** Subscribe to state changes */\n subscribe(fn: (state: ThemeState) => void): () => void\n /** Clean up subscriptions */\n destroy(): void\n}\n\nfunction resolveTheme(mode: ThemeMode, systemPrefersDark: boolean): ResolvedTheme {\n if (mode === 'system') {\n return systemPrefersDark ? 'dark' : 'light'\n }\n return mode\n}\n\nexport function createTheme(\n config: ThemeConfig = {},\n storage?: StorageAdapter,\n mediaQuery?: MediaQueryAdapter,\n): ThemeAPI {\n const {\n defaultMode = 'system',\n storageKey = 'rfr-theme',\n } = config\n\n const listeners = new Set<(state: ThemeState) => void>()\n let cleanupMediaQuery: (() => void) | null = null\n\n // Read persisted mode or use default\n const persisted = storage?.get(storageKey) as ThemeMode | null\n let mode: ThemeMode = persisted && ['light', 'dark', 'system'].includes(persisted)\n ? persisted\n : defaultMode\n\n // Detect system preference\n let systemPrefersDark = mediaQuery?.matches('(prefers-color-scheme: dark)') ?? false\n\n let state: ThemeState = {\n mode,\n resolved: resolveTheme(mode, systemPrefersDark),\n }\n\n function notify() {\n for (const fn of listeners) {\n fn(state)\n }\n }\n\n function updateState(newMode: ThemeMode) {\n mode = newMode\n state = { mode, resolved: resolveTheme(mode, systemPrefersDark) }\n storage?.set(storageKey, mode)\n notify()\n }\n\n // Listen for system preference changes\n if (mediaQuery) {\n cleanupMediaQuery = mediaQuery.subscribe(\n '(prefers-color-scheme: dark)',\n (matches) => {\n systemPrefersDark = matches\n if (mode === 'system') {\n state = { mode, resolved: resolveTheme(mode, systemPrefersDark) }\n notify()\n }\n },\n )\n }\n\n return {\n getState() {\n return state\n },\n\n setMode(newMode: ThemeMode) {\n if (newMode !== mode) {\n updateState(newMode)\n }\n },\n\n subscribe(fn: (state: ThemeState) => void) {\n listeners.add(fn)\n return () => {\n listeners.delete(fn)\n }\n },\n\n destroy() {\n listeners.clear()\n cleanupMediaQuery?.()\n },\n }\n}\n","/**\n * Inline script for preventing theme flash on page load.\n * Inject this as a <script> tag in the <head> before any CSS.\n * Works with any framework (React, Angular, Astro, plain HTML).\n */\n\nexport function getThemeScript(\n storageKey = 'rfr-theme',\n attribute: 'class' | 'data-theme' = 'class',\n): string {\n // This string is injected as innerHTML of a <script> tag.\n // It runs before any CSS/JS loads, preventing flash of wrong theme.\n return `(function(){try{var m=localStorage.getItem('${storageKey}');var s=window.matchMedia('(prefers-color-scheme:dark)').matches;var t=m==='dark'||(m!=='light'&&s)?'dark':'light';var d=document.documentElement;${\n attribute === 'class'\n ? \"d.classList.remove('light','dark');d.classList.add(t);\"\n : `d.setAttribute('${attribute}',t);`\n }d.style.colorScheme=t;}catch(e){}})()`\n}\n","/**\n * Browser DOM adapters for the theme machine.\n * These bridge the headless core to browser APIs.\n */\n\nimport type { StorageAdapter, MediaQueryAdapter, ResolvedTheme } from './theme-machine.js'\n\n/** localStorage adapter */\nexport function createLocalStorageAdapter(): StorageAdapter {\n return {\n get(key) {\n try {\n return localStorage.getItem(key)\n } catch {\n return null\n }\n },\n set(key, value) {\n try {\n localStorage.setItem(key, value)\n } catch {\n // localStorage unavailable (SSR, incognito quota exceeded, etc.)\n }\n },\n }\n}\n\n/** matchMedia adapter */\nexport function createMediaQueryAdapter(): MediaQueryAdapter {\n return {\n matches(query) {\n if (typeof window === 'undefined') return false\n return window.matchMedia(query).matches\n },\n subscribe(query, callback) {\n if (typeof window === 'undefined') return () => {}\n const mql = window.matchMedia(query)\n const handler = (e: MediaQueryListEvent) => callback(e.matches)\n mql.addEventListener('change', handler)\n return () => mql.removeEventListener('change', handler)\n },\n }\n}\n\n/** Apply resolved theme to the document */\nexport function applyThemeToDOM(\n resolved: ResolvedTheme,\n attribute: 'class' | 'data-theme' = 'class',\n): void {\n if (typeof document === 'undefined') return\n\n const root = document.documentElement\n if (attribute === 'class') {\n root.classList.remove('light', 'dark')\n root.classList.add(resolved)\n } else {\n root.setAttribute(attribute, resolved)\n }\n root.style.colorScheme = resolved\n}\n","import * as React from 'react'\nimport {\n createTheme,\n createLocalStorageAdapter,\n createMediaQueryAdapter,\n applyThemeToDOM,\n type ThemeMode,\n type ResolvedTheme,\n type ThemeConfig,\n type ThemeAPI,\n} from '@refraction-ui/theme'\n\nexport interface ThemeContextValue {\n mode: ThemeMode\n resolved: ResolvedTheme\n setMode: (mode: ThemeMode) => void\n}\n\nconst ThemeContext = React.createContext<ThemeContextValue | null>(null)\n\nexport interface ThemeProviderProps extends ThemeConfig {\n children: React.ReactNode\n}\n\nexport function ThemeProvider({\n children,\n defaultMode = 'system',\n storageKey = 'rfr-theme',\n attribute = 'class',\n}: ThemeProviderProps) {\n const themeRef = React.useRef<ThemeAPI | null>(null)\n\n // Initialize theme machine once (client-side only for adapters)\n if (!themeRef.current) {\n const isBrowser = typeof window !== 'undefined'\n themeRef.current = createTheme(\n { defaultMode, storageKey, attribute },\n isBrowser ? createLocalStorageAdapter() : undefined,\n isBrowser ? createMediaQueryAdapter() : undefined,\n )\n }\n\n const [state, setState] = React.useState(() => themeRef.current!.getState())\n\n React.useEffect(() => {\n const theme = themeRef.current!\n // Apply initial theme to DOM\n applyThemeToDOM(theme.getState().resolved, attribute)\n\n // Subscribe to changes\n const unsub = theme.subscribe((newState) => {\n setState(newState)\n applyThemeToDOM(newState.resolved, attribute)\n })\n\n return () => {\n unsub()\n theme.destroy()\n }\n }, [attribute])\n\n const contextValue = React.useMemo<ThemeContextValue>(\n () => ({\n mode: state.mode,\n resolved: state.resolved,\n setMode: (mode: ThemeMode) => themeRef.current?.setMode(mode),\n }),\n [state.mode, state.resolved],\n )\n\n return React.createElement(ThemeContext.Provider, { value: contextValue }, children)\n}\n\nexport function useTheme(): ThemeContextValue {\n const context = React.useContext(ThemeContext)\n if (!context) {\n throw new Error('useTheme must be used within a <ThemeProvider>')\n }\n return context\n}\n","import * as React from 'react'\nimport { useTheme } from './theme-provider.js'\nimport type { ThemeMode } from '@refraction-ui/theme'\n\nconst modes: { value: ThemeMode; label: string; icon: string }[] = [\n { value: 'light', label: 'Light', icon: 'sun' },\n { value: 'dark', label: 'Dark', icon: 'moon' },\n { value: 'system', label: 'System', icon: 'monitor' },\n]\n\n// Inline SVG icons — no external icon library dependency\nconst icons: Record<string, React.ReactNode> = {\n sun: React.createElement('svg', {\n xmlns: 'http://www.w3.org/2000/svg', width: 16, height: 16, viewBox: '0 0 24 24',\n fill: 'none', stroke: 'currentColor', strokeWidth: 2, strokeLinecap: 'round', strokeLinejoin: 'round',\n },\n React.createElement('circle', { cx: 12, cy: 12, r: 5 }),\n React.createElement('path', { d: 'M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42' }),\n ),\n moon: React.createElement('svg', {\n xmlns: 'http://www.w3.org/2000/svg', width: 16, height: 16, viewBox: '0 0 24 24',\n fill: 'none', stroke: 'currentColor', strokeWidth: 2, strokeLinecap: 'round', strokeLinejoin: 'round',\n },\n React.createElement('path', { d: 'M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z' }),\n ),\n monitor: React.createElement('svg', {\n xmlns: 'http://www.w3.org/2000/svg', width: 16, height: 16, viewBox: '0 0 24 24',\n fill: 'none', stroke: 'currentColor', strokeWidth: 2, strokeLinecap: 'round', strokeLinejoin: 'round',\n },\n React.createElement('rect', { x: 2, y: 3, width: 20, height: 14, rx: 2, ry: 2 }),\n React.createElement('line', { x1: 8, y1: 21, x2: 16, y2: 21 }),\n React.createElement('line', { x1: 12, y1: 17, x2: 12, y2: 21 }),\n ),\n}\n\nexport interface ThemeToggleProps {\n className?: string\n /** 'dropdown' shows a menu, 'segmented' shows inline buttons */\n variant?: 'dropdown' | 'segmented'\n}\n\nexport function ThemeToggle({ className, variant = 'segmented' }: ThemeToggleProps) {\n const { mode, setMode } = useTheme()\n\n if (variant === 'segmented') {\n return React.createElement('div', {\n className: `inline-flex items-center gap-1 rounded-lg border p-1 ${className ?? ''}`,\n role: 'radiogroup',\n 'aria-label': 'Theme',\n },\n modes.map(({ value, label, icon }) =>\n React.createElement('button', {\n key: value,\n type: 'button',\n role: 'radio',\n 'aria-checked': mode === value,\n 'aria-label': label,\n className: `inline-flex items-center justify-center rounded-md p-1.5 text-sm transition-colors ${\n mode === value\n ? 'bg-accent text-accent-foreground'\n : 'text-muted-foreground hover:bg-muted'\n }`,\n onClick: () => setMode(value),\n }, icons[icon]),\n ),\n )\n }\n\n // Dropdown variant — simplified, no external dropdown dependency\n const [open, setOpen] = React.useState(false)\n const ref = React.useRef<HTMLDivElement>(null)\n\n React.useEffect(() => {\n if (!open) return\n const handler = (e: MouseEvent) => {\n if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false)\n }\n document.addEventListener('mousedown', handler)\n return () => document.removeEventListener('mousedown', handler)\n }, [open])\n\n const currentIcon = modes.find((m) => m.value === mode)?.icon ?? 'monitor'\n\n return React.createElement('div', { ref, className: `relative ${className ?? ''}` },\n React.createElement('button', {\n type: 'button',\n 'aria-label': 'Toggle theme',\n 'aria-expanded': open,\n className: 'inline-flex items-center justify-center rounded-md p-2 text-sm transition-colors hover:bg-muted',\n onClick: () => setOpen(!open),\n }, icons[currentIcon]),\n open && React.createElement('div', {\n className: 'absolute right-0 top-full mt-1 z-50 min-w-[8rem] rounded-md border bg-popover p-1 shadow-md',\n role: 'menu',\n },\n modes.map(({ value, label, icon }) =>\n React.createElement('button', {\n key: value,\n type: 'button',\n role: 'menuitem',\n className: `flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-sm transition-colors hover:bg-accent ${\n mode === value ? 'bg-accent' : ''\n }`,\n onClick: () => { setMode(value); setOpen(false) },\n }, icons[icon], label),\n ),\n ),\n )\n}\n","import * as React from 'react'\nimport { getThemeScript } from '@refraction-ui/theme'\n\nexport interface ThemeScriptProps {\n storageKey?: string\n attribute?: 'class' | 'data-theme'\n}\n\n/**\n * Renders an inline <script> that prevents theme flash on SSR pages.\n * Place this in the <head> of your document (in Next.js layout.tsx, Remix root, etc.)\n */\nexport function ThemeScript({\n storageKey = 'rfr-theme',\n attribute = 'class',\n}: ThemeScriptProps) {\n return React.createElement('script', {\n dangerouslySetInnerHTML: {\n __html: getThemeScript(storageKey, attribute),\n },\n })\n}\n"]}
1
+ {"version":3,"sources":["../../theme/src/theme-machine.ts","../../theme/src/theme-script.ts","../../theme/src/dom-adapters.ts","../../react-theme/src/theme-provider.tsx","../../react-theme/src/theme-toggle.tsx","../../react-theme/src/theme-script-component.tsx"],"names":["React","React3"],"mappings":"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","file":"theme.js","sourcesContent":["/**\n * Headless theme state machine — pure TypeScript, zero DOM dependencies.\n * Manages light/dark/system mode with system preference tracking.\n */\n\nexport type ThemeMode = 'light' | 'dark' | 'system'\nexport type ResolvedTheme = 'light' | 'dark'\n\nexport interface ThemeState {\n /** User's chosen mode */\n mode: ThemeMode\n /** Resolved theme after system preference detection */\n resolved: ResolvedTheme\n}\n\nexport interface ThemeConfig {\n /** Initial mode. Default: 'system' */\n defaultMode?: ThemeMode\n /** localStorage key. Default: 'rfr-theme' */\n storageKey?: string\n /** HTML attribute to set. Default: 'class' */\n attribute?: 'class' | 'data-theme'\n}\n\nexport interface StorageAdapter {\n get(key: string): string | null\n set(key: string, value: string): void\n}\n\nexport interface MediaQueryAdapter {\n matches(query: string): boolean\n subscribe(query: string, callback: (matches: boolean) => void): () => void\n}\n\nexport interface ThemeAPI {\n /** Get current state */\n getState(): ThemeState\n /** Set mode (light/dark/system) */\n setMode(mode: ThemeMode): void\n /** Subscribe to state changes */\n subscribe(fn: (state: ThemeState) => void): () => void\n /** Clean up subscriptions */\n destroy(): void\n}\n\nfunction resolveTheme(mode: ThemeMode, systemPrefersDark: boolean): ResolvedTheme {\n if (mode === 'system') {\n return systemPrefersDark ? 'dark' : 'light'\n }\n return mode\n}\n\nexport function createTheme(\n config: ThemeConfig = {},\n storage?: StorageAdapter,\n mediaQuery?: MediaQueryAdapter,\n): ThemeAPI {\n const {\n defaultMode = 'system',\n storageKey = 'rfr-theme',\n } = config\n\n const listeners = new Set<(state: ThemeState) => void>()\n let cleanupMediaQuery: (() => void) | null = null\n\n // Read persisted mode or use default\n const persisted = storage?.get(storageKey) as ThemeMode | null\n let mode: ThemeMode = persisted && ['light', 'dark', 'system'].includes(persisted)\n ? persisted\n : defaultMode\n\n // Detect system preference\n let systemPrefersDark = mediaQuery?.matches('(prefers-color-scheme: dark)') ?? false\n\n let state: ThemeState = {\n mode,\n resolved: resolveTheme(mode, systemPrefersDark),\n }\n\n function notify() {\n for (const fn of listeners) {\n fn(state)\n }\n }\n\n function updateState(newMode: ThemeMode) {\n mode = newMode\n state = { mode, resolved: resolveTheme(mode, systemPrefersDark) }\n storage?.set(storageKey, mode)\n notify()\n }\n\n // Listen for system preference changes\n if (mediaQuery) {\n cleanupMediaQuery = mediaQuery.subscribe(\n '(prefers-color-scheme: dark)',\n (matches) => {\n systemPrefersDark = matches\n if (mode === 'system') {\n state = { mode, resolved: resolveTheme(mode, systemPrefersDark) }\n notify()\n }\n },\n )\n }\n\n return {\n getState() {\n return state\n },\n\n setMode(newMode: ThemeMode) {\n if (newMode !== mode) {\n updateState(newMode)\n }\n },\n\n subscribe(fn: (state: ThemeState) => void) {\n listeners.add(fn)\n return () => {\n listeners.delete(fn)\n }\n },\n\n destroy() {\n listeners.clear()\n cleanupMediaQuery?.()\n },\n }\n}\n","/**\n * Inline script for preventing theme flash on page load.\n * Inject this as a <script> tag in the <head> before any CSS.\n * Works with any framework (React, Angular, Astro, plain HTML).\n */\n\nexport function getThemeScript(\n storageKey = 'rfr-theme',\n attribute: 'class' | 'data-theme' = 'class',\n): string {\n // This string is injected as innerHTML of a <script> tag.\n // It runs before any CSS/JS loads, preventing flash of wrong theme.\n return `(function(){try{var m=localStorage.getItem('${storageKey}');var s=window.matchMedia('(prefers-color-scheme:dark)').matches;var t=m==='dark'||(m!=='light'&&s)?'dark':'light';var d=document.documentElement;${\n attribute === 'class'\n ? \"d.classList.remove('light','dark');d.classList.add(t);\"\n : `d.setAttribute('${attribute}',t);`\n }d.style.colorScheme=t;}catch(e){}})()`\n}\n","/**\n * Browser DOM adapters for the theme machine.\n * These bridge the headless core to browser APIs.\n */\n\nimport type { StorageAdapter, MediaQueryAdapter, ResolvedTheme } from './theme-machine.js'\n\n/** localStorage adapter */\nexport function createLocalStorageAdapter(): StorageAdapter {\n return {\n get(key) {\n try {\n return localStorage.getItem(key)\n } catch {\n return null\n }\n },\n set(key, value) {\n try {\n localStorage.setItem(key, value)\n } catch {\n // localStorage unavailable (SSR, incognito quota exceeded, etc.)\n }\n },\n }\n}\n\n/** matchMedia adapter */\nexport function createMediaQueryAdapter(): MediaQueryAdapter {\n return {\n matches(query) {\n if (typeof window === 'undefined') return false\n return window.matchMedia(query).matches\n },\n subscribe(query, callback) {\n if (typeof window === 'undefined') return () => {}\n const mql = window.matchMedia(query)\n const handler = (e: MediaQueryListEvent) => callback(e.matches)\n mql.addEventListener('change', handler)\n return () => mql.removeEventListener('change', handler)\n },\n }\n}\n\n/** Apply resolved theme to the document */\nexport function applyThemeToDOM(\n resolved: ResolvedTheme,\n attribute: 'class' | 'data-theme' = 'class',\n): void {\n if (typeof document === 'undefined') return\n\n const root = document.documentElement\n if (attribute === 'class') {\n root.classList.remove('light', 'dark')\n root.classList.add(resolved)\n } else {\n root.setAttribute(attribute, resolved)\n }\n root.style.colorScheme = resolved\n}\n","import * as React from 'react'\nimport {\n createTheme,\n createLocalStorageAdapter,\n createMediaQueryAdapter,\n applyThemeToDOM,\n type ThemeMode,\n type ResolvedTheme,\n type ThemeConfig,\n type ThemeAPI,\n} from '@refraction-ui/theme'\nimport { devWarn } from '@refraction-ui/shared'\n\nexport interface ThemeContextValue {\n mode: ThemeMode\n resolved: ResolvedTheme\n setMode: (mode: ThemeMode) => void\n}\n\nconst ThemeContext = React.createContext<ThemeContextValue | null>(null)\n\nexport interface ThemeProviderProps extends ThemeConfig {\n children: React.ReactNode\n}\n\nexport function ThemeProvider({\n children,\n defaultMode = 'system',\n storageKey = 'rfr-theme',\n attribute = 'class',\n}: ThemeProviderProps) {\n const themeRef = React.useRef<ThemeAPI | null>(null)\n\n // Initialize theme machine once (client-side only for adapters)\n if (!themeRef.current) {\n const isBrowser = typeof window !== 'undefined'\n themeRef.current = createTheme(\n { defaultMode, storageKey, attribute },\n isBrowser ? createLocalStorageAdapter() : undefined,\n isBrowser ? createMediaQueryAdapter() : undefined,\n )\n }\n\n const [state, setState] = React.useState(() => themeRef.current!.getState())\n\n React.useEffect(() => {\n const theme = themeRef.current!\n // Apply initial theme to DOM\n applyThemeToDOM(theme.getState().resolved, attribute)\n\n // Subscribe to changes\n const unsub = theme.subscribe((newState) => {\n setState(newState)\n applyThemeToDOM(newState.resolved, attribute)\n })\n\n return () => {\n unsub()\n theme.destroy()\n }\n }, [attribute])\n\n const contextValue = React.useMemo<ThemeContextValue>(\n () => ({\n mode: state.mode,\n resolved: state.resolved,\n setMode: (mode: ThemeMode) => themeRef.current?.setMode(mode),\n }),\n [state.mode, state.resolved],\n )\n\n return React.createElement(ThemeContext.Provider, { value: contextValue }, children)\n}\n\nexport function useTheme(): ThemeContextValue {\n const context = React.useContext(ThemeContext)\n if (!context) {\n devWarn(\n 'react-theme/use-theme-outside-provider',\n 'useTheme() was called outside a <ThemeProvider>. Wrap your app (or the consuming subtree) in <ThemeProvider> so the theme context is available.',\n )\n throw new Error('useTheme must be used within a <ThemeProvider>')\n }\n return context\n}\n","import * as React from 'react'\nimport { useTheme } from './theme-provider.js'\nimport type { ThemeMode } from '@refraction-ui/theme'\n\nconst modes: { value: ThemeMode; label: string; icon: string }[] = [\n { value: 'light', label: 'Light', icon: 'sun' },\n { value: 'dark', label: 'Dark', icon: 'moon' },\n { value: 'system', label: 'System', icon: 'monitor' },\n]\n\n// Inline SVG icons — no external icon library dependency\nconst icons: Record<string, React.ReactNode> = {\n sun: React.createElement('svg', {\n xmlns: 'http://www.w3.org/2000/svg', width: 16, height: 16, viewBox: '0 0 24 24',\n fill: 'none', stroke: 'currentColor', strokeWidth: 2, strokeLinecap: 'round', strokeLinejoin: 'round',\n },\n React.createElement('circle', { cx: 12, cy: 12, r: 5 }),\n React.createElement('path', { d: 'M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42' }),\n ),\n moon: React.createElement('svg', {\n xmlns: 'http://www.w3.org/2000/svg', width: 16, height: 16, viewBox: '0 0 24 24',\n fill: 'none', stroke: 'currentColor', strokeWidth: 2, strokeLinecap: 'round', strokeLinejoin: 'round',\n },\n React.createElement('path', { d: 'M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z' }),\n ),\n monitor: React.createElement('svg', {\n xmlns: 'http://www.w3.org/2000/svg', width: 16, height: 16, viewBox: '0 0 24 24',\n fill: 'none', stroke: 'currentColor', strokeWidth: 2, strokeLinecap: 'round', strokeLinejoin: 'round',\n },\n React.createElement('rect', { x: 2, y: 3, width: 20, height: 14, rx: 2, ry: 2 }),\n React.createElement('line', { x1: 8, y1: 21, x2: 16, y2: 21 }),\n React.createElement('line', { x1: 12, y1: 17, x2: 12, y2: 21 }),\n ),\n}\n\nexport interface ThemeToggleProps {\n className?: string\n /** 'dropdown' shows a menu, 'segmented' shows inline buttons */\n variant?: 'dropdown' | 'segmented'\n}\n\nexport function ThemeToggle({ className, variant = 'segmented' }: ThemeToggleProps) {\n const { mode, setMode } = useTheme()\n\n if (variant === 'segmented') {\n return React.createElement('div', {\n className: `inline-flex items-center gap-1 rounded-lg border p-1 ${className ?? ''}`,\n role: 'radiogroup',\n 'aria-label': 'Theme',\n },\n modes.map(({ value, label, icon }) =>\n React.createElement('button', {\n key: value,\n type: 'button',\n role: 'radio',\n 'aria-checked': mode === value,\n 'aria-label': label,\n className: `inline-flex items-center justify-center rounded-md p-1.5 text-sm transition-colors ${\n mode === value\n ? 'bg-accent text-accent-foreground'\n : 'text-muted-foreground hover:bg-muted'\n }`,\n onClick: () => setMode(value),\n }, icons[icon]),\n ),\n )\n }\n\n // Dropdown variant — simplified, no external dropdown dependency\n const [open, setOpen] = React.useState(false)\n const ref = React.useRef<HTMLDivElement>(null)\n\n React.useEffect(() => {\n if (!open) return\n const handler = (e: MouseEvent) => {\n if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false)\n }\n document.addEventListener('mousedown', handler)\n return () => document.removeEventListener('mousedown', handler)\n }, [open])\n\n const currentIcon = modes.find((m) => m.value === mode)?.icon ?? 'monitor'\n\n return React.createElement('div', { ref, className: `relative ${className ?? ''}` },\n React.createElement('button', {\n type: 'button',\n 'aria-label': 'Toggle theme',\n 'aria-expanded': open,\n className: 'inline-flex items-center justify-center rounded-md p-2 text-sm transition-colors hover:bg-muted',\n onClick: () => setOpen(!open),\n }, icons[currentIcon]),\n open && React.createElement('div', {\n className: 'absolute right-0 top-full mt-1 z-50 min-w-[8rem] rounded-md border bg-popover p-1 shadow-md',\n role: 'menu',\n },\n modes.map(({ value, label, icon }) =>\n React.createElement('button', {\n key: value,\n type: 'button',\n role: 'menuitem',\n className: `flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-sm transition-colors hover:bg-accent ${\n mode === value ? 'bg-accent' : ''\n }`,\n onClick: () => { setMode(value); setOpen(false) },\n }, icons[icon], label),\n ),\n ),\n )\n}\n","import * as React from 'react'\nimport { getThemeScript } from '@refraction-ui/theme'\n\nexport interface ThemeScriptProps {\n storageKey?: string\n attribute?: 'class' | 'data-theme'\n}\n\n/**\n * Renders an inline <script> that prevents theme flash on SSR pages.\n * Place this in the <head> of your document (in Next.js layout.tsx, Remix root, etc.)\n */\nexport function ThemeScript({\n storageKey = 'rfr-theme',\n attribute = 'class',\n}: ThemeScriptProps) {\n return React.createElement('script', {\n dangerouslySetInnerHTML: {\n __html: getThemeScript(storageKey, attribute),\n },\n })\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@refraction-ui/react",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "All Refraction UI React components in one package — headless, accessible, zero-dependency",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -133,7 +133,9 @@
133
133
  "@refraction-ui/react-card-grid": "workspace:*",
134
134
  "@refraction-ui/react-payment": "workspace:*",
135
135
  "@refraction-ui/react-command-input": "workspace:*",
136
- "@refraction-ui/react-sheet": "workspace:*"
136
+ "@refraction-ui/react-sheet": "workspace:*",
137
+ "@refraction-ui/react-logger": "workspace:*",
138
+ "@refraction-ui/react-analytics": "workspace:*"
137
139
  },
138
140
  "publishConfig": {
139
141
  "access": "public"
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../shared/src/aria.ts","../../shared/src/keyboard.ts","../../shared/src/state-machine.ts","../../shared/src/cn.ts","../../shared/src/cva.ts"],"names":[],"mappings":"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","file":"chunk-ZWRGVWUY.js","sourcesContent":["/** Merge multiple ARIA prop objects, later values override earlier ones */\nexport function mergeAriaProps(\n ...propSets: Array<Record<string, unknown>>\n): Record<string, unknown> {\n const result: Record<string, unknown> = {}\n for (const props of propSets) {\n for (const [key, value] of Object.entries(props)) {\n if (value !== undefined) {\n result[key] = value\n }\n }\n }\n return result\n}\n\nlet idCounter = 0\n\n/**\n * Generate a unique ID, safe for SSR (deterministic within a render pass).\n * In browsers, uses crypto.randomUUID when available.\n */\nexport function generateId(prefix = 'rfr'): string {\n idCounter++\n return `${prefix}-${idCounter}`\n}\n\n/** Reset the ID counter (useful for tests) */\nexport function resetIdCounter(): void {\n idCounter = 0\n}\n","/** Standard keyboard key constants */\nexport const Keys = {\n Enter: 'Enter',\n Space: ' ',\n Escape: 'Escape',\n Tab: 'Tab',\n ArrowUp: 'ArrowUp',\n ArrowDown: 'ArrowDown',\n ArrowLeft: 'ArrowLeft',\n ArrowRight: 'ArrowRight',\n Home: 'Home',\n End: 'End',\n PageUp: 'PageUp',\n PageDown: 'PageDown',\n Backspace: 'Backspace',\n Delete: 'Delete',\n} as const\n\nexport type KeyboardKey = (typeof Keys)[keyof typeof Keys]\n\n/** Map of key → handler function */\nexport type KeyboardHandlerMap = Partial<\n Record<string, (event: KeyboardEvent) => void>\n>\n\n/** Create a keyboard event handler from a handler map */\nexport function createKeyboardHandler(\n handlers: KeyboardHandlerMap,\n): (event: KeyboardEvent) => void {\n return (event: KeyboardEvent) => {\n const handler = handlers[event.key]\n if (handler) {\n handler(event)\n }\n }\n}\n","/**\n * Minimal state machine — zero dependencies, < 1KB.\n * Inspired by XState concepts but dramatically simpler.\n */\n\nexport interface MachineConfig<TState extends string, TEvent extends string> {\n initial: TState\n states: Record<TState, {\n on?: Partial<Record<TEvent, TState>>\n }>\n}\n\nexport interface Machine<TState extends string, TEvent extends string> {\n /** Current state */\n state: TState\n /** Send an event to transition */\n send(event: TEvent): void\n /** Subscribe to state changes. Returns unsubscribe function. */\n subscribe(fn: (state: TState) => void): () => void\n /** Check if machine is in a given state */\n matches(state: TState): boolean\n}\n\nexport function createMachine<TState extends string, TEvent extends string>(\n config: MachineConfig<TState, TEvent>,\n): Machine<TState, TEvent> {\n let current = config.initial\n const listeners = new Set<(state: TState) => void>()\n\n return {\n get state() {\n return current\n },\n\n send(event: TEvent) {\n const stateConfig = config.states[current]\n const next = stateConfig?.on?.[event]\n if (next && next !== current) {\n current = next\n for (const fn of listeners) {\n fn(current)\n }\n }\n },\n\n subscribe(fn: (state: TState) => void) {\n listeners.add(fn)\n return () => {\n listeners.delete(fn)\n }\n },\n\n matches(state: TState) {\n return current === state\n },\n }\n}\n","/**\n * Lightweight class name utility — our own implementation.\n * Handles conditional classes, arrays, and falsy values.\n * No external dependencies (no clsx, no tailwind-merge).\n *\n * For Tailwind class conflict resolution (e.g., 'p-2 p-4' → 'p-4'),\n * consumers can use @refraction-ui/tailwind-config which provides\n * a tw-merge-aware variant of this function.\n */\n\ntype ClassValue = string | number | boolean | undefined | null | ClassValue[]\ntype ClassRecord = Record<string, boolean | undefined | null>\n\nexport function cn(...inputs: Array<ClassValue | ClassRecord>): string {\n const classes: string[] = []\n\n for (const input of inputs) {\n if (!input) continue\n\n if (typeof input === 'string') {\n classes.push(input)\n } else if (typeof input === 'number') {\n classes.push(String(input))\n } else if (Array.isArray(input)) {\n const nested = cn(...input)\n if (nested) classes.push(nested)\n } else if (typeof input === 'object') {\n for (const [key, value] of Object.entries(input)) {\n if (value) classes.push(key)\n }\n }\n }\n\n return classes.join(' ')\n}\n","/**\n * Lightweight class-variance-authority alternative — zero dependencies.\n * Creates variant-driven class name functions for components.\n */\n\ninterface VariantConfig {\n [variant: string]: Record<string, string>\n}\n\ninterface CVAConfig<V extends VariantConfig> {\n base?: string\n variants?: V\n defaultVariants?: {\n [K in keyof V]?: keyof V[K]\n }\n compoundVariants?: Array<\n {\n [K in keyof V]?: keyof V[K]\n } & { class: string }\n >\n}\n\ntype VariantProps<V extends VariantConfig> = {\n [K in keyof V]?: keyof V[K]\n}\n\nexport function cva<V extends VariantConfig>(config: CVAConfig<V>) {\n return (props?: VariantProps<V> & { className?: string }): string => {\n const classes: string[] = []\n\n if (config.base) {\n classes.push(config.base)\n }\n\n if (config.variants) {\n for (const [variantKey, variantOptions] of Object.entries(config.variants)) {\n const selectedValue =\n (props as Record<string, unknown> | undefined)?.[variantKey] ??\n config.defaultVariants?.[variantKey]\n\n if (selectedValue != null) {\n const variantClass = (variantOptions as Record<string, string>)[\n selectedValue as string\n ]\n if (variantClass) {\n classes.push(variantClass)\n }\n }\n }\n }\n\n if (config.compoundVariants) {\n for (const compound of config.compoundVariants) {\n const { class: compoundClass, ...conditions } = compound\n let matches = true\n\n for (const [key, value] of Object.entries(conditions)) {\n const propValue =\n (props as Record<string, unknown>)?.[key] ??\n config.defaultVariants?.[key]\n if (propValue !== value) {\n matches = false\n break\n }\n }\n\n if (matches) {\n classes.push(compoundClass as string)\n }\n }\n }\n\n if (props?.className) {\n classes.push(props.className)\n }\n\n return classes.filter(Boolean).join(' ')\n }\n}\n"]}