@waveso/ui 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/accordion.js +2 -2
- package/dist/accordion.js.map +1 -1
- package/dist/action-bar.js +2 -2
- package/dist/action-bar.js.map +1 -1
- package/dist/alert-dialog.js +4 -4
- package/dist/alert-dialog.js.map +1 -1
- package/dist/alert.js +5 -5
- package/dist/alert.js.map +1 -1
- package/dist/animate.d.ts.map +1 -1
- package/dist/animate.js +1 -2
- package/dist/animate.js.map +1 -1
- package/dist/autocomplete.js +8 -8
- package/dist/autocomplete.js.map +1 -1
- package/dist/avatar.js +5 -5
- package/dist/avatar.js.map +1 -1
- package/dist/badge.d.ts +1 -1
- package/dist/badge.d.ts.map +1 -1
- package/dist/badge.js +5 -6
- package/dist/badge.js.map +1 -1
- package/dist/breadcrumb.js +3 -3
- package/dist/breadcrumb.js.map +1 -1
- package/dist/button-group.js +5 -5
- package/dist/button-group.js.map +1 -1
- package/dist/button.d.ts +1 -1
- package/dist/button.d.ts.map +1 -1
- package/dist/button.js +9 -10
- package/dist/button.js.map +1 -1
- package/dist/card.js +4 -4
- package/dist/card.js.map +1 -1
- package/dist/checkbox.js +1 -1
- package/dist/checkbox.js.map +1 -1
- package/dist/combobox.d.ts.map +1 -1
- package/dist/combobox.js +10 -10
- package/dist/combobox.js.map +1 -1
- package/dist/context-menu.js +9 -9
- package/dist/context-menu.js.map +1 -1
- package/dist/dialog.d.ts.map +1 -1
- package/dist/dialog.js +4 -4
- package/dist/dialog.js.map +1 -1
- package/dist/drawer.js +4 -4
- package/dist/drawer.js.map +1 -1
- package/dist/field.js +2 -2
- package/dist/field.js.map +1 -1
- package/dist/form.js +2 -2
- package/dist/form.js.map +1 -1
- package/dist/infinite-scroll.js +2 -2
- package/dist/infinite-scroll.js.map +1 -1
- package/dist/input-group.d.ts +1 -1
- package/dist/input-group.js +5 -5
- package/dist/input-group.js.map +1 -1
- package/dist/input-otp.js +3 -3
- package/dist/input-otp.js.map +1 -1
- package/dist/input.js +1 -1
- package/dist/input.js.map +1 -1
- package/dist/item.js +4 -4
- package/dist/item.js.map +1 -1
- package/dist/kbd.js +1 -1
- package/dist/kbd.js.map +1 -1
- package/dist/menu.js +9 -9
- package/dist/menu.js.map +1 -1
- package/dist/menubar.js +1 -1
- package/dist/menubar.js.map +1 -1
- package/dist/popover.js +2 -2
- package/dist/popover.js.map +1 -1
- package/dist/preview-card.js +1 -1
- package/dist/preview-card.js.map +1 -1
- package/dist/progress.js +2 -2
- package/dist/progress.js.map +1 -1
- package/dist/radio.js +2 -2
- package/dist/radio.js.map +1 -1
- package/dist/scroll-area.js +2 -2
- package/dist/scroll-area.js.map +1 -1
- package/dist/select.js +8 -8
- package/dist/select.js.map +1 -1
- package/dist/separator.js +1 -1
- package/dist/separator.js.map +1 -1
- package/dist/sidebar.js +19 -19
- package/dist/sidebar.js.map +1 -1
- package/dist/skeleton.js +1 -1
- package/dist/skeleton.js.map +1 -1
- package/dist/slider.js +2 -2
- package/dist/slider.js.map +1 -1
- package/dist/styles.css +405 -173
- package/dist/switch.js +2 -2
- package/dist/switch.js.map +1 -1
- package/dist/table.js +4 -4
- package/dist/table.js.map +1 -1
- package/dist/tabs.js +3 -3
- package/dist/tabs.js.map +1 -1
- package/dist/textarea.js +1 -1
- package/dist/textarea.js.map +1 -1
- package/dist/toast.d.ts +3 -3
- package/dist/toast.d.ts.map +1 -1
- package/dist/toast.js +37 -10
- package/dist/toast.js.map +1 -1
- package/dist/toggle-group.js +2 -2
- package/dist/toggle-group.js.map +1 -1
- package/dist/toggle.js +3 -3
- package/dist/toggle.js.map +1 -1
- package/dist/tooltip.js +1 -1
- package/dist/tooltip.js.map +1 -1
- package/package.json +2 -5
package/dist/accordion.js
CHANGED
|
@@ -25,7 +25,7 @@ function AccordionTrigger({ className, children, ...props }) {
|
|
|
25
25
|
className: "flex",
|
|
26
26
|
children: /* @__PURE__ */ jsxs(Accordion$1.Trigger, {
|
|
27
27
|
"data-slot": "accordion-trigger",
|
|
28
|
-
className: cn("cursor-clickable focus-visible:ring-
|
|
28
|
+
className: cn("cursor-clickable focus-visible:ring-focus/50 focus-visible:border-focus focus-visible:after:border-focus **:data-[slot=accordion-trigger-icon]:text-muted group/accordion-trigger relative flex flex-1 items-start justify-between rounded-md border border-transparent py-2.5 text-left text-sm font-medium motion-color outline-none hover:underline focus-visible:ring-3 aria-disabled:pointer-events-none aria-disabled:opacity-50 **:data-[slot=accordion-trigger-icon]:ml-auto **:data-[slot=accordion-trigger-icon]:size-4", className),
|
|
29
29
|
...props,
|
|
30
30
|
children: [
|
|
31
31
|
children,
|
|
@@ -48,7 +48,7 @@ function AccordionContent({ className, children, ...props }) {
|
|
|
48
48
|
...props,
|
|
49
49
|
children: /* @__PURE__ */ jsx("div", {
|
|
50
50
|
"data-slot": "accordion-content",
|
|
51
|
-
className: cn("[&_a]:hover:text-
|
|
51
|
+
className: cn("[&_a]:hover:text-contrast h-(--accordion-panel-height) pt-0 pb-2.5 data-ending-style:h-0 data-starting-style:h-0 [&_a]:underline [&_a]:underline-offset-3 [&_p:not(:last-child)]:mb-4", className),
|
|
52
52
|
children
|
|
53
53
|
})
|
|
54
54
|
});
|
package/dist/accordion.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"accordion.js","names":["AccordionPrimitive"],"sources":["../src/accordion.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\n\nimport { Accordion as AccordionPrimitive } from \"@base-ui/react/accordion\"\n\nimport { cn } from \"./lib/utils\"\n\nimport { ChevronDownIcon, ChevronUpIcon } from \"./lib/internal-icons\"\n\ntype AccordionProps = React.ComponentProps<typeof AccordionPrimitive.Root>\ntype AccordionItemProps = React.ComponentProps<typeof AccordionPrimitive.Item>\ntype AccordionTriggerProps = React.ComponentProps<typeof AccordionPrimitive.Trigger>\ntype AccordionContentProps = React.ComponentProps<typeof AccordionPrimitive.Panel>\n\nfunction Accordion({ className, ...props }: AccordionProps) {\n return (\n <AccordionPrimitive.Root\n data-slot=\"accordion\"\n className={cn(\n \"overflow-hidden flex w-full flex-col\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AccordionItem({ className, ...props }: AccordionItemProps) {\n return (\n <AccordionPrimitive.Item\n data-slot=\"accordion-item\"\n className={cn(\n \"not-last:border-b\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AccordionTrigger({\n className,\n children,\n ...props\n}: AccordionTriggerProps) {\n return (\n <AccordionPrimitive.Header data-slot=\"accordion-header\" className=\"flex\">\n <AccordionPrimitive.Trigger\n data-slot=\"accordion-trigger\"\n className={cn(\n \"cursor-clickable focus-visible:ring-
|
|
1
|
+
{"version":3,"file":"accordion.js","names":["AccordionPrimitive"],"sources":["../src/accordion.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\n\nimport { Accordion as AccordionPrimitive } from \"@base-ui/react/accordion\"\n\nimport { cn } from \"./lib/utils\"\n\nimport { ChevronDownIcon, ChevronUpIcon } from \"./lib/internal-icons\"\n\ntype AccordionProps = React.ComponentProps<typeof AccordionPrimitive.Root>\ntype AccordionItemProps = React.ComponentProps<typeof AccordionPrimitive.Item>\ntype AccordionTriggerProps = React.ComponentProps<typeof AccordionPrimitive.Trigger>\ntype AccordionContentProps = React.ComponentProps<typeof AccordionPrimitive.Panel>\n\nfunction Accordion({ className, ...props }: AccordionProps) {\n return (\n <AccordionPrimitive.Root\n data-slot=\"accordion\"\n className={cn(\n \"overflow-hidden flex w-full flex-col\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AccordionItem({ className, ...props }: AccordionItemProps) {\n return (\n <AccordionPrimitive.Item\n data-slot=\"accordion-item\"\n className={cn(\n \"not-last:border-b\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AccordionTrigger({\n className,\n children,\n ...props\n}: AccordionTriggerProps) {\n return (\n <AccordionPrimitive.Header data-slot=\"accordion-header\" className=\"flex\">\n <AccordionPrimitive.Trigger\n data-slot=\"accordion-trigger\"\n className={cn(\n \"cursor-clickable focus-visible:ring-focus/50 focus-visible:border-focus focus-visible:after:border-focus **:data-[slot=accordion-trigger-icon]:text-muted group/accordion-trigger relative flex flex-1 items-start justify-between rounded-md border border-transparent py-2.5 text-left text-sm font-medium motion-color outline-none hover:underline focus-visible:ring-3 aria-disabled:pointer-events-none aria-disabled:opacity-50 **:data-[slot=accordion-trigger-icon]:ml-auto **:data-[slot=accordion-trigger-icon]:size-4\",\n className\n )}\n {...props}\n >\n {children}\n <ChevronDownIcon data-slot=\"accordion-trigger-icon\" className=\"pointer-events-none shrink-0 group-aria-expanded/accordion-trigger:hidden\" />\n <ChevronUpIcon data-slot=\"accordion-trigger-icon\" className=\"pointer-events-none hidden shrink-0 group-aria-expanded/accordion-trigger:inline\" />\n </AccordionPrimitive.Trigger>\n </AccordionPrimitive.Header>\n )\n}\n\nfunction AccordionContent({\n className,\n children,\n ...props\n}: AccordionContentProps) {\n return (\n <AccordionPrimitive.Panel\n data-slot=\"accordion-panel\"\n className=\"data-open:animate-accordion-down data-closed:animate-accordion-up overflow-hidden text-sm\"\n {...props}\n >\n <div\n data-slot=\"accordion-content\"\n className={cn(\n \"[&_a]:hover:text-contrast h-(--accordion-panel-height) pt-0 pb-2.5 data-ending-style:h-0 data-starting-style:h-0 [&_a]:underline [&_a]:underline-offset-3 [&_p:not(:last-child)]:mb-4\",\n className\n )}\n >\n {children}\n </div>\n </AccordionPrimitive.Panel>\n )\n}\n\nexport {\n Accordion,\n AccordionItem,\n AccordionTrigger,\n AccordionContent,\n}\n"],"mappings":";;;;;;;AAeA,SAAS,UAAU,EAAE,WAAW,GAAG,SAAyB;AAC1D,QACE,oBAACA,YAAmB,MAApB;EACE,aAAU;EACV,WAAW,GACT,wCACA,UACD;EACD,GAAI;EACJ,CAAA;;AAIN,SAAS,cAAc,EAAE,WAAW,GAAG,SAA6B;AAClE,QACE,oBAACA,YAAmB,MAApB;EACE,aAAU;EACV,WAAW,GACT,qBACA,UACD;EACD,GAAI;EACJ,CAAA;;AAIN,SAAS,iBAAiB,EACxB,WACA,UACA,GAAG,SACqB;AACxB,QACE,oBAACA,YAAmB,QAApB;EAA2B,aAAU;EAAmB,WAAU;YAChE,qBAACA,YAAmB,SAApB;GACE,aAAU;GACV,WAAW,GACT,qgBACA,UACD;GACD,GAAI;aANN;IAQG;IACD,oBAAC,iBAAD;KAAiB,aAAU;KAAyB,WAAU;KAA8E,CAAA;IAC5I,oBAAC,eAAD;KAAe,aAAU;KAAyB,WAAU;KAAqF,CAAA;IACtH;;EACH,CAAA;;AAIhC,SAAS,iBAAiB,EACxB,WACA,UACA,GAAG,SACqB;AACxB,QACE,oBAACA,YAAmB,OAApB;EACE,aAAU;EACV,WAAU;EACV,GAAI;YAEJ,oBAAC,OAAD;GACE,aAAU;GACV,WAAW,GACT,yLACA,UACD;GAEA;GACG,CAAA;EACmB,CAAA"}
|
package/dist/action-bar.js
CHANGED
|
@@ -182,10 +182,10 @@ function ActionBarProvider({ children, message = "You have unsaved changes", plu
|
|
|
182
182
|
className: "fixed bottom-6 left-1/2 z-50",
|
|
183
183
|
children: /* @__PURE__ */ jsxs("div", {
|
|
184
184
|
"data-slot": "action-bar-content",
|
|
185
|
-
className: cn("flex items-center gap-6 rounded-
|
|
185
|
+
className: cn("flex items-center gap-6 rounded-lg border border-line/60 bg-surface px-5 py-2.5 shadow-lg ring-1 ring-line backdrop-blur-sm", className),
|
|
186
186
|
children: [/* @__PURE__ */ jsx("span", {
|
|
187
187
|
"data-slot": "action-bar-message",
|
|
188
|
-
className: "whitespace-nowrap text-sm font-medium text-
|
|
188
|
+
className: "whitespace-nowrap text-sm font-medium text-contrast",
|
|
189
189
|
children: displayMessage
|
|
190
190
|
}), /* @__PURE__ */ jsxs("div", {
|
|
191
191
|
"data-slot": "action-bar-actions",
|
package/dist/action-bar.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action-bar.js","names":[],"sources":["../src/action-bar.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\"\n\nimport { cn } from \"./lib/utils\"\nimport { Button } from \"./button\"\nimport { Spinner } from \"./spinner\"\nimport { Kbd } from \"./kbd\"\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** State a form registers with the ActionBar. */\nexport interface ActionBarEntry {\n /** Whether this form has unsaved changes. */\n hasChanges: boolean\n /** Whether this form is currently saving. */\n saving: boolean\n /** Save this form's changes. */\n onSave: () => void | Promise<void>\n /** Discard this form's changes. */\n onReset: () => void\n}\n\ninterface ActionBarContextValue {\n register: (id: string, entry: ActionBarEntry) => void\n unregister: (id: string) => void\n /** Returns true if any registered form has unsaved changes. */\n hasDirty: () => boolean\n /** Trigger the jiggle effect on blocked navigation. */\n jiggle: () => void\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst JIGGLE_STEPS = 6\nconst JIGGLE_INTERVAL = 50\nconst JIGGLE_RANGE = 15\n\n/**\n * SSR-safe platform detection. Returns `false` on the server and on the\n * first client render so hydration matches, then resolves the real\n * platform after mount. Avoids the `⌘S`/`Ctrl+S` hydration mismatch\n * that a module-scope `navigator` read would cause.\n */\nfunction useIsMac(): boolean {\n const [isMac, setIsMac] = React.useState(false)\n React.useEffect(() => {\n setIsMac(/Mac|iPhone|iPad/.test(navigator.userAgent))\n }, [])\n return isMac\n}\n\n// ---------------------------------------------------------------------------\n// Context\n// ---------------------------------------------------------------------------\n\nconst ActionBarContext = React.createContext<ActionBarContextValue | null>(null)\n\n// ---------------------------------------------------------------------------\n// Provider\n// ---------------------------------------------------------------------------\n\nexport interface ActionBarProviderProps {\n children: React.ReactNode\n /** Message when one form has changes. */\n message?: string\n /** Message template for multiple dirty forms. */\n pluralMessage?: (count: number) => string\n /**\n * Announced to assistive tech (and the only feedback reduced-motion\n * users get) when guarded navigation is blocked.\n */\n blockedMessage?: string\n /** Additional className for the bar's outer wrapper. */\n className?: string\n}\n\n/**\n * Global action bar for unsaved changes.\n *\n * Place once at the root layout. Forms register via `useActionBar()`.\n *\n * Features:\n * - Multi-form aggregation (Save All / Reset All)\n * - ⌘S / Ctrl+S keyboard shortcut\n * - Navigation guard with Discord-style page jiggle\n * - `beforeunload` guard for browser close/refresh\n *\n * @example\n * ```tsx\n * // Root layout — once\n * <ActionBarProvider>{children}</ActionBarProvider>\n *\n * // Any form component\n * useActionBar('profile', { hasChanges, saving, onSave, onReset });\n * ```\n */\nfunction ActionBarProvider({\n children,\n message = \"You have unsaved changes\",\n pluralMessage = (count) => `${count} unsaved changes`,\n blockedMessage = \"Save or reset your changes before leaving this page\",\n className,\n}: ActionBarProviderProps) {\n const entriesRef = React.useRef(new Map<string, ActionBarEntry>())\n const [, forceUpdate] = React.useState(0)\n const [jiggleTransform, setJiggleTransform] = React.useState<string | null>(\n null\n )\n const jiggleTimerRef = React.useRef<ReturnType<typeof setTimeout> | null>(\n null\n )\n const contentRef = React.useRef<HTMLDivElement>(null)\n const isMac = useIsMac()\n const prefersReducedMotion = useReducedMotion()\n const reducedMotionRef = React.useRef(prefersReducedMotion)\n reducedMotionRef.current = prefersReducedMotion\n // Assertive announcement for blocked navigation. This is the *only*\n // feedback channel that works for screen-reader and reduced-motion\n // users (the visual jiggle is suppressed for them), so it is driven\n // independently of the shake.\n const [blockedNotice, setBlockedNotice] = React.useState(\"\")\n\n // --- Registry ---\n\n const register = React.useCallback((id: string, entry: ActionBarEntry) => {\n const prev = entriesRef.current.get(id)\n entriesRef.current.set(id, entry)\n if (\n !prev ||\n prev.hasChanges !== entry.hasChanges ||\n prev.saving !== entry.saving\n ) {\n forceUpdate((n) => n + 1)\n }\n }, [])\n\n const unregister = React.useCallback((id: string) => {\n if (entriesRef.current.delete(id)) {\n forceUpdate((n) => n + 1)\n }\n }, [])\n\n const hasDirty = React.useCallback(() => {\n for (const entry of entriesRef.current.values()) {\n if (entry.hasChanges) return true\n }\n return false\n }, [])\n\n // --- Jiggle ---\n\n const jiggle = React.useCallback(() => {\n // Announce to assistive tech on every blocked attempt. Clearing\n // first guarantees a text change so an identical message\n // re-announces on repeat presses.\n setBlockedNotice(\"\")\n requestAnimationFrame(() => setBlockedNotice(blockedMessage))\n\n // Vestibular safety: the random-translate shake is purely a motion\n // cue, so skip it under prefers-reduced-motion. The assertive\n // announcement above is the accessible equivalent.\n if (reducedMotionRef.current) return\n if (jiggleTimerRef.current) return\n\n let step = 0\n\n function tick() {\n step++\n if (step >= JIGGLE_STEPS) {\n setJiggleTransform(null)\n jiggleTimerRef.current = null\n return\n }\n const x = (Math.random() - 0.5) * 2 * JIGGLE_RANGE\n const y = (Math.random() - 0.5) * 2 * JIGGLE_RANGE\n setJiggleTransform(\n `translate3d(${x.toFixed(5)}px, ${y.toFixed(5)}px, 0px)`\n )\n jiggleTimerRef.current = setTimeout(tick, JIGGLE_INTERVAL)\n }\n\n tick()\n }, [blockedMessage])\n\n // --- Aggregated state ---\n\n const dirty: ActionBarEntry[] = []\n let anySaving = false\n\n for (const entry of entriesRef.current.values()) {\n if (entry.hasChanges) dirty.push(entry)\n if (entry.saving) anySaving = true\n }\n\n const showBar = dirty.length > 0 || anySaving\n const dirtyCount = dirty.length\n const displayMessage =\n dirtyCount > 1 ? pluralMessage(dirtyCount) : message\n\n // --- Save / Reset ---\n\n const handleSaveAll = React.useCallback(async () => {\n const saves = [...entriesRef.current.values()]\n .filter((e) => e.hasChanges)\n .map((e) => e.onSave())\n await Promise.all(saves)\n }, [])\n\n const handleResetAll = React.useCallback(() => {\n for (const entry of entriesRef.current.values()) {\n if (entry.hasChanges) entry.onReset()\n }\n }, [])\n\n // --- ⌘S / Ctrl+S ---\n\n React.useEffect(() => {\n function handleKeyDown(e: KeyboardEvent) {\n if ((e.metaKey || e.ctrlKey) && e.key === \"s\") {\n e.preventDefault()\n if (hasDirty()) {\n handleSaveAll()\n }\n }\n }\n\n document.addEventListener(\"keydown\", handleKeyDown)\n return () => document.removeEventListener(\"keydown\", handleKeyDown)\n }, [hasDirty, handleSaveAll])\n\n // --- beforeunload ---\n\n React.useEffect(() => {\n function handleBeforeUnload(e: BeforeUnloadEvent) {\n if (hasDirty()) {\n e.preventDefault()\n }\n }\n\n window.addEventListener(\"beforeunload\", handleBeforeUnload)\n return () => window.removeEventListener(\"beforeunload\", handleBeforeUnload)\n }, [hasDirty])\n\n // --- Context ---\n\n const ctx = React.useMemo(\n () => ({ register, unregister, hasDirty, jiggle }),\n [register, unregister, hasDirty, jiggle]\n )\n\n return (\n <ActionBarContext.Provider value={ctx}>\n <div\n data-slot=\"action-bar-shell\"\n ref={contentRef}\n style={jiggleTransform ? { transform: jiggleTransform } : undefined}\n >\n {children}\n </div>\n\n {/*\n Persistent SR-only live regions. They are always mounted so the\n announcement fires reliably when their text changes — a region\n mounted already-populated is not announced consistently across\n screen reader / browser combinations.\n */}\n <span data-slot=\"action-bar-status\" aria-live=\"polite\" className=\"sr-only\">\n {showBar ? displayMessage : \"\"}\n </span>\n <span\n data-slot=\"action-bar-blocked-status\"\n aria-live=\"assertive\"\n className=\"sr-only\"\n >\n {blockedNotice}\n </span>\n\n <AnimatePresence>\n {showBar && (\n <motion.div\n data-slot=\"action-bar\"\n initial={\n prefersReducedMotion\n ? { opacity: 0, x: \"-50%\" }\n : { opacity: 0, y: 20, x: \"-50%\" }\n }\n animate={{ opacity: 1, y: 0, x: \"-50%\" }}\n exit={\n prefersReducedMotion\n ? { opacity: 0, x: \"-50%\" }\n : { opacity: 0, y: 20, x: \"-50%\" }\n }\n transition={{ duration: 0.2, ease: \"easeOut\" }}\n className=\"fixed bottom-6 left-1/2 z-50\"\n >\n <div\n data-slot=\"action-bar-content\"\n className={cn(\n \"flex items-center gap-6 rounded-xl border border-border/60 bg-card px-5 py-2.5 shadow-lg ring-1 ring-black/5 backdrop-blur-sm dark:ring-white/5\",\n className\n )}\n >\n <span\n data-slot=\"action-bar-message\"\n className=\"whitespace-nowrap text-sm font-medium text-foreground\"\n >\n {displayMessage}\n </span>\n\n <div\n data-slot=\"action-bar-actions\"\n className=\"flex items-center gap-1.5\"\n >\n <Button\n type=\"button\"\n variant=\"ghost\"\n disabled={anySaving}\n onClick={handleResetAll}\n className=\"h-9 px-3 text-sm hover:text-destructive\"\n >\n Reset\n </Button>\n\n <Button\n type=\"button\"\n variant=\"default\"\n disabled={anySaving}\n onClick={handleSaveAll}\n className=\"h-9 px-4 text-sm\"\n >\n {anySaving ? (\n <>\n <Spinner className=\"mr-1.5 h-3.5 w-3.5\" />\n Saving\n </>\n ) : (\n <>\n Save\n <Kbd className=\"ml-1.5\">\n {isMac ? \"⌘S\" : \"Ctrl+S\"}\n </Kbd>\n </>\n )}\n </Button>\n </div>\n </div>\n </motion.div>\n )}\n </AnimatePresence>\n </ActionBarContext.Provider>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Hook — register form state\n// ---------------------------------------------------------------------------\n\n/**\n * Register a form's unsaved state with the global ActionBar.\n *\n * Unregisters automatically on unmount.\n *\n * @param id — Unique key (e.g., 'profile', 'notifications')\n * @param entry — Current form state\n */\nfunction useActionBar(id: string, entry: ActionBarEntry) {\n const ctx = React.useContext(ActionBarContext)\n if (!ctx)\n throw new Error(\"useActionBar must be used within <ActionBarProvider>\")\n\n const { register, unregister } = ctx\n\n // Intentionally no dependency array: `entry` (and its `onSave`/\n // `onReset` closures) is rebuilt by the caller every render, so we\n // must re-register each render to keep the latest closures. The\n // `register` impl diffs the entry and only forces an update when\n // `hasChanges`/`saving` actually changed, so this can't loop.\n React.useEffect(() => {\n register(id, entry)\n })\n\n React.useEffect(() => {\n return () => unregister(id)\n }, [id, unregister])\n}\n\n// ---------------------------------------------------------------------------\n// Navigation guard hook\n// ---------------------------------------------------------------------------\n\n/**\n * Returns a function that guards navigation.\n * If unsaved changes exist, triggers the jiggle and blocks navigation.\n * Otherwise navigates normally via the provided callback.\n *\n * @param navigate — Your navigation function (e.g., `router.push`)\n *\n * @example\n * ```tsx\n * const router = useRouter();\n * const guardedPush = useActionBarGuard(router.push);\n * <button onClick={() => guardedPush('/settings')}>Settings</button>\n * ```\n */\nfunction useActionBarGuard(navigate: (href: string) => void) {\n const ctx = React.useContext(ActionBarContext)\n\n return React.useCallback(\n (href: string) => {\n if (ctx?.hasDirty()) {\n ctx.jiggle()\n return false\n }\n navigate(href)\n return true\n },\n [ctx, navigate]\n )\n}\n\n// ---------------------------------------------------------------------------\n// Exports\n// ---------------------------------------------------------------------------\n\nexport {\n ActionBarProvider,\n useActionBar,\n useActionBarGuard,\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"action-bar.js","names":[],"sources":["../src/action-bar.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\"\n\nimport { cn } from \"./lib/utils\"\nimport { Button } from \"./button\"\nimport { Spinner } from \"./spinner\"\nimport { Kbd } from \"./kbd\"\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** State a form registers with the ActionBar. */\nexport interface ActionBarEntry {\n /** Whether this form has unsaved changes. */\n hasChanges: boolean\n /** Whether this form is currently saving. */\n saving: boolean\n /** Save this form's changes. */\n onSave: () => void | Promise<void>\n /** Discard this form's changes. */\n onReset: () => void\n}\n\ninterface ActionBarContextValue {\n register: (id: string, entry: ActionBarEntry) => void\n unregister: (id: string) => void\n /** Returns true if any registered form has unsaved changes. */\n hasDirty: () => boolean\n /** Trigger the jiggle effect on blocked navigation. */\n jiggle: () => void\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst JIGGLE_STEPS = 6\nconst JIGGLE_INTERVAL = 50\nconst JIGGLE_RANGE = 15\n\n/**\n * SSR-safe platform detection. Returns `false` on the server and on the\n * first client render so hydration matches, then resolves the real\n * platform after mount. Avoids the `⌘S`/`Ctrl+S` hydration mismatch\n * that a module-scope `navigator` read would cause.\n */\nfunction useIsMac(): boolean {\n const [isMac, setIsMac] = React.useState(false)\n React.useEffect(() => {\n setIsMac(/Mac|iPhone|iPad/.test(navigator.userAgent))\n }, [])\n return isMac\n}\n\n// ---------------------------------------------------------------------------\n// Context\n// ---------------------------------------------------------------------------\n\nconst ActionBarContext = React.createContext<ActionBarContextValue | null>(null)\n\n// ---------------------------------------------------------------------------\n// Provider\n// ---------------------------------------------------------------------------\n\nexport interface ActionBarProviderProps {\n children: React.ReactNode\n /** Message when one form has changes. */\n message?: string\n /** Message template for multiple dirty forms. */\n pluralMessage?: (count: number) => string\n /**\n * Announced to assistive tech (and the only feedback reduced-motion\n * users get) when guarded navigation is blocked.\n */\n blockedMessage?: string\n /** Additional className for the bar's outer wrapper. */\n className?: string\n}\n\n/**\n * Global action bar for unsaved changes.\n *\n * Place once at the root layout. Forms register via `useActionBar()`.\n *\n * Features:\n * - Multi-form aggregation (Save All / Reset All)\n * - ⌘S / Ctrl+S keyboard shortcut\n * - Navigation guard with Discord-style page jiggle\n * - `beforeunload` guard for browser close/refresh\n *\n * @example\n * ```tsx\n * // Root layout — once\n * <ActionBarProvider>{children}</ActionBarProvider>\n *\n * // Any form component\n * useActionBar('profile', { hasChanges, saving, onSave, onReset });\n * ```\n */\nfunction ActionBarProvider({\n children,\n message = \"You have unsaved changes\",\n pluralMessage = (count) => `${count} unsaved changes`,\n blockedMessage = \"Save or reset your changes before leaving this page\",\n className,\n}: ActionBarProviderProps) {\n const entriesRef = React.useRef(new Map<string, ActionBarEntry>())\n const [, forceUpdate] = React.useState(0)\n const [jiggleTransform, setJiggleTransform] = React.useState<string | null>(\n null\n )\n const jiggleTimerRef = React.useRef<ReturnType<typeof setTimeout> | null>(\n null\n )\n const contentRef = React.useRef<HTMLDivElement>(null)\n const isMac = useIsMac()\n const prefersReducedMotion = useReducedMotion()\n const reducedMotionRef = React.useRef(prefersReducedMotion)\n reducedMotionRef.current = prefersReducedMotion\n // Assertive announcement for blocked navigation. This is the *only*\n // feedback channel that works for screen-reader and reduced-motion\n // users (the visual jiggle is suppressed for them), so it is driven\n // independently of the shake.\n const [blockedNotice, setBlockedNotice] = React.useState(\"\")\n\n // --- Registry ---\n\n const register = React.useCallback((id: string, entry: ActionBarEntry) => {\n const prev = entriesRef.current.get(id)\n entriesRef.current.set(id, entry)\n if (\n !prev ||\n prev.hasChanges !== entry.hasChanges ||\n prev.saving !== entry.saving\n ) {\n forceUpdate((n) => n + 1)\n }\n }, [])\n\n const unregister = React.useCallback((id: string) => {\n if (entriesRef.current.delete(id)) {\n forceUpdate((n) => n + 1)\n }\n }, [])\n\n const hasDirty = React.useCallback(() => {\n for (const entry of entriesRef.current.values()) {\n if (entry.hasChanges) return true\n }\n return false\n }, [])\n\n // --- Jiggle ---\n\n const jiggle = React.useCallback(() => {\n // Announce to assistive tech on every blocked attempt. Clearing\n // first guarantees a text change so an identical message\n // re-announces on repeat presses.\n setBlockedNotice(\"\")\n requestAnimationFrame(() => setBlockedNotice(blockedMessage))\n\n // Vestibular safety: the random-translate shake is purely a motion\n // cue, so skip it under prefers-reduced-motion. The assertive\n // announcement above is the accessible equivalent.\n if (reducedMotionRef.current) return\n if (jiggleTimerRef.current) return\n\n let step = 0\n\n function tick() {\n step++\n if (step >= JIGGLE_STEPS) {\n setJiggleTransform(null)\n jiggleTimerRef.current = null\n return\n }\n const x = (Math.random() - 0.5) * 2 * JIGGLE_RANGE\n const y = (Math.random() - 0.5) * 2 * JIGGLE_RANGE\n setJiggleTransform(\n `translate3d(${x.toFixed(5)}px, ${y.toFixed(5)}px, 0px)`\n )\n jiggleTimerRef.current = setTimeout(tick, JIGGLE_INTERVAL)\n }\n\n tick()\n }, [blockedMessage])\n\n // --- Aggregated state ---\n\n const dirty: ActionBarEntry[] = []\n let anySaving = false\n\n for (const entry of entriesRef.current.values()) {\n if (entry.hasChanges) dirty.push(entry)\n if (entry.saving) anySaving = true\n }\n\n const showBar = dirty.length > 0 || anySaving\n const dirtyCount = dirty.length\n const displayMessage =\n dirtyCount > 1 ? pluralMessage(dirtyCount) : message\n\n // --- Save / Reset ---\n\n const handleSaveAll = React.useCallback(async () => {\n const saves = [...entriesRef.current.values()]\n .filter((e) => e.hasChanges)\n .map((e) => e.onSave())\n await Promise.all(saves)\n }, [])\n\n const handleResetAll = React.useCallback(() => {\n for (const entry of entriesRef.current.values()) {\n if (entry.hasChanges) entry.onReset()\n }\n }, [])\n\n // --- ⌘S / Ctrl+S ---\n\n React.useEffect(() => {\n function handleKeyDown(e: KeyboardEvent) {\n if ((e.metaKey || e.ctrlKey) && e.key === \"s\") {\n e.preventDefault()\n if (hasDirty()) {\n handleSaveAll()\n }\n }\n }\n\n document.addEventListener(\"keydown\", handleKeyDown)\n return () => document.removeEventListener(\"keydown\", handleKeyDown)\n }, [hasDirty, handleSaveAll])\n\n // --- beforeunload ---\n\n React.useEffect(() => {\n function handleBeforeUnload(e: BeforeUnloadEvent) {\n if (hasDirty()) {\n e.preventDefault()\n }\n }\n\n window.addEventListener(\"beforeunload\", handleBeforeUnload)\n return () => window.removeEventListener(\"beforeunload\", handleBeforeUnload)\n }, [hasDirty])\n\n // --- Context ---\n\n const ctx = React.useMemo(\n () => ({ register, unregister, hasDirty, jiggle }),\n [register, unregister, hasDirty, jiggle]\n )\n\n return (\n <ActionBarContext.Provider value={ctx}>\n <div\n data-slot=\"action-bar-shell\"\n ref={contentRef}\n style={jiggleTransform ? { transform: jiggleTransform } : undefined}\n >\n {children}\n </div>\n\n {/*\n Persistent SR-only live regions. They are always mounted so the\n announcement fires reliably when their text changes — a region\n mounted already-populated is not announced consistently across\n screen reader / browser combinations.\n */}\n <span data-slot=\"action-bar-status\" aria-live=\"polite\" className=\"sr-only\">\n {showBar ? displayMessage : \"\"}\n </span>\n <span\n data-slot=\"action-bar-blocked-status\"\n aria-live=\"assertive\"\n className=\"sr-only\"\n >\n {blockedNotice}\n </span>\n\n <AnimatePresence>\n {showBar && (\n <motion.div\n data-slot=\"action-bar\"\n initial={\n prefersReducedMotion\n ? { opacity: 0, x: \"-50%\" }\n : { opacity: 0, y: 20, x: \"-50%\" }\n }\n animate={{ opacity: 1, y: 0, x: \"-50%\" }}\n exit={\n prefersReducedMotion\n ? { opacity: 0, x: \"-50%\" }\n : { opacity: 0, y: 20, x: \"-50%\" }\n }\n transition={{ duration: 0.2, ease: \"easeOut\" }}\n className=\"fixed bottom-6 left-1/2 z-50\"\n >\n <div\n data-slot=\"action-bar-content\"\n className={cn(\n \"flex items-center gap-6 rounded-lg border border-line/60 bg-surface px-5 py-2.5 shadow-lg ring-1 ring-line backdrop-blur-sm\",\n className\n )}\n >\n <span\n data-slot=\"action-bar-message\"\n className=\"whitespace-nowrap text-sm font-medium text-contrast\"\n >\n {displayMessage}\n </span>\n\n <div\n data-slot=\"action-bar-actions\"\n className=\"flex items-center gap-1.5\"\n >\n <Button\n type=\"button\"\n variant=\"ghost\"\n disabled={anySaving}\n onClick={handleResetAll}\n className=\"h-9 px-3 text-sm hover:text-destructive\"\n >\n Reset\n </Button>\n\n <Button\n type=\"button\"\n variant=\"default\"\n disabled={anySaving}\n onClick={handleSaveAll}\n className=\"h-9 px-4 text-sm\"\n >\n {anySaving ? (\n <>\n <Spinner className=\"mr-1.5 h-3.5 w-3.5\" />\n Saving\n </>\n ) : (\n <>\n Save\n <Kbd className=\"ml-1.5\">\n {isMac ? \"⌘S\" : \"Ctrl+S\"}\n </Kbd>\n </>\n )}\n </Button>\n </div>\n </div>\n </motion.div>\n )}\n </AnimatePresence>\n </ActionBarContext.Provider>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Hook — register form state\n// ---------------------------------------------------------------------------\n\n/**\n * Register a form's unsaved state with the global ActionBar.\n *\n * Unregisters automatically on unmount.\n *\n * @param id — Unique key (e.g., 'profile', 'notifications')\n * @param entry — Current form state\n */\nfunction useActionBar(id: string, entry: ActionBarEntry) {\n const ctx = React.useContext(ActionBarContext)\n if (!ctx)\n throw new Error(\"useActionBar must be used within <ActionBarProvider>\")\n\n const { register, unregister } = ctx\n\n // Intentionally no dependency array: `entry` (and its `onSave`/\n // `onReset` closures) is rebuilt by the caller every render, so we\n // must re-register each render to keep the latest closures. The\n // `register` impl diffs the entry and only forces an update when\n // `hasChanges`/`saving` actually changed, so this can't loop.\n React.useEffect(() => {\n register(id, entry)\n })\n\n React.useEffect(() => {\n return () => unregister(id)\n }, [id, unregister])\n}\n\n// ---------------------------------------------------------------------------\n// Navigation guard hook\n// ---------------------------------------------------------------------------\n\n/**\n * Returns a function that guards navigation.\n * If unsaved changes exist, triggers the jiggle and blocks navigation.\n * Otherwise navigates normally via the provided callback.\n *\n * @param navigate — Your navigation function (e.g., `router.push`)\n *\n * @example\n * ```tsx\n * const router = useRouter();\n * const guardedPush = useActionBarGuard(router.push);\n * <button onClick={() => guardedPush('/settings')}>Settings</button>\n * ```\n */\nfunction useActionBarGuard(navigate: (href: string) => void) {\n const ctx = React.useContext(ActionBarContext)\n\n return React.useCallback(\n (href: string) => {\n if (ctx?.hasDirty()) {\n ctx.jiggle()\n return false\n }\n navigate(href)\n return true\n },\n [ctx, navigate]\n )\n}\n\n// ---------------------------------------------------------------------------\n// Exports\n// ---------------------------------------------------------------------------\n\nexport {\n ActionBarProvider,\n useActionBar,\n useActionBarGuard,\n}\n"],"mappings":";;;;;;;;;AAuCA,MAAM,eAAe;AACrB,MAAM,kBAAkB;AACxB,MAAM,eAAe;;;;;;;AAQrB,SAAS,WAAoB;CAC3B,MAAM,CAAC,OAAO,YAAY,MAAM,SAAS,MAAM;AAC/C,OAAM,gBAAgB;AACpB,WAAS,kBAAkB,KAAK,UAAU,UAAU,CAAC;IACpD,EAAE,CAAC;AACN,QAAO;;AAOT,MAAM,mBAAmB,MAAM,cAA4C,KAAK;;;;;;;;;;;;;;;;;;;;;AAyChF,SAAS,kBAAkB,EACzB,UACA,UAAU,4BACV,iBAAiB,UAAU,GAAG,MAAM,mBACpC,iBAAiB,uDACjB,aACyB;CACzB,MAAM,aAAa,MAAM,uBAAO,IAAI,KAA6B,CAAC;CAClE,MAAM,GAAG,eAAe,MAAM,SAAS,EAAE;CACzC,MAAM,CAAC,iBAAiB,sBAAsB,MAAM,SAClD,KACD;CACD,MAAM,iBAAiB,MAAM,OAC3B,KACD;CACD,MAAM,aAAa,MAAM,OAAuB,KAAK;CACrD,MAAM,QAAQ,UAAU;CACxB,MAAM,uBAAuB,kBAAkB;CAC/C,MAAM,mBAAmB,MAAM,OAAO,qBAAqB;AAC3D,kBAAiB,UAAU;CAK3B,MAAM,CAAC,eAAe,oBAAoB,MAAM,SAAS,GAAG;CAI5D,MAAM,WAAW,MAAM,aAAa,IAAY,UAA0B;EACxE,MAAM,OAAO,WAAW,QAAQ,IAAI,GAAG;AACvC,aAAW,QAAQ,IAAI,IAAI,MAAM;AACjC,MACE,CAAC,QACD,KAAK,eAAe,MAAM,cAC1B,KAAK,WAAW,MAAM,OAEtB,cAAa,MAAM,IAAI,EAAE;IAE1B,EAAE,CAAC;CAEN,MAAM,aAAa,MAAM,aAAa,OAAe;AACnD,MAAI,WAAW,QAAQ,OAAO,GAAG,CAC/B,cAAa,MAAM,IAAI,EAAE;IAE1B,EAAE,CAAC;CAEN,MAAM,WAAW,MAAM,kBAAkB;AACvC,OAAK,MAAM,SAAS,WAAW,QAAQ,QAAQ,CAC7C,KAAI,MAAM,WAAY,QAAO;AAE/B,SAAO;IACN,EAAE,CAAC;CAIN,MAAM,SAAS,MAAM,kBAAkB;AAIrC,mBAAiB,GAAG;AACpB,8BAA4B,iBAAiB,eAAe,CAAC;AAK7D,MAAI,iBAAiB,QAAS;AAC9B,MAAI,eAAe,QAAS;EAE5B,IAAI,OAAO;EAEX,SAAS,OAAO;AACd;AACA,OAAI,QAAQ,cAAc;AACxB,uBAAmB,KAAK;AACxB,mBAAe,UAAU;AACzB;;GAEF,MAAM,KAAK,KAAK,QAAQ,GAAG,MAAO,IAAI;GACtC,MAAM,KAAK,KAAK,QAAQ,GAAG,MAAO,IAAI;AACtC,sBACE,eAAe,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,UAChD;AACD,kBAAe,UAAU,WAAW,MAAM,gBAAgB;;AAG5D,QAAM;IACL,CAAC,eAAe,CAAC;CAIpB,MAAM,QAA0B,EAAE;CAClC,IAAI,YAAY;AAEhB,MAAK,MAAM,SAAS,WAAW,QAAQ,QAAQ,EAAE;AAC/C,MAAI,MAAM,WAAY,OAAM,KAAK,MAAM;AACvC,MAAI,MAAM,OAAQ,aAAY;;CAGhC,MAAM,UAAU,MAAM,SAAS,KAAK;CACpC,MAAM,aAAa,MAAM;CACzB,MAAM,iBACJ,aAAa,IAAI,cAAc,WAAW,GAAG;CAI/C,MAAM,gBAAgB,MAAM,YAAY,YAAY;EAClD,MAAM,QAAQ,CAAC,GAAG,WAAW,QAAQ,QAAQ,CAAC,CAC3C,QAAQ,MAAM,EAAE,WAAW,CAC3B,KAAK,MAAM,EAAE,QAAQ,CAAC;AACzB,QAAM,QAAQ,IAAI,MAAM;IACvB,EAAE,CAAC;CAEN,MAAM,iBAAiB,MAAM,kBAAkB;AAC7C,OAAK,MAAM,SAAS,WAAW,QAAQ,QAAQ,CAC7C,KAAI,MAAM,WAAY,OAAM,SAAS;IAEtC,EAAE,CAAC;AAIN,OAAM,gBAAgB;EACpB,SAAS,cAAc,GAAkB;AACvC,QAAK,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,KAAK;AAC7C,MAAE,gBAAgB;AAClB,QAAI,UAAU,CACZ,gBAAe;;;AAKrB,WAAS,iBAAiB,WAAW,cAAc;AACnD,eAAa,SAAS,oBAAoB,WAAW,cAAc;IAClE,CAAC,UAAU,cAAc,CAAC;AAI7B,OAAM,gBAAgB;EACpB,SAAS,mBAAmB,GAAsB;AAChD,OAAI,UAAU,CACZ,GAAE,gBAAgB;;AAItB,SAAO,iBAAiB,gBAAgB,mBAAmB;AAC3D,eAAa,OAAO,oBAAoB,gBAAgB,mBAAmB;IAC1E,CAAC,SAAS,CAAC;CAId,MAAM,MAAM,MAAM,eACT;EAAE;EAAU;EAAY;EAAU;EAAQ,GACjD;EAAC;EAAU;EAAY;EAAU;EAAO,CACzC;AAED,QACE,qBAAC,iBAAiB,UAAlB;EAA2B,OAAO;YAAlC;GACE,oBAAC,OAAD;IACE,aAAU;IACV,KAAK;IACL,OAAO,kBAAkB,EAAE,WAAW,iBAAiB,GAAG,KAAA;IAEzD;IACG,CAAA;GAQN,oBAAC,QAAD;IAAM,aAAU;IAAoB,aAAU;IAAS,WAAU;cAC9D,UAAU,iBAAiB;IACvB,CAAA;GACP,oBAAC,QAAD;IACE,aAAU;IACV,aAAU;IACV,WAAU;cAET;IACI,CAAA;GAEP,oBAAC,iBAAD,EAAA,UACG,WACC,oBAAC,OAAO,KAAR;IACE,aAAU;IACV,SACE,uBACI;KAAE,SAAS;KAAG,GAAG;KAAQ,GACzB;KAAE,SAAS;KAAG,GAAG;KAAI,GAAG;KAAQ;IAEtC,SAAS;KAAE,SAAS;KAAG,GAAG;KAAG,GAAG;KAAQ;IACxC,MACE,uBACI;KAAE,SAAS;KAAG,GAAG;KAAQ,GACzB;KAAE,SAAS;KAAG,GAAG;KAAI,GAAG;KAAQ;IAEtC,YAAY;KAAE,UAAU;KAAK,MAAM;KAAW;IAC9C,WAAU;cAEV,qBAAC,OAAD;KACE,aAAU;KACV,WAAW,GACT,+HACA,UACD;eALH,CAOE,oBAAC,QAAD;MACE,aAAU;MACV,WAAU;gBAET;MACI,CAAA,EAEP,qBAAC,OAAD;MACE,aAAU;MACV,WAAU;gBAFZ,CAIE,oBAAC,QAAD;OACE,MAAK;OACL,SAAQ;OACR,UAAU;OACV,SAAS;OACT,WAAU;iBACX;OAEQ,CAAA,EAET,oBAAC,QAAD;OACE,MAAK;OACL,SAAQ;OACR,UAAU;OACV,SAAS;OACT,WAAU;iBAET,YACC,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,SAAD,EAAS,WAAU,sBAAuB,CAAA,EAAA,SAEzC,EAAA,CAAA,GAEH,qBAAA,UAAA,EAAA,UAAA,CAAE,QAEA,oBAAC,KAAD;QAAK,WAAU;kBACZ,QAAQ,OAAO;QACZ,CAAA,CACL,EAAA,CAAA;OAEE,CAAA,CACL;QACF;;IACK,CAAA,EAEC,CAAA;GACQ;;;;;;;;;;;AAgBhC,SAAS,aAAa,IAAY,OAAuB;CACvD,MAAM,MAAM,MAAM,WAAW,iBAAiB;AAC9C,KAAI,CAAC,IACH,OAAM,IAAI,MAAM,uDAAuD;CAEzE,MAAM,EAAE,UAAU,eAAe;AAOjC,OAAM,gBAAgB;AACpB,WAAS,IAAI,MAAM;GACnB;AAEF,OAAM,gBAAgB;AACpB,eAAa,WAAW,GAAG;IAC1B,CAAC,IAAI,WAAW,CAAC;;;;;;;;;;;;;;;;AAqBtB,SAAS,kBAAkB,UAAkC;CAC3D,MAAM,MAAM,MAAM,WAAW,iBAAiB;AAE9C,QAAO,MAAM,aACV,SAAiB;AAChB,MAAI,KAAK,UAAU,EAAE;AACnB,OAAI,QAAQ;AACZ,UAAO;;AAET,WAAS,KAAK;AACd,SAAO;IAET,CAAC,KAAK,SAAS,CAChB"}
|
package/dist/alert-dialog.js
CHANGED
|
@@ -34,7 +34,7 @@ function AlertDialogContent({ className, size = "default", ...props }) {
|
|
|
34
34
|
return /* @__PURE__ */ jsxs(AlertDialogPortal, { children: [/* @__PURE__ */ jsx(AlertDialogOverlay, {}), /* @__PURE__ */ jsx(AlertDialog$1.Popup, {
|
|
35
35
|
"data-slot": "alert-dialog-content",
|
|
36
36
|
"data-size": size,
|
|
37
|
-
className: cn("motion-scale bg-
|
|
37
|
+
className: cn("motion-scale-lg bg-foundation ring-contrast/10 group/alert-dialog-content fixed top-1/2 left-1/2 z-50 grid w-full -translate-x-1/2 -translate-y-1/2 gap-4 rounded-lg p-4 ring-1 outline-none data-[size=default]:max-w-xs data-[size=sm]:max-w-xs data-[size=lg]:max-w-lg data-[size=xl]:max-w-xl data-[size=default]:sm:max-w-sm data-[size=lg]:sm:max-w-lg data-[size=xl]:sm:max-w-xl", className),
|
|
38
38
|
...props
|
|
39
39
|
})] });
|
|
40
40
|
}
|
|
@@ -48,14 +48,14 @@ function AlertDialogHeader({ className, ...props }) {
|
|
|
48
48
|
function AlertDialogFooter({ className, ...props }) {
|
|
49
49
|
return /* @__PURE__ */ jsx("div", {
|
|
50
50
|
"data-slot": "alert-dialog-footer",
|
|
51
|
-
className: cn("bg-
|
|
51
|
+
className: cn("bg-secondary/50 -mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-lg border-t p-4 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end", className),
|
|
52
52
|
...props
|
|
53
53
|
});
|
|
54
54
|
}
|
|
55
55
|
function AlertDialogMedia({ className, ...props }) {
|
|
56
56
|
return /* @__PURE__ */ jsx("div", {
|
|
57
57
|
"data-slot": "alert-dialog-media",
|
|
58
|
-
className: cn("bg-
|
|
58
|
+
className: cn("bg-secondary mb-2 inline-flex size-10 items-center justify-center rounded-md sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*='size-'])]:size-6", className),
|
|
59
59
|
...props
|
|
60
60
|
});
|
|
61
61
|
}
|
|
@@ -69,7 +69,7 @@ function AlertDialogTitle({ className, ...props }) {
|
|
|
69
69
|
function AlertDialogDescription({ className, ...props }) {
|
|
70
70
|
return /* @__PURE__ */ jsx(AlertDialog$1.Description, {
|
|
71
71
|
"data-slot": "alert-dialog-description",
|
|
72
|
-
className: cn("text-muted
|
|
72
|
+
className: cn("text-muted *:[a]:hover:text-contrast text-sm text-balance md:text-pretty *:[a]:underline *:[a]:underline-offset-3", className),
|
|
73
73
|
...props
|
|
74
74
|
});
|
|
75
75
|
}
|
package/dist/alert-dialog.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"alert-dialog.js","names":["AlertDialogPrimitive"],"sources":["../src/alert-dialog.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { AlertDialog as AlertDialogPrimitive } from \"@base-ui/react/alert-dialog\"\n\nimport { Button } from \"./button\"\nimport { cn } from \"./lib/utils\"\n\ntype AlertDialogProps = React.ComponentProps<typeof AlertDialogPrimitive.Root>\n\ntype AlertDialogTriggerProps = React.ComponentProps<typeof AlertDialogPrimitive.Trigger>\n\ntype AlertDialogPortalProps = React.ComponentProps<typeof AlertDialogPrimitive.Portal>\n\ntype AlertDialogOverlayProps = React.ComponentProps<typeof AlertDialogPrimitive.Backdrop>\n\ntype AlertDialogContentProps = React.ComponentProps<typeof AlertDialogPrimitive.Popup> & {\n size?: \"default\" | \"sm\" | \"lg\" | \"xl\"\n}\n\ntype AlertDialogHeaderProps = React.ComponentProps<\"div\">\n\ntype AlertDialogFooterProps = React.ComponentProps<\"div\">\n\ntype AlertDialogMediaProps = React.ComponentProps<\"div\">\n\ntype AlertDialogTitleProps = React.ComponentProps<typeof AlertDialogPrimitive.Title>\n\ntype AlertDialogDescriptionProps = React.ComponentProps<typeof AlertDialogPrimitive.Description>\n\ntype AlertDialogActionProps = React.ComponentProps<typeof Button>\n\ntype AlertDialogCancelProps = React.ComponentProps<typeof AlertDialogPrimitive.Close> &\n Pick<React.ComponentProps<typeof Button>, \"variant\" | \"size\">\n\nfunction AlertDialog({ ...props }: AlertDialogProps) {\n return <AlertDialogPrimitive.Root data-slot=\"alert-dialog\" {...props} />\n}\n\nfunction AlertDialogTrigger({ ...props }: AlertDialogTriggerProps) {\n return <AlertDialogPrimitive.Trigger data-slot=\"alert-dialog-trigger\" {...props} />\n}\n\nfunction AlertDialogPortal({ ...props }: AlertDialogPortalProps) {\n return <AlertDialogPrimitive.Portal data-slot=\"alert-dialog-portal\" {...props} />\n}\n\nfunction AlertDialogOverlay({ className, ...props }: AlertDialogOverlayProps) {\n return (\n <AlertDialogPrimitive.Backdrop\n data-slot=\"alert-dialog-overlay\"\n className={cn(\n \"motion-scrim fixed inset-0 isolate z-50 bg-black/10 supports-backdrop-filter:backdrop-blur-xs\",\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction AlertDialogContent({\n className,\n size = \"default\",\n ...props\n}: AlertDialogContentProps) {\n return (\n <AlertDialogPortal>\n <AlertDialogOverlay />\n <AlertDialogPrimitive.Popup\n data-slot=\"alert-dialog-content\"\n data-size={size}\n className={cn(\n \"motion-scale bg-
|
|
1
|
+
{"version":3,"file":"alert-dialog.js","names":["AlertDialogPrimitive"],"sources":["../src/alert-dialog.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { AlertDialog as AlertDialogPrimitive } from \"@base-ui/react/alert-dialog\"\n\nimport { Button } from \"./button\"\nimport { cn } from \"./lib/utils\"\n\ntype AlertDialogProps = React.ComponentProps<typeof AlertDialogPrimitive.Root>\n\ntype AlertDialogTriggerProps = React.ComponentProps<typeof AlertDialogPrimitive.Trigger>\n\ntype AlertDialogPortalProps = React.ComponentProps<typeof AlertDialogPrimitive.Portal>\n\ntype AlertDialogOverlayProps = React.ComponentProps<typeof AlertDialogPrimitive.Backdrop>\n\ntype AlertDialogContentProps = React.ComponentProps<typeof AlertDialogPrimitive.Popup> & {\n size?: \"default\" | \"sm\" | \"lg\" | \"xl\"\n}\n\ntype AlertDialogHeaderProps = React.ComponentProps<\"div\">\n\ntype AlertDialogFooterProps = React.ComponentProps<\"div\">\n\ntype AlertDialogMediaProps = React.ComponentProps<\"div\">\n\ntype AlertDialogTitleProps = React.ComponentProps<typeof AlertDialogPrimitive.Title>\n\ntype AlertDialogDescriptionProps = React.ComponentProps<typeof AlertDialogPrimitive.Description>\n\ntype AlertDialogActionProps = React.ComponentProps<typeof Button>\n\ntype AlertDialogCancelProps = React.ComponentProps<typeof AlertDialogPrimitive.Close> &\n Pick<React.ComponentProps<typeof Button>, \"variant\" | \"size\">\n\nfunction AlertDialog({ ...props }: AlertDialogProps) {\n return <AlertDialogPrimitive.Root data-slot=\"alert-dialog\" {...props} />\n}\n\nfunction AlertDialogTrigger({ ...props }: AlertDialogTriggerProps) {\n return <AlertDialogPrimitive.Trigger data-slot=\"alert-dialog-trigger\" {...props} />\n}\n\nfunction AlertDialogPortal({ ...props }: AlertDialogPortalProps) {\n return <AlertDialogPrimitive.Portal data-slot=\"alert-dialog-portal\" {...props} />\n}\n\nfunction AlertDialogOverlay({ className, ...props }: AlertDialogOverlayProps) {\n return (\n <AlertDialogPrimitive.Backdrop\n data-slot=\"alert-dialog-overlay\"\n className={cn(\n \"motion-scrim fixed inset-0 isolate z-50 bg-black/10 supports-backdrop-filter:backdrop-blur-xs\",\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction AlertDialogContent({\n className,\n size = \"default\",\n ...props\n}: AlertDialogContentProps) {\n return (\n <AlertDialogPortal>\n <AlertDialogOverlay />\n <AlertDialogPrimitive.Popup\n data-slot=\"alert-dialog-content\"\n data-size={size}\n className={cn(\n \"motion-scale-lg bg-foundation ring-contrast/10 group/alert-dialog-content fixed top-1/2 left-1/2 z-50 grid w-full -translate-x-1/2 -translate-y-1/2 gap-4 rounded-lg p-4 ring-1 outline-none data-[size=default]:max-w-xs data-[size=sm]:max-w-xs data-[size=lg]:max-w-lg data-[size=xl]:max-w-xl data-[size=default]:sm:max-w-sm data-[size=lg]:sm:max-w-lg data-[size=xl]:sm:max-w-xl\",\n className,\n )}\n {...props}\n />\n </AlertDialogPortal>\n )\n}\n\nfunction AlertDialogHeader({ className, ...props }: AlertDialogHeaderProps) {\n return (\n <div\n data-slot=\"alert-dialog-header\"\n className={cn(\n \"grid grid-rows-[auto_1fr] place-items-center gap-1.5 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-4 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-left sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr] group-data-[size=lg]/alert-dialog-content:place-items-start group-data-[size=lg]/alert-dialog-content:text-left group-data-[size=xl]/alert-dialog-content:place-items-start group-data-[size=xl]/alert-dialog-content:text-left\",\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction AlertDialogFooter({ className, ...props }: AlertDialogFooterProps) {\n return (\n <div\n data-slot=\"alert-dialog-footer\"\n className={cn(\n \"bg-secondary/50 -mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-lg border-t p-4 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end\",\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction AlertDialogMedia({ className, ...props }: AlertDialogMediaProps) {\n return (\n <div\n data-slot=\"alert-dialog-media\"\n className={cn(\n \"bg-secondary mb-2 inline-flex size-10 items-center justify-center rounded-md sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*='size-'])]:size-6\",\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction AlertDialogTitle({ className, ...props }: AlertDialogTitleProps) {\n return (\n <AlertDialogPrimitive.Title\n data-slot=\"alert-dialog-title\"\n className={cn(\n \"text-base font-medium sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2\",\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction AlertDialogDescription({\n className,\n ...props\n}: AlertDialogDescriptionProps) {\n return (\n <AlertDialogPrimitive.Description\n data-slot=\"alert-dialog-description\"\n className={cn(\n \"text-muted *:[a]:hover:text-contrast text-sm text-balance md:text-pretty *:[a]:underline *:[a]:underline-offset-3\",\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction AlertDialogAction({\n className,\n ...props\n}: AlertDialogActionProps) {\n return (\n <Button\n data-slot=\"alert-dialog-action\"\n className={cn(className)}\n {...props}\n />\n )\n}\n\nfunction AlertDialogCancel({\n className,\n variant = \"outline\",\n size = \"default\",\n ...props\n}: AlertDialogCancelProps) {\n return (\n <AlertDialogPrimitive.Close\n data-slot=\"alert-dialog-cancel\"\n className={className}\n render={<Button variant={variant} size={size} />}\n {...props}\n />\n )\n}\n\nexport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogMedia,\n AlertDialogOverlay,\n AlertDialogPortal,\n AlertDialogTitle,\n AlertDialogTrigger,\n}\n"],"mappings":";;;;;;;AAmCA,SAAS,YAAY,EAAE,GAAG,SAA2B;AACnD,QAAO,oBAACA,cAAqB,MAAtB;EAA2B,aAAU;EAAe,GAAI;EAAS,CAAA;;AAG1E,SAAS,mBAAmB,EAAE,GAAG,SAAkC;AACjE,QAAO,oBAACA,cAAqB,SAAtB;EAA8B,aAAU;EAAuB,GAAI;EAAS,CAAA;;AAGrF,SAAS,kBAAkB,EAAE,GAAG,SAAiC;AAC/D,QAAO,oBAACA,cAAqB,QAAtB;EAA6B,aAAU;EAAsB,GAAI;EAAS,CAAA;;AAGnF,SAAS,mBAAmB,EAAE,WAAW,GAAG,SAAkC;AAC5E,QACE,oBAACA,cAAqB,UAAtB;EACE,aAAU;EACV,WAAW,GACT,iGACA,UACD;EACD,GAAI;EACJ,CAAA;;AAIN,SAAS,mBAAmB,EAC1B,WACA,OAAO,WACP,GAAG,SACuB;AAC1B,QACE,qBAAC,mBAAD,EAAA,UAAA,CACE,oBAAC,oBAAD,EAAsB,CAAA,EACtB,oBAACA,cAAqB,OAAtB;EACE,aAAU;EACV,aAAW;EACX,WAAW,GACT,2XACA,UACD;EACD,GAAI;EACJ,CAAA,CACgB,EAAA,CAAA;;AAIxB,SAAS,kBAAkB,EAAE,WAAW,GAAG,SAAiC;AAC1E,QACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,snBACA,UACD;EACD,GAAI;EACJ,CAAA;;AAIN,SAAS,kBAAkB,EAAE,WAAW,GAAG,SAAiC;AAC1E,QACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,qNACA,UACD;EACD,GAAI;EACJ,CAAA;;AAIN,SAAS,iBAAiB,EAAE,WAAW,GAAG,SAAgC;AACxE,QACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,kLACA,UACD;EACD,GAAI;EACJ,CAAA;;AAIN,SAAS,iBAAiB,EAAE,WAAW,GAAG,SAAgC;AACxE,QACE,oBAACA,cAAqB,OAAtB;EACE,aAAU;EACV,WAAW,GACT,qJACA,UACD;EACD,GAAI;EACJ,CAAA;;AAIN,SAAS,uBAAuB,EAC9B,WACA,GAAG,SAC2B;AAC9B,QACE,oBAACA,cAAqB,aAAtB;EACE,aAAU;EACV,WAAW,GACT,qHACA,UACD;EACD,GAAI;EACJ,CAAA;;AAIN,SAAS,kBAAkB,EACzB,WACA,GAAG,SACsB;AACzB,QACE,oBAAC,QAAD;EACE,aAAU;EACV,WAAW,GAAG,UAAU;EACxB,GAAI;EACJ,CAAA;;AAIN,SAAS,kBAAkB,EACzB,WACA,UAAU,WACV,OAAO,WACP,GAAG,SACsB;AACzB,QACE,oBAACA,cAAqB,OAAtB;EACE,aAAU;EACC;EACX,QAAQ,oBAAC,QAAD;GAAiB;GAAe;GAAQ,CAAA;EAChD,GAAI;EACJ,CAAA"}
|
package/dist/alert.js
CHANGED
|
@@ -3,10 +3,10 @@ import "react";
|
|
|
3
3
|
import { jsx } from "react/jsx-runtime";
|
|
4
4
|
import { cva } from "class-variance-authority";
|
|
5
5
|
//#region src/alert.tsx
|
|
6
|
-
const alertVariants = cva("grid gap-0.5 rounded-
|
|
6
|
+
const alertVariants = cva("grid gap-0.5 rounded-md border border-edge px-2.5 py-2 text-left text-sm has-data-[slot=alert-action]:relative has-data-[slot=alert-action]:pr-18 has-data-[icon]:grid-cols-[auto_1fr] has-data-[icon]:gap-x-2 *:[svg]:row-span-2 *:[svg]:translate-y-0.5 *:[svg]:text-current *:[svg:not([class*='size-'])]:size-4 w-full relative group/alert", {
|
|
7
7
|
variants: { variant: {
|
|
8
|
-
default: "bg-
|
|
9
|
-
destructive: "text-destructive bg-
|
|
8
|
+
default: "bg-surface text-contrast",
|
|
9
|
+
destructive: "text-destructive bg-surface *:data-[slot=alert-description]:text-destructive/90 *:[svg]:text-current"
|
|
10
10
|
} },
|
|
11
11
|
defaultVariants: { variant: "default" }
|
|
12
12
|
});
|
|
@@ -21,14 +21,14 @@ function Alert({ className, variant, ...props }) {
|
|
|
21
21
|
function AlertTitle({ className, ...props }) {
|
|
22
22
|
return /* @__PURE__ */ jsx("div", {
|
|
23
23
|
"data-slot": "alert-title",
|
|
24
|
-
className: cn("[&_a]:hover:text-
|
|
24
|
+
className: cn("[&_a]:hover:text-contrast font-medium group-has-data-[icon]/alert:col-start-2 [&_a]:underline [&_a]:underline-offset-3", className),
|
|
25
25
|
...props
|
|
26
26
|
});
|
|
27
27
|
}
|
|
28
28
|
function AlertDescription({ className, ...props }) {
|
|
29
29
|
return /* @__PURE__ */ jsx("div", {
|
|
30
30
|
"data-slot": "alert-description",
|
|
31
|
-
className: cn("text-muted
|
|
31
|
+
className: cn("text-muted [&_a]:hover:text-contrast text-sm text-balance md:text-pretty [&_a]:underline [&_a]:underline-offset-3 [&_p:not(:last-child)]:mb-4", className),
|
|
32
32
|
...props
|
|
33
33
|
});
|
|
34
34
|
}
|
package/dist/alert.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"alert.js","names":[],"sources":["../src/alert.tsx"],"sourcesContent":["import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"./lib/utils\"\n\nconst alertVariants = cva(\n \"grid gap-0.5 rounded-
|
|
1
|
+
{"version":3,"file":"alert.js","names":[],"sources":["../src/alert.tsx"],"sourcesContent":["import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"./lib/utils\"\n\nconst alertVariants = cva(\n \"grid gap-0.5 rounded-md border border-edge px-2.5 py-2 text-left text-sm has-data-[slot=alert-action]:relative has-data-[slot=alert-action]:pr-18 has-data-[icon]:grid-cols-[auto_1fr] has-data-[icon]:gap-x-2 *:[svg]:row-span-2 *:[svg]:translate-y-0.5 *:[svg]:text-current *:[svg:not([class*='size-'])]:size-4 w-full relative group/alert\",\n {\n variants: {\n variant: {\n default: \"bg-surface text-contrast\",\n destructive:\n \"text-destructive bg-surface *:data-[slot=alert-description]:text-destructive/90 *:[svg]:text-current\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n)\n\ntype AlertProps = React.ComponentProps<\"div\"> & VariantProps<typeof alertVariants>\ntype AlertTitleProps = React.ComponentProps<\"div\">\ntype AlertDescriptionProps = React.ComponentProps<\"div\">\ntype AlertActionProps = React.ComponentProps<\"div\">\n\nfunction Alert({\n className,\n variant,\n ...props\n}: AlertProps) {\n return (\n <div\n data-slot=\"alert\"\n role=\"alert\"\n className={cn(alertVariants({ variant }), className)}\n {...props}\n />\n )\n}\n\nfunction AlertTitle({ className, ...props }: AlertTitleProps) {\n return (\n <div\n data-slot=\"alert-title\"\n className={cn(\n \"[&_a]:hover:text-contrast font-medium group-has-data-[icon]/alert:col-start-2 [&_a]:underline [&_a]:underline-offset-3\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AlertDescription({\n className,\n ...props\n}: AlertDescriptionProps) {\n return (\n <div\n data-slot=\"alert-description\"\n className={cn(\n \"text-muted [&_a]:hover:text-contrast text-sm text-balance md:text-pretty [&_a]:underline [&_a]:underline-offset-3 [&_p:not(:last-child)]:mb-4\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AlertAction({ className, ...props }: AlertActionProps) {\n return (\n <div\n data-slot=\"alert-action\"\n className={cn(\"absolute top-2 right-2\", className)}\n {...props}\n />\n )\n}\n\nexport {\n Alert,\n AlertTitle,\n AlertDescription,\n AlertAction\n}\n"],"mappings":";;;;;AAKA,MAAM,gBAAgB,IACpB,mVACA;CACE,UAAU,EACR,SAAS;EACP,SAAS;EACT,aACE;EACH,EACF;CACD,iBAAiB,EACf,SAAS,WACV;CACF,CACF;AAOD,SAAS,MAAM,EACb,WACA,SACA,GAAG,SACU;AACb,QACE,oBAAC,OAAD;EACE,aAAU;EACV,MAAK;EACL,WAAW,GAAG,cAAc,EAAE,SAAS,CAAC,EAAE,UAAU;EACpD,GAAI;EACJ,CAAA;;AAIN,SAAS,WAAW,EAAE,WAAW,GAAG,SAA0B;AAC5D,QACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,0HACA,UACD;EACD,GAAI;EACJ,CAAA;;AAIN,SAAS,iBAAiB,EACxB,WACA,GAAG,SACqB;AACxB,QACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,iJACA,UACD;EACD,GAAI;EACJ,CAAA;;AAIN,SAAS,YAAY,EAAE,WAAW,GAAG,SAA2B;AAC9D,QACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GAAG,0BAA0B,UAAU;EAClD,GAAI;EACJ,CAAA"}
|
package/dist/animate.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"animate.d.ts","names":[],"sources":["../src/animate.tsx"],"mappings":";;;;;;KAkBK,SAAA;AAAA,UAEK,kBAAA;EACR,QAAA,EAAU,YAAA;;EAEV,KAAA;EALY;EAOZ,IAAA,GAAO,SAAA;EAPK;EASZ,QAAA;EAPQ;EASR,KAAA;;EAEA,IAAA;EANO;EAQP,MAAA;EAQuB;EANvB,IAAA;EAdA;EAgBA,MAAA;EAdA;EAgBA,IAAA;EAdO;EAgBP,UAAA,GAAa,UAAA;AAAA;AAAA,UAGL,cAAA;EACR,QAAA,EAAU,YAAA;EAVV;EAYA,KAAA;EARA;EAUA,IAAA,GAAO,SAAA;EARM;EAUb,QAAA;EAVuB;EAYvB,KAAA;EATsB;EAWtB,IAAA;EAVU;EAYV,MAAA;EAMa;EAJb,IAAA;EAIuB;EAFvB,MAAA;EAhBU;EAkBV,UAAA,GAAa,UAAA;AAAA;AAAA,UAGL,YAAA;EACR,QAAA,EAAU,YAAA;EAdV;EAgBA,QAAA;EAZA;EAcA,SAAA;AAAA;AAAA,UAGQ,UAAA;EACR,QAAA,EAAU,YAAA;EAZa;EAcvB,GAAA;EAXQ;EAaR,GAAA;;EAEA,QAAA;EAdA;EAgBA,OAAA;EAdA;EAgBA,MAAA;AAAA;AAAA,UAGQ,UAAA;EACR,QAAA,EAAU,YAAA;EAfQ;EAiBlB,QAAA;EAhBsB;EAkBtB,QAAA;EAlBU;EAoBV,MAAA;EAhBA;EAkBA,MAAA;AAAA;;;;AAZM;;;;;;;;;;;;AAYA;
|
|
1
|
+
{"version":3,"file":"animate.d.ts","names":[],"sources":["../src/animate.tsx"],"mappings":";;;;;;KAkBK,SAAA;AAAA,UAEK,kBAAA;EACR,QAAA,EAAU,YAAA;;EAEV,KAAA;EALY;EAOZ,IAAA,GAAO,SAAA;EAPK;EASZ,QAAA;EAPQ;EASR,KAAA;;EAEA,IAAA;EANO;EAQP,MAAA;EAQuB;EANvB,IAAA;EAdA;EAgBA,MAAA;EAdA;EAgBA,IAAA;EAdO;EAgBP,UAAA,GAAa,UAAA;AAAA;AAAA,UAGL,cAAA;EACR,QAAA,EAAU,YAAA;EAVV;EAYA,KAAA;EARA;EAUA,IAAA,GAAO,SAAA;EARM;EAUb,QAAA;EAVuB;EAYvB,KAAA;EATsB;EAWtB,IAAA;EAVU;EAYV,MAAA;EAMa;EAJb,IAAA;EAIuB;EAFvB,MAAA;EAhBU;EAkBV,UAAA,GAAa,UAAA;AAAA;AAAA,UAGL,YAAA;EACR,QAAA,EAAU,YAAA;EAdV;EAgBA,QAAA;EAZA;EAcA,SAAA;AAAA;AAAA,UAGQ,UAAA;EACR,QAAA,EAAU,YAAA;EAZa;EAcvB,GAAA;EAXQ;EAaR,GAAA;;EAEA,QAAA;EAdA;EAgBA,OAAA;EAdA;EAgBA,MAAA;AAAA;AAAA,UAGQ,UAAA;EACR,QAAA,EAAU,YAAA;EAfQ;EAiBlB,QAAA;EAhBsB;EAkBtB,QAAA;EAlBU;EAoBV,MAAA;EAhBA;EAkBA,MAAA;AAAA;;;;AAZM;;;;;;;;;;;;AAYA;iBA+HC,aAAA,CAAA;EACP,QAAA;EACA,KAAA;EACA,IAAA;EACA,QAAA;EACA,KAAA;EACA,IAAA;EACA,MAAA;EACA,IAAA;EACA,MAAA;EACA,IAAA;EACA;AAAA,GACC,kBAAA,GAAkB,YAAA,mBAAA,OAAA,CAAA,qBAAA;;;;;;;;;;;;;;iBAoDZ,SAAA,CAAA;EACP,QAAA;EACA,KAAA;EACA,IAAA;EACA,QAAA;EACA,KAAA;EACA,IAAA;EACA,MAAA;EACA,IAAA;EACA,MAAA;EACA;AAAA,GACC,cAAA,GAAc,YAAA,mBAAA,OAAA,CAAA,qBAAA;;;;;;;;;;;;;iBA8CR,OAAA,CAAA;EACP,QAAA;EACA,QAAA;EACA;AAAA,GACC,YAAA,GAAY,oBAAA,CAAA,GAAA,CAAA,OAAA;;;;;;;;;;;;iBA0BN,KAAA,CAAA;EACP,QAAA;EACA,GAAA;EACA,GAAA;EACA,QAAA;EACA,OAAA;EACA;AAAA,GACC,UAAA,GAAU,oBAAA,CAAA,GAAA,CAAA,OAAA;;;;;;AAlJQ;;;;;;iBAsMZ,KAAA,CAAA;EACP,QAAA;EACA,QAAA;EACA,QAAA;EACA,MAAA;EACA;AAAA,GACC,UAAA,GAAU,oBAAA,CAAA,GAAA,CAAA,OAAA"}
|
package/dist/animate.js
CHANGED
|
@@ -34,8 +34,7 @@ const FLIP_MAP = {
|
|
|
34
34
|
};
|
|
35
35
|
/** Overshoot ("spring") easing for the opt-in `spring` prop on
|
|
36
36
|
* `AnimateIn` / `AnimateOnView`. This is `animate.tsx`'s own page-entrance
|
|
37
|
-
* bounce — the CSS recipe system intentionally has no spring
|
|
38
|
-
* curve), so this is a standalone constant, not a shared token. */
|
|
37
|
+
* bounce — the CSS recipe system intentionally has no spring, so this is a standalone constant, not a shared token. */
|
|
39
38
|
const SPRING_EASE = "cubic-bezier(0.34, 1.45, 0.64, 1)";
|
|
40
39
|
function buildStyles(opts) {
|
|
41
40
|
const { from, distance, doScale, blur, rotate, flip } = opts;
|
package/dist/animate.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"animate.js","names":[],"sources":["../src/animate.tsx"],"sourcesContent":["\"use client\"\n\nimport {\n Children,\n type CSSProperties,\n type ReactElement,\n type Ref,\n cloneElement,\n isValidElement,\n useEffect,\n useId,\n useRef,\n useState,\n} from \"react\"\nimport { useInView, type Transition } from \"motion/react\"\n\n// ── Types ────────────────────────────────────────────────────────────\n\ntype Direction = \"up\" | \"down\" | \"left\" | \"right\"\n\ninterface AnimateOnViewProps {\n children: ReactElement\n /** Delay in seconds before animation starts. Default: 0 */\n delay?: number\n /** Direction to animate from. Default: 'down' */\n from?: Direction\n /** Distance in px. Default: 16 (scroll reveals need more travel than `AnimateIn`) */\n distance?: number\n /** Also scale in (0.85 → 1). Default: false */\n scale?: boolean\n /** Blur in from a given amount in px. Default: false */\n blur?: boolean | number\n /** Rotate in from a given angle in degrees. Default: 0 */\n rotate?: number\n /** 3D flip entrance along the axis matching `from`. Default: false */\n flip?: boolean\n /** Spring easing with overshoot. Default: false */\n spring?: boolean\n /** Trigger once or every time it enters view. Default: true */\n once?: boolean\n /** Custom transition override */\n transition?: Transition\n}\n\ninterface AnimateInProps {\n children: ReactElement\n /** Delay in seconds before animation starts. Default: 0 */\n delay?: number\n /** Direction to animate from. Default: 'down' */\n from?: Direction\n /** Distance in px. Default: 4 */\n distance?: number\n /** Also scale in (0.85 → 1). Default: false */\n scale?: boolean\n /** Blur in from a given amount in px. Default: false */\n blur?: boolean | number\n /** Rotate in from a given angle in degrees. Default: 0 */\n rotate?: number\n /** 3D flip entrance along the axis matching `from`. Default: false */\n flip?: boolean\n /** Spring easing with overshoot. Default: false */\n spring?: boolean\n /** Custom transition override */\n transition?: Transition\n}\n\ninterface StaggerProps {\n children: ReactElement[]\n /** Delay increment between each child in seconds. Default: 0.08 */\n interval?: number\n /** Base delay before the first child animates in seconds. Default: 0 */\n baseDelay?: number\n}\n\ninterface PulseProps {\n children: ReactElement\n /** Min scale factor. Default: 0.97 */\n min?: number\n /** Max scale factor. Default: 1.03 */\n max?: number\n /** Animation duration in seconds. Default: 2 */\n duration?: number\n /** Also pulse opacity between these bounds [min, max]. Off by default. */\n opacity?: [number, number]\n /** Pause animation. Default: false */\n paused?: boolean\n}\n\ninterface FloatProps {\n children: ReactElement\n /** Vertical float distance in px. Default: 6 */\n distance?: number\n /** Animation duration in seconds. Default: 3 */\n duration?: number\n /** Also rotate slightly while floating (degrees). Default: 0 */\n rotate?: number\n /** Pause animation. Default: false */\n paused?: boolean\n}\n\n// ── Internals ────────────────────────────────────────────────────────\n\n/**\n * Direction map: `from` means where the element COMES FROM.\n * `from=\"left\"` = starts to the left, slides right into place.\n */\nconst DIRECTION_MAP = {\n up: { prop: \"translateY\", value: -1 },\n down: { prop: \"translateY\", value: 1 },\n left: { prop: \"translateX\", value: -1 },\n right: { prop: \"translateX\", value: 1 },\n} as const\n\n/** Flip axis: vertical directions flip around X, horizontal around Y */\nconst FLIP_MAP = {\n up: \"rotateX(90deg)\",\n down: \"rotateX(-90deg)\",\n left: \"rotateY(-90deg)\",\n right: \"rotateY(90deg)\",\n} as const\n\n/** Overshoot (\"spring\") easing for the opt-in `spring` prop on\n * `AnimateIn` / `AnimateOnView`. This is `animate.tsx`'s own page-entrance\n * bounce — the CSS recipe system intentionally has no spring (one circ-out\n * curve), so this is a standalone constant, not a shared token. */\nconst SPRING_EASE = \"cubic-bezier(0.34, 1.45, 0.64, 1)\"\n\ninterface BuildStylesOptions {\n from: Direction\n distance: number\n doScale: boolean\n blur: boolean | number\n rotate: number\n flip: boolean\n}\n\nfunction buildStyles(opts: BuildStylesOptions) {\n const { from, distance, doScale, blur, rotate, flip } = opts\n const dir = DIRECTION_MAP[from]\n\n const hiddenParts: string[] = []\n if (flip) hiddenParts.push(\"perspective(800px)\")\n hiddenParts.push(`${dir.prop}(${dir.value * distance}px)`)\n if (doScale) hiddenParts.push(\"scale(0.85)\")\n if (rotate) hiddenParts.push(`rotate(${rotate}deg)`)\n if (flip) hiddenParts.push(FLIP_MAP[from])\n\n const visibleParts: string[] = []\n if (flip) visibleParts.push(\"perspective(800px)\")\n visibleParts.push(\"translateX(0) translateY(0)\")\n if (doScale) visibleParts.push(\"scale(1)\")\n if (rotate) visibleParts.push(\"rotate(0deg)\")\n if (flip) visibleParts.push(from === \"up\" || from === \"down\" ? \"rotateX(0deg)\" : \"rotateY(0deg)\")\n\n const blurPx = blur === true ? 8 : typeof blur === \"number\" ? blur : 0\n\n const hidden: CSSProperties = {\n opacity: \"0\",\n transform: hiddenParts.join(\" \"),\n }\n\n const visible: CSSProperties = {\n opacity: \"1\",\n transform: visibleParts.join(\" \"),\n }\n\n if (blurPx > 0) {\n hidden.filter = `blur(${blurPx}px)`\n visible.filter = \"blur(0px)\"\n }\n\n return { hidden, visible, hasFilter: blurPx > 0 }\n}\n\nfunction mergeRefs<T>(...refs: (Ref<T> | undefined)[]) {\n return (el: T | null) => {\n refs.forEach((ref) => {\n if (typeof ref === \"function\") ref(el)\n else if (ref && typeof ref === \"object\") {\n ;(ref as { current: T | null }).current = el\n }\n })\n }\n}\n\nfunction getTransitionParams(transition?: Transition, useSpring?: boolean, fallbackDuration = 0.15) {\n const duration =\n (transition as Record<string, number>)?.duration ?? fallbackDuration\n const ease =\n useSpring ? SPRING_EASE : ((transition as Record<string, string>)?.ease ?? \"ease-out\")\n return { duration, ease }\n}\n\nfunction buildTransitionStr(\n duration: number,\n ease: string,\n delay: number,\n hasFilter: boolean,\n) {\n const parts = [\n `opacity ${duration}s ${ease} ${delay}s`,\n `transform ${duration}s ${ease} ${delay}s`,\n ]\n if (hasFilter) parts.push(`filter ${duration}s ${ease} ${delay}s`)\n return parts.join(\", \")\n}\n\n// ── AnimateOnView ────────────────────────────────────────────────────\n\n/**\n * Animates a child element when it scrolls into view.\n *\n * Defaults are tuned for scroll reveals — larger travel and a slower duration\n * than `AnimateIn` — so the motion reads as the content enters the viewport.\n *\n * Zero DOM overhead — applies styles directly to the child via cloneElement.\n * Renders children unchanged on server to avoid hydration mismatch.\n *\n * @example\n * ```tsx\n * <AnimateOnView from=\"up\" blur scale>\n * <Card>Hello</Card>\n * </AnimateOnView>\n * ```\n */\nfunction AnimateOnView({\n children,\n delay = 0,\n from = \"down\",\n distance = 16,\n scale = false,\n blur = false,\n rotate = 0,\n flip = false,\n spring = false,\n once = true,\n transition,\n}: AnimateOnViewProps) {\n const ref = useRef<HTMLElement>(null)\n const [hydrated, setHydrated] = useState(false)\n const isInView = useInView(ref, { once, margin: \"-50px\" })\n\n useEffect(() => {\n setHydrated(true)\n }, [])\n\n if (!isValidElement(children)) return children\n\n const childProps = children.props as Record<string, unknown>\n const existingStyle = (childProps.style ?? {}) as CSSProperties\n const existingRef = (childProps as { ref?: Ref<HTMLElement> }).ref\n\n if (!hydrated) {\n return cloneElement(children, {\n ref: mergeRefs(ref, existingRef),\n } as Record<string, unknown>)\n }\n\n const styles = buildStyles({ from, distance, doScale: scale, blur, rotate, flip })\n const { duration, ease } = getTransitionParams(transition, spring, 0.4)\n const currentStyle = isInView ? styles.visible : styles.hidden\n const transitionStr = buildTransitionStr(duration, ease, delay, styles.hasFilter)\n\n return cloneElement(children, {\n ref: mergeRefs(ref, existingRef),\n style: {\n ...existingStyle,\n ...currentStyle,\n ...(isInView ? { transition: transitionStr } : {}),\n willChange: \"opacity, transform\",\n },\n } as Record<string, unknown>)\n}\n\n// ── AnimateIn ────────────────────────────────────────────────────────\n\n/**\n * Animates a child element immediately on mount.\n *\n * Zero DOM overhead — applies styles directly to the child via cloneElement.\n * Uses a two-phase approach: hidden → visible with requestAnimationFrame.\n *\n * @example\n * ```tsx\n * <AnimateIn from=\"up\" blur spring>\n * <h1>Welcome</h1>\n * </AnimateIn>\n * ```\n */\nfunction AnimateIn({\n children,\n delay = 0,\n from = \"down\",\n distance = 4,\n scale = false,\n blur = false,\n rotate = 0,\n flip = false,\n spring = false,\n transition,\n}: AnimateInProps) {\n const ref = useRef<HTMLElement>(null)\n const [visible, setVisible] = useState(false)\n\n useEffect(() => {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => setVisible(true))\n })\n }, [])\n\n if (!isValidElement(children)) return children\n\n const childProps = children.props as Record<string, unknown>\n const existingStyle = (childProps.style ?? {}) as CSSProperties\n const existingRef = (childProps as { ref?: Ref<HTMLElement> }).ref\n\n const styles = buildStyles({ from, distance, doScale: scale, blur, rotate, flip })\n const { duration, ease } = getTransitionParams(transition, spring)\n const currentStyle = visible ? styles.visible : styles.hidden\n const transitionStr = buildTransitionStr(duration, ease, delay, styles.hasFilter)\n\n return cloneElement(children, {\n ref: mergeRefs(ref, existingRef),\n style: {\n ...existingStyle,\n ...currentStyle,\n ...(visible ? { transition: transitionStr } : {}),\n willChange: \"opacity, transform\",\n },\n } as Record<string, unknown>)\n}\n\n// ── Stagger ──────────────────────────────────────────────────────────\n\n/**\n * Auto-staggers delay on child AnimateIn/AnimateOnView elements.\n * Eliminates manual `delay={i * 0.08}` math.\n *\n * @example\n * ```tsx\n * <Stagger interval={0.1}>\n * <AnimateIn from=\"up\"><Card>One</Card></AnimateIn>\n * <AnimateIn from=\"up\"><Card>Two</Card></AnimateIn>\n * </Stagger>\n * ```\n */\nfunction Stagger({\n children,\n interval = 0.08,\n baseDelay = 0,\n}: StaggerProps) {\n return (\n <>\n {Children.map(children, (child, index) => {\n if (!isValidElement(child)) return child\n return cloneElement(child as ReactElement<{ delay?: number }>, {\n delay: baseDelay + index * interval,\n })\n })}\n </>\n )\n}\n\n// ── Pulse ────────────────────────────────────────────────────────────\n\n/**\n * Continuous, subtle scale pulse. Great for live indicators and CTAs.\n * Zero DOM overhead — injects a scoped keyframe via `<style>`.\n *\n * @example\n * ```tsx\n * <Pulse>\n * <span className=\"size-3 rounded-full bg-green-500\" />\n * </Pulse>\n * ```\n */\nfunction Pulse({\n children,\n min = 0.97,\n max = 1.03,\n duration = 2,\n opacity,\n paused = false,\n}: PulseProps) {\n const id = useId().replace(/:/g, \"\")\n const [hydrated, setHydrated] = useState(false)\n\n useEffect(() => {\n setHydrated(true)\n }, [])\n\n if (!isValidElement(children)) return children\n if (!hydrated) return children\n\n const name = `pulse-${id}`\n const opacityFrom = opacity?.[0] ?? 1\n const opacityTo = opacity?.[1] ?? 1\n\n const keyframes = `@keyframes ${name} {\n 0%, 100% { transform: scale(${min}); opacity: ${opacityFrom}; }\n 50% { transform: scale(${max}); opacity: ${opacityTo}; }\n}`\n\n const childProps = children.props as Record<string, unknown>\n const existingStyle = (childProps.style ?? {}) as CSSProperties\n const existingRef = (childProps as { ref?: Ref<HTMLElement> }).ref\n\n return (\n <>\n <style>{keyframes}</style>\n {cloneElement(children, {\n ref: existingRef ? mergeRefs(existingRef) : undefined,\n style: {\n ...existingStyle,\n animation: `${name} ${duration}s ease-in-out infinite`,\n animationPlayState: paused ? \"paused\" : \"running\",\n },\n } as Record<string, unknown>)}\n </>\n )\n}\n\n// ── Float ────────────────────────────────────────────────────────────\n\n/**\n * Gentle continuous up/down float. Perfect for decorative elements.\n * Zero DOM overhead — injects a scoped keyframe via `<style>`.\n *\n * @example\n * ```tsx\n * <Float distance={10} duration={4}>\n * <Card>Floating</Card>\n * </Float>\n * ```\n */\nfunction Float({\n children,\n distance = 6,\n duration = 3,\n rotate = 0,\n paused = false,\n}: FloatProps) {\n const id = useId().replace(/:/g, \"\")\n const [hydrated, setHydrated] = useState(false)\n\n useEffect(() => {\n setHydrated(true)\n }, [])\n\n if (!isValidElement(children)) return children\n if (!hydrated) return children\n\n const name = `float-${id}`\n const rotA = rotate ? ` rotate(${-rotate}deg)` : \"\"\n const rotB = rotate ? ` rotate(${rotate}deg)` : \"\"\n\n const keyframes = `@keyframes ${name} {\n 0%, 100% { transform: translateY(0px)${rotA}; }\n 50% { transform: translateY(${-distance}px)${rotB}; }\n}`\n\n const childProps = children.props as Record<string, unknown>\n const existingStyle = (childProps.style ?? {}) as CSSProperties\n const existingRef = (childProps as { ref?: Ref<HTMLElement> }).ref\n\n return (\n <>\n <style>{keyframes}</style>\n {cloneElement(children, {\n ...(existingRef ? { ref: existingRef } : {}),\n style: {\n ...existingStyle,\n animation: `${name} ${duration}s ease-in-out infinite`,\n animationPlayState: paused ? \"paused\" : \"running\",\n },\n } as Record<string, unknown>)}\n </>\n )\n}\n\n// ── Exports ──────────────────────────────────────────────────────────\n\nexport { AnimateOnView, AnimateIn, Stagger, Pulse, Float }\nexport type {\n AnimateOnViewProps,\n AnimateInProps,\n StaggerProps,\n PulseProps,\n FloatProps,\n Direction,\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"animate.js","names":[],"sources":["../src/animate.tsx"],"sourcesContent":["\"use client\"\n\nimport {\n Children,\n type CSSProperties,\n type ReactElement,\n type Ref,\n cloneElement,\n isValidElement,\n useEffect,\n useId,\n useRef,\n useState,\n} from \"react\"\nimport { useInView, type Transition } from \"motion/react\"\n\n// ── Types ────────────────────────────────────────────────────────────\n\ntype Direction = \"up\" | \"down\" | \"left\" | \"right\"\n\ninterface AnimateOnViewProps {\n children: ReactElement\n /** Delay in seconds before animation starts. Default: 0 */\n delay?: number\n /** Direction to animate from. Default: 'down' */\n from?: Direction\n /** Distance in px. Default: 16 (scroll reveals need more travel than `AnimateIn`) */\n distance?: number\n /** Also scale in (0.85 → 1). Default: false */\n scale?: boolean\n /** Blur in from a given amount in px. Default: false */\n blur?: boolean | number\n /** Rotate in from a given angle in degrees. Default: 0 */\n rotate?: number\n /** 3D flip entrance along the axis matching `from`. Default: false */\n flip?: boolean\n /** Spring easing with overshoot. Default: false */\n spring?: boolean\n /** Trigger once or every time it enters view. Default: true */\n once?: boolean\n /** Custom transition override */\n transition?: Transition\n}\n\ninterface AnimateInProps {\n children: ReactElement\n /** Delay in seconds before animation starts. Default: 0 */\n delay?: number\n /** Direction to animate from. Default: 'down' */\n from?: Direction\n /** Distance in px. Default: 4 */\n distance?: number\n /** Also scale in (0.85 → 1). Default: false */\n scale?: boolean\n /** Blur in from a given amount in px. Default: false */\n blur?: boolean | number\n /** Rotate in from a given angle in degrees. Default: 0 */\n rotate?: number\n /** 3D flip entrance along the axis matching `from`. Default: false */\n flip?: boolean\n /** Spring easing with overshoot. Default: false */\n spring?: boolean\n /** Custom transition override */\n transition?: Transition\n}\n\ninterface StaggerProps {\n children: ReactElement[]\n /** Delay increment between each child in seconds. Default: 0.08 */\n interval?: number\n /** Base delay before the first child animates in seconds. Default: 0 */\n baseDelay?: number\n}\n\ninterface PulseProps {\n children: ReactElement\n /** Min scale factor. Default: 0.97 */\n min?: number\n /** Max scale factor. Default: 1.03 */\n max?: number\n /** Animation duration in seconds. Default: 2 */\n duration?: number\n /** Also pulse opacity between these bounds [min, max]. Off by default. */\n opacity?: [number, number]\n /** Pause animation. Default: false */\n paused?: boolean\n}\n\ninterface FloatProps {\n children: ReactElement\n /** Vertical float distance in px. Default: 6 */\n distance?: number\n /** Animation duration in seconds. Default: 3 */\n duration?: number\n /** Also rotate slightly while floating (degrees). Default: 0 */\n rotate?: number\n /** Pause animation. Default: false */\n paused?: boolean\n}\n\n// ── Internals ────────────────────────────────────────────────────────\n\n/**\n * Direction map: `from` means where the element COMES FROM.\n * `from=\"left\"` = starts to the left, slides right into place.\n */\nconst DIRECTION_MAP = {\n up: { prop: \"translateY\", value: -1 },\n down: { prop: \"translateY\", value: 1 },\n left: { prop: \"translateX\", value: -1 },\n right: { prop: \"translateX\", value: 1 },\n} as const\n\n/** Flip axis: vertical directions flip around X, horizontal around Y */\nconst FLIP_MAP = {\n up: \"rotateX(90deg)\",\n down: \"rotateX(-90deg)\",\n left: \"rotateY(-90deg)\",\n right: \"rotateY(90deg)\",\n} as const\n\n/** Overshoot (\"spring\") easing for the opt-in `spring` prop on\n * `AnimateIn` / `AnimateOnView`. This is `animate.tsx`'s own page-entrance\n * bounce — the CSS recipe system intentionally has no spring, so this is a standalone constant, not a shared token. */\nconst SPRING_EASE = \"cubic-bezier(0.34, 1.45, 0.64, 1)\"\n\ninterface BuildStylesOptions {\n from: Direction\n distance: number\n doScale: boolean\n blur: boolean | number\n rotate: number\n flip: boolean\n}\n\nfunction buildStyles(opts: BuildStylesOptions) {\n const { from, distance, doScale, blur, rotate, flip } = opts\n const dir = DIRECTION_MAP[from]\n\n const hiddenParts: string[] = []\n if (flip) hiddenParts.push(\"perspective(800px)\")\n hiddenParts.push(`${dir.prop}(${dir.value * distance}px)`)\n if (doScale) hiddenParts.push(\"scale(0.85)\")\n if (rotate) hiddenParts.push(`rotate(${rotate}deg)`)\n if (flip) hiddenParts.push(FLIP_MAP[from])\n\n const visibleParts: string[] = []\n if (flip) visibleParts.push(\"perspective(800px)\")\n visibleParts.push(\"translateX(0) translateY(0)\")\n if (doScale) visibleParts.push(\"scale(1)\")\n if (rotate) visibleParts.push(\"rotate(0deg)\")\n if (flip) visibleParts.push(from === \"up\" || from === \"down\" ? \"rotateX(0deg)\" : \"rotateY(0deg)\")\n\n const blurPx = blur === true ? 8 : typeof blur === \"number\" ? blur : 0\n\n const hidden: CSSProperties = {\n opacity: \"0\",\n transform: hiddenParts.join(\" \"),\n }\n\n const visible: CSSProperties = {\n opacity: \"1\",\n transform: visibleParts.join(\" \"),\n }\n\n if (blurPx > 0) {\n hidden.filter = `blur(${blurPx}px)`\n visible.filter = \"blur(0px)\"\n }\n\n return { hidden, visible, hasFilter: blurPx > 0 }\n}\n\nfunction mergeRefs<T>(...refs: (Ref<T> | undefined)[]) {\n return (el: T | null) => {\n refs.forEach((ref) => {\n if (typeof ref === \"function\") ref(el)\n else if (ref && typeof ref === \"object\") {\n ;(ref as { current: T | null }).current = el\n }\n })\n }\n}\n\nfunction getTransitionParams(transition?: Transition, useSpring?: boolean, fallbackDuration = 0.15) {\n const duration =\n (transition as Record<string, number>)?.duration ?? fallbackDuration\n const ease =\n useSpring ? SPRING_EASE : ((transition as Record<string, string>)?.ease ?? \"ease-out\")\n return { duration, ease }\n}\n\nfunction buildTransitionStr(\n duration: number,\n ease: string,\n delay: number,\n hasFilter: boolean,\n) {\n const parts = [\n `opacity ${duration}s ${ease} ${delay}s`,\n `transform ${duration}s ${ease} ${delay}s`,\n ]\n if (hasFilter) parts.push(`filter ${duration}s ${ease} ${delay}s`)\n return parts.join(\", \")\n}\n\n// ── AnimateOnView ────────────────────────────────────────────────────\n\n/**\n * Animates a child element when it scrolls into view.\n *\n * Defaults are tuned for scroll reveals — larger travel and a slower duration\n * than `AnimateIn` — so the motion reads as the content enters the viewport.\n *\n * Zero DOM overhead — applies styles directly to the child via cloneElement.\n * Renders children unchanged on server to avoid hydration mismatch.\n *\n * @example\n * ```tsx\n * <AnimateOnView from=\"up\" blur scale>\n * <Card>Hello</Card>\n * </AnimateOnView>\n * ```\n */\nfunction AnimateOnView({\n children,\n delay = 0,\n from = \"down\",\n distance = 16,\n scale = false,\n blur = false,\n rotate = 0,\n flip = false,\n spring = false,\n once = true,\n transition,\n}: AnimateOnViewProps) {\n const ref = useRef<HTMLElement>(null)\n const [hydrated, setHydrated] = useState(false)\n const isInView = useInView(ref, { once, margin: \"-50px\" })\n\n useEffect(() => {\n setHydrated(true)\n }, [])\n\n if (!isValidElement(children)) return children\n\n const childProps = children.props as Record<string, unknown>\n const existingStyle = (childProps.style ?? {}) as CSSProperties\n const existingRef = (childProps as { ref?: Ref<HTMLElement> }).ref\n\n if (!hydrated) {\n return cloneElement(children, {\n ref: mergeRefs(ref, existingRef),\n } as Record<string, unknown>)\n }\n\n const styles = buildStyles({ from, distance, doScale: scale, blur, rotate, flip })\n const { duration, ease } = getTransitionParams(transition, spring, 0.4)\n const currentStyle = isInView ? styles.visible : styles.hidden\n const transitionStr = buildTransitionStr(duration, ease, delay, styles.hasFilter)\n\n return cloneElement(children, {\n ref: mergeRefs(ref, existingRef),\n style: {\n ...existingStyle,\n ...currentStyle,\n ...(isInView ? { transition: transitionStr } : {}),\n willChange: \"opacity, transform\",\n },\n } as Record<string, unknown>)\n}\n\n// ── AnimateIn ────────────────────────────────────────────────────────\n\n/**\n * Animates a child element immediately on mount.\n *\n * Zero DOM overhead — applies styles directly to the child via cloneElement.\n * Uses a two-phase approach: hidden → visible with requestAnimationFrame.\n *\n * @example\n * ```tsx\n * <AnimateIn from=\"up\" blur spring>\n * <h1>Welcome</h1>\n * </AnimateIn>\n * ```\n */\nfunction AnimateIn({\n children,\n delay = 0,\n from = \"down\",\n distance = 4,\n scale = false,\n blur = false,\n rotate = 0,\n flip = false,\n spring = false,\n transition,\n}: AnimateInProps) {\n const ref = useRef<HTMLElement>(null)\n const [visible, setVisible] = useState(false)\n\n useEffect(() => {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => setVisible(true))\n })\n }, [])\n\n if (!isValidElement(children)) return children\n\n const childProps = children.props as Record<string, unknown>\n const existingStyle = (childProps.style ?? {}) as CSSProperties\n const existingRef = (childProps as { ref?: Ref<HTMLElement> }).ref\n\n const styles = buildStyles({ from, distance, doScale: scale, blur, rotate, flip })\n const { duration, ease } = getTransitionParams(transition, spring)\n const currentStyle = visible ? styles.visible : styles.hidden\n const transitionStr = buildTransitionStr(duration, ease, delay, styles.hasFilter)\n\n return cloneElement(children, {\n ref: mergeRefs(ref, existingRef),\n style: {\n ...existingStyle,\n ...currentStyle,\n ...(visible ? { transition: transitionStr } : {}),\n willChange: \"opacity, transform\",\n },\n } as Record<string, unknown>)\n}\n\n// ── Stagger ──────────────────────────────────────────────────────────\n\n/**\n * Auto-staggers delay on child AnimateIn/AnimateOnView elements.\n * Eliminates manual `delay={i * 0.08}` math.\n *\n * @example\n * ```tsx\n * <Stagger interval={0.1}>\n * <AnimateIn from=\"up\"><Card>One</Card></AnimateIn>\n * <AnimateIn from=\"up\"><Card>Two</Card></AnimateIn>\n * </Stagger>\n * ```\n */\nfunction Stagger({\n children,\n interval = 0.08,\n baseDelay = 0,\n}: StaggerProps) {\n return (\n <>\n {Children.map(children, (child, index) => {\n if (!isValidElement(child)) return child\n return cloneElement(child as ReactElement<{ delay?: number }>, {\n delay: baseDelay + index * interval,\n })\n })}\n </>\n )\n}\n\n// ── Pulse ────────────────────────────────────────────────────────────\n\n/**\n * Continuous, subtle scale pulse. Great for live indicators and CTAs.\n * Zero DOM overhead — injects a scoped keyframe via `<style>`.\n *\n * @example\n * ```tsx\n * <Pulse>\n * <span className=\"size-3 rounded-full bg-green-500\" />\n * </Pulse>\n * ```\n */\nfunction Pulse({\n children,\n min = 0.97,\n max = 1.03,\n duration = 2,\n opacity,\n paused = false,\n}: PulseProps) {\n const id = useId().replace(/:/g, \"\")\n const [hydrated, setHydrated] = useState(false)\n\n useEffect(() => {\n setHydrated(true)\n }, [])\n\n if (!isValidElement(children)) return children\n if (!hydrated) return children\n\n const name = `pulse-${id}`\n const opacityFrom = opacity?.[0] ?? 1\n const opacityTo = opacity?.[1] ?? 1\n\n const keyframes = `@keyframes ${name} {\n 0%, 100% { transform: scale(${min}); opacity: ${opacityFrom}; }\n 50% { transform: scale(${max}); opacity: ${opacityTo}; }\n}`\n\n const childProps = children.props as Record<string, unknown>\n const existingStyle = (childProps.style ?? {}) as CSSProperties\n const existingRef = (childProps as { ref?: Ref<HTMLElement> }).ref\n\n return (\n <>\n <style>{keyframes}</style>\n {cloneElement(children, {\n ref: existingRef ? mergeRefs(existingRef) : undefined,\n style: {\n ...existingStyle,\n animation: `${name} ${duration}s ease-in-out infinite`,\n animationPlayState: paused ? \"paused\" : \"running\",\n },\n } as Record<string, unknown>)}\n </>\n )\n}\n\n// ── Float ────────────────────────────────────────────────────────────\n\n/**\n * Gentle continuous up/down float. Perfect for decorative elements.\n * Zero DOM overhead — injects a scoped keyframe via `<style>`.\n *\n * @example\n * ```tsx\n * <Float distance={10} duration={4}>\n * <Card>Floating</Card>\n * </Float>\n * ```\n */\nfunction Float({\n children,\n distance = 6,\n duration = 3,\n rotate = 0,\n paused = false,\n}: FloatProps) {\n const id = useId().replace(/:/g, \"\")\n const [hydrated, setHydrated] = useState(false)\n\n useEffect(() => {\n setHydrated(true)\n }, [])\n\n if (!isValidElement(children)) return children\n if (!hydrated) return children\n\n const name = `float-${id}`\n const rotA = rotate ? ` rotate(${-rotate}deg)` : \"\"\n const rotB = rotate ? ` rotate(${rotate}deg)` : \"\"\n\n const keyframes = `@keyframes ${name} {\n 0%, 100% { transform: translateY(0px)${rotA}; }\n 50% { transform: translateY(${-distance}px)${rotB}; }\n}`\n\n const childProps = children.props as Record<string, unknown>\n const existingStyle = (childProps.style ?? {}) as CSSProperties\n const existingRef = (childProps as { ref?: Ref<HTMLElement> }).ref\n\n return (\n <>\n <style>{keyframes}</style>\n {cloneElement(children, {\n ...(existingRef ? { ref: existingRef } : {}),\n style: {\n ...existingStyle,\n animation: `${name} ${duration}s ease-in-out infinite`,\n animationPlayState: paused ? \"paused\" : \"running\",\n },\n } as Record<string, unknown>)}\n </>\n )\n}\n\n// ── Exports ──────────────────────────────────────────────────────────\n\nexport { AnimateOnView, AnimateIn, Stagger, Pulse, Float }\nexport type {\n AnimateOnViewProps,\n AnimateInProps,\n StaggerProps,\n PulseProps,\n FloatProps,\n Direction,\n}\n"],"mappings":"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"}
|
package/dist/autocomplete.js
CHANGED
|
@@ -13,7 +13,7 @@ function Autocomplete({ ...props }) {
|
|
|
13
13
|
function AutocompleteInput({ className, ...props }) {
|
|
14
14
|
return /* @__PURE__ */ jsx(Autocomplete$1.Input, {
|
|
15
15
|
"data-slot": "autocomplete-input",
|
|
16
|
-
className: cn("dark:bg-
|
|
16
|
+
className: cn("dark:bg-edge/30 border-edge focus-visible:border-focus focus-visible:ring-focus/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 disabled:bg-edge/50 dark:disabled:bg-edge/80 placeholder:text-soft h-8 w-full min-w-0 rounded-md border bg-transparent px-2.5 py-1 text-base transition-colors outline-none focus-visible:ring-3 disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:ring-3 md:text-sm", className),
|
|
17
17
|
...props
|
|
18
18
|
});
|
|
19
19
|
}
|
|
@@ -68,28 +68,28 @@ function AutocompletePositioner({ className, ...props }) {
|
|
|
68
68
|
function AutocompletePopup({ className, ...props }) {
|
|
69
69
|
return /* @__PURE__ */ jsx(Autocomplete$1.Popup, {
|
|
70
70
|
"data-slot": "autocomplete-popup",
|
|
71
|
-
className: cn("motion-
|
|
71
|
+
className: cn("motion-pop-md bg-elevated text-contrast ring-contrast/10 group/autocomplete-content relative max-h-(--available-height) min-w-(--anchor-width) origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-md shadow-md ring-1", className),
|
|
72
72
|
...props
|
|
73
73
|
});
|
|
74
74
|
}
|
|
75
75
|
function AutocompleteArrow({ className, ...props }) {
|
|
76
76
|
return /* @__PURE__ */ jsx(Autocomplete$1.Arrow, {
|
|
77
77
|
"data-slot": "autocomplete-arrow",
|
|
78
|
-
className: cn("fill-
|
|
78
|
+
className: cn("fill-elevated", className),
|
|
79
79
|
...props
|
|
80
80
|
});
|
|
81
81
|
}
|
|
82
82
|
function AutocompleteStatus({ className, ...props }) {
|
|
83
83
|
return /* @__PURE__ */ jsx(Autocomplete$1.Status, {
|
|
84
84
|
"data-slot": "autocomplete-status",
|
|
85
|
-
className: cn("text-muted
|
|
85
|
+
className: cn("text-muted flex w-full justify-center py-2 text-center text-sm", className),
|
|
86
86
|
...props
|
|
87
87
|
});
|
|
88
88
|
}
|
|
89
89
|
function AutocompleteEmpty({ className, ...props }) {
|
|
90
90
|
return /* @__PURE__ */ jsx(Autocomplete$1.Empty, {
|
|
91
91
|
"data-slot": "autocomplete-empty",
|
|
92
|
-
className: cn("text-muted
|
|
92
|
+
className: cn("text-muted hidden w-full justify-center py-2 text-center text-sm group-data-empty/autocomplete-content:flex", className),
|
|
93
93
|
...props
|
|
94
94
|
});
|
|
95
95
|
}
|
|
@@ -110,14 +110,14 @@ function AutocompleteRow({ className, ...props }) {
|
|
|
110
110
|
function AutocompleteItem({ className, ...props }) {
|
|
111
111
|
return /* @__PURE__ */ jsx(Autocomplete$1.Item, {
|
|
112
112
|
"data-slot": "autocomplete-item",
|
|
113
|
-
className: cn("data-highlighted:bg-
|
|
113
|
+
className: cn("data-highlighted:bg-primary data-highlighted:text-white relative flex w-full cursor-clickable items-center gap-2 rounded-sm py-1 pl-1.5 pr-1.5 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className),
|
|
114
114
|
...props
|
|
115
115
|
});
|
|
116
116
|
}
|
|
117
117
|
function AutocompleteSeparator({ className, ...props }) {
|
|
118
118
|
return /* @__PURE__ */ jsx(Autocomplete$1.Separator, {
|
|
119
119
|
"data-slot": "autocomplete-separator",
|
|
120
|
-
className: cn("bg-
|
|
120
|
+
className: cn("bg-line -mx-1 my-1 h-px", className),
|
|
121
121
|
...props
|
|
122
122
|
});
|
|
123
123
|
}
|
|
@@ -131,7 +131,7 @@ function AutocompleteGroup({ className, ...props }) {
|
|
|
131
131
|
function AutocompleteGroupLabel({ className, ...props }) {
|
|
132
132
|
return /* @__PURE__ */ jsx(Autocomplete$1.GroupLabel, {
|
|
133
133
|
"data-slot": "autocomplete-group-label",
|
|
134
|
-
className: cn("text-muted
|
|
134
|
+
className: cn("text-muted px-2 py-1.5 text-xs", className),
|
|
135
135
|
...props
|
|
136
136
|
});
|
|
137
137
|
}
|
package/dist/autocomplete.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"autocomplete.js","names":["AutocompletePrimitive"],"sources":["../src/autocomplete.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\n\nimport { Autocomplete as AutocompletePrimitive } from \"@base-ui/react/autocomplete\"\n\nimport { cn } from \"./lib/utils\"\n\ntype AutocompleteProps = React.ComponentProps<typeof AutocompletePrimitive.Root>\ntype AutocompleteInputProps = React.ComponentProps<typeof AutocompletePrimitive.Input>\ntype AutocompleteTriggerProps = React.ComponentProps<typeof AutocompletePrimitive.Trigger>\ntype AutocompleteIconProps = React.ComponentProps<typeof AutocompletePrimitive.Icon>\ntype AutocompleteClearProps = React.ComponentProps<typeof AutocompletePrimitive.Clear>\ntype AutocompleteValueProps = React.ComponentProps<typeof AutocompletePrimitive.Value>\n\ntype AutocompletePortalProps = React.ComponentProps<typeof AutocompletePrimitive.Portal>\ntype AutocompleteBackdropProps = React.ComponentProps<typeof AutocompletePrimitive.Backdrop>\ntype AutocompletePositionerProps = React.ComponentProps<typeof AutocompletePrimitive.Positioner>\ntype AutocompletePopupProps = React.ComponentProps<typeof AutocompletePrimitive.Popup>\ntype AutocompleteArrowProps = React.ComponentProps<typeof AutocompletePrimitive.Arrow>\ntype AutocompleteStatusProps = React.ComponentProps<typeof AutocompletePrimitive.Status>\ntype AutocompleteEmptyProps = React.ComponentProps<typeof AutocompletePrimitive.Empty>\n\ntype AutocompleteListProps = React.ComponentProps<typeof AutocompletePrimitive.List>\ntype AutocompleteRowProps = React.ComponentProps<typeof AutocompletePrimitive.Row>\ntype AutocompleteItemProps = React.ComponentProps<typeof AutocompletePrimitive.Item>\ntype AutocompleteSeparatorProps = React.ComponentProps<typeof AutocompletePrimitive.Separator>\ntype AutocompleteGroupProps = React.ComponentProps<typeof AutocompletePrimitive.Group>\ntype AutocompleteGroupLabelProps = React.ComponentProps<typeof AutocompletePrimitive.GroupLabel>\ntype AutocompleteCollectionProps = React.ComponentProps<typeof AutocompletePrimitive.Collection>\n\ntype AutocompleteContentProps = AutocompletePopupProps &\n Pick<\n AutocompletePositionerProps,\n \"align\" | \"alignOffset\" | \"side\" | \"sideOffset\"\n >\n\nfunction Autocomplete({ ...props }: AutocompleteProps) {\n return <AutocompletePrimitive.Root data-slot=\"autocomplete\" {...props} />\n}\n\nfunction AutocompleteInput({ className, ...props }: AutocompleteInputProps) {\n return (\n <AutocompletePrimitive.Input\n data-slot=\"autocomplete-input\"\n className={cn(\n \"dark:bg-input/30 border-input focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 disabled:bg-input/50 dark:disabled:bg-input/80 placeholder:text-muted-foreground h-8 w-full min-w-0 rounded-lg border bg-transparent px-2.5 py-1 text-base transition-colors outline-none focus-visible:ring-3 disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:ring-3 md:text-sm\",\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction AutocompleteTrigger({ className, ...props }: AutocompleteTriggerProps) {\n return (\n <AutocompletePrimitive.Trigger\n data-slot=\"autocomplete-trigger\"\n className={cn(\"shrink-0\", className)}\n {...props}\n />\n )\n}\n\nfunction AutocompleteIcon({ className, ...props }: AutocompleteIconProps) {\n return (\n <AutocompletePrimitive.Icon\n data-slot=\"autocomplete-icon\"\n className={cn(\"shrink-0\", className)}\n {...props}\n />\n )\n}\n\nfunction AutocompleteClear({ className, ...props }: AutocompleteClearProps) {\n return (\n <AutocompletePrimitive.Clear\n data-slot=\"autocomplete-clear\"\n className={cn(\"shrink-0\", className)}\n {...props}\n />\n )\n}\n\nfunction AutocompleteValue({ ...props }: AutocompleteValueProps) {\n return (\n <AutocompletePrimitive.Value data-slot=\"autocomplete-value\" {...props} />\n )\n}\n\nfunction AutocompletePortal({ className, ...props }: AutocompletePortalProps) {\n return (\n <AutocompletePrimitive.Portal\n data-slot=\"autocomplete-portal\"\n className={cn(className)}\n {...props}\n />\n )\n}\n\nfunction AutocompleteBackdrop({ className, ...props }: AutocompleteBackdropProps) {\n return (\n <AutocompletePrimitive.Backdrop\n data-slot=\"autocomplete-backdrop\"\n className={cn(\"fixed inset-0\", className)}\n {...props}\n />\n )\n}\n\nfunction AutocompletePositioner({ className, ...props }: AutocompletePositionerProps) {\n return (\n <AutocompletePrimitive.Positioner\n data-slot=\"autocomplete-positioner\"\n className={cn(className)}\n {...props}\n />\n )\n}\n\nfunction AutocompletePopup({ className, ...props }: AutocompletePopupProps) {\n return (\n <AutocompletePrimitive.Popup\n data-slot=\"autocomplete-popup\"\n className={cn(\n \"motion-slide bg-popover text-popover-foreground ring-foreground/10 group/autocomplete-content relative max-h-(--available-height) min-w-(--anchor-width) origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-lg shadow-md ring-1\",\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction AutocompleteArrow({ className, ...props }: AutocompleteArrowProps) {\n return (\n <AutocompletePrimitive.Arrow\n data-slot=\"autocomplete-arrow\"\n className={cn(\"fill-popover\", className)}\n {...props}\n />\n )\n}\n\nfunction AutocompleteStatus({ className, ...props }: AutocompleteStatusProps) {\n return (\n <AutocompletePrimitive.Status\n data-slot=\"autocomplete-status\"\n className={cn(\"text-muted-foreground flex w-full justify-center py-2 text-center text-sm\", className)}\n {...props}\n />\n )\n}\n\nfunction AutocompleteEmpty({ className, ...props }: AutocompleteEmptyProps) {\n return (\n <AutocompletePrimitive.Empty\n data-slot=\"autocomplete-empty\"\n className={cn(\"text-muted-foreground hidden w-full justify-center py-2 text-center text-sm group-data-empty/autocomplete-content:flex\", className)}\n {...props}\n />\n )\n}\n\nfunction AutocompleteList({ className, ...props }: AutocompleteListProps) {\n return (\n <AutocompletePrimitive.List\n data-slot=\"autocomplete-list\"\n className={cn(\"scroll-py-1 overflow-y-auto overscroll-contain p-1 data-empty:p-0\", className)}\n {...props}\n />\n )\n}\n\nfunction AutocompleteRow({ className, ...props }: AutocompleteRowProps) {\n return (\n <AutocompletePrimitive.Row\n data-slot=\"autocomplete-row\"\n className={cn(className)}\n {...props}\n />\n )\n}\n\nfunction AutocompleteItem({ className, ...props }: AutocompleteItemProps) {\n return (\n <AutocompletePrimitive.Item\n data-slot=\"autocomplete-item\"\n className={cn(\n \"data-highlighted:bg-accent data-highlighted:text-accent-foreground relative flex w-full cursor-clickable items-center gap-2 rounded-md py-1 pl-1.5 pr-1.5 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction AutocompleteSeparator({ className, ...props }: AutocompleteSeparatorProps) {\n return (\n <AutocompletePrimitive.Separator\n data-slot=\"autocomplete-separator\"\n className={cn(\"bg-border -mx-1 my-1 h-px\", className)}\n {...props}\n />\n )\n}\n\nfunction AutocompleteGroup({ className, ...props }: AutocompleteGroupProps) {\n return (\n <AutocompletePrimitive.Group\n data-slot=\"autocomplete-group\"\n className={cn(\"pt-1\", className)}\n {...props}\n />\n )\n}\n\nfunction AutocompleteGroupLabel({ className, ...props }: AutocompleteGroupLabelProps) {\n return (\n <AutocompletePrimitive.GroupLabel\n data-slot=\"autocomplete-group-label\"\n className={cn(\"text-muted-foreground px-2 py-1.5 text-xs\", className)}\n {...props}\n />\n )\n}\n\nfunction AutocompleteCollection({ ...props }: AutocompleteCollectionProps) {\n return (\n <AutocompletePrimitive.Collection\n data-slot=\"autocomplete-collection\"\n {...props}\n />\n )\n}\n\nfunction AutocompleteContent({\n className,\n align = \"start\",\n alignOffset = 0,\n side = \"bottom\",\n sideOffset = 6,\n ...props\n}: AutocompleteContentProps) {\n return (\n <AutocompletePortal>\n <AutocompletePositioner\n align={align}\n alignOffset={alignOffset}\n side={side}\n sideOffset={sideOffset}\n className=\"isolate z-50\"\n >\n <AutocompletePopup className={className} {...props} />\n </AutocompletePositioner>\n </AutocompletePortal>\n )\n}\n\nexport {\n Autocomplete,\n AutocompleteArrow,\n AutocompleteBackdrop,\n AutocompleteClear,\n AutocompleteCollection,\n AutocompleteContent,\n AutocompleteEmpty,\n AutocompleteGroup,\n AutocompleteGroupLabel,\n AutocompleteIcon,\n AutocompleteInput,\n AutocompleteItem,\n AutocompleteList,\n AutocompletePopup,\n AutocompletePortal,\n AutocompletePositioner,\n AutocompleteRow,\n AutocompleteSeparator,\n AutocompleteStatus,\n AutocompleteTrigger,\n AutocompleteValue,\n}"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"autocomplete.js","names":["AutocompletePrimitive"],"sources":["../src/autocomplete.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\n\nimport { Autocomplete as AutocompletePrimitive } from \"@base-ui/react/autocomplete\"\n\nimport { cn } from \"./lib/utils\"\n\ntype AutocompleteProps = React.ComponentProps<typeof AutocompletePrimitive.Root>\ntype AutocompleteInputProps = React.ComponentProps<typeof AutocompletePrimitive.Input>\ntype AutocompleteTriggerProps = React.ComponentProps<typeof AutocompletePrimitive.Trigger>\ntype AutocompleteIconProps = React.ComponentProps<typeof AutocompletePrimitive.Icon>\ntype AutocompleteClearProps = React.ComponentProps<typeof AutocompletePrimitive.Clear>\ntype AutocompleteValueProps = React.ComponentProps<typeof AutocompletePrimitive.Value>\n\ntype AutocompletePortalProps = React.ComponentProps<typeof AutocompletePrimitive.Portal>\ntype AutocompleteBackdropProps = React.ComponentProps<typeof AutocompletePrimitive.Backdrop>\ntype AutocompletePositionerProps = React.ComponentProps<typeof AutocompletePrimitive.Positioner>\ntype AutocompletePopupProps = React.ComponentProps<typeof AutocompletePrimitive.Popup>\ntype AutocompleteArrowProps = React.ComponentProps<typeof AutocompletePrimitive.Arrow>\ntype AutocompleteStatusProps = React.ComponentProps<typeof AutocompletePrimitive.Status>\ntype AutocompleteEmptyProps = React.ComponentProps<typeof AutocompletePrimitive.Empty>\n\ntype AutocompleteListProps = React.ComponentProps<typeof AutocompletePrimitive.List>\ntype AutocompleteRowProps = React.ComponentProps<typeof AutocompletePrimitive.Row>\ntype AutocompleteItemProps = React.ComponentProps<typeof AutocompletePrimitive.Item>\ntype AutocompleteSeparatorProps = React.ComponentProps<typeof AutocompletePrimitive.Separator>\ntype AutocompleteGroupProps = React.ComponentProps<typeof AutocompletePrimitive.Group>\ntype AutocompleteGroupLabelProps = React.ComponentProps<typeof AutocompletePrimitive.GroupLabel>\ntype AutocompleteCollectionProps = React.ComponentProps<typeof AutocompletePrimitive.Collection>\n\ntype AutocompleteContentProps = AutocompletePopupProps &\n Pick<\n AutocompletePositionerProps,\n \"align\" | \"alignOffset\" | \"side\" | \"sideOffset\"\n >\n\nfunction Autocomplete({ ...props }: AutocompleteProps) {\n return <AutocompletePrimitive.Root data-slot=\"autocomplete\" {...props} />\n}\n\nfunction AutocompleteInput({ className, ...props }: AutocompleteInputProps) {\n return (\n <AutocompletePrimitive.Input\n data-slot=\"autocomplete-input\"\n className={cn(\n \"dark:bg-edge/30 border-edge focus-visible:border-focus focus-visible:ring-focus/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 disabled:bg-edge/50 dark:disabled:bg-edge/80 placeholder:text-soft h-8 w-full min-w-0 rounded-md border bg-transparent px-2.5 py-1 text-base transition-colors outline-none focus-visible:ring-3 disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:ring-3 md:text-sm\",\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction AutocompleteTrigger({ className, ...props }: AutocompleteTriggerProps) {\n return (\n <AutocompletePrimitive.Trigger\n data-slot=\"autocomplete-trigger\"\n className={cn(\"shrink-0\", className)}\n {...props}\n />\n )\n}\n\nfunction AutocompleteIcon({ className, ...props }: AutocompleteIconProps) {\n return (\n <AutocompletePrimitive.Icon\n data-slot=\"autocomplete-icon\"\n className={cn(\"shrink-0\", className)}\n {...props}\n />\n )\n}\n\nfunction AutocompleteClear({ className, ...props }: AutocompleteClearProps) {\n return (\n <AutocompletePrimitive.Clear\n data-slot=\"autocomplete-clear\"\n className={cn(\"shrink-0\", className)}\n {...props}\n />\n )\n}\n\nfunction AutocompleteValue({ ...props }: AutocompleteValueProps) {\n return (\n <AutocompletePrimitive.Value data-slot=\"autocomplete-value\" {...props} />\n )\n}\n\nfunction AutocompletePortal({ className, ...props }: AutocompletePortalProps) {\n return (\n <AutocompletePrimitive.Portal\n data-slot=\"autocomplete-portal\"\n className={cn(className)}\n {...props}\n />\n )\n}\n\nfunction AutocompleteBackdrop({ className, ...props }: AutocompleteBackdropProps) {\n return (\n <AutocompletePrimitive.Backdrop\n data-slot=\"autocomplete-backdrop\"\n className={cn(\"fixed inset-0\", className)}\n {...props}\n />\n )\n}\n\nfunction AutocompletePositioner({ className, ...props }: AutocompletePositionerProps) {\n return (\n <AutocompletePrimitive.Positioner\n data-slot=\"autocomplete-positioner\"\n className={cn(className)}\n {...props}\n />\n )\n}\n\nfunction AutocompletePopup({ className, ...props }: AutocompletePopupProps) {\n return (\n <AutocompletePrimitive.Popup\n data-slot=\"autocomplete-popup\"\n className={cn(\n \"motion-pop-md bg-elevated text-contrast ring-contrast/10 group/autocomplete-content relative max-h-(--available-height) min-w-(--anchor-width) origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-md shadow-md ring-1\",\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction AutocompleteArrow({ className, ...props }: AutocompleteArrowProps) {\n return (\n <AutocompletePrimitive.Arrow\n data-slot=\"autocomplete-arrow\"\n className={cn(\"fill-elevated\", className)}\n {...props}\n />\n )\n}\n\nfunction AutocompleteStatus({ className, ...props }: AutocompleteStatusProps) {\n return (\n <AutocompletePrimitive.Status\n data-slot=\"autocomplete-status\"\n className={cn(\"text-muted flex w-full justify-center py-2 text-center text-sm\", className)}\n {...props}\n />\n )\n}\n\nfunction AutocompleteEmpty({ className, ...props }: AutocompleteEmptyProps) {\n return (\n <AutocompletePrimitive.Empty\n data-slot=\"autocomplete-empty\"\n className={cn(\"text-muted hidden w-full justify-center py-2 text-center text-sm group-data-empty/autocomplete-content:flex\", className)}\n {...props}\n />\n )\n}\n\nfunction AutocompleteList({ className, ...props }: AutocompleteListProps) {\n return (\n <AutocompletePrimitive.List\n data-slot=\"autocomplete-list\"\n className={cn(\"scroll-py-1 overflow-y-auto overscroll-contain p-1 data-empty:p-0\", className)}\n {...props}\n />\n )\n}\n\nfunction AutocompleteRow({ className, ...props }: AutocompleteRowProps) {\n return (\n <AutocompletePrimitive.Row\n data-slot=\"autocomplete-row\"\n className={cn(className)}\n {...props}\n />\n )\n}\n\nfunction AutocompleteItem({ className, ...props }: AutocompleteItemProps) {\n return (\n <AutocompletePrimitive.Item\n data-slot=\"autocomplete-item\"\n className={cn(\n \"data-highlighted:bg-primary data-highlighted:text-white relative flex w-full cursor-clickable items-center gap-2 rounded-sm py-1 pl-1.5 pr-1.5 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction AutocompleteSeparator({ className, ...props }: AutocompleteSeparatorProps) {\n return (\n <AutocompletePrimitive.Separator\n data-slot=\"autocomplete-separator\"\n className={cn(\"bg-line -mx-1 my-1 h-px\", className)}\n {...props}\n />\n )\n}\n\nfunction AutocompleteGroup({ className, ...props }: AutocompleteGroupProps) {\n return (\n <AutocompletePrimitive.Group\n data-slot=\"autocomplete-group\"\n className={cn(\"pt-1\", className)}\n {...props}\n />\n )\n}\n\nfunction AutocompleteGroupLabel({ className, ...props }: AutocompleteGroupLabelProps) {\n return (\n <AutocompletePrimitive.GroupLabel\n data-slot=\"autocomplete-group-label\"\n className={cn(\"text-muted px-2 py-1.5 text-xs\", className)}\n {...props}\n />\n )\n}\n\nfunction AutocompleteCollection({ ...props }: AutocompleteCollectionProps) {\n return (\n <AutocompletePrimitive.Collection\n data-slot=\"autocomplete-collection\"\n {...props}\n />\n )\n}\n\nfunction AutocompleteContent({\n className,\n align = \"start\",\n alignOffset = 0,\n side = \"bottom\",\n sideOffset = 6,\n ...props\n}: AutocompleteContentProps) {\n return (\n <AutocompletePortal>\n <AutocompletePositioner\n align={align}\n alignOffset={alignOffset}\n side={side}\n sideOffset={sideOffset}\n className=\"isolate z-50\"\n >\n <AutocompletePopup className={className} {...props} />\n </AutocompletePositioner>\n </AutocompletePortal>\n )\n}\n\nexport {\n Autocomplete,\n AutocompleteArrow,\n AutocompleteBackdrop,\n AutocompleteClear,\n AutocompleteCollection,\n AutocompleteContent,\n AutocompleteEmpty,\n AutocompleteGroup,\n AutocompleteGroupLabel,\n AutocompleteIcon,\n AutocompleteInput,\n AutocompleteItem,\n AutocompleteList,\n AutocompletePopup,\n AutocompletePortal,\n AutocompletePositioner,\n AutocompleteRow,\n AutocompleteSeparator,\n AutocompleteStatus,\n AutocompleteTrigger,\n AutocompleteValue,\n}"],"mappings":"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"}
|
package/dist/avatar.js
CHANGED
|
@@ -8,7 +8,7 @@ function Avatar({ className, size = "default", ...props }) {
|
|
|
8
8
|
return /* @__PURE__ */ jsx(Avatar$1.Root, {
|
|
9
9
|
"data-slot": "avatar",
|
|
10
10
|
"data-size": size,
|
|
11
|
-
className: cn("after:border-
|
|
11
|
+
className: cn("after:border-line group/avatar relative flex size-8 shrink-0 rounded-full select-none after:absolute after:inset-0 after:rounded-full after:border after:mix-blend-darken data-[size=lg]:size-10 data-[size=sm]:size-6 dark:after:mix-blend-lighten", className),
|
|
12
12
|
...props
|
|
13
13
|
});
|
|
14
14
|
}
|
|
@@ -22,28 +22,28 @@ function AvatarImage({ className, ...props }) {
|
|
|
22
22
|
function AvatarFallback({ className, ...props }) {
|
|
23
23
|
return /* @__PURE__ */ jsx(Avatar$1.Fallback, {
|
|
24
24
|
"data-slot": "avatar-fallback",
|
|
25
|
-
className: cn("bg-
|
|
25
|
+
className: cn("bg-secondary text-muted flex size-full items-center justify-center rounded-full text-sm group-data-[size=sm]/avatar:text-xs", className),
|
|
26
26
|
...props
|
|
27
27
|
});
|
|
28
28
|
}
|
|
29
29
|
function AvatarBadge({ className, ...props }) {
|
|
30
30
|
return /* @__PURE__ */ jsx("span", {
|
|
31
31
|
"data-slot": "avatar-badge",
|
|
32
|
-
className: cn("bg-primary text-
|
|
32
|
+
className: cn("bg-primary text-white ring-foundation absolute right-0 bottom-0 z-10 inline-flex items-center justify-center rounded-full bg-blend-color ring-2 select-none", "group-data-[size=sm]/avatar:size-2 group-data-[size=sm]/avatar:[&>svg]:hidden", "group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2", "group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2", className),
|
|
33
33
|
...props
|
|
34
34
|
});
|
|
35
35
|
}
|
|
36
36
|
function AvatarGroup({ className, ...props }) {
|
|
37
37
|
return /* @__PURE__ */ jsx("div", {
|
|
38
38
|
"data-slot": "avatar-group",
|
|
39
|
-
className: cn("*:data-[slot=avatar]:ring-
|
|
39
|
+
className: cn("*:data-[slot=avatar]:ring-foundation group/avatar-group flex -space-x-2 *:data-[slot=avatar]:ring-2", className),
|
|
40
40
|
...props
|
|
41
41
|
});
|
|
42
42
|
}
|
|
43
43
|
function AvatarGroupCount({ className, ...props }) {
|
|
44
44
|
return /* @__PURE__ */ jsx("div", {
|
|
45
45
|
"data-slot": "avatar-group-count",
|
|
46
|
-
className: cn("bg-
|
|
46
|
+
className: cn("bg-secondary text-muted ring-foundation relative flex size-8 shrink-0 items-center justify-center rounded-full text-sm ring-2 group-has-data-[size=lg]/avatar-group:size-10 group-has-data-[size=sm]/avatar-group:size-6 [&>svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 group-has-data-[size=sm]/avatar-group:[&>svg]:size-3", className),
|
|
47
47
|
...props
|
|
48
48
|
});
|
|
49
49
|
}
|