@particle-academy/react-fancy 6.0.0 → 6.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +75 -0
- package/dist/badge.cjs +3 -2
- package/dist/badge.js +2 -1
- package/dist/breadcrumbs.cjs +2 -2
- package/dist/breadcrumbs.js +1 -1
- package/dist/button.cjs +3 -3
- package/dist/button.js +1 -1
- package/dist/callout.cjs +2 -2
- package/dist/callout.js +1 -1
- package/dist/chat-thread.cjs +7 -6
- package/dist/chat-thread.js +5 -4
- package/dist/{chunk-PACFMPSX.js → chunk-23KQF47X.js} +5 -5
- package/dist/{chunk-PACFMPSX.js.map → chunk-23KQF47X.js.map} +1 -1
- package/dist/{chunk-GBR4Q6CP.js → chunk-3AA2KGZG.js} +3 -3
- package/dist/{chunk-GBR4Q6CP.js.map → chunk-3AA2KGZG.js.map} +1 -1
- package/dist/{chunk-YUNOVQQJ.js → chunk-3S5ED522.js} +12 -2
- package/dist/chunk-3S5ED522.js.map +1 -0
- package/dist/{chunk-WLDDGIGC.js → chunk-4GPH7HOR.js} +11 -3
- package/dist/chunk-4GPH7HOR.js.map +1 -0
- package/dist/{chunk-LWOA2ET6.js → chunk-B6WTCAGY.js} +3 -3
- package/dist/{chunk-LWOA2ET6.js.map → chunk-B6WTCAGY.js.map} +1 -1
- package/dist/{chunk-JKH5ODNG.cjs → chunk-CKO2KCUN.cjs} +9 -9
- package/dist/{chunk-JKH5ODNG.cjs.map → chunk-CKO2KCUN.cjs.map} +1 -1
- package/dist/{chunk-BQFPC5FL.js → chunk-ESCIXKFT.js} +3 -3
- package/dist/{chunk-BQFPC5FL.js.map → chunk-ESCIXKFT.js.map} +1 -1
- package/dist/{chunk-35S5BTZH.cjs → chunk-EWE776WI.cjs} +35 -4
- package/dist/chunk-EWE776WI.cjs.map +1 -0
- package/dist/{chunk-VZ7IDHUY.js → chunk-F4OYQ2XZ.js} +4 -4
- package/dist/{chunk-VZ7IDHUY.js.map → chunk-F4OYQ2XZ.js.map} +1 -1
- package/dist/{chunk-ND5SBHGH.cjs → chunk-FKZB27OM.cjs} +6 -6
- package/dist/{chunk-ND5SBHGH.cjs.map → chunk-FKZB27OM.cjs.map} +1 -1
- package/dist/{chunk-IU5WQUUC.js → chunk-FR4RHVPR.js} +34 -6
- package/dist/chunk-FR4RHVPR.js.map +1 -0
- package/dist/{chunk-EZA6GWZL.cjs → chunk-GK7IGL7N.cjs} +195 -8
- package/dist/chunk-GK7IGL7N.cjs.map +1 -0
- package/dist/{chunk-KOECVLC4.js → chunk-GSMD5NK5.js} +3 -3
- package/dist/{chunk-KOECVLC4.js.map → chunk-GSMD5NK5.js.map} +1 -1
- package/dist/{chunk-ZXGX5RI5.cjs → chunk-I2VAGZXY.cjs} +4 -4
- package/dist/{chunk-ZXGX5RI5.cjs.map → chunk-I2VAGZXY.cjs.map} +1 -1
- package/dist/{chunk-IA6JKI4P.cjs → chunk-K7JOZQRK.cjs} +15 -15
- package/dist/{chunk-IA6JKI4P.cjs.map → chunk-K7JOZQRK.cjs.map} +1 -1
- package/dist/{chunk-H2YRZYKK.cjs → chunk-KFA7B6WP.cjs} +4 -4
- package/dist/{chunk-H2YRZYKK.cjs.map → chunk-KFA7B6WP.cjs.map} +1 -1
- package/dist/{chunk-IB673TEG.cjs → chunk-KOAMRCSC.cjs} +12 -2
- package/dist/chunk-KOAMRCSC.cjs.map +1 -0
- package/dist/{chunk-ZXZJYVWP.js → chunk-KPRSRWNM.js} +3 -3
- package/dist/{chunk-ZXZJYVWP.js.map → chunk-KPRSRWNM.js.map} +1 -1
- package/dist/{chunk-VNOUXFZ2.cjs → chunk-KSSTFLV2.cjs} +20 -20
- package/dist/{chunk-VNOUXFZ2.cjs.map → chunk-KSSTFLV2.cjs.map} +1 -1
- package/dist/{chunk-YJHP5FVA.js → chunk-MTDOFZIB.js} +196 -9
- package/dist/chunk-MTDOFZIB.js.map +1 -0
- package/dist/{chunk-BX6ZVWTO.cjs → chunk-NZHVDWOM.cjs} +11 -3
- package/dist/chunk-NZHVDWOM.cjs.map +1 -0
- package/dist/chunk-OCHUZ7J3.cjs +60 -0
- package/dist/chunk-OCHUZ7J3.cjs.map +1 -0
- package/dist/{chunk-BGRVHPGP.cjs → chunk-OUNGGQIS.cjs} +6 -6
- package/dist/{chunk-BGRVHPGP.cjs.map → chunk-OUNGGQIS.cjs.map} +1 -1
- package/dist/chunk-OZ4QFJ7N.js +58 -0
- package/dist/chunk-OZ4QFJ7N.js.map +1 -0
- package/dist/{chunk-CQ54H7DZ.cjs → chunk-RZUYCZ5D.cjs} +33 -5
- package/dist/chunk-RZUYCZ5D.cjs.map +1 -0
- package/dist/{chunk-MOU6O324.cjs → chunk-S53A6JIE.js} +3 -58
- package/dist/chunk-S53A6JIE.js.map +1 -0
- package/dist/{chunk-X354OVSC.cjs → chunk-SRICSNL4.cjs} +12 -12
- package/dist/{chunk-X354OVSC.cjs.map → chunk-SRICSNL4.cjs.map} +1 -1
- package/dist/{chunk-3RIBZZLT.js → chunk-TH4JZAMK.js} +5 -5
- package/dist/{chunk-3RIBZZLT.js.map → chunk-TH4JZAMK.js.map} +1 -1
- package/dist/{chunk-CWWMT57K.js → chunk-WF6AYHOS.js} +4 -4
- package/dist/{chunk-CWWMT57K.js.map → chunk-WF6AYHOS.js.map} +1 -1
- package/dist/{chunk-A67EDGC7.js → chunk-WJHPZS3U.js} +35 -4
- package/dist/chunk-WJHPZS3U.js.map +1 -0
- package/dist/{chunk-LCNHEYIM.cjs → chunk-WNWEC5OU.cjs} +3 -3
- package/dist/{chunk-LCNHEYIM.cjs.map → chunk-WNWEC5OU.cjs.map} +1 -1
- package/dist/{chunk-6FCQD2KQ.js → chunk-X6LGRB4H.cjs} +7 -55
- package/dist/chunk-X6LGRB4H.cjs.map +1 -0
- package/dist/content-renderer.cjs +5 -5
- package/dist/content-renderer.js +2 -2
- package/dist/editor.cjs +5 -5
- package/dist/editor.js +3 -3
- package/dist/index.cjs +58 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +16 -15
- package/dist/index.js.map +1 -1
- package/dist/inputs.cjs +2 -2
- package/dist/inputs.js +1 -1
- package/dist/json-editor.cjs +16 -15
- package/dist/json-editor.js +5 -4
- package/dist/magic-wand.cjs +5 -4
- package/dist/magic-wand.js +4 -3
- package/dist/multi-switch.cjs +2 -2
- package/dist/multi-switch.js +1 -1
- package/dist/prompt-input.cjs +5 -5
- package/dist/prompt-input.js +2 -2
- package/dist/reason-tag.cjs +3 -3
- package/dist/reason-tag.js +2 -2
- package/dist/sidebar.cjs +4 -3
- package/dist/sidebar.d.cts +49 -4
- package/dist/sidebar.d.ts +49 -4
- package/dist/sidebar.js +2 -1
- package/dist/tabs.cjs +4 -3
- package/dist/tabs.js +2 -1
- package/dist/toast.cjs +5 -4
- package/dist/toast.js +3 -2
- package/docs/Button.md +8 -0
- package/docs/Sidebar.md +75 -1
- package/package.json +1 -1
- package/dist/chunk-35S5BTZH.cjs.map +0 -1
- package/dist/chunk-6FCQD2KQ.js.map +0 -1
- package/dist/chunk-A67EDGC7.js.map +0 -1
- package/dist/chunk-BX6ZVWTO.cjs.map +0 -1
- package/dist/chunk-CQ54H7DZ.cjs.map +0 -1
- package/dist/chunk-EZA6GWZL.cjs.map +0 -1
- package/dist/chunk-IB673TEG.cjs.map +0 -1
- package/dist/chunk-IU5WQUUC.js.map +0 -1
- package/dist/chunk-MOU6O324.cjs.map +0 -1
- package/dist/chunk-WLDDGIGC.js.map +0 -1
- package/dist/chunk-YJHP5FVA.js.map +0 -1
- package/dist/chunk-YUNOVQQJ.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Portal } from './chunk-RBCMKPBX.js';
|
|
2
|
-
import { Badge } from './chunk-
|
|
2
|
+
import { Badge } from './chunk-OZ4QFJ7N.js';
|
|
3
3
|
import { useControllableState } from './chunk-EDYAXGUM.js';
|
|
4
4
|
import { cn } from './chunk-MMW2JGKZ.js';
|
|
5
5
|
import { createContext, useContext, useEffect, useRef, useState, useCallback, useMemo } from 'react';
|
|
@@ -301,5 +301,5 @@ var Toast = {
|
|
|
301
301
|
};
|
|
302
302
|
|
|
303
303
|
export { Toast, useToast };
|
|
304
|
-
//# sourceMappingURL=chunk-
|
|
305
|
-
//# sourceMappingURL=chunk-
|
|
304
|
+
//# sourceMappingURL=chunk-ESCIXKFT.js.map
|
|
305
|
+
//# sourceMappingURL=chunk-ESCIXKFT.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/Toast/Toast.context.ts","../src/components/Toast/ToastItem.tsx","../src/components/Toast/ToastStack.tsx","../src/components/Toast/Toast.tsx"],"names":["useEffect","jsx","jsxs","POSITION_STYLES","useRef"],"mappings":"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","file":"chunk-BQFPC5FL.js","sourcesContent":["import { createContext, useContext } from \"react\";\nimport type { ToastContextValue } from \"./Toast.types\";\n\nexport const ToastContext = createContext<ToastContextValue | null>(null);\n\nexport function useToast(): ToastContextValue {\n const ctx = useContext(ToastContext);\n if (!ctx) {\n throw new Error(\"useToast must be used within a <Toast.Provider>\");\n }\n return ctx;\n}\n","import { useEffect } from \"react\";\nimport { AlertTriangle, Check, Info, X, XCircle } from \"lucide-react\";\nimport { cn } from \"../../utils/cn\";\nimport type { ToastItemProps } from \"./Toast.types\";\n\nconst VARIANT_STYLES = {\n default:\n \"border-[color:var(--fancy-border,var(--color-zinc-200))] bg-[color:var(--fancy-surface,var(--color-white))] dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))] dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\",\n success:\n \"border-emerald-200 bg-emerald-50 dark:border-emerald-800 dark:bg-emerald-950\",\n error:\n \"border-red-200 bg-red-50 dark:border-red-800 dark:bg-red-950\",\n warning:\n \"border-amber-200 bg-amber-50 dark:border-amber-800 dark:bg-amber-950\",\n info: \"border-blue-200 bg-blue-50 dark:border-blue-800 dark:bg-blue-950\",\n} as const;\n\nconst VARIANT_ICON_COLORS = {\n default: \"text-zinc-400\",\n success: \"text-emerald-500\",\n error: \"text-red-500\",\n warning: \"text-amber-500\",\n info: \"text-blue-500\",\n} as const;\n\nexport function ToastItem({ data, onDismiss }: ToastItemProps) {\n const { id, title, description, variant = \"default\", action } = data;\n // An action toast does not expire by default.\n const duration = data.duration ?? (action ? 0 : 5000);\n\n useEffect(() => {\n if (duration <= 0) return;\n const timer = setTimeout(() => onDismiss(id), duration);\n return () => clearTimeout(timer);\n }, [id, duration, onDismiss]);\n\n return (\n <div\n data-react-fancy-toast-item=\"\"\n role=\"alert\"\n // Scoped to the toast rather than the document: a global Escape handler\n // would fight whatever modal or drawer is already listening.\n onKeyDown={(e) => {\n if (e.key === \"Escape\") onDismiss(id);\n }}\n className={cn(\n \"fancy-toast-in pointer-events-auto w-80 rounded-xl border p-4 shadow-lg\",\n VARIANT_STYLES[variant],\n )}\n >\n <div className=\"flex items-start gap-3\">\n <div className={cn(\"mt-0.5 shrink-0\", VARIANT_ICON_COLORS[variant])}>\n {variant === \"success\" && <Check size={16} />}\n {variant === \"error\" && <XCircle size={16} />}\n {variant === \"warning\" && <AlertTriangle size={16} />}\n {variant === \"info\" && <Info size={16} />}\n </div>\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium text-[color:var(--fancy-text,var(--color-zinc-900))] dark:text-[color:var(--fancy-text-dark,var(--color-zinc-100))]\">{title}</p>\n {description && (\n <p className=\"mt-1 text-xs text-[color:var(--fancy-text-muted,var(--color-zinc-500))] dark:text-[color:var(--fancy-text-muted-dark,var(--color-zinc-400))]\">\n {description}\n </p>\n )}\n </div>\n {action && (\n <button\n type=\"button\"\n onClick={() => {\n action.onClick();\n // The offer is consumed; leaving it up invites undoing an\n // already-undone action.\n onDismiss(id);\n }}\n className=\"shrink-0 self-center rounded-md px-2 py-1 text-xs font-medium text-zinc-700 underline-offset-2 transition-colors hover:bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] hover:underline dark:text-zinc-200 dark:hover:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))]\"\n >\n {action.label}\n </button>\n )}\n <button\n type=\"button\"\n onClick={() => onDismiss(id)}\n className=\"shrink-0 rounded p-0.5 text-zinc-400 transition-colors hover:text-zinc-600 dark:hover:text-zinc-300\"\n aria-label=\"Dismiss\"\n >\n <X size={14} />\n </button>\n </div>\n </div>\n );\n}\n\nToastItem.displayName = \"ToastItem\";\n","import { useEffect, useRef, type ReactNode } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { useControllableState } from \"../../hooks/use-controllable-state\";\nimport { Portal } from \"../Portal\";\nimport { Badge } from \"../Badge\";\nimport type { ToastPosition } from \"./Toast.types\";\n\nexport interface ToastStackProps<T> {\n /**\n * Everything to show — the stack is a VIEW of this list and owns none of it.\n * There is no limit and no timer: an item leaves only when you remove it.\n */\n items: readonly T[];\n /** One card's content, actions included. Only the front card is interactive. */\n renderItem: (item: T, state: { index: number; isFront: boolean }) => ReactNode;\n /** A stable key per item. Defaults to `item.id`, then the index. */\n getKey?: (item: T, index: number) => string;\n /** How many cards show behind the front one. Default 2. */\n depth?: number;\n /** How far each card behind peeks out above the one in front, in px. Default 8. */\n offset?: number;\n /** How much smaller each card behind is than the one in front. Default 0.05. */\n scaleStep?: number;\n /** Which item is in front, if you want to own it. Wraps; out-of-range values are clamped. */\n frontIndex?: number;\n defaultFrontIndex?: number;\n onFrontIndexChange?: (index: number) => void;\n /** A screen corner, or `\"inline\"` to render where it is placed. Default `\"bottom-right\"`. */\n position?: ToastPosition | \"inline\";\n /** The stack's accessible name. Default \"Notifications\". */\n label?: string;\n /** Classes for each card's shell, merged onto the defaults. */\n cardClassName?: string;\n className?: string;\n}\n\nconst POSITION_STYLES: Record<ToastPosition, string> = {\n \"top-right\": \"top-4 right-4\",\n \"top-left\": \"top-4 left-4\",\n \"bottom-right\": \"bottom-4 right-4\",\n \"bottom-left\": \"bottom-4 left-4\",\n};\n\n/** Pixels of wheel travel that count as one step. A mouse notch is ~100; a trackpad sends many small ones. */\nconst WHEEL_STEP = 50;\n\nconst CARD =\n \"rounded-xl border border-[color:var(--fancy-border,var(--color-zinc-200))] bg-[color:var(--fancy-surface,var(--color-white))] p-4 shadow-lg dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))] dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\";\n\nfunction defaultKey(item: unknown, index: number): string {\n const id = (item as { id?: unknown } | null)?.id;\n return typeof id === \"string\" || typeof id === \"number\" ? String(id) : String(index);\n}\n\nfunction isTextField(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) return false;\n return (\n target.isContentEditable ||\n target.getAttribute(\"contenteditable\") === \"true\" ||\n /^(INPUT|TEXTAREA|SELECT)$/.test(target.tagName)\n );\n}\n\n/**\n * A controlled stack of actionable toasts — approval requests, say — that the\n * person walks through rather than races.\n *\n * Built for react-fancy#33. The owner's requirements were that requests stack\n * behind each other with a slight top offset, that scrolling over the stack\n * walks through them, and that a pending request NEVER expires or disappears.\n * The last is why this is a view of the caller's list rather than a queue it\n * keeps: there is nothing here that can drop an item, because nothing here owns\n * one. (The imperative provider's `maxToasts` silently drops the oldest.)\n */\nexport function ToastStack<T>({\n items,\n renderItem,\n getKey = defaultKey,\n depth = 2,\n offset = 8,\n scaleStep = 0.05,\n frontIndex: controlledFront,\n defaultFrontIndex = 0,\n onFrontIndexChange,\n position = \"bottom-right\",\n label = \"Notifications\",\n cardClassName,\n className,\n}: ToastStackProps<T>) {\n const [rawFront, setFront] = useControllableState(\n controlledFront,\n defaultFrontIndex,\n onFrontIndexChange,\n );\n const count = items.length;\n // Clamped for display rather than corrected through onChange: a list that\n // shrinks under a far-forward index must not make render report a change.\n const front = count === 0 ? 0 : ((rawFront % count) + count) % count;\n\n const stackRef = useRef<HTMLDivElement>(null);\n const wheelTravel = useRef(0);\n const live = useRef({ front, count });\n live.current = { front, count };\n\n const step = (by: number) => {\n const { front: current, count: n } = live.current;\n if (n < 2) return;\n setFront((((current + by) % n) + n) % n);\n };\n const stepRef = useRef(step);\n stepRef.current = step;\n\n /*\n * A native listener, because React's wheel listener is passive and cannot stop\n * the page scrolling underneath — and a stack that cycles AND scrolls the page\n * moves two things at once under the person's hand.\n */\n useEffect(() => {\n const el = stackRef.current;\n if (!el) return;\n\n const onWheel = (e: WheelEvent) => {\n if (live.current.count < 2 || e.deltaY === 0) return;\n e.preventDefault();\n\n // Line or page mode: every event is a notch.\n if (e.deltaMode !== 0) {\n wheelTravel.current = 0;\n stepRef.current(Math.sign(e.deltaY));\n return;\n }\n // A notch-sized event steps at once; small trackpad deltas add up first.\n if (Math.abs(e.deltaY) >= WHEEL_STEP) {\n wheelTravel.current = 0;\n stepRef.current(Math.sign(e.deltaY));\n return;\n }\n wheelTravel.current += e.deltaY;\n if (Math.abs(wheelTravel.current) >= WHEEL_STEP) {\n stepRef.current(Math.sign(wheelTravel.current));\n wheelTravel.current = 0;\n }\n };\n\n el.addEventListener(\"wheel\", onWheel, { passive: false });\n return () => el.removeEventListener(\"wheel\", onWheel);\n // Re-bound when the element can change: it appears with the first item, and\n // moving between a corner and inline remounts it.\n }, [count > 0, position]);\n\n if (count === 0) return null;\n\n const visibleBehind = Math.min(Math.max(0, depth), count - 1);\n const hidden = count - 1 - visibleBehind;\n\n const card = (index: number, k: number) => {\n const item = items[index];\n const isFront = k === 0;\n return (\n <div\n key={getKey(item, index)}\n data-react-fancy-toast-stack-card={isFront ? \"front\" : \"behind\"}\n aria-hidden={isFront ? undefined : true}\n inert={isFront ? undefined : true}\n className={cn(\n CARD,\n \"origin-top transition-transform duration-200\",\n isFront ? \"relative\" : \"pointer-events-none absolute inset-0 overflow-hidden\",\n cardClassName,\n )}\n style={{\n zIndex: depth + 1 - k,\n transform: isFront ? undefined : `translateY(-${k * offset}px) scale(${1 - k * scaleStep})`,\n }}\n >\n {renderItem(item, { index, isFront })}\n </div>\n );\n };\n\n const stackEl = (\n <div\n ref={stackRef}\n data-react-fancy-toast-stack=\"\"\n role=\"region\"\n aria-label={label}\n tabIndex={0}\n onKeyDown={(e) => {\n if (isTextField(e.target)) return;\n if (e.key === \"ArrowDown\" || e.key === \"ArrowRight\") {\n e.preventDefault();\n step(1);\n } else if (e.key === \"ArrowUp\" || e.key === \"ArrowLeft\") {\n e.preventDefault();\n step(-1);\n }\n }}\n className={cn(\n \"pointer-events-auto relative w-80 rounded-xl outline-none focus-visible:ring-2 focus-visible:ring-violet-500 focus-visible:ring-offset-2\",\n className,\n )}\n style={{ paddingTop: visibleBehind * offset }}\n >\n <div className=\"relative\">\n {/*\n * z-index decides what paints on top; the front card sizes the box.\n * The front card comes FIRST in the DOM, then the cards behind in walk\n * order: the ones behind are absolutely positioned against this box, so\n * their place in the source changes nothing visible -- but it is what\n * a DOM query, `textContent` and copy-paste read.\n */}\n {card(front, 0)}\n {Array.from({ length: visibleBehind }, (_, i) => i + 1).map((k) =>\n card((front + k) % count, k),\n )}\n </div>\n {hidden > 0 && (\n /*\n * Opaque in BOTH themes, because it sits over the cards peeking out\n * behind the front one -- often a light image header. The soft zinc\n * Badge is `dark:bg-zinc-900/30`, which let that image through and left\n * zinc-300 text on a light screenshot (fancy-app-update#1). The dark\n * pair is overridden here, not in Badge, so every other soft badge\n * keeps its look; the ring separates it from a zinc-900 card edge.\n */\n <Badge\n data-react-fancy-toast-stack-more=\"\"\n size=\"sm\"\n variant=\"soft\"\n color=\"zinc\"\n className=\"absolute -top-2 right-2 z-20 shadow-sm ring-1 ring-[color:var(--fancy-border,var(--color-zinc-200))] dark:bg-zinc-800 dark:text-zinc-100 dark:ring-[color:var(--fancy-border-dark,var(--color-zinc-700))]\"\n >\n +{hidden}\n </Badge>\n )}\n <span data-react-fancy-toast-stack-status=\"\" aria-live=\"polite\" className=\"sr-only\">\n {count > 1 ? `${front + 1} of ${count}` : \"\"}\n </span>\n </div>\n );\n\n if (position === \"inline\") return stackEl;\n\n return (\n <Portal>\n <div\n data-react-fancy-toast-stack-position={position}\n className={cn(\"pointer-events-none fixed z-[100]\", POSITION_STYLES[position])}\n >\n {stackEl}\n </div>\n </Portal>\n );\n}\n\nToastStack.displayName = \"ToastStack\";\n","import { useCallback, useMemo, useRef, useState } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { Portal } from \"../Portal\";\nimport { ToastContext } from \"./Toast.context\";\nimport { ToastItem } from \"./ToastItem\";\nimport { ToastStack } from \"./ToastStack\";\nimport type { ToastData, ToastProviderProps } from \"./Toast.types\";\n\nconst POSITION_STYLES = {\n \"top-right\": \"top-4 right-4\",\n \"top-left\": \"top-4 left-4\",\n \"bottom-right\": \"bottom-4 right-4\",\n \"bottom-left\": \"bottom-4 left-4\",\n} as const;\n\nfunction ToastProvider({\n children,\n position = \"bottom-right\",\n maxToasts = 5,\n}: ToastProviderProps) {\n const [toasts, setToasts] = useState<ToastData[]>([]);\n const idCounter = useRef(0);\n\n const toast = useCallback(\n (data: Omit<ToastData, \"id\">) => {\n const id = `toast-${++idCounter.current}`;\n setToasts((prev) => [...prev.slice(-(maxToasts - 1)), { ...data, id }]);\n return id;\n },\n [maxToasts],\n );\n\n const dismiss = useCallback((id: string) => {\n setToasts((prev) => prev.filter((t) => t.id !== id));\n }, []);\n\n const ctx = useMemo(() => ({ toasts, toast, dismiss }), [toasts, toast, dismiss]);\n\n return (\n <ToastContext.Provider value={ctx}>\n {children}\n <Portal>\n <div\n data-react-fancy-toast=\"\"\n className={cn(\n \"fixed z-[100] flex flex-col gap-2 pointer-events-none\",\n POSITION_STYLES[position],\n )}\n >\n {toasts.map((t) => (\n <ToastItem key={t.id} data={t} onDismiss={dismiss} />\n ))}\n </div>\n </Portal>\n </ToastContext.Provider>\n );\n}\n\nexport const Toast = {\n Provider: ToastProvider,\n Stack: ToastStack,\n Item: ToastItem,\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/Toast/Toast.context.ts","../src/components/Toast/ToastItem.tsx","../src/components/Toast/ToastStack.tsx","../src/components/Toast/Toast.tsx"],"names":["useEffect","jsx","jsxs","POSITION_STYLES","useRef"],"mappings":"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","file":"chunk-ESCIXKFT.js","sourcesContent":["import { createContext, useContext } from \"react\";\nimport type { ToastContextValue } from \"./Toast.types\";\n\nexport const ToastContext = createContext<ToastContextValue | null>(null);\n\nexport function useToast(): ToastContextValue {\n const ctx = useContext(ToastContext);\n if (!ctx) {\n throw new Error(\"useToast must be used within a <Toast.Provider>\");\n }\n return ctx;\n}\n","import { useEffect } from \"react\";\nimport { AlertTriangle, Check, Info, X, XCircle } from \"lucide-react\";\nimport { cn } from \"../../utils/cn\";\nimport type { ToastItemProps } from \"./Toast.types\";\n\nconst VARIANT_STYLES = {\n default:\n \"border-[color:var(--fancy-border,var(--color-zinc-200))] bg-[color:var(--fancy-surface,var(--color-white))] dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))] dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\",\n success:\n \"border-emerald-200 bg-emerald-50 dark:border-emerald-800 dark:bg-emerald-950\",\n error:\n \"border-red-200 bg-red-50 dark:border-red-800 dark:bg-red-950\",\n warning:\n \"border-amber-200 bg-amber-50 dark:border-amber-800 dark:bg-amber-950\",\n info: \"border-blue-200 bg-blue-50 dark:border-blue-800 dark:bg-blue-950\",\n} as const;\n\nconst VARIANT_ICON_COLORS = {\n default: \"text-zinc-400\",\n success: \"text-emerald-500\",\n error: \"text-red-500\",\n warning: \"text-amber-500\",\n info: \"text-blue-500\",\n} as const;\n\nexport function ToastItem({ data, onDismiss }: ToastItemProps) {\n const { id, title, description, variant = \"default\", action } = data;\n // An action toast does not expire by default.\n const duration = data.duration ?? (action ? 0 : 5000);\n\n useEffect(() => {\n if (duration <= 0) return;\n const timer = setTimeout(() => onDismiss(id), duration);\n return () => clearTimeout(timer);\n }, [id, duration, onDismiss]);\n\n return (\n <div\n data-react-fancy-toast-item=\"\"\n role=\"alert\"\n // Scoped to the toast rather than the document: a global Escape handler\n // would fight whatever modal or drawer is already listening.\n onKeyDown={(e) => {\n if (e.key === \"Escape\") onDismiss(id);\n }}\n className={cn(\n \"fancy-toast-in pointer-events-auto w-80 rounded-xl border p-4 shadow-lg\",\n VARIANT_STYLES[variant],\n )}\n >\n <div className=\"flex items-start gap-3\">\n <div className={cn(\"mt-0.5 shrink-0\", VARIANT_ICON_COLORS[variant])}>\n {variant === \"success\" && <Check size={16} />}\n {variant === \"error\" && <XCircle size={16} />}\n {variant === \"warning\" && <AlertTriangle size={16} />}\n {variant === \"info\" && <Info size={16} />}\n </div>\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium text-[color:var(--fancy-text,var(--color-zinc-900))] dark:text-[color:var(--fancy-text-dark,var(--color-zinc-100))]\">{title}</p>\n {description && (\n <p className=\"mt-1 text-xs text-[color:var(--fancy-text-muted,var(--color-zinc-500))] dark:text-[color:var(--fancy-text-muted-dark,var(--color-zinc-400))]\">\n {description}\n </p>\n )}\n </div>\n {action && (\n <button\n type=\"button\"\n onClick={() => {\n action.onClick();\n // The offer is consumed; leaving it up invites undoing an\n // already-undone action.\n onDismiss(id);\n }}\n className=\"shrink-0 self-center rounded-md px-2 py-1 text-xs font-medium text-zinc-700 underline-offset-2 transition-colors hover:bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] hover:underline dark:text-zinc-200 dark:hover:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))]\"\n >\n {action.label}\n </button>\n )}\n <button\n type=\"button\"\n onClick={() => onDismiss(id)}\n className=\"shrink-0 rounded p-0.5 text-zinc-400 transition-colors hover:text-zinc-600 dark:hover:text-zinc-300\"\n aria-label=\"Dismiss\"\n >\n <X size={14} />\n </button>\n </div>\n </div>\n );\n}\n\nToastItem.displayName = \"ToastItem\";\n","import { useEffect, useRef, type ReactNode } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { useControllableState } from \"../../hooks/use-controllable-state\";\nimport { Portal } from \"../Portal\";\nimport { Badge } from \"../Badge\";\nimport type { ToastPosition } from \"./Toast.types\";\n\nexport interface ToastStackProps<T> {\n /**\n * Everything to show — the stack is a VIEW of this list and owns none of it.\n * There is no limit and no timer: an item leaves only when you remove it.\n */\n items: readonly T[];\n /** One card's content, actions included. Only the front card is interactive. */\n renderItem: (item: T, state: { index: number; isFront: boolean }) => ReactNode;\n /** A stable key per item. Defaults to `item.id`, then the index. */\n getKey?: (item: T, index: number) => string;\n /** How many cards show behind the front one. Default 2. */\n depth?: number;\n /** How far each card behind peeks out above the one in front, in px. Default 8. */\n offset?: number;\n /** How much smaller each card behind is than the one in front. Default 0.05. */\n scaleStep?: number;\n /** Which item is in front, if you want to own it. Wraps; out-of-range values are clamped. */\n frontIndex?: number;\n defaultFrontIndex?: number;\n onFrontIndexChange?: (index: number) => void;\n /** A screen corner, or `\"inline\"` to render where it is placed. Default `\"bottom-right\"`. */\n position?: ToastPosition | \"inline\";\n /** The stack's accessible name. Default \"Notifications\". */\n label?: string;\n /** Classes for each card's shell, merged onto the defaults. */\n cardClassName?: string;\n className?: string;\n}\n\nconst POSITION_STYLES: Record<ToastPosition, string> = {\n \"top-right\": \"top-4 right-4\",\n \"top-left\": \"top-4 left-4\",\n \"bottom-right\": \"bottom-4 right-4\",\n \"bottom-left\": \"bottom-4 left-4\",\n};\n\n/** Pixels of wheel travel that count as one step. A mouse notch is ~100; a trackpad sends many small ones. */\nconst WHEEL_STEP = 50;\n\nconst CARD =\n \"rounded-xl border border-[color:var(--fancy-border,var(--color-zinc-200))] bg-[color:var(--fancy-surface,var(--color-white))] p-4 shadow-lg dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))] dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\";\n\nfunction defaultKey(item: unknown, index: number): string {\n const id = (item as { id?: unknown } | null)?.id;\n return typeof id === \"string\" || typeof id === \"number\" ? String(id) : String(index);\n}\n\nfunction isTextField(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) return false;\n return (\n target.isContentEditable ||\n target.getAttribute(\"contenteditable\") === \"true\" ||\n /^(INPUT|TEXTAREA|SELECT)$/.test(target.tagName)\n );\n}\n\n/**\n * A controlled stack of actionable toasts — approval requests, say — that the\n * person walks through rather than races.\n *\n * Built for react-fancy#33. The owner's requirements were that requests stack\n * behind each other with a slight top offset, that scrolling over the stack\n * walks through them, and that a pending request NEVER expires or disappears.\n * The last is why this is a view of the caller's list rather than a queue it\n * keeps: there is nothing here that can drop an item, because nothing here owns\n * one. (The imperative provider's `maxToasts` silently drops the oldest.)\n */\nexport function ToastStack<T>({\n items,\n renderItem,\n getKey = defaultKey,\n depth = 2,\n offset = 8,\n scaleStep = 0.05,\n frontIndex: controlledFront,\n defaultFrontIndex = 0,\n onFrontIndexChange,\n position = \"bottom-right\",\n label = \"Notifications\",\n cardClassName,\n className,\n}: ToastStackProps<T>) {\n const [rawFront, setFront] = useControllableState(\n controlledFront,\n defaultFrontIndex,\n onFrontIndexChange,\n );\n const count = items.length;\n // Clamped for display rather than corrected through onChange: a list that\n // shrinks under a far-forward index must not make render report a change.\n const front = count === 0 ? 0 : ((rawFront % count) + count) % count;\n\n const stackRef = useRef<HTMLDivElement>(null);\n const wheelTravel = useRef(0);\n const live = useRef({ front, count });\n live.current = { front, count };\n\n const step = (by: number) => {\n const { front: current, count: n } = live.current;\n if (n < 2) return;\n setFront((((current + by) % n) + n) % n);\n };\n const stepRef = useRef(step);\n stepRef.current = step;\n\n /*\n * A native listener, because React's wheel listener is passive and cannot stop\n * the page scrolling underneath — and a stack that cycles AND scrolls the page\n * moves two things at once under the person's hand.\n */\n useEffect(() => {\n const el = stackRef.current;\n if (!el) return;\n\n const onWheel = (e: WheelEvent) => {\n if (live.current.count < 2 || e.deltaY === 0) return;\n e.preventDefault();\n\n // Line or page mode: every event is a notch.\n if (e.deltaMode !== 0) {\n wheelTravel.current = 0;\n stepRef.current(Math.sign(e.deltaY));\n return;\n }\n // A notch-sized event steps at once; small trackpad deltas add up first.\n if (Math.abs(e.deltaY) >= WHEEL_STEP) {\n wheelTravel.current = 0;\n stepRef.current(Math.sign(e.deltaY));\n return;\n }\n wheelTravel.current += e.deltaY;\n if (Math.abs(wheelTravel.current) >= WHEEL_STEP) {\n stepRef.current(Math.sign(wheelTravel.current));\n wheelTravel.current = 0;\n }\n };\n\n el.addEventListener(\"wheel\", onWheel, { passive: false });\n return () => el.removeEventListener(\"wheel\", onWheel);\n // Re-bound when the element can change: it appears with the first item, and\n // moving between a corner and inline remounts it.\n }, [count > 0, position]);\n\n if (count === 0) return null;\n\n const visibleBehind = Math.min(Math.max(0, depth), count - 1);\n const hidden = count - 1 - visibleBehind;\n\n const card = (index: number, k: number) => {\n const item = items[index];\n const isFront = k === 0;\n return (\n <div\n key={getKey(item, index)}\n data-react-fancy-toast-stack-card={isFront ? \"front\" : \"behind\"}\n aria-hidden={isFront ? undefined : true}\n inert={isFront ? undefined : true}\n className={cn(\n CARD,\n \"origin-top transition-transform duration-200\",\n isFront ? \"relative\" : \"pointer-events-none absolute inset-0 overflow-hidden\",\n cardClassName,\n )}\n style={{\n zIndex: depth + 1 - k,\n transform: isFront ? undefined : `translateY(-${k * offset}px) scale(${1 - k * scaleStep})`,\n }}\n >\n {renderItem(item, { index, isFront })}\n </div>\n );\n };\n\n const stackEl = (\n <div\n ref={stackRef}\n data-react-fancy-toast-stack=\"\"\n role=\"region\"\n aria-label={label}\n tabIndex={0}\n onKeyDown={(e) => {\n if (isTextField(e.target)) return;\n if (e.key === \"ArrowDown\" || e.key === \"ArrowRight\") {\n e.preventDefault();\n step(1);\n } else if (e.key === \"ArrowUp\" || e.key === \"ArrowLeft\") {\n e.preventDefault();\n step(-1);\n }\n }}\n className={cn(\n \"pointer-events-auto relative w-80 rounded-xl outline-none focus-visible:ring-2 focus-visible:ring-violet-500 focus-visible:ring-offset-2\",\n className,\n )}\n style={{ paddingTop: visibleBehind * offset }}\n >\n <div className=\"relative\">\n {/*\n * z-index decides what paints on top; the front card sizes the box.\n * The front card comes FIRST in the DOM, then the cards behind in walk\n * order: the ones behind are absolutely positioned against this box, so\n * their place in the source changes nothing visible -- but it is what\n * a DOM query, `textContent` and copy-paste read.\n */}\n {card(front, 0)}\n {Array.from({ length: visibleBehind }, (_, i) => i + 1).map((k) =>\n card((front + k) % count, k),\n )}\n </div>\n {hidden > 0 && (\n /*\n * Opaque in BOTH themes, because it sits over the cards peeking out\n * behind the front one -- often a light image header. The soft zinc\n * Badge is `dark:bg-zinc-900/30`, which let that image through and left\n * zinc-300 text on a light screenshot (fancy-app-update#1). The dark\n * pair is overridden here, not in Badge, so every other soft badge\n * keeps its look; the ring separates it from a zinc-900 card edge.\n */\n <Badge\n data-react-fancy-toast-stack-more=\"\"\n size=\"sm\"\n variant=\"soft\"\n color=\"zinc\"\n className=\"absolute -top-2 right-2 z-20 shadow-sm ring-1 ring-[color:var(--fancy-border,var(--color-zinc-200))] dark:bg-zinc-800 dark:text-zinc-100 dark:ring-[color:var(--fancy-border-dark,var(--color-zinc-700))]\"\n >\n +{hidden}\n </Badge>\n )}\n <span data-react-fancy-toast-stack-status=\"\" aria-live=\"polite\" className=\"sr-only\">\n {count > 1 ? `${front + 1} of ${count}` : \"\"}\n </span>\n </div>\n );\n\n if (position === \"inline\") return stackEl;\n\n return (\n <Portal>\n <div\n data-react-fancy-toast-stack-position={position}\n className={cn(\"pointer-events-none fixed z-[100]\", POSITION_STYLES[position])}\n >\n {stackEl}\n </div>\n </Portal>\n );\n}\n\nToastStack.displayName = \"ToastStack\";\n","import { useCallback, useMemo, useRef, useState } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { Portal } from \"../Portal\";\nimport { ToastContext } from \"./Toast.context\";\nimport { ToastItem } from \"./ToastItem\";\nimport { ToastStack } from \"./ToastStack\";\nimport type { ToastData, ToastProviderProps } from \"./Toast.types\";\n\nconst POSITION_STYLES = {\n \"top-right\": \"top-4 right-4\",\n \"top-left\": \"top-4 left-4\",\n \"bottom-right\": \"bottom-4 right-4\",\n \"bottom-left\": \"bottom-4 left-4\",\n} as const;\n\nfunction ToastProvider({\n children,\n position = \"bottom-right\",\n maxToasts = 5,\n}: ToastProviderProps) {\n const [toasts, setToasts] = useState<ToastData[]>([]);\n const idCounter = useRef(0);\n\n const toast = useCallback(\n (data: Omit<ToastData, \"id\">) => {\n const id = `toast-${++idCounter.current}`;\n setToasts((prev) => [...prev.slice(-(maxToasts - 1)), { ...data, id }]);\n return id;\n },\n [maxToasts],\n );\n\n const dismiss = useCallback((id: string) => {\n setToasts((prev) => prev.filter((t) => t.id !== id));\n }, []);\n\n const ctx = useMemo(() => ({ toasts, toast, dismiss }), [toasts, toast, dismiss]);\n\n return (\n <ToastContext.Provider value={ctx}>\n {children}\n <Portal>\n <div\n data-react-fancy-toast=\"\"\n className={cn(\n \"fixed z-[100] flex flex-col gap-2 pointer-events-none\",\n POSITION_STYLES[position],\n )}\n >\n {toasts.map((t) => (\n <ToastItem key={t.id} data={t} onDismiss={dismiss} />\n ))}\n </div>\n </Portal>\n </ToastContext.Provider>\n );\n}\n\nexport const Toast = {\n Provider: ToastProvider,\n Stack: ToastStack,\n Item: ToastItem,\n};\n"]}
|
|
@@ -74,8 +74,37 @@ function BreadcrumbsDropdown({ items, activeLabel }) {
|
|
|
74
74
|
"block w-full px-3 py-1.5 text-left text-sm",
|
|
75
75
|
item.active ? "font-medium text-zinc-900 dark:text-white" : "text-[color:var(--fancy-text-muted,var(--color-zinc-500))] hover:bg-zinc-50 hover:text-[color:var(--fancy-text-soft,var(--color-zinc-700))] dark:text-[color:var(--fancy-text-muted-dark,var(--color-zinc-400))] dark:hover:bg-zinc-800 dark:hover:text-[color:var(--fancy-text-soft-dark,var(--color-zinc-300))]"
|
|
76
76
|
);
|
|
77
|
-
if (item.href && !item.active) {
|
|
78
|
-
|
|
77
|
+
if ((item.href || item.as) && !item.active) {
|
|
78
|
+
const Link = item.as ?? "a";
|
|
79
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
80
|
+
Link,
|
|
81
|
+
{
|
|
82
|
+
...item.href ? { href: item.href } : {},
|
|
83
|
+
className: cls,
|
|
84
|
+
onClick: () => {
|
|
85
|
+
item.onClick?.();
|
|
86
|
+
setOpen(false);
|
|
87
|
+
},
|
|
88
|
+
children: item.label
|
|
89
|
+
},
|
|
90
|
+
i
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
if (item.onClick && !item.active) {
|
|
94
|
+
const onClick = item.onClick;
|
|
95
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
96
|
+
"button",
|
|
97
|
+
{
|
|
98
|
+
type: "button",
|
|
99
|
+
className: chunkZU5Q77OT_cjs.cn(cls, "cursor-pointer border-0 bg-transparent"),
|
|
100
|
+
onClick: () => {
|
|
101
|
+
onClick();
|
|
102
|
+
setOpen(false);
|
|
103
|
+
},
|
|
104
|
+
children: item.label
|
|
105
|
+
},
|
|
106
|
+
i
|
|
107
|
+
);
|
|
79
108
|
}
|
|
80
109
|
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: cls, children: item.label }, i);
|
|
81
110
|
}) })
|
|
@@ -97,6 +126,8 @@ function BreadcrumbsRoot({
|
|
|
97
126
|
return {
|
|
98
127
|
label: el.props?.children,
|
|
99
128
|
href: el.props?.href,
|
|
129
|
+
as: el.props?.as,
|
|
130
|
+
onClick: el.props?.onClick,
|
|
100
131
|
active: el.props?.active
|
|
101
132
|
};
|
|
102
133
|
});
|
|
@@ -137,5 +168,5 @@ var Breadcrumbs = Object.assign(BreadcrumbsRoot, {
|
|
|
137
168
|
});
|
|
138
169
|
|
|
139
170
|
exports.Breadcrumbs = Breadcrumbs;
|
|
140
|
-
//# sourceMappingURL=chunk-
|
|
141
|
-
//# sourceMappingURL=chunk-
|
|
171
|
+
//# sourceMappingURL=chunk-EWE776WI.cjs.map
|
|
172
|
+
//# sourceMappingURL=chunk-EWE776WI.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/Breadcrumbs/BreadcrumbsItem.tsx","../src/components/Breadcrumbs/BreadcrumbsDropdown.tsx","../src/components/Breadcrumbs/Breadcrumbs.tsx"],"names":["cn","jsx","useState","useRef","useOutsideClick","useEscapeKey","jsxs","ChevronDown","Children","ChevronRight","Fragment"],"mappings":"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","file":"chunk-EWE776WI.cjs","sourcesContent":["import type { ElementType } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport type { BreadcrumbsItemProps } from \"./Breadcrumbs.types\";\n\nexport function BreadcrumbsItem({\n children,\n href,\n as: As,\n active = false,\n onClick,\n className,\n ...rest\n}: BreadcrumbsItemProps) {\n const baseClass = cn(\n \"text-sm\",\n active\n ? \"font-medium text-zinc-900 dark:text-white\"\n : \"text-[color:var(--fancy-text-muted,var(--color-zinc-500))] hover:text-[color:var(--fancy-text-soft,var(--color-zinc-700))] dark:text-[color:var(--fancy-text-muted-dark,var(--color-zinc-400))] dark:hover:text-[color:var(--fancy-text-soft-dark,var(--color-zinc-300))]\",\n className,\n );\n\n // The CURRENT crumb stays a <span> even with `as`: it is the page you are on,\n // so a link to it is a link to nowhere, and `aria-current=\"page\"` is the point.\n if ((href || As) && !active) {\n const Link = (As ?? \"a\") as ElementType;\n\n return (\n <Link\n data-react-fancy-breadcrumbs-item=\"\"\n {...(href ? { href } : {})}\n onClick={onClick}\n className={baseClass}\n {...rest}\n >\n {children}\n </Link>\n );\n }\n\n // A crumb that navigates through a callback rather than a URL. Controlled\n // components own their navigation and have no href to give — a repository\n // browser walking directories, a wizard stepping back — and until this\n // existed the only way to make such a crumb clickable was to nest a button\n // inside the span below, which is interactive content inside a non-\n // interactive element.\n if (onClick && !active) {\n return (\n <button\n type=\"button\"\n data-react-fancy-breadcrumbs-item=\"\"\n onClick={onClick}\n className={cn(baseClass, \"cursor-pointer border-0 bg-transparent p-0\")}\n {...rest}\n >\n {children}\n </button>\n );\n }\n\n return (\n <span data-react-fancy-breadcrumbs-item=\"\" className={baseClass} aria-current={active ? \"page\" : undefined} {...rest}>\n {children}\n </span>\n );\n}\n\nBreadcrumbsItem.displayName = \"BreadcrumbsItem\";\n","import { useState, useRef, type ElementType, type ReactNode } from \"react\";\nimport { ChevronDown } from \"lucide-react\";\nimport { cn } from \"../../utils/cn\";\nimport { useOutsideClick } from \"../../hooks/use-outside-click\";\nimport { useEscapeKey } from \"../../hooks/use-escape-key\";\n\ninterface BreadcrumbsDropdownItem {\n label: ReactNode;\n href?: string;\n as?: ElementType;\n onClick?: () => void;\n active?: boolean;\n}\n\ninterface BreadcrumbsDropdownProps {\n items: BreadcrumbsDropdownItem[];\n activeLabel: ReactNode;\n}\n\nexport function BreadcrumbsDropdown({ items, activeLabel }: BreadcrumbsDropdownProps) {\n const [open, setOpen] = useState(false);\n const ref = useRef<HTMLDivElement>(null);\n\n useOutsideClick(ref, () => setOpen(false), open);\n useEscapeKey(() => setOpen(false), open);\n\n return (\n <div ref={ref} data-react-fancy-breadcrumbs-dropdown=\"\" className=\"relative flex md:hidden\">\n <button\n type=\"button\"\n onClick={() => setOpen((v) => !v)}\n className=\"flex items-center gap-1 rounded-lg px-2 py-1 text-sm font-medium text-zinc-900 hover:bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] dark:text-white dark:hover:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))]\"\n >\n {activeLabel}\n <ChevronDown size={14} className={cn(\"transition-transform\", open && \"rotate-180\")} />\n </button>\n {open && (\n <div className=\"absolute top-full left-0 z-50 mt-1 min-w-[180px] rounded-lg border border-[color:var(--fancy-border,var(--color-zinc-200))] bg-[color:var(--fancy-surface,var(--color-white))] py-1 shadow-lg dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))] dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\">\n {items.map((item, i) => {\n const cls = cn(\n \"block w-full px-3 py-1.5 text-left text-sm\",\n item.active\n ? \"font-medium text-zinc-900 dark:text-white\"\n : \"text-[color:var(--fancy-text-muted,var(--color-zinc-500))] hover:bg-zinc-50 hover:text-[color:var(--fancy-text-soft,var(--color-zinc-700))] dark:text-[color:var(--fancy-text-muted-dark,var(--color-zinc-400))] dark:hover:bg-zinc-800 dark:hover:text-[color:var(--fancy-text-soft-dark,var(--color-zinc-300))]\",\n );\n\n // Mirrors BreadcrumbsItem: href / `as` wins, then onClick, and the\n // active crumb stays inert whatever it carries.\n if ((item.href || item.as) && !item.active) {\n const Link = (item.as ?? \"a\") as ElementType;\n return (\n <Link\n key={i}\n {...(item.href ? { href: item.href } : {})}\n className={cls}\n onClick={() => {\n item.onClick?.();\n setOpen(false);\n }}\n >\n {item.label}\n </Link>\n );\n }\n\n if (item.onClick && !item.active) {\n const onClick = item.onClick;\n return (\n <button\n key={i}\n type=\"button\"\n className={cn(cls, \"cursor-pointer border-0 bg-transparent\")}\n onClick={() => {\n onClick();\n setOpen(false);\n }}\n >\n {item.label}\n </button>\n );\n }\n\n return (\n <span key={i} className={cls}>\n {item.label}\n </span>\n );\n })}\n </div>\n )}\n </div>\n );\n}\n\nBreadcrumbsDropdown.displayName = \"BreadcrumbsDropdown\";\n","import { Children, Fragment, useState, type ReactElement } from \"react\";\nimport { ChevronRight } from \"lucide-react\";\nimport { cn } from \"../../utils/cn\";\nimport { BreadcrumbsItem } from \"./BreadcrumbsItem\";\nimport { BreadcrumbsDropdown } from \"./BreadcrumbsDropdown\";\nimport type { BreadcrumbsProps, BreadcrumbsItemProps } from \"./Breadcrumbs.types\";\n\nfunction BreadcrumbsRoot({\n children,\n separator,\n shrink,\n className,\n}: BreadcrumbsProps) {\n const items = Children.toArray(children);\n const [expanded, setExpanded] = useState(false);\n\n const sep = separator ?? (\n <ChevronRight size={12} className=\"text-zinc-400\" />\n );\n\n const lastItem = items[items.length - 1];\n\n // Extract info from children for mobile dropdown\n const dropdownItems = items.map((child) => {\n const el = child as ReactElement<BreadcrumbsItemProps>;\n return {\n label: el.props?.children,\n href: el.props?.href,\n as: el.props?.as,\n onClick: el.props?.onClick,\n active: el.props?.active,\n };\n });\n\n const activeLabel = dropdownItems[dropdownItems.length - 1]?.label ?? \"Menu\";\n\n const showShrunk = shrink && !expanded && items.length > 1;\n\n return (\n <>\n {/* Desktop trail */}\n <nav\n data-react-fancy-breadcrumbs=\"\"\n aria-label=\"Breadcrumb\"\n className={cn(\"hidden items-center gap-2 md:flex\", className)}\n onMouseLeave={() => shrink && setExpanded(false)}\n >\n {showShrunk ? (\n <>\n <button\n type=\"button\"\n onClick={() => setExpanded(true)}\n onMouseEnter={() => setExpanded(true)}\n className=\"text-sm text-zinc-400 hover:text-zinc-600 dark:hover:text-zinc-300\"\n >\n ...\n </button>\n <span aria-hidden=\"true\">{sep}</span>\n {lastItem}\n </>\n ) : (\n items.map((child, i) => (\n <Fragment key={i}>\n {i > 0 && <span aria-hidden=\"true\">{sep}</span>}\n {child}\n </Fragment>\n ))\n )}\n </nav>\n\n {/* Mobile dropdown */}\n <BreadcrumbsDropdown items={dropdownItems} activeLabel={activeLabel} />\n </>\n );\n}\n\nexport const Breadcrumbs = Object.assign(BreadcrumbsRoot, {\n Item: BreadcrumbsItem,\n});\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Textarea } from './chunk-UVUBV4VZ.js';
|
|
2
2
|
import { Portal } from './chunk-RBCMKPBX.js';
|
|
3
|
-
import { Badge } from './chunk-
|
|
4
|
-
import { Button } from './chunk-
|
|
3
|
+
import { Badge } from './chunk-OZ4QFJ7N.js';
|
|
4
|
+
import { Button } from './chunk-4GPH7HOR.js';
|
|
5
5
|
import { useRef, useState, useCallback, useEffect } from 'react';
|
|
6
6
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
7
7
|
|
|
@@ -260,5 +260,5 @@ function selectionPoint(ta, start, end) {
|
|
|
260
260
|
}
|
|
261
261
|
|
|
262
262
|
export { MagicWand };
|
|
263
|
-
//# sourceMappingURL=chunk-
|
|
264
|
-
//# sourceMappingURL=chunk-
|
|
263
|
+
//# sourceMappingURL=chunk-F4OYQ2XZ.js.map
|
|
264
|
+
//# sourceMappingURL=chunk-F4OYQ2XZ.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/MagicWand/MagicWand.tsx"],"names":[],"mappings":"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","file":"chunk-VZ7IDHUY.js","sourcesContent":["import { useCallback, useEffect, useRef, useState, type RefObject } from \"react\";\nimport { Button } from \"../Button\";\nimport { Badge } from \"../Badge\";\nimport { Portal } from \"../Portal\";\nimport { Textarea } from \"../inputs/Textarea/Textarea\";\n\n/**\n * MagicWand — selection-anchored floating toolbar for text inputs.\n *\n * When the user highlights text inside the wrapped <Textarea>, a small\n * pill of AI quick-actions floats above the selection. Clicking an\n * action invokes the host callback with the selected substring + range;\n * the host returns a replacement string and MagicWand swaps it in-place.\n *\n * <MagicWand\n * value={body}\n * onValueChange={setBody}\n * actions={[\n * { id: \"rephrase\", label: \"Rephrase\", hint: \"same meaning, different words\",\n * run: async (s) => await ai.rephrase(s) },\n * …\n * ]}\n * />\n *\n * Pass `target` to act on a textarea, input or editor the HOST renders instead:\n * MagicWand then renders no textarea of its own, only the floating wand.\n *\n * <textarea ref={ref} value={body} onChange={(e) => setBody(e.target.value)} />\n * <MagicWand target={ref} value={body} onValueChange={setBody} actions={…} />\n *\n * Two appearances: `\"floating\"` (default — full labels) and `\"pill\"`\n * (icon-only, compact). Auto-hides on click-away or scroll by default.\n */\nexport type MagicWandSelection = { start: number; end: number; text: string };\n\nexport type MagicWandAction = {\n /** Stable id, also shown as the busy-state key. */\n id: string;\n /** Display label (first character used in `pill` mode). */\n label: string;\n /** Tooltip body. */\n hint?: string;\n /** Optional kind chip rendered next to the label. */\n tag?: string;\n /** Returns the replacement text for the selection. */\n run: (selection: string, range: MagicWandSelection) => Promise<string> | string;\n};\n\nexport type MagicWandAppearance = \"pill\" | \"floating\";\n\n/** A viewport rectangle, the shape `getBoundingClientRect()` returns. */\nexport type MagicWandRect = { left: number; top: number; width: number; height: number };\n\n/**\n * How MagicWand reads a selection out of an editor it does not own — a code\n * editor, a contenteditable, anything that is not a plain textarea.\n *\n * Read-only on purpose. The write goes through `onValueChange`, like every other\n * edit, so the host's `value` stays the one source of truth and the editor is\n * updated the way it always is: from that value.\n */\nexport interface MagicWandTargetAdapter {\n /**\n * The editor's element. MagicWand listens on it for `mouseup` / `keyup` /\n * `select` to know the selection may have changed, and treats a click inside\n * it as \"not away\" for `autoHide`.\n */\n element: RefObject<HTMLElement | null> | HTMLElement | null;\n /** The selection as offsets into `value`. `null` or `start === end` hides the wand. */\n getSelection: () => { start: number; end: number } | null;\n /** Where the selection is on screen. Default: the top-centre of `element`. */\n getSelectionRect?: () => MagicWandRect | null;\n}\n\n/** A host-owned textarea / input by ref, or an adapter for anything else. */\nexport type MagicWandTarget =\n | RefObject<HTMLTextAreaElement | HTMLInputElement | null>\n | MagicWandTargetAdapter;\n\nexport interface MagicWandProps {\n /** Controlled value — of the built-in textarea, or of `target`. */\n value: string;\n /** Called on every edit, and with the result of an action. */\n onValueChange: (v: string) => void;\n /** Action list. */\n actions: MagicWandAction[];\n /**\n * Act on a textarea / input / editor the host renders, instead of rendering\n * one. A ref to a textarea or input works as is; anything else takes a\n * `MagicWandTargetAdapter`. `value` must still be the target's current value.\n */\n target?: MagicWandTarget;\n /** Visual treatment. Defaults to \"floating\". */\n appearance?: MagicWandAppearance;\n /** Auto-hide the wand on click-away or scroll. Defaults to true. */\n autoHide?: boolean;\n /** Textarea rows (built-in textarea only). */\n rows?: number;\n /** Placeholder (built-in textarea only). */\n placeholder?: string;\n /** Called after an action runs successfully. */\n onAction?: (action: MagicWandAction, selection: MagicWandSelection, replacement: string) => void;\n}\n\nfunction isAdapter(target: MagicWandTarget): target is MagicWandTargetAdapter {\n return typeof (target as MagicWandTargetAdapter).getSelection === \"function\";\n}\n\nfunction targetElement(target: MagicWandTarget | undefined): HTMLElement | null {\n if (!target) return null;\n if (!isAdapter(target)) return target.current;\n const el = target.element;\n if (!el) return null;\n return el instanceof HTMLElement ? el : el.current;\n}\n\ntype TextField = HTMLTextAreaElement | HTMLInputElement;\n\n/** The selection and the viewport point the wand should sit above, or null. */\nfunction readTarget(\n target: MagicWandTarget,\n): { start: number; end: number; point: { x: number; y: number } } | null {\n if (!isAdapter(target)) {\n const field = target.current as TextField | null;\n if (!field) return null;\n const start = field.selectionStart ?? 0;\n const end = field.selectionEnd ?? 0;\n if (start === end) return null;\n return { start, end, point: selectionPoint(field, start, end) };\n }\n\n const range = target.getSelection();\n if (!range || range.start === range.end) return null;\n const rect = target.getSelectionRect?.() ?? targetElement(target)?.getBoundingClientRect() ?? null;\n const point = rect ? { x: rect.left + rect.width / 2, y: rect.top } : { x: 0, y: 0 };\n return { start: Math.min(range.start, range.end), end: Math.max(range.start, range.end), point };\n}\n\nexport function MagicWand({\n value,\n onValueChange,\n actions,\n target,\n appearance = \"floating\",\n autoHide = true,\n rows = 6,\n placeholder,\n onAction,\n}: MagicWandProps) {\n const taRef = useRef<HTMLTextAreaElement>(null);\n const wandRef = useRef<HTMLDivElement>(null);\n const [sel, setSel] = useState<MagicWandSelection | null>(null);\n const [pos, setPos] = useState<{ x: number; y: number } | null>(null);\n const [busy, setBusy] = useState<string | null>(null);\n\n const external = target !== undefined;\n // Latest value + target for the listeners, which attach once per element.\n const latest = useRef({ value, target });\n latest.current = { value, target };\n\n const hide = useCallback(() => {\n setSel(null);\n setPos(null);\n }, []);\n\n const measureSelection = useCallback(() => {\n const ta = taRef.current;\n if (!ta) return;\n const start = ta.selectionStart ?? 0;\n const end = ta.selectionEnd ?? 0;\n if (start === end) {\n hide();\n return;\n }\n const text = ta.value.slice(start, end);\n setSel({ start, end, text });\n // The built-in wand is positioned inside this component's `relative` box.\n const point = selectionPoint(ta, start, end);\n const box = (ta.offsetParent as HTMLElement | null)?.getBoundingClientRect() ?? ta.getBoundingClientRect();\n setPos({ x: point.x - box.left, y: point.y - box.top });\n }, [hide]);\n\n const measureTarget = useCallback(() => {\n const { target: t, value: v } = latest.current;\n if (!t) return;\n const read = readTarget(t);\n if (!read) {\n hide();\n return;\n }\n setSel({ start: read.start, end: read.end, text: v.slice(read.start, read.end) });\n setPos(read.point);\n }, [hide]);\n\n // The target's element is only known after the host renders it, so it is\n // re-resolved after every render and the listeners move if it changes.\n const [targetEl, setTargetEl] = useState<HTMLElement | null>(null);\n useEffect(() => {\n const next = targetElement(target);\n if (next !== targetEl) setTargetEl(next);\n });\n\n useEffect(() => {\n if (!targetEl) return;\n const events = [\"mouseup\", \"keyup\", \"select\"] as const;\n for (const e of events) targetEl.addEventListener(e, measureTarget);\n return () => {\n for (const e of events) targetEl.removeEventListener(e, measureTarget);\n };\n }, [targetEl, measureTarget]);\n\n useEffect(() => {\n if (!autoHide) return;\n window.addEventListener(\"scroll\", hide, true);\n return () => window.removeEventListener(\"scroll\", hide, true);\n }, [autoHide, hide]);\n\n useEffect(() => {\n if (!autoHide) return;\n const onDocMouseDown = (e: MouseEvent) => {\n const node = e.target as Node;\n if (wandRef.current?.contains(node)) return;\n if (taRef.current?.contains(node)) return;\n if (targetElement(latest.current.target)?.contains(node)) return;\n hide();\n };\n document.addEventListener(\"mousedown\", onDocMouseDown);\n return () => document.removeEventListener(\"mousedown\", onDocMouseDown);\n }, [autoHide, hide]);\n\n const handleAction = async (action: MagicWandAction) => {\n if (!sel) return;\n setBusy(action.id);\n try {\n const replacement = await action.run(sel.text, sel);\n const next = value.slice(0, sel.start) + replacement + value.slice(sel.end);\n onValueChange(next);\n onAction?.(action, sel, replacement);\n } finally {\n setBusy(null);\n hide();\n }\n };\n\n const wand =\n sel && pos ? (\n <Wand\n ref={wandRef}\n pos={pos}\n fixed={external}\n actions={actions}\n appearance={appearance}\n busy={busy}\n onAction={handleAction}\n selectionLength={sel.text.length}\n />\n ) : null;\n\n if (external) {\n return wand ? <Portal>{wand}</Portal> : null;\n }\n\n return (\n <div className=\"relative\">\n <Textarea\n ref={taRef as unknown as React.Ref<HTMLTextAreaElement>}\n value={value}\n onValueChange={onValueChange}\n onSelect={measureSelection}\n onKeyUp={measureSelection}\n onMouseUp={measureSelection}\n rows={rows}\n placeholder={placeholder}\n />\n {wand}\n </div>\n );\n}\n\nfunction Wand({\n ref,\n pos,\n fixed,\n actions,\n appearance,\n busy,\n onAction,\n selectionLength,\n}: {\n ref: React.RefObject<HTMLDivElement | null>;\n pos: { x: number; y: number };\n /** Viewport-positioned (portalled, for an external target) rather than inside the wrapper. */\n fixed: boolean;\n actions: MagicWandAction[];\n appearance: MagicWandAppearance;\n busy: string | null;\n onAction: (a: MagicWandAction) => void;\n selectionLength: number;\n}) {\n return (\n <div\n ref={ref}\n data-react-fancy-magic-wand=\"\"\n className={`${fixed ? \"fixed z-50\" : \"absolute z-20\"} -translate-x-1/2 -translate-y-full`}\n style={{ left: pos.x, top: pos.y - 6 }}\n >\n <div className=\"flex items-center gap-1 rounded-full border border-violet-300 bg-[color:var(--fancy-surface,var(--color-white))] px-1.5 py-1 shadow-lg ring-1 ring-violet-200 dark:border-violet-700 dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))] dark:ring-violet-900\">\n <span className=\"ml-1 mr-0.5 inline-flex items-center gap-1 text-[10px] font-medium text-violet-700 dark:text-violet-300\">\n <span aria-hidden>✦</span>\n {appearance === \"floating\" && (\n <Badge color=\"violet\">{selectionLength} chars</Badge>\n )}\n </span>\n {actions.map((a) => (\n <Button\n key={a.id}\n size=\"sm\"\n variant=\"ghost\"\n data-react-fancy-magic-wand-action={a.id}\n onClick={() => onAction(a)}\n disabled={busy !== null}\n title={a.hint}\n >\n {busy === a.id ? \"…\" : appearance === \"pill\" ? a.label[0] : a.label}\n {appearance === \"floating\" && a.tag && (\n <span className=\"ml-1 rounded-full bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] px-1 text-[9px] font-medium text-zinc-500 dark:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))]\">\n {a.tag}\n </span>\n )}\n </Button>\n ))}\n </div>\n <div className=\"absolute left-1/2 top-full -translate-x-1/2 -translate-y-px\">\n <div className=\"h-2 w-2 rotate-45 border-b border-r border-violet-300 bg-[color:var(--fancy-surface,var(--color-white))] dark:border-violet-700 dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\" />\n </div>\n </div>\n );\n}\n\n/**\n * Caret/selection geometry: mirror the field into a hidden div and measure the\n * selected substring's bounding rect. Returns the VIEWPORT point at the top\n * centre of the selection. Not perfect for resized textareas, but works for\n * typical chat composers.\n */\nfunction selectionPoint(ta: TextField, start: number, end: number): { x: number; y: number } {\n const div = document.createElement(\"div\");\n const style = getComputedStyle(ta);\n const props = [\n \"boxSizing\",\n \"width\",\n \"height\",\n \"overflowX\",\n \"overflowY\",\n \"borderTopWidth\",\n \"borderRightWidth\",\n \"borderBottomWidth\",\n \"borderLeftWidth\",\n \"paddingTop\",\n \"paddingRight\",\n \"paddingBottom\",\n \"paddingLeft\",\n \"fontStyle\",\n \"fontVariant\",\n \"fontWeight\",\n \"fontStretch\",\n \"fontSize\",\n \"fontSizeAdjust\",\n \"lineHeight\",\n \"fontFamily\",\n \"textAlign\",\n \"textTransform\",\n \"textIndent\",\n \"letterSpacing\",\n \"wordSpacing\",\n \"tabSize\",\n ] as const;\n for (const p of props) (div.style as any)[p] = (style as any)[p];\n div.style.position = \"absolute\";\n div.style.top = \"-9999px\";\n div.style.left = \"-9999px\";\n div.style.whiteSpace = \"pre-wrap\";\n div.style.wordWrap = \"break-word\";\n\n const value = ta.value;\n div.textContent = value.substring(0, start);\n const startSpan = document.createElement(\"span\");\n startSpan.textContent = value.substring(start, end) || \".\";\n div.appendChild(startSpan);\n\n document.body.appendChild(div);\n const taRect = ta.getBoundingClientRect();\n const spanRect = startSpan.getBoundingClientRect();\n const divRect = div.getBoundingClientRect();\n const offsetX = spanRect.left - divRect.left;\n const offsetY = spanRect.top - divRect.top;\n document.body.removeChild(div);\n\n return {\n x: taRect.left + offsetX + spanRect.width / 2,\n y: taRect.top + offsetY - ta.scrollTop,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/MagicWand/MagicWand.tsx"],"names":[],"mappings":"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","file":"chunk-F4OYQ2XZ.js","sourcesContent":["import { useCallback, useEffect, useRef, useState, type RefObject } from \"react\";\nimport { Button } from \"../Button\";\nimport { Badge } from \"../Badge\";\nimport { Portal } from \"../Portal\";\nimport { Textarea } from \"../inputs/Textarea/Textarea\";\n\n/**\n * MagicWand — selection-anchored floating toolbar for text inputs.\n *\n * When the user highlights text inside the wrapped <Textarea>, a small\n * pill of AI quick-actions floats above the selection. Clicking an\n * action invokes the host callback with the selected substring + range;\n * the host returns a replacement string and MagicWand swaps it in-place.\n *\n * <MagicWand\n * value={body}\n * onValueChange={setBody}\n * actions={[\n * { id: \"rephrase\", label: \"Rephrase\", hint: \"same meaning, different words\",\n * run: async (s) => await ai.rephrase(s) },\n * …\n * ]}\n * />\n *\n * Pass `target` to act on a textarea, input or editor the HOST renders instead:\n * MagicWand then renders no textarea of its own, only the floating wand.\n *\n * <textarea ref={ref} value={body} onChange={(e) => setBody(e.target.value)} />\n * <MagicWand target={ref} value={body} onValueChange={setBody} actions={…} />\n *\n * Two appearances: `\"floating\"` (default — full labels) and `\"pill\"`\n * (icon-only, compact). Auto-hides on click-away or scroll by default.\n */\nexport type MagicWandSelection = { start: number; end: number; text: string };\n\nexport type MagicWandAction = {\n /** Stable id, also shown as the busy-state key. */\n id: string;\n /** Display label (first character used in `pill` mode). */\n label: string;\n /** Tooltip body. */\n hint?: string;\n /** Optional kind chip rendered next to the label. */\n tag?: string;\n /** Returns the replacement text for the selection. */\n run: (selection: string, range: MagicWandSelection) => Promise<string> | string;\n};\n\nexport type MagicWandAppearance = \"pill\" | \"floating\";\n\n/** A viewport rectangle, the shape `getBoundingClientRect()` returns. */\nexport type MagicWandRect = { left: number; top: number; width: number; height: number };\n\n/**\n * How MagicWand reads a selection out of an editor it does not own — a code\n * editor, a contenteditable, anything that is not a plain textarea.\n *\n * Read-only on purpose. The write goes through `onValueChange`, like every other\n * edit, so the host's `value` stays the one source of truth and the editor is\n * updated the way it always is: from that value.\n */\nexport interface MagicWandTargetAdapter {\n /**\n * The editor's element. MagicWand listens on it for `mouseup` / `keyup` /\n * `select` to know the selection may have changed, and treats a click inside\n * it as \"not away\" for `autoHide`.\n */\n element: RefObject<HTMLElement | null> | HTMLElement | null;\n /** The selection as offsets into `value`. `null` or `start === end` hides the wand. */\n getSelection: () => { start: number; end: number } | null;\n /** Where the selection is on screen. Default: the top-centre of `element`. */\n getSelectionRect?: () => MagicWandRect | null;\n}\n\n/** A host-owned textarea / input by ref, or an adapter for anything else. */\nexport type MagicWandTarget =\n | RefObject<HTMLTextAreaElement | HTMLInputElement | null>\n | MagicWandTargetAdapter;\n\nexport interface MagicWandProps {\n /** Controlled value — of the built-in textarea, or of `target`. */\n value: string;\n /** Called on every edit, and with the result of an action. */\n onValueChange: (v: string) => void;\n /** Action list. */\n actions: MagicWandAction[];\n /**\n * Act on a textarea / input / editor the host renders, instead of rendering\n * one. A ref to a textarea or input works as is; anything else takes a\n * `MagicWandTargetAdapter`. `value` must still be the target's current value.\n */\n target?: MagicWandTarget;\n /** Visual treatment. Defaults to \"floating\". */\n appearance?: MagicWandAppearance;\n /** Auto-hide the wand on click-away or scroll. Defaults to true. */\n autoHide?: boolean;\n /** Textarea rows (built-in textarea only). */\n rows?: number;\n /** Placeholder (built-in textarea only). */\n placeholder?: string;\n /** Called after an action runs successfully. */\n onAction?: (action: MagicWandAction, selection: MagicWandSelection, replacement: string) => void;\n}\n\nfunction isAdapter(target: MagicWandTarget): target is MagicWandTargetAdapter {\n return typeof (target as MagicWandTargetAdapter).getSelection === \"function\";\n}\n\nfunction targetElement(target: MagicWandTarget | undefined): HTMLElement | null {\n if (!target) return null;\n if (!isAdapter(target)) return target.current;\n const el = target.element;\n if (!el) return null;\n return el instanceof HTMLElement ? el : el.current;\n}\n\ntype TextField = HTMLTextAreaElement | HTMLInputElement;\n\n/** The selection and the viewport point the wand should sit above, or null. */\nfunction readTarget(\n target: MagicWandTarget,\n): { start: number; end: number; point: { x: number; y: number } } | null {\n if (!isAdapter(target)) {\n const field = target.current as TextField | null;\n if (!field) return null;\n const start = field.selectionStart ?? 0;\n const end = field.selectionEnd ?? 0;\n if (start === end) return null;\n return { start, end, point: selectionPoint(field, start, end) };\n }\n\n const range = target.getSelection();\n if (!range || range.start === range.end) return null;\n const rect = target.getSelectionRect?.() ?? targetElement(target)?.getBoundingClientRect() ?? null;\n const point = rect ? { x: rect.left + rect.width / 2, y: rect.top } : { x: 0, y: 0 };\n return { start: Math.min(range.start, range.end), end: Math.max(range.start, range.end), point };\n}\n\nexport function MagicWand({\n value,\n onValueChange,\n actions,\n target,\n appearance = \"floating\",\n autoHide = true,\n rows = 6,\n placeholder,\n onAction,\n}: MagicWandProps) {\n const taRef = useRef<HTMLTextAreaElement>(null);\n const wandRef = useRef<HTMLDivElement>(null);\n const [sel, setSel] = useState<MagicWandSelection | null>(null);\n const [pos, setPos] = useState<{ x: number; y: number } | null>(null);\n const [busy, setBusy] = useState<string | null>(null);\n\n const external = target !== undefined;\n // Latest value + target for the listeners, which attach once per element.\n const latest = useRef({ value, target });\n latest.current = { value, target };\n\n const hide = useCallback(() => {\n setSel(null);\n setPos(null);\n }, []);\n\n const measureSelection = useCallback(() => {\n const ta = taRef.current;\n if (!ta) return;\n const start = ta.selectionStart ?? 0;\n const end = ta.selectionEnd ?? 0;\n if (start === end) {\n hide();\n return;\n }\n const text = ta.value.slice(start, end);\n setSel({ start, end, text });\n // The built-in wand is positioned inside this component's `relative` box.\n const point = selectionPoint(ta, start, end);\n const box = (ta.offsetParent as HTMLElement | null)?.getBoundingClientRect() ?? ta.getBoundingClientRect();\n setPos({ x: point.x - box.left, y: point.y - box.top });\n }, [hide]);\n\n const measureTarget = useCallback(() => {\n const { target: t, value: v } = latest.current;\n if (!t) return;\n const read = readTarget(t);\n if (!read) {\n hide();\n return;\n }\n setSel({ start: read.start, end: read.end, text: v.slice(read.start, read.end) });\n setPos(read.point);\n }, [hide]);\n\n // The target's element is only known after the host renders it, so it is\n // re-resolved after every render and the listeners move if it changes.\n const [targetEl, setTargetEl] = useState<HTMLElement | null>(null);\n useEffect(() => {\n const next = targetElement(target);\n if (next !== targetEl) setTargetEl(next);\n });\n\n useEffect(() => {\n if (!targetEl) return;\n const events = [\"mouseup\", \"keyup\", \"select\"] as const;\n for (const e of events) targetEl.addEventListener(e, measureTarget);\n return () => {\n for (const e of events) targetEl.removeEventListener(e, measureTarget);\n };\n }, [targetEl, measureTarget]);\n\n useEffect(() => {\n if (!autoHide) return;\n window.addEventListener(\"scroll\", hide, true);\n return () => window.removeEventListener(\"scroll\", hide, true);\n }, [autoHide, hide]);\n\n useEffect(() => {\n if (!autoHide) return;\n const onDocMouseDown = (e: MouseEvent) => {\n const node = e.target as Node;\n if (wandRef.current?.contains(node)) return;\n if (taRef.current?.contains(node)) return;\n if (targetElement(latest.current.target)?.contains(node)) return;\n hide();\n };\n document.addEventListener(\"mousedown\", onDocMouseDown);\n return () => document.removeEventListener(\"mousedown\", onDocMouseDown);\n }, [autoHide, hide]);\n\n const handleAction = async (action: MagicWandAction) => {\n if (!sel) return;\n setBusy(action.id);\n try {\n const replacement = await action.run(sel.text, sel);\n const next = value.slice(0, sel.start) + replacement + value.slice(sel.end);\n onValueChange(next);\n onAction?.(action, sel, replacement);\n } finally {\n setBusy(null);\n hide();\n }\n };\n\n const wand =\n sel && pos ? (\n <Wand\n ref={wandRef}\n pos={pos}\n fixed={external}\n actions={actions}\n appearance={appearance}\n busy={busy}\n onAction={handleAction}\n selectionLength={sel.text.length}\n />\n ) : null;\n\n if (external) {\n return wand ? <Portal>{wand}</Portal> : null;\n }\n\n return (\n <div className=\"relative\">\n <Textarea\n ref={taRef as unknown as React.Ref<HTMLTextAreaElement>}\n value={value}\n onValueChange={onValueChange}\n onSelect={measureSelection}\n onKeyUp={measureSelection}\n onMouseUp={measureSelection}\n rows={rows}\n placeholder={placeholder}\n />\n {wand}\n </div>\n );\n}\n\nfunction Wand({\n ref,\n pos,\n fixed,\n actions,\n appearance,\n busy,\n onAction,\n selectionLength,\n}: {\n ref: React.RefObject<HTMLDivElement | null>;\n pos: { x: number; y: number };\n /** Viewport-positioned (portalled, for an external target) rather than inside the wrapper. */\n fixed: boolean;\n actions: MagicWandAction[];\n appearance: MagicWandAppearance;\n busy: string | null;\n onAction: (a: MagicWandAction) => void;\n selectionLength: number;\n}) {\n return (\n <div\n ref={ref}\n data-react-fancy-magic-wand=\"\"\n className={`${fixed ? \"fixed z-50\" : \"absolute z-20\"} -translate-x-1/2 -translate-y-full`}\n style={{ left: pos.x, top: pos.y - 6 }}\n >\n <div className=\"flex items-center gap-1 rounded-full border border-violet-300 bg-[color:var(--fancy-surface,var(--color-white))] px-1.5 py-1 shadow-lg ring-1 ring-violet-200 dark:border-violet-700 dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))] dark:ring-violet-900\">\n <span className=\"ml-1 mr-0.5 inline-flex items-center gap-1 text-[10px] font-medium text-violet-700 dark:text-violet-300\">\n <span aria-hidden>✦</span>\n {appearance === \"floating\" && (\n <Badge color=\"violet\">{selectionLength} chars</Badge>\n )}\n </span>\n {actions.map((a) => (\n <Button\n key={a.id}\n size=\"sm\"\n variant=\"ghost\"\n data-react-fancy-magic-wand-action={a.id}\n onClick={() => onAction(a)}\n disabled={busy !== null}\n title={a.hint}\n >\n {busy === a.id ? \"…\" : appearance === \"pill\" ? a.label[0] : a.label}\n {appearance === \"floating\" && a.tag && (\n <span className=\"ml-1 rounded-full bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] px-1 text-[9px] font-medium text-zinc-500 dark:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))]\">\n {a.tag}\n </span>\n )}\n </Button>\n ))}\n </div>\n <div className=\"absolute left-1/2 top-full -translate-x-1/2 -translate-y-px\">\n <div className=\"h-2 w-2 rotate-45 border-b border-r border-violet-300 bg-[color:var(--fancy-surface,var(--color-white))] dark:border-violet-700 dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\" />\n </div>\n </div>\n );\n}\n\n/**\n * Caret/selection geometry: mirror the field into a hidden div and measure the\n * selected substring's bounding rect. Returns the VIEWPORT point at the top\n * centre of the selection. Not perfect for resized textareas, but works for\n * typical chat composers.\n */\nfunction selectionPoint(ta: TextField, start: number, end: number): { x: number; y: number } {\n const div = document.createElement(\"div\");\n const style = getComputedStyle(ta);\n const props = [\n \"boxSizing\",\n \"width\",\n \"height\",\n \"overflowX\",\n \"overflowY\",\n \"borderTopWidth\",\n \"borderRightWidth\",\n \"borderBottomWidth\",\n \"borderLeftWidth\",\n \"paddingTop\",\n \"paddingRight\",\n \"paddingBottom\",\n \"paddingLeft\",\n \"fontStyle\",\n \"fontVariant\",\n \"fontWeight\",\n \"fontStretch\",\n \"fontSize\",\n \"fontSizeAdjust\",\n \"lineHeight\",\n \"fontFamily\",\n \"textAlign\",\n \"textTransform\",\n \"textIndent\",\n \"letterSpacing\",\n \"wordSpacing\",\n \"tabSize\",\n ] as const;\n for (const p of props) (div.style as any)[p] = (style as any)[p];\n div.style.position = \"absolute\";\n div.style.top = \"-9999px\";\n div.style.left = \"-9999px\";\n div.style.whiteSpace = \"pre-wrap\";\n div.style.wordWrap = \"break-word\";\n\n const value = ta.value;\n div.textContent = value.substring(0, start);\n const startSpan = document.createElement(\"span\");\n startSpan.textContent = value.substring(start, end) || \".\";\n div.appendChild(startSpan);\n\n document.body.appendChild(div);\n const taRect = ta.getBoundingClientRect();\n const spanRect = startSpan.getBoundingClientRect();\n const divRect = div.getBoundingClientRect();\n const offsetX = spanRect.left - divRect.left;\n const offsetY = spanRect.top - divRect.top;\n document.body.removeChild(div);\n\n return {\n x: taRect.left + offsetX + spanRect.width / 2,\n y: taRect.top + offsetY - ta.scrollTop,\n };\n}\n"]}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
var chunkMAZEX4EZ_cjs = require('./chunk-MAZEX4EZ.cjs');
|
|
4
4
|
var chunkTI7D4QDM_cjs = require('./chunk-TI7D4QDM.cjs');
|
|
5
|
-
var
|
|
6
|
-
var
|
|
5
|
+
var chunkOCHUZ7J3_cjs = require('./chunk-OCHUZ7J3.cjs');
|
|
6
|
+
var chunkNZHVDWOM_cjs = require('./chunk-NZHVDWOM.cjs');
|
|
7
7
|
var react = require('react');
|
|
8
8
|
var jsxRuntime = require('react/jsx-runtime');
|
|
9
9
|
|
|
@@ -178,13 +178,13 @@ function Wand({
|
|
|
178
178
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 rounded-full border border-violet-300 bg-[color:var(--fancy-surface,var(--color-white))] px-1.5 py-1 shadow-lg ring-1 ring-violet-200 dark:border-violet-700 dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))] dark:ring-violet-900", children: [
|
|
179
179
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ml-1 mr-0.5 inline-flex items-center gap-1 text-[10px] font-medium text-violet-700 dark:text-violet-300", children: [
|
|
180
180
|
/* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, children: "\u2726" }),
|
|
181
|
-
appearance === "floating" && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
181
|
+
appearance === "floating" && /* @__PURE__ */ jsxRuntime.jsxs(chunkOCHUZ7J3_cjs.Badge, { color: "violet", children: [
|
|
182
182
|
selectionLength,
|
|
183
183
|
" chars"
|
|
184
184
|
] })
|
|
185
185
|
] }),
|
|
186
186
|
actions.map((a) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
187
|
-
|
|
187
|
+
chunkNZHVDWOM_cjs.Button,
|
|
188
188
|
{
|
|
189
189
|
size: "sm",
|
|
190
190
|
variant: "ghost",
|
|
@@ -262,5 +262,5 @@ function selectionPoint(ta, start, end) {
|
|
|
262
262
|
}
|
|
263
263
|
|
|
264
264
|
exports.MagicWand = MagicWand;
|
|
265
|
-
//# sourceMappingURL=chunk-
|
|
266
|
-
//# sourceMappingURL=chunk-
|
|
265
|
+
//# sourceMappingURL=chunk-FKZB27OM.cjs.map
|
|
266
|
+
//# sourceMappingURL=chunk-FKZB27OM.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/MagicWand/MagicWand.tsx"],"names":["useRef","useState","useCallback","useEffect","jsx","Portal","jsxs","Textarea","Badge","Button"],"mappings":"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","file":"chunk-ND5SBHGH.cjs","sourcesContent":["import { useCallback, useEffect, useRef, useState, type RefObject } from \"react\";\nimport { Button } from \"../Button\";\nimport { Badge } from \"../Badge\";\nimport { Portal } from \"../Portal\";\nimport { Textarea } from \"../inputs/Textarea/Textarea\";\n\n/**\n * MagicWand — selection-anchored floating toolbar for text inputs.\n *\n * When the user highlights text inside the wrapped <Textarea>, a small\n * pill of AI quick-actions floats above the selection. Clicking an\n * action invokes the host callback with the selected substring + range;\n * the host returns a replacement string and MagicWand swaps it in-place.\n *\n * <MagicWand\n * value={body}\n * onValueChange={setBody}\n * actions={[\n * { id: \"rephrase\", label: \"Rephrase\", hint: \"same meaning, different words\",\n * run: async (s) => await ai.rephrase(s) },\n * …\n * ]}\n * />\n *\n * Pass `target` to act on a textarea, input or editor the HOST renders instead:\n * MagicWand then renders no textarea of its own, only the floating wand.\n *\n * <textarea ref={ref} value={body} onChange={(e) => setBody(e.target.value)} />\n * <MagicWand target={ref} value={body} onValueChange={setBody} actions={…} />\n *\n * Two appearances: `\"floating\"` (default — full labels) and `\"pill\"`\n * (icon-only, compact). Auto-hides on click-away or scroll by default.\n */\nexport type MagicWandSelection = { start: number; end: number; text: string };\n\nexport type MagicWandAction = {\n /** Stable id, also shown as the busy-state key. */\n id: string;\n /** Display label (first character used in `pill` mode). */\n label: string;\n /** Tooltip body. */\n hint?: string;\n /** Optional kind chip rendered next to the label. */\n tag?: string;\n /** Returns the replacement text for the selection. */\n run: (selection: string, range: MagicWandSelection) => Promise<string> | string;\n};\n\nexport type MagicWandAppearance = \"pill\" | \"floating\";\n\n/** A viewport rectangle, the shape `getBoundingClientRect()` returns. */\nexport type MagicWandRect = { left: number; top: number; width: number; height: number };\n\n/**\n * How MagicWand reads a selection out of an editor it does not own — a code\n * editor, a contenteditable, anything that is not a plain textarea.\n *\n * Read-only on purpose. The write goes through `onValueChange`, like every other\n * edit, so the host's `value` stays the one source of truth and the editor is\n * updated the way it always is: from that value.\n */\nexport interface MagicWandTargetAdapter {\n /**\n * The editor's element. MagicWand listens on it for `mouseup` / `keyup` /\n * `select` to know the selection may have changed, and treats a click inside\n * it as \"not away\" for `autoHide`.\n */\n element: RefObject<HTMLElement | null> | HTMLElement | null;\n /** The selection as offsets into `value`. `null` or `start === end` hides the wand. */\n getSelection: () => { start: number; end: number } | null;\n /** Where the selection is on screen. Default: the top-centre of `element`. */\n getSelectionRect?: () => MagicWandRect | null;\n}\n\n/** A host-owned textarea / input by ref, or an adapter for anything else. */\nexport type MagicWandTarget =\n | RefObject<HTMLTextAreaElement | HTMLInputElement | null>\n | MagicWandTargetAdapter;\n\nexport interface MagicWandProps {\n /** Controlled value — of the built-in textarea, or of `target`. */\n value: string;\n /** Called on every edit, and with the result of an action. */\n onValueChange: (v: string) => void;\n /** Action list. */\n actions: MagicWandAction[];\n /**\n * Act on a textarea / input / editor the host renders, instead of rendering\n * one. A ref to a textarea or input works as is; anything else takes a\n * `MagicWandTargetAdapter`. `value` must still be the target's current value.\n */\n target?: MagicWandTarget;\n /** Visual treatment. Defaults to \"floating\". */\n appearance?: MagicWandAppearance;\n /** Auto-hide the wand on click-away or scroll. Defaults to true. */\n autoHide?: boolean;\n /** Textarea rows (built-in textarea only). */\n rows?: number;\n /** Placeholder (built-in textarea only). */\n placeholder?: string;\n /** Called after an action runs successfully. */\n onAction?: (action: MagicWandAction, selection: MagicWandSelection, replacement: string) => void;\n}\n\nfunction isAdapter(target: MagicWandTarget): target is MagicWandTargetAdapter {\n return typeof (target as MagicWandTargetAdapter).getSelection === \"function\";\n}\n\nfunction targetElement(target: MagicWandTarget | undefined): HTMLElement | null {\n if (!target) return null;\n if (!isAdapter(target)) return target.current;\n const el = target.element;\n if (!el) return null;\n return el instanceof HTMLElement ? el : el.current;\n}\n\ntype TextField = HTMLTextAreaElement | HTMLInputElement;\n\n/** The selection and the viewport point the wand should sit above, or null. */\nfunction readTarget(\n target: MagicWandTarget,\n): { start: number; end: number; point: { x: number; y: number } } | null {\n if (!isAdapter(target)) {\n const field = target.current as TextField | null;\n if (!field) return null;\n const start = field.selectionStart ?? 0;\n const end = field.selectionEnd ?? 0;\n if (start === end) return null;\n return { start, end, point: selectionPoint(field, start, end) };\n }\n\n const range = target.getSelection();\n if (!range || range.start === range.end) return null;\n const rect = target.getSelectionRect?.() ?? targetElement(target)?.getBoundingClientRect() ?? null;\n const point = rect ? { x: rect.left + rect.width / 2, y: rect.top } : { x: 0, y: 0 };\n return { start: Math.min(range.start, range.end), end: Math.max(range.start, range.end), point };\n}\n\nexport function MagicWand({\n value,\n onValueChange,\n actions,\n target,\n appearance = \"floating\",\n autoHide = true,\n rows = 6,\n placeholder,\n onAction,\n}: MagicWandProps) {\n const taRef = useRef<HTMLTextAreaElement>(null);\n const wandRef = useRef<HTMLDivElement>(null);\n const [sel, setSel] = useState<MagicWandSelection | null>(null);\n const [pos, setPos] = useState<{ x: number; y: number } | null>(null);\n const [busy, setBusy] = useState<string | null>(null);\n\n const external = target !== undefined;\n // Latest value + target for the listeners, which attach once per element.\n const latest = useRef({ value, target });\n latest.current = { value, target };\n\n const hide = useCallback(() => {\n setSel(null);\n setPos(null);\n }, []);\n\n const measureSelection = useCallback(() => {\n const ta = taRef.current;\n if (!ta) return;\n const start = ta.selectionStart ?? 0;\n const end = ta.selectionEnd ?? 0;\n if (start === end) {\n hide();\n return;\n }\n const text = ta.value.slice(start, end);\n setSel({ start, end, text });\n // The built-in wand is positioned inside this component's `relative` box.\n const point = selectionPoint(ta, start, end);\n const box = (ta.offsetParent as HTMLElement | null)?.getBoundingClientRect() ?? ta.getBoundingClientRect();\n setPos({ x: point.x - box.left, y: point.y - box.top });\n }, [hide]);\n\n const measureTarget = useCallback(() => {\n const { target: t, value: v } = latest.current;\n if (!t) return;\n const read = readTarget(t);\n if (!read) {\n hide();\n return;\n }\n setSel({ start: read.start, end: read.end, text: v.slice(read.start, read.end) });\n setPos(read.point);\n }, [hide]);\n\n // The target's element is only known after the host renders it, so it is\n // re-resolved after every render and the listeners move if it changes.\n const [targetEl, setTargetEl] = useState<HTMLElement | null>(null);\n useEffect(() => {\n const next = targetElement(target);\n if (next !== targetEl) setTargetEl(next);\n });\n\n useEffect(() => {\n if (!targetEl) return;\n const events = [\"mouseup\", \"keyup\", \"select\"] as const;\n for (const e of events) targetEl.addEventListener(e, measureTarget);\n return () => {\n for (const e of events) targetEl.removeEventListener(e, measureTarget);\n };\n }, [targetEl, measureTarget]);\n\n useEffect(() => {\n if (!autoHide) return;\n window.addEventListener(\"scroll\", hide, true);\n return () => window.removeEventListener(\"scroll\", hide, true);\n }, [autoHide, hide]);\n\n useEffect(() => {\n if (!autoHide) return;\n const onDocMouseDown = (e: MouseEvent) => {\n const node = e.target as Node;\n if (wandRef.current?.contains(node)) return;\n if (taRef.current?.contains(node)) return;\n if (targetElement(latest.current.target)?.contains(node)) return;\n hide();\n };\n document.addEventListener(\"mousedown\", onDocMouseDown);\n return () => document.removeEventListener(\"mousedown\", onDocMouseDown);\n }, [autoHide, hide]);\n\n const handleAction = async (action: MagicWandAction) => {\n if (!sel) return;\n setBusy(action.id);\n try {\n const replacement = await action.run(sel.text, sel);\n const next = value.slice(0, sel.start) + replacement + value.slice(sel.end);\n onValueChange(next);\n onAction?.(action, sel, replacement);\n } finally {\n setBusy(null);\n hide();\n }\n };\n\n const wand =\n sel && pos ? (\n <Wand\n ref={wandRef}\n pos={pos}\n fixed={external}\n actions={actions}\n appearance={appearance}\n busy={busy}\n onAction={handleAction}\n selectionLength={sel.text.length}\n />\n ) : null;\n\n if (external) {\n return wand ? <Portal>{wand}</Portal> : null;\n }\n\n return (\n <div className=\"relative\">\n <Textarea\n ref={taRef as unknown as React.Ref<HTMLTextAreaElement>}\n value={value}\n onValueChange={onValueChange}\n onSelect={measureSelection}\n onKeyUp={measureSelection}\n onMouseUp={measureSelection}\n rows={rows}\n placeholder={placeholder}\n />\n {wand}\n </div>\n );\n}\n\nfunction Wand({\n ref,\n pos,\n fixed,\n actions,\n appearance,\n busy,\n onAction,\n selectionLength,\n}: {\n ref: React.RefObject<HTMLDivElement | null>;\n pos: { x: number; y: number };\n /** Viewport-positioned (portalled, for an external target) rather than inside the wrapper. */\n fixed: boolean;\n actions: MagicWandAction[];\n appearance: MagicWandAppearance;\n busy: string | null;\n onAction: (a: MagicWandAction) => void;\n selectionLength: number;\n}) {\n return (\n <div\n ref={ref}\n data-react-fancy-magic-wand=\"\"\n className={`${fixed ? \"fixed z-50\" : \"absolute z-20\"} -translate-x-1/2 -translate-y-full`}\n style={{ left: pos.x, top: pos.y - 6 }}\n >\n <div className=\"flex items-center gap-1 rounded-full border border-violet-300 bg-[color:var(--fancy-surface,var(--color-white))] px-1.5 py-1 shadow-lg ring-1 ring-violet-200 dark:border-violet-700 dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))] dark:ring-violet-900\">\n <span className=\"ml-1 mr-0.5 inline-flex items-center gap-1 text-[10px] font-medium text-violet-700 dark:text-violet-300\">\n <span aria-hidden>✦</span>\n {appearance === \"floating\" && (\n <Badge color=\"violet\">{selectionLength} chars</Badge>\n )}\n </span>\n {actions.map((a) => (\n <Button\n key={a.id}\n size=\"sm\"\n variant=\"ghost\"\n data-react-fancy-magic-wand-action={a.id}\n onClick={() => onAction(a)}\n disabled={busy !== null}\n title={a.hint}\n >\n {busy === a.id ? \"…\" : appearance === \"pill\" ? a.label[0] : a.label}\n {appearance === \"floating\" && a.tag && (\n <span className=\"ml-1 rounded-full bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] px-1 text-[9px] font-medium text-zinc-500 dark:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))]\">\n {a.tag}\n </span>\n )}\n </Button>\n ))}\n </div>\n <div className=\"absolute left-1/2 top-full -translate-x-1/2 -translate-y-px\">\n <div className=\"h-2 w-2 rotate-45 border-b border-r border-violet-300 bg-[color:var(--fancy-surface,var(--color-white))] dark:border-violet-700 dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\" />\n </div>\n </div>\n );\n}\n\n/**\n * Caret/selection geometry: mirror the field into a hidden div and measure the\n * selected substring's bounding rect. Returns the VIEWPORT point at the top\n * centre of the selection. Not perfect for resized textareas, but works for\n * typical chat composers.\n */\nfunction selectionPoint(ta: TextField, start: number, end: number): { x: number; y: number } {\n const div = document.createElement(\"div\");\n const style = getComputedStyle(ta);\n const props = [\n \"boxSizing\",\n \"width\",\n \"height\",\n \"overflowX\",\n \"overflowY\",\n \"borderTopWidth\",\n \"borderRightWidth\",\n \"borderBottomWidth\",\n \"borderLeftWidth\",\n \"paddingTop\",\n \"paddingRight\",\n \"paddingBottom\",\n \"paddingLeft\",\n \"fontStyle\",\n \"fontVariant\",\n \"fontWeight\",\n \"fontStretch\",\n \"fontSize\",\n \"fontSizeAdjust\",\n \"lineHeight\",\n \"fontFamily\",\n \"textAlign\",\n \"textTransform\",\n \"textIndent\",\n \"letterSpacing\",\n \"wordSpacing\",\n \"tabSize\",\n ] as const;\n for (const p of props) (div.style as any)[p] = (style as any)[p];\n div.style.position = \"absolute\";\n div.style.top = \"-9999px\";\n div.style.left = \"-9999px\";\n div.style.whiteSpace = \"pre-wrap\";\n div.style.wordWrap = \"break-word\";\n\n const value = ta.value;\n div.textContent = value.substring(0, start);\n const startSpan = document.createElement(\"span\");\n startSpan.textContent = value.substring(start, end) || \".\";\n div.appendChild(startSpan);\n\n document.body.appendChild(div);\n const taRect = ta.getBoundingClientRect();\n const spanRect = startSpan.getBoundingClientRect();\n const divRect = div.getBoundingClientRect();\n const offsetX = spanRect.left - divRect.left;\n const offsetY = spanRect.top - divRect.top;\n document.body.removeChild(div);\n\n return {\n x: taRect.left + offsetX + spanRect.width / 2,\n y: taRect.top + offsetY - ta.scrollTop,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/MagicWand/MagicWand.tsx"],"names":["useRef","useState","useCallback","useEffect","jsx","Portal","jsxs","Textarea","Badge","Button"],"mappings":"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","file":"chunk-FKZB27OM.cjs","sourcesContent":["import { useCallback, useEffect, useRef, useState, type RefObject } from \"react\";\nimport { Button } from \"../Button\";\nimport { Badge } from \"../Badge\";\nimport { Portal } from \"../Portal\";\nimport { Textarea } from \"../inputs/Textarea/Textarea\";\n\n/**\n * MagicWand — selection-anchored floating toolbar for text inputs.\n *\n * When the user highlights text inside the wrapped <Textarea>, a small\n * pill of AI quick-actions floats above the selection. Clicking an\n * action invokes the host callback with the selected substring + range;\n * the host returns a replacement string and MagicWand swaps it in-place.\n *\n * <MagicWand\n * value={body}\n * onValueChange={setBody}\n * actions={[\n * { id: \"rephrase\", label: \"Rephrase\", hint: \"same meaning, different words\",\n * run: async (s) => await ai.rephrase(s) },\n * …\n * ]}\n * />\n *\n * Pass `target` to act on a textarea, input or editor the HOST renders instead:\n * MagicWand then renders no textarea of its own, only the floating wand.\n *\n * <textarea ref={ref} value={body} onChange={(e) => setBody(e.target.value)} />\n * <MagicWand target={ref} value={body} onValueChange={setBody} actions={…} />\n *\n * Two appearances: `\"floating\"` (default — full labels) and `\"pill\"`\n * (icon-only, compact). Auto-hides on click-away or scroll by default.\n */\nexport type MagicWandSelection = { start: number; end: number; text: string };\n\nexport type MagicWandAction = {\n /** Stable id, also shown as the busy-state key. */\n id: string;\n /** Display label (first character used in `pill` mode). */\n label: string;\n /** Tooltip body. */\n hint?: string;\n /** Optional kind chip rendered next to the label. */\n tag?: string;\n /** Returns the replacement text for the selection. */\n run: (selection: string, range: MagicWandSelection) => Promise<string> | string;\n};\n\nexport type MagicWandAppearance = \"pill\" | \"floating\";\n\n/** A viewport rectangle, the shape `getBoundingClientRect()` returns. */\nexport type MagicWandRect = { left: number; top: number; width: number; height: number };\n\n/**\n * How MagicWand reads a selection out of an editor it does not own — a code\n * editor, a contenteditable, anything that is not a plain textarea.\n *\n * Read-only on purpose. The write goes through `onValueChange`, like every other\n * edit, so the host's `value` stays the one source of truth and the editor is\n * updated the way it always is: from that value.\n */\nexport interface MagicWandTargetAdapter {\n /**\n * The editor's element. MagicWand listens on it for `mouseup` / `keyup` /\n * `select` to know the selection may have changed, and treats a click inside\n * it as \"not away\" for `autoHide`.\n */\n element: RefObject<HTMLElement | null> | HTMLElement | null;\n /** The selection as offsets into `value`. `null` or `start === end` hides the wand. */\n getSelection: () => { start: number; end: number } | null;\n /** Where the selection is on screen. Default: the top-centre of `element`. */\n getSelectionRect?: () => MagicWandRect | null;\n}\n\n/** A host-owned textarea / input by ref, or an adapter for anything else. */\nexport type MagicWandTarget =\n | RefObject<HTMLTextAreaElement | HTMLInputElement | null>\n | MagicWandTargetAdapter;\n\nexport interface MagicWandProps {\n /** Controlled value — of the built-in textarea, or of `target`. */\n value: string;\n /** Called on every edit, and with the result of an action. */\n onValueChange: (v: string) => void;\n /** Action list. */\n actions: MagicWandAction[];\n /**\n * Act on a textarea / input / editor the host renders, instead of rendering\n * one. A ref to a textarea or input works as is; anything else takes a\n * `MagicWandTargetAdapter`. `value` must still be the target's current value.\n */\n target?: MagicWandTarget;\n /** Visual treatment. Defaults to \"floating\". */\n appearance?: MagicWandAppearance;\n /** Auto-hide the wand on click-away or scroll. Defaults to true. */\n autoHide?: boolean;\n /** Textarea rows (built-in textarea only). */\n rows?: number;\n /** Placeholder (built-in textarea only). */\n placeholder?: string;\n /** Called after an action runs successfully. */\n onAction?: (action: MagicWandAction, selection: MagicWandSelection, replacement: string) => void;\n}\n\nfunction isAdapter(target: MagicWandTarget): target is MagicWandTargetAdapter {\n return typeof (target as MagicWandTargetAdapter).getSelection === \"function\";\n}\n\nfunction targetElement(target: MagicWandTarget | undefined): HTMLElement | null {\n if (!target) return null;\n if (!isAdapter(target)) return target.current;\n const el = target.element;\n if (!el) return null;\n return el instanceof HTMLElement ? el : el.current;\n}\n\ntype TextField = HTMLTextAreaElement | HTMLInputElement;\n\n/** The selection and the viewport point the wand should sit above, or null. */\nfunction readTarget(\n target: MagicWandTarget,\n): { start: number; end: number; point: { x: number; y: number } } | null {\n if (!isAdapter(target)) {\n const field = target.current as TextField | null;\n if (!field) return null;\n const start = field.selectionStart ?? 0;\n const end = field.selectionEnd ?? 0;\n if (start === end) return null;\n return { start, end, point: selectionPoint(field, start, end) };\n }\n\n const range = target.getSelection();\n if (!range || range.start === range.end) return null;\n const rect = target.getSelectionRect?.() ?? targetElement(target)?.getBoundingClientRect() ?? null;\n const point = rect ? { x: rect.left + rect.width / 2, y: rect.top } : { x: 0, y: 0 };\n return { start: Math.min(range.start, range.end), end: Math.max(range.start, range.end), point };\n}\n\nexport function MagicWand({\n value,\n onValueChange,\n actions,\n target,\n appearance = \"floating\",\n autoHide = true,\n rows = 6,\n placeholder,\n onAction,\n}: MagicWandProps) {\n const taRef = useRef<HTMLTextAreaElement>(null);\n const wandRef = useRef<HTMLDivElement>(null);\n const [sel, setSel] = useState<MagicWandSelection | null>(null);\n const [pos, setPos] = useState<{ x: number; y: number } | null>(null);\n const [busy, setBusy] = useState<string | null>(null);\n\n const external = target !== undefined;\n // Latest value + target for the listeners, which attach once per element.\n const latest = useRef({ value, target });\n latest.current = { value, target };\n\n const hide = useCallback(() => {\n setSel(null);\n setPos(null);\n }, []);\n\n const measureSelection = useCallback(() => {\n const ta = taRef.current;\n if (!ta) return;\n const start = ta.selectionStart ?? 0;\n const end = ta.selectionEnd ?? 0;\n if (start === end) {\n hide();\n return;\n }\n const text = ta.value.slice(start, end);\n setSel({ start, end, text });\n // The built-in wand is positioned inside this component's `relative` box.\n const point = selectionPoint(ta, start, end);\n const box = (ta.offsetParent as HTMLElement | null)?.getBoundingClientRect() ?? ta.getBoundingClientRect();\n setPos({ x: point.x - box.left, y: point.y - box.top });\n }, [hide]);\n\n const measureTarget = useCallback(() => {\n const { target: t, value: v } = latest.current;\n if (!t) return;\n const read = readTarget(t);\n if (!read) {\n hide();\n return;\n }\n setSel({ start: read.start, end: read.end, text: v.slice(read.start, read.end) });\n setPos(read.point);\n }, [hide]);\n\n // The target's element is only known after the host renders it, so it is\n // re-resolved after every render and the listeners move if it changes.\n const [targetEl, setTargetEl] = useState<HTMLElement | null>(null);\n useEffect(() => {\n const next = targetElement(target);\n if (next !== targetEl) setTargetEl(next);\n });\n\n useEffect(() => {\n if (!targetEl) return;\n const events = [\"mouseup\", \"keyup\", \"select\"] as const;\n for (const e of events) targetEl.addEventListener(e, measureTarget);\n return () => {\n for (const e of events) targetEl.removeEventListener(e, measureTarget);\n };\n }, [targetEl, measureTarget]);\n\n useEffect(() => {\n if (!autoHide) return;\n window.addEventListener(\"scroll\", hide, true);\n return () => window.removeEventListener(\"scroll\", hide, true);\n }, [autoHide, hide]);\n\n useEffect(() => {\n if (!autoHide) return;\n const onDocMouseDown = (e: MouseEvent) => {\n const node = e.target as Node;\n if (wandRef.current?.contains(node)) return;\n if (taRef.current?.contains(node)) return;\n if (targetElement(latest.current.target)?.contains(node)) return;\n hide();\n };\n document.addEventListener(\"mousedown\", onDocMouseDown);\n return () => document.removeEventListener(\"mousedown\", onDocMouseDown);\n }, [autoHide, hide]);\n\n const handleAction = async (action: MagicWandAction) => {\n if (!sel) return;\n setBusy(action.id);\n try {\n const replacement = await action.run(sel.text, sel);\n const next = value.slice(0, sel.start) + replacement + value.slice(sel.end);\n onValueChange(next);\n onAction?.(action, sel, replacement);\n } finally {\n setBusy(null);\n hide();\n }\n };\n\n const wand =\n sel && pos ? (\n <Wand\n ref={wandRef}\n pos={pos}\n fixed={external}\n actions={actions}\n appearance={appearance}\n busy={busy}\n onAction={handleAction}\n selectionLength={sel.text.length}\n />\n ) : null;\n\n if (external) {\n return wand ? <Portal>{wand}</Portal> : null;\n }\n\n return (\n <div className=\"relative\">\n <Textarea\n ref={taRef as unknown as React.Ref<HTMLTextAreaElement>}\n value={value}\n onValueChange={onValueChange}\n onSelect={measureSelection}\n onKeyUp={measureSelection}\n onMouseUp={measureSelection}\n rows={rows}\n placeholder={placeholder}\n />\n {wand}\n </div>\n );\n}\n\nfunction Wand({\n ref,\n pos,\n fixed,\n actions,\n appearance,\n busy,\n onAction,\n selectionLength,\n}: {\n ref: React.RefObject<HTMLDivElement | null>;\n pos: { x: number; y: number };\n /** Viewport-positioned (portalled, for an external target) rather than inside the wrapper. */\n fixed: boolean;\n actions: MagicWandAction[];\n appearance: MagicWandAppearance;\n busy: string | null;\n onAction: (a: MagicWandAction) => void;\n selectionLength: number;\n}) {\n return (\n <div\n ref={ref}\n data-react-fancy-magic-wand=\"\"\n className={`${fixed ? \"fixed z-50\" : \"absolute z-20\"} -translate-x-1/2 -translate-y-full`}\n style={{ left: pos.x, top: pos.y - 6 }}\n >\n <div className=\"flex items-center gap-1 rounded-full border border-violet-300 bg-[color:var(--fancy-surface,var(--color-white))] px-1.5 py-1 shadow-lg ring-1 ring-violet-200 dark:border-violet-700 dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))] dark:ring-violet-900\">\n <span className=\"ml-1 mr-0.5 inline-flex items-center gap-1 text-[10px] font-medium text-violet-700 dark:text-violet-300\">\n <span aria-hidden>✦</span>\n {appearance === \"floating\" && (\n <Badge color=\"violet\">{selectionLength} chars</Badge>\n )}\n </span>\n {actions.map((a) => (\n <Button\n key={a.id}\n size=\"sm\"\n variant=\"ghost\"\n data-react-fancy-magic-wand-action={a.id}\n onClick={() => onAction(a)}\n disabled={busy !== null}\n title={a.hint}\n >\n {busy === a.id ? \"…\" : appearance === \"pill\" ? a.label[0] : a.label}\n {appearance === \"floating\" && a.tag && (\n <span className=\"ml-1 rounded-full bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] px-1 text-[9px] font-medium text-zinc-500 dark:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))]\">\n {a.tag}\n </span>\n )}\n </Button>\n ))}\n </div>\n <div className=\"absolute left-1/2 top-full -translate-x-1/2 -translate-y-px\">\n <div className=\"h-2 w-2 rotate-45 border-b border-r border-violet-300 bg-[color:var(--fancy-surface,var(--color-white))] dark:border-violet-700 dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\" />\n </div>\n </div>\n );\n}\n\n/**\n * Caret/selection geometry: mirror the field into a hidden div and measure the\n * selected substring's bounding rect. Returns the VIEWPORT point at the top\n * centre of the selection. Not perfect for resized textareas, but works for\n * typical chat composers.\n */\nfunction selectionPoint(ta: TextField, start: number, end: number): { x: number; y: number } {\n const div = document.createElement(\"div\");\n const style = getComputedStyle(ta);\n const props = [\n \"boxSizing\",\n \"width\",\n \"height\",\n \"overflowX\",\n \"overflowY\",\n \"borderTopWidth\",\n \"borderRightWidth\",\n \"borderBottomWidth\",\n \"borderLeftWidth\",\n \"paddingTop\",\n \"paddingRight\",\n \"paddingBottom\",\n \"paddingLeft\",\n \"fontStyle\",\n \"fontVariant\",\n \"fontWeight\",\n \"fontStretch\",\n \"fontSize\",\n \"fontSizeAdjust\",\n \"lineHeight\",\n \"fontFamily\",\n \"textAlign\",\n \"textTransform\",\n \"textIndent\",\n \"letterSpacing\",\n \"wordSpacing\",\n \"tabSize\",\n ] as const;\n for (const p of props) (div.style as any)[p] = (style as any)[p];\n div.style.position = \"absolute\";\n div.style.top = \"-9999px\";\n div.style.left = \"-9999px\";\n div.style.whiteSpace = \"pre-wrap\";\n div.style.wordWrap = \"break-word\";\n\n const value = ta.value;\n div.textContent = value.substring(0, start);\n const startSpan = document.createElement(\"span\");\n startSpan.textContent = value.substring(start, end) || \".\";\n div.appendChild(startSpan);\n\n document.body.appendChild(div);\n const taRect = ta.getBoundingClientRect();\n const spanRect = startSpan.getBoundingClientRect();\n const divRect = div.getBoundingClientRect();\n const offsetX = spanRect.left - divRect.left;\n const offsetY = spanRect.top - divRect.top;\n document.body.removeChild(div);\n\n return {\n x: taRect.left + offsetX + spanRect.width / 2,\n y: taRect.top + offsetY - ta.scrollTop,\n };\n}\n"]}
|