@hex-core/components 1.8.1 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_tsup-dts-rollup.d.ts +855 -18
- package/dist/accordion.js.map +1 -1
- package/dist/alert-dialog.js.map +1 -1
- package/dist/alert.js.map +1 -1
- package/dist/arc.js.map +1 -1
- package/dist/attachment.js.map +1 -1
- package/dist/audio-player.js.map +1 -1
- package/dist/audio-waveform.js.map +1 -1
- package/dist/auth-forgot-password.d.ts +2 -0
- package/dist/auth-forgot-password.js +400 -0
- package/dist/auth-forgot-password.js.map +1 -0
- package/dist/auth-reset-password.d.ts +2 -0
- package/dist/auth-reset-password.js +323 -0
- package/dist/auth-reset-password.js.map +1 -0
- package/dist/auth-sign-in-split.d.ts +3 -0
- package/dist/auth-sign-in-split.js +443 -0
- package/dist/auth-sign-in-split.js.map +1 -0
- package/dist/auth-sign-up-card.d.ts +3 -0
- package/dist/auth-sign-up-card.js +590 -0
- package/dist/auth-sign-up-card.js.map +1 -0
- package/dist/auth-verify-email.d.ts +2 -0
- package/dist/auth-verify-email.js +339 -0
- package/dist/auth-verify-email.js.map +1 -0
- package/dist/auth-verify-otp.d.ts +2 -0
- package/dist/auth-verify-otp.js +349 -0
- package/dist/auth-verify-otp.js.map +1 -0
- package/dist/avatar.js.map +1 -1
- package/dist/badge.js.map +1 -1
- package/dist/branch.d.ts +2 -0
- package/dist/branch.js +136 -0
- package/dist/branch.js.map +1 -0
- package/dist/breadcrumb.js.map +1 -1
- package/dist/button.js.map +1 -1
- package/dist/calendar.js.map +1 -1
- package/dist/canvas.js.map +1 -1
- package/dist/card.js.map +1 -1
- package/dist/chain-of-thought.d.ts +3 -0
- package/dist/chain-of-thought.js +119 -0
- package/dist/chain-of-thought.js.map +1 -0
- package/dist/checkbox.js.map +1 -1
- package/dist/chord.js.map +1 -1
- package/dist/citation.js.map +1 -1
- package/dist/cloze.js.map +1 -1
- package/dist/cluster.js.map +1 -1
- package/dist/code-block-copy.js.map +1 -1
- package/dist/code-block.js.map +1 -1
- package/dist/color-picker.js.map +1 -1
- package/dist/combobox.js.map +1 -1
- package/dist/command.js.map +1 -1
- package/dist/compare-table.js.map +1 -1
- package/dist/composer.js.map +1 -1
- package/dist/container.js.map +1 -1
- package/dist/context-menu.js.map +1 -1
- package/dist/conversation.d.ts +3 -0
- package/dist/conversation.js +358 -0
- package/dist/conversation.js.map +1 -0
- package/dist/data-table.js.map +1 -1
- package/dist/date-picker.js.map +1 -1
- package/dist/deck.js.map +1 -1
- package/dist/dendrogram.js.map +1 -1
- package/dist/diagram.js.map +1 -1
- package/dist/dialog.js.map +1 -1
- package/dist/drawer.js.map +1 -1
- package/dist/dropdown-menu.js.map +1 -1
- package/dist/dropzone.js.map +1 -1
- package/dist/empty.js.map +1 -1
- package/dist/error-state.js.map +1 -1
- package/dist/file-tree.js.map +1 -1
- package/dist/flashcard.js.map +1 -1
- package/dist/flowchart.js.map +1 -1
- package/dist/form.js.map +1 -1
- package/dist/funnel.js.map +1 -1
- package/dist/gantt.js.map +1 -1
- package/dist/grid.js.map +1 -1
- package/dist/hover-card.js.map +1 -1
- package/dist/image-occlusion.js.map +1 -1
- package/dist/index.d.ts +40 -0
- package/dist/index.js +4839 -2813
- package/dist/index.js.map +1 -1
- package/dist/inline-citation.d.ts +2 -0
- package/dist/inline-citation.js +108 -0
- package/dist/inline-citation.js.map +1 -0
- package/dist/input-otp.js.map +1 -1
- package/dist/input.js.map +1 -1
- package/dist/label.js.map +1 -1
- package/dist/loading-indicator.js.map +1 -1
- package/dist/loading.js.map +1 -1
- package/dist/markdown.d.ts +1 -0
- package/dist/markdown.js +784 -4
- package/dist/markdown.js.map +1 -1
- package/dist/matrix.js.map +1 -1
- package/dist/menubar.js.map +1 -1
- package/dist/message-actions.js.map +1 -1
- package/dist/message-list.js.map +1 -1
- package/dist/message.js.map +1 -1
- package/dist/mind-map.js.map +1 -1
- package/dist/multi-combobox.js.map +1 -1
- package/dist/navigation-menu.js.map +1 -1
- package/dist/org-chart.js.map +1 -1
- package/dist/pagination.js.map +1 -1
- package/dist/plan.d.ts +3 -0
- package/dist/plan.js +183 -0
- package/dist/plan.js.map +1 -0
- package/dist/popover.js.map +1 -1
- package/dist/progress.js.map +1 -1
- package/dist/pyramid.js.map +1 -1
- package/dist/quiz.js.map +1 -1
- package/dist/radio-group.js.map +1 -1
- package/dist/reasoning.js.map +1 -1
- package/dist/resizable.js.map +1 -1
- package/dist/sankey.js.map +1 -1
- package/dist/schemas.d.ts +8 -0
- package/dist/schemas.js +774 -17
- package/dist/schemas.js.map +1 -1
- package/dist/scroll-area.js.map +1 -1
- package/dist/select.js.map +1 -1
- package/dist/separator.js.map +1 -1
- package/dist/sequence.js.map +1 -1
- package/dist/sheet.js.map +1 -1
- package/dist/shimmer.d.ts +2 -0
- package/dist/shimmer.js +39 -0
- package/dist/shimmer.js.map +1 -0
- package/dist/sidebar.js.map +1 -1
- package/dist/skeleton.js.map +1 -1
- package/dist/slider.js.map +1 -1
- package/dist/sources.d.ts +3 -0
- package/dist/sources.js +164 -0
- package/dist/sources.js.map +1 -0
- package/dist/spaced-repetition.js.map +1 -1
- package/dist/spacer.js.map +1 -1
- package/dist/speech-recognition.js.map +1 -1
- package/dist/stack.js.map +1 -1
- package/dist/stepper.js.map +1 -1
- package/dist/suggestion.js.map +1 -1
- package/dist/sunburst.js.map +1 -1
- package/dist/switch.js.map +1 -1
- package/dist/table.js.map +1 -1
- package/dist/tabs.js.map +1 -1
- package/dist/tag.js.map +1 -1
- package/dist/task.d.ts +3 -0
- package/dist/task.js +189 -0
- package/dist/task.js.map +1 -0
- package/dist/terminal.js +11 -0
- package/dist/terminal.js.map +1 -1
- package/dist/textarea.js.map +1 -1
- package/dist/time-axis.js.map +1 -1
- package/dist/time-picker.js.map +1 -1
- package/dist/timeline.js.map +1 -1
- package/dist/toggle-group.js.map +1 -1
- package/dist/toggle.js.map +1 -1
- package/dist/tool-call.js +5 -6
- package/dist/tool-call.js.map +1 -1
- package/dist/toolbar.js.map +1 -1
- package/dist/tooltip.js.map +1 -1
- package/dist/tree-map.js.map +1 -1
- package/dist/tree.js.map +1 -1
- package/dist/venn.js.map +1 -1
- package/package.json +9 -4
package/dist/date-picker.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/utils.ts","../src/components/calendar/calendar.tsx","../src/components/popover/popover.tsx","../src/components/date-picker/date-picker.tsx"],"names":["jsx","React2","jsxs"],"mappings":"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","file":"date-picker.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { DayPicker } from \"react-day-picker\";\nimport { cn } from \"../../lib/utils.js\";\n\n/*\n * react-day-picker v9 renders each caption-layout dropdown as:\n * <span class=\"rdp-dropdown_root\">\n * <select class=\"rdp-dropdown\">…</select>\n * <span aria-hidden=\"true\">{label}<chevron/></span>\n * </span>\n * The library expects the consumer's theme to layer the native <select>\n * transparently over the visible label span. Without that overlay both\n * elements paint side-by-side and the month/year labels duplicate. We use a\n * plain <style> block (rather than Tailwind arbitrary variants) because the\n * `_` in the rdp class names trips up Tailwind's underscore-as-space rule and\n * RDP v9's ClassNames merger doesn't run user classes for these keys.\n */\nconst RDP_DROPDOWN_OVERLAY_CSS = `\n.rdp-dropdowns {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\tgap: var(--gap-sm, 0.5rem);\n\tfont-size: 0.875rem;\n\tfont-weight: 500;\n}\n.rdp-dropdown_root {\n\tposition: relative;\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: var(--space-1, 0.25rem);\n\tborder-radius: 0.375rem;\n\tpadding: var(--space-1, 0.25rem) var(--space-2, 0.5rem);\n\ttransition: background-color var(--duration-normal, 200ms) ease-out;\n}\n.rdp-dropdown_root:hover {\n\tbackground-color: hsl(var(--accent));\n}\n.rdp-dropdown_root:has(:focus-visible) {\n\toutline: 2px solid hsl(var(--ring));\n\toutline-offset: 2px;\n}\n.rdp-dropdown {\n\tposition: absolute;\n\tinset: 0;\n\tz-index: 10;\n\twidth: 100%;\n\theight: 100%;\n\tcursor: pointer;\n\tappearance: none;\n\tbackground: transparent;\n\tborder: 0;\n\topacity: 0;\n}\n.rdp-dropdown:disabled {\n\tcursor: not-allowed;\n}\n`;\n\n/**\n * Calendar date grid built on react-day-picker v9. Forwards all DayPicker\n * props. Pair `mode` + `selected` + `onSelect` for selection control;\n * pass `captionLayout=\"dropdown\"` with `startMonth`/`endMonth` for\n * native year-dropdown navigation.\n * @returns A themed react-day-picker instance with our dropdown overlay CSS.\n */\nfunction Calendar({\n\tclassName,\n\tclassNames,\n\tshowOutsideDays = true,\n\t...props\n}: React.ComponentProps<typeof DayPicker>) {\n\treturn (\n\t\t<>\n\t\t\t<style\n\t\t\t\t// Single static stylesheet; React inlines once per page\n\t\t\t\t// regardless of Calendar instance count.\n\t\t\t\tdangerouslySetInnerHTML={{ __html: RDP_DROPDOWN_OVERLAY_CSS }}\n\t\t\t/>\n\t\t<DayPicker\n\t\t\tshowOutsideDays={showOutsideDays}\n\t\t\tclassName={cn(\"relative p-[var(--space-3,0.75rem)]\", className)}\n\t\t\tclassNames={{\n\t\t\t\tmonths: \"flex flex-col sm:flex-row gap-[var(--gap-md,1rem)]\",\n\t\t\t\tmonth: \"flex flex-col gap-[var(--gap-md,1rem)]\",\n\t\t\t\tmonth_caption: \"flex h-7 items-center justify-center\",\n\t\t\t\tcaption_label: \"text-sm font-medium\",\n\t\t\t\tnav: \"absolute inset-x-3 top-3 z-10 flex items-center justify-between pointer-events-none [&>button]:pointer-events-auto\",\n\t\t\t\tbutton_previous: cn(\n\t\t\t\t\t\"inline-flex h-7 w-7 items-center justify-center rounded-md border border-foreground/[0.08] bg-transparent p-0 opacity-60 transition-all duration-[var(--duration-normal,200ms)] ease-out hover:opacity-100 disabled:pointer-events-none disabled:opacity-30\",\n\t\t\t\t),\n\t\t\t\tbutton_next: cn(\n\t\t\t\t\t\"inline-flex h-7 w-7 items-center justify-center rounded-md border border-foreground/[0.08] bg-transparent p-0 opacity-60 transition-all duration-[var(--duration-normal,200ms)] ease-out hover:opacity-100 disabled:pointer-events-none disabled:opacity-30\",\n\t\t\t\t),\n\t\t\t\tmonth_grid: \"w-full border-collapse space-y-1\",\n\t\t\t\tweekdays: \"flex\",\n\t\t\t\tweekday: \"text-muted-foreground rounded-md w-[var(--control-height-sm,2.25rem)] font-normal text-[0.8rem]\",\n\t\t\t\tweek: \"flex w-full mt-[var(--space-2,0.5rem)]\",\n\t\t\t\tday: \"relative p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([aria-selected])]:bg-accent [&:has([aria-selected].range-end)]:rounded-r-md [&:has([aria-selected].range-start)]:rounded-l-md first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md\",\n\t\t\t\tday_button:\n\t\t\t\t\t\"inline-flex h-[var(--control-height-sm,2.25rem)] w-[var(--control-height-sm,2.25rem)] items-center justify-center rounded-md p-0 text-sm font-normal transition-all duration-[var(--duration-normal,200ms)] ease-out hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 aria-selected:opacity-100\",\n\t\t\t\tselected:\n\t\t\t\t\t\"bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground\",\n\t\t\t\ttoday: \"bg-accent text-accent-foreground\",\n\t\t\t\toutside:\n\t\t\t\t\t\"day-outside text-muted-foreground aria-selected:bg-accent/50 aria-selected:text-muted-foreground\",\n\t\t\t\tdisabled: \"text-muted-foreground opacity-50\",\n\t\t\t\trange_start: \"day-range-start range-start\",\n\t\t\t\trange_end: \"day-range-end range-end\",\n\t\t\t\trange_middle:\n\t\t\t\t\t\"aria-selected:bg-accent aria-selected:text-accent-foreground rounded-none\",\n\t\t\t\thidden: \"invisible\",\n\t\t\t\t...classNames,\n\t\t\t}}\n\t\t\tcomponents={{\n\t\t\t\tChevron: ({ orientation, className: chevronClassName }) => {\n\t\t\t\t\tconst rotation =\n\t\t\t\t\t\torientation === \"left\"\n\t\t\t\t\t\t\t? \"rotate-90\"\n\t\t\t\t\t\t\t: orientation === \"right\"\n\t\t\t\t\t\t\t\t? \"-rotate-90\"\n\t\t\t\t\t\t\t\t: orientation === \"up\"\n\t\t\t\t\t\t\t\t\t? \"rotate-180\"\n\t\t\t\t\t\t\t\t\t: \"\";\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<svg\n\t\t\t\t\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\t\tstrokeWidth=\"2\"\n\t\t\t\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\t\t\t\tclassName={cn(\"h-4 w-4\", rotation, chevronClassName)}\n\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<polyline points=\"6 9 12 15 18 9\" />\n\t\t\t\t\t\t</svg>\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t}}\n\t\t\t{...props}\n\t\t/>\n\t\t</>\n\t);\n}\nCalendar.displayName = \"Calendar\";\n\nexport { Calendar };\n","\"use client\";\n\nimport * as PopoverPrimitive from \"@radix-ui/react-popover\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/** Root container for a popover. */\nconst Popover = PopoverPrimitive.Root;\n\n/** The element that anchors and opens the popover. */\nconst PopoverTrigger = PopoverPrimitive.Trigger;\n\n/** Helper to explicitly anchor the popover to a different element. */\nconst PopoverAnchor = PopoverPrimitive.Anchor;\n\n/** The floating popover content panel. */\nconst PopoverContent = React.forwardRef<\n\tReact.ComponentRef<typeof PopoverPrimitive.Content>,\n\tReact.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>\n>(({ className, align = \"center\", sideOffset = 4, ...props }, ref) => (\n\t<PopoverPrimitive.Portal>\n\t\t<PopoverPrimitive.Content\n\t\t\tref={ref}\n\t\t\talign={align}\n\t\t\tsideOffset={sideOffset}\n\t\t\tclassName={cn(\n\t\t\t\t\"z-50 w-72 rounded-md border border-foreground/[0.08] bg-popover p-[var(--space-4,1rem)] text-popover-foreground shadow-md outline-none\",\n\t\t\t\t\"data-[state=open]:animate-in data-[state=closed]:animate-out\",\n\t\t\t\t\"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n\t\t\t\t\"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95\",\n\t\t\t\t\"data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t</PopoverPrimitive.Portal>\n));\nPopoverContent.displayName = \"PopoverContent\";\n\nexport { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };\n","\"use client\";\n\nimport { format } from \"date-fns\";\nimport * as React from \"react\";\nimport { Calendar } from \"../calendar/calendar.js\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"../popover/popover.js\";\nimport { cn } from \"../../lib/utils.js\";\n\ninterface DatePickerProps {\n\t/** Controlled selected date. */\n\tvalue?: Date;\n\t/** Fired when the user picks a date in the calendar. */\n\tonChange?: (date: Date | undefined) => void;\n\t/** Placeholder shown when no date is selected. */\n\tplaceholder?: string;\n\t/** date-fns format string for the trigger label. */\n\tdateFormat?: string;\n\t/** Disable the trigger. */\n\tdisabled?: boolean;\n\t/** Extra class names on the trigger button. */\n\tclassName?: string;\n\t/** Accessible label for the trigger (required when no visible label is adjacent). */\n\t\"aria-label\"?: string;\n\t/**\n\t * Caption layout forwarded to react-day-picker. Use `\"dropdown\"` (or\n\t * `\"dropdown-years\"` / `\"dropdown-months\"`) to render native `<select>`\n\t * navigation — useful for birth-date pickers and far-out years.\n\t *\n\t * Always pair `dropdown` layouts with explicit `startMonth` and `endMonth`;\n\t * the RDP default span is ±100 years.\n\t */\n\tcaptionLayout?: \"label\" | \"dropdown\" | \"dropdown-months\" | \"dropdown-years\";\n\t/** Earliest month/year navigable in the calendar. Forwarded to react-day-picker. */\n\tstartMonth?: Date;\n\t/** Latest month/year navigable in the calendar. Forwarded to react-day-picker. */\n\tendMonth?: Date;\n}\n\n/**\n * Date picker composed from Popover + Calendar + a styled trigger button.\n *\n * This is a minimal single-date picker. For multi/range, compose Calendar + Popover yourself.\n * @returns A button that opens a single-date calendar popover.\n */\nfunction DatePicker({\n\tvalue,\n\tonChange,\n\tplaceholder = \"Pick a date\",\n\tdateFormat = \"PPP\",\n\tdisabled,\n\tclassName,\n\t\"aria-label\": ariaLabel,\n\tcaptionLayout,\n\tstartMonth,\n\tendMonth,\n}: DatePickerProps) {\n\tconst [open, setOpen] = React.useState(false);\n\n\treturn (\n\t\t<Popover open={open} onOpenChange={setOpen}>\n\t\t\t<PopoverTrigger asChild>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\taria-label={ariaLabel ?? placeholder}\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\"inline-flex h-[var(--control-height-md,2.5rem)] w-[240px] items-center justify-start gap-[var(--gap-sm,0.5rem)] rounded-md border border-input bg-background px-[var(--space-3,0.75rem)] py-[var(--space-2,0.5rem)] text-left text-sm font-normal transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\t\t\t\"shadow-sm inset-ring-1 inset-ring-foreground/[0.06]\",\n\t\t\t\t\t\t\"hover:bg-accent hover:text-accent-foreground\",\n\t\t\t\t\t\t\"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n\t\t\t\t\t\t\"disabled:pointer-events-none disabled:opacity-50\",\n\t\t\t\t\t\t!value && \"text-muted-foreground\",\n\t\t\t\t\t\tclassName,\n\t\t\t\t\t)}\n\t\t\t\t>\n\t\t\t\t\t<svg\n\t\t\t\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\tstrokeWidth=\"2\"\n\t\t\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\t\t\tclassName=\"h-4 w-4\"\n\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<rect x=\"3\" y=\"4\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\" />\n\t\t\t\t\t\t<line x1=\"16\" y1=\"2\" x2=\"16\" y2=\"6\" />\n\t\t\t\t\t\t<line x1=\"8\" y1=\"2\" x2=\"8\" y2=\"6\" />\n\t\t\t\t\t\t<line x1=\"3\" y1=\"10\" x2=\"21\" y2=\"10\" />\n\t\t\t\t\t</svg>\n\t\t\t\t\t<span>{value ? format(value, dateFormat) : placeholder}</span>\n\t\t\t\t</button>\n\t\t\t</PopoverTrigger>\n\t\t\t<PopoverContent className=\"w-auto p-0\" align=\"start\">\n\t\t\t\t{/* Hardcoded mode='single' — for range/multi, compose Calendar + Popover directly. */}\n\t\t\t\t<Calendar\n\t\t\t\t\tmode=\"single\"\n\t\t\t\t\tselected={value}\n\t\t\t\t\tonSelect={(date) => {\n\t\t\t\t\t\tonChange?.(date);\n\t\t\t\t\t\tsetOpen(false);\n\t\t\t\t\t}}\n\t\t\t\t\tcaptionLayout={captionLayout}\n\t\t\t\t\tstartMonth={startMonth}\n\t\t\t\t\tendMonth={endMonth}\n\t\t\t\t\tautoFocus\n\t\t\t\t/>\n\t\t\t</PopoverContent>\n\t\t</Popover>\n\t);\n}\nDatePicker.displayName = \"DatePicker\";\n\nexport { DatePicker };\nexport type { DatePickerProps };\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/components/calendar/calendar.tsx","../src/components/popover/popover.tsx","../src/components/date-picker/date-picker.tsx"],"names":["jsx","React2","jsxs"],"mappings":"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","file":"date-picker.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n\nconst SAFE_URL_SCHEMES = [\"http:\", \"https:\", \"mailto:\"] as const;\n\n/**\n * Allowlist a URL for use as an `<a href>` against untrusted input.\n *\n * Returns the raw string when it's `http(s):` / `mailto:` / a relative\n * URL (no scheme); returns `undefined` otherwise. Defends against\n * `javascript:` / `data:` / `vbscript:` injection from streamed model\n * output or third-party JSON payloads that flow into citation chips.\n *\n * Inside a Markdown render path, `rehype-sanitize` already strips\n * `javascript:` from inline-link hrefs — but it does NOT introspect\n * JSON nested inside attribute values (e.g. `<sources data='[…]'/>`),\n * so the components that consume that data must guard themselves.\n *\n * @param raw - The candidate URL, or `undefined` when none was supplied.\n * @returns The URL when safe to render, otherwise `undefined`.\n */\nexport function safeUrl(raw: string | undefined): string | undefined {\n\tif (raw === undefined || raw === \"\") return undefined;\n\t// Relative URLs have no scheme — `new URL(relative)` throws without a base,\n\t// so a thrown URL means either malformed input OR a relative path. Treat\n\t// \"throws + does not contain a colon\" as a relative path (safe).\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(raw);\n\t} catch {\n\t\treturn raw.includes(\":\") ? undefined : raw;\n\t}\n\treturn SAFE_URL_SCHEMES.some((scheme) => scheme === parsed.protocol) ? raw : undefined;\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { DayPicker } from \"react-day-picker\";\nimport { cn } from \"../../lib/utils.js\";\n\n/*\n * react-day-picker v9 renders each caption-layout dropdown as:\n * <span class=\"rdp-dropdown_root\">\n * <select class=\"rdp-dropdown\">…</select>\n * <span aria-hidden=\"true\">{label}<chevron/></span>\n * </span>\n * The library expects the consumer's theme to layer the native <select>\n * transparently over the visible label span. Without that overlay both\n * elements paint side-by-side and the month/year labels duplicate. We use a\n * plain <style> block (rather than Tailwind arbitrary variants) because the\n * `_` in the rdp class names trips up Tailwind's underscore-as-space rule and\n * RDP v9's ClassNames merger doesn't run user classes for these keys.\n */\nconst RDP_DROPDOWN_OVERLAY_CSS = `\n.rdp-dropdowns {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\tgap: var(--gap-sm, 0.5rem);\n\tfont-size: 0.875rem;\n\tfont-weight: 500;\n}\n.rdp-dropdown_root {\n\tposition: relative;\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: var(--space-1, 0.25rem);\n\tborder-radius: 0.375rem;\n\tpadding: var(--space-1, 0.25rem) var(--space-2, 0.5rem);\n\ttransition: background-color var(--duration-normal, 200ms) ease-out;\n}\n.rdp-dropdown_root:hover {\n\tbackground-color: hsl(var(--accent));\n}\n.rdp-dropdown_root:has(:focus-visible) {\n\toutline: 2px solid hsl(var(--ring));\n\toutline-offset: 2px;\n}\n.rdp-dropdown {\n\tposition: absolute;\n\tinset: 0;\n\tz-index: 10;\n\twidth: 100%;\n\theight: 100%;\n\tcursor: pointer;\n\tappearance: none;\n\tbackground: transparent;\n\tborder: 0;\n\topacity: 0;\n}\n.rdp-dropdown:disabled {\n\tcursor: not-allowed;\n}\n`;\n\n/**\n * Calendar date grid built on react-day-picker v9. Forwards all DayPicker\n * props. Pair `mode` + `selected` + `onSelect` for selection control;\n * pass `captionLayout=\"dropdown\"` with `startMonth`/`endMonth` for\n * native year-dropdown navigation.\n * @returns A themed react-day-picker instance with our dropdown overlay CSS.\n */\nfunction Calendar({\n\tclassName,\n\tclassNames,\n\tshowOutsideDays = true,\n\t...props\n}: React.ComponentProps<typeof DayPicker>) {\n\treturn (\n\t\t<>\n\t\t\t<style\n\t\t\t\t// Single static stylesheet; React inlines once per page\n\t\t\t\t// regardless of Calendar instance count.\n\t\t\t\tdangerouslySetInnerHTML={{ __html: RDP_DROPDOWN_OVERLAY_CSS }}\n\t\t\t/>\n\t\t<DayPicker\n\t\t\tshowOutsideDays={showOutsideDays}\n\t\t\tclassName={cn(\"relative p-[var(--space-3,0.75rem)]\", className)}\n\t\t\tclassNames={{\n\t\t\t\tmonths: \"flex flex-col sm:flex-row gap-[var(--gap-md,1rem)]\",\n\t\t\t\tmonth: \"flex flex-col gap-[var(--gap-md,1rem)]\",\n\t\t\t\tmonth_caption: \"flex h-7 items-center justify-center\",\n\t\t\t\tcaption_label: \"text-sm font-medium\",\n\t\t\t\tnav: \"absolute inset-x-3 top-3 z-10 flex items-center justify-between pointer-events-none [&>button]:pointer-events-auto\",\n\t\t\t\tbutton_previous: cn(\n\t\t\t\t\t\"inline-flex h-7 w-7 items-center justify-center rounded-md border border-foreground/[0.08] bg-transparent p-0 opacity-60 transition-all duration-[var(--duration-normal,200ms)] ease-out hover:opacity-100 disabled:pointer-events-none disabled:opacity-30\",\n\t\t\t\t),\n\t\t\t\tbutton_next: cn(\n\t\t\t\t\t\"inline-flex h-7 w-7 items-center justify-center rounded-md border border-foreground/[0.08] bg-transparent p-0 opacity-60 transition-all duration-[var(--duration-normal,200ms)] ease-out hover:opacity-100 disabled:pointer-events-none disabled:opacity-30\",\n\t\t\t\t),\n\t\t\t\tmonth_grid: \"w-full border-collapse space-y-1\",\n\t\t\t\tweekdays: \"flex\",\n\t\t\t\tweekday: \"text-muted-foreground rounded-md w-[var(--control-height-sm,2.25rem)] font-normal text-[0.8rem]\",\n\t\t\t\tweek: \"flex w-full mt-[var(--space-2,0.5rem)]\",\n\t\t\t\tday: \"relative p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([aria-selected])]:bg-accent [&:has([aria-selected].range-end)]:rounded-r-md [&:has([aria-selected].range-start)]:rounded-l-md first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md\",\n\t\t\t\tday_button:\n\t\t\t\t\t\"inline-flex h-[var(--control-height-sm,2.25rem)] w-[var(--control-height-sm,2.25rem)] items-center justify-center rounded-md p-0 text-sm font-normal transition-all duration-[var(--duration-normal,200ms)] ease-out hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 aria-selected:opacity-100\",\n\t\t\t\tselected:\n\t\t\t\t\t\"bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground\",\n\t\t\t\ttoday: \"bg-accent text-accent-foreground\",\n\t\t\t\toutside:\n\t\t\t\t\t\"day-outside text-muted-foreground aria-selected:bg-accent/50 aria-selected:text-muted-foreground\",\n\t\t\t\tdisabled: \"text-muted-foreground opacity-50\",\n\t\t\t\trange_start: \"day-range-start range-start\",\n\t\t\t\trange_end: \"day-range-end range-end\",\n\t\t\t\trange_middle:\n\t\t\t\t\t\"aria-selected:bg-accent aria-selected:text-accent-foreground rounded-none\",\n\t\t\t\thidden: \"invisible\",\n\t\t\t\t...classNames,\n\t\t\t}}\n\t\t\tcomponents={{\n\t\t\t\tChevron: ({ orientation, className: chevronClassName }) => {\n\t\t\t\t\tconst rotation =\n\t\t\t\t\t\torientation === \"left\"\n\t\t\t\t\t\t\t? \"rotate-90\"\n\t\t\t\t\t\t\t: orientation === \"right\"\n\t\t\t\t\t\t\t\t? \"-rotate-90\"\n\t\t\t\t\t\t\t\t: orientation === \"up\"\n\t\t\t\t\t\t\t\t\t? \"rotate-180\"\n\t\t\t\t\t\t\t\t\t: \"\";\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<svg\n\t\t\t\t\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\t\tstrokeWidth=\"2\"\n\t\t\t\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\t\t\t\tclassName={cn(\"h-4 w-4\", rotation, chevronClassName)}\n\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<polyline points=\"6 9 12 15 18 9\" />\n\t\t\t\t\t\t</svg>\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t}}\n\t\t\t{...props}\n\t\t/>\n\t\t</>\n\t);\n}\nCalendar.displayName = \"Calendar\";\n\nexport { Calendar };\n","\"use client\";\n\nimport * as PopoverPrimitive from \"@radix-ui/react-popover\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/** Root container for a popover. */\nconst Popover = PopoverPrimitive.Root;\n\n/** The element that anchors and opens the popover. */\nconst PopoverTrigger = PopoverPrimitive.Trigger;\n\n/** Helper to explicitly anchor the popover to a different element. */\nconst PopoverAnchor = PopoverPrimitive.Anchor;\n\n/** The floating popover content panel. */\nconst PopoverContent = React.forwardRef<\n\tReact.ComponentRef<typeof PopoverPrimitive.Content>,\n\tReact.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>\n>(({ className, align = \"center\", sideOffset = 4, ...props }, ref) => (\n\t<PopoverPrimitive.Portal>\n\t\t<PopoverPrimitive.Content\n\t\t\tref={ref}\n\t\t\talign={align}\n\t\t\tsideOffset={sideOffset}\n\t\t\tclassName={cn(\n\t\t\t\t\"z-50 w-72 rounded-md border border-foreground/[0.08] bg-popover p-[var(--space-4,1rem)] text-popover-foreground shadow-md outline-none\",\n\t\t\t\t\"data-[state=open]:animate-in data-[state=closed]:animate-out\",\n\t\t\t\t\"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n\t\t\t\t\"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95\",\n\t\t\t\t\"data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t</PopoverPrimitive.Portal>\n));\nPopoverContent.displayName = \"PopoverContent\";\n\nexport { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };\n","\"use client\";\n\nimport { format } from \"date-fns\";\nimport * as React from \"react\";\nimport { Calendar } from \"../calendar/calendar.js\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"../popover/popover.js\";\nimport { cn } from \"../../lib/utils.js\";\n\ninterface DatePickerProps {\n\t/** Controlled selected date. */\n\tvalue?: Date;\n\t/** Fired when the user picks a date in the calendar. */\n\tonChange?: (date: Date | undefined) => void;\n\t/** Placeholder shown when no date is selected. */\n\tplaceholder?: string;\n\t/** date-fns format string for the trigger label. */\n\tdateFormat?: string;\n\t/** Disable the trigger. */\n\tdisabled?: boolean;\n\t/** Extra class names on the trigger button. */\n\tclassName?: string;\n\t/** Accessible label for the trigger (required when no visible label is adjacent). */\n\t\"aria-label\"?: string;\n\t/**\n\t * Caption layout forwarded to react-day-picker. Use `\"dropdown\"` (or\n\t * `\"dropdown-years\"` / `\"dropdown-months\"`) to render native `<select>`\n\t * navigation — useful for birth-date pickers and far-out years.\n\t *\n\t * Always pair `dropdown` layouts with explicit `startMonth` and `endMonth`;\n\t * the RDP default span is ±100 years.\n\t */\n\tcaptionLayout?: \"label\" | \"dropdown\" | \"dropdown-months\" | \"dropdown-years\";\n\t/** Earliest month/year navigable in the calendar. Forwarded to react-day-picker. */\n\tstartMonth?: Date;\n\t/** Latest month/year navigable in the calendar. Forwarded to react-day-picker. */\n\tendMonth?: Date;\n}\n\n/**\n * Date picker composed from Popover + Calendar + a styled trigger button.\n *\n * This is a minimal single-date picker. For multi/range, compose Calendar + Popover yourself.\n * @returns A button that opens a single-date calendar popover.\n */\nfunction DatePicker({\n\tvalue,\n\tonChange,\n\tplaceholder = \"Pick a date\",\n\tdateFormat = \"PPP\",\n\tdisabled,\n\tclassName,\n\t\"aria-label\": ariaLabel,\n\tcaptionLayout,\n\tstartMonth,\n\tendMonth,\n}: DatePickerProps) {\n\tconst [open, setOpen] = React.useState(false);\n\n\treturn (\n\t\t<Popover open={open} onOpenChange={setOpen}>\n\t\t\t<PopoverTrigger asChild>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\taria-label={ariaLabel ?? placeholder}\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\"inline-flex h-[var(--control-height-md,2.5rem)] w-[240px] items-center justify-start gap-[var(--gap-sm,0.5rem)] rounded-md border border-input bg-background px-[var(--space-3,0.75rem)] py-[var(--space-2,0.5rem)] text-left text-sm font-normal transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\t\t\t\"shadow-sm inset-ring-1 inset-ring-foreground/[0.06]\",\n\t\t\t\t\t\t\"hover:bg-accent hover:text-accent-foreground\",\n\t\t\t\t\t\t\"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n\t\t\t\t\t\t\"disabled:pointer-events-none disabled:opacity-50\",\n\t\t\t\t\t\t!value && \"text-muted-foreground\",\n\t\t\t\t\t\tclassName,\n\t\t\t\t\t)}\n\t\t\t\t>\n\t\t\t\t\t<svg\n\t\t\t\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\tstrokeWidth=\"2\"\n\t\t\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\t\t\tclassName=\"h-4 w-4\"\n\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<rect x=\"3\" y=\"4\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\" />\n\t\t\t\t\t\t<line x1=\"16\" y1=\"2\" x2=\"16\" y2=\"6\" />\n\t\t\t\t\t\t<line x1=\"8\" y1=\"2\" x2=\"8\" y2=\"6\" />\n\t\t\t\t\t\t<line x1=\"3\" y1=\"10\" x2=\"21\" y2=\"10\" />\n\t\t\t\t\t</svg>\n\t\t\t\t\t<span>{value ? format(value, dateFormat) : placeholder}</span>\n\t\t\t\t</button>\n\t\t\t</PopoverTrigger>\n\t\t\t<PopoverContent className=\"w-auto p-0\" align=\"start\">\n\t\t\t\t{/* Hardcoded mode='single' — for range/multi, compose Calendar + Popover directly. */}\n\t\t\t\t<Calendar\n\t\t\t\t\tmode=\"single\"\n\t\t\t\t\tselected={value}\n\t\t\t\t\tonSelect={(date) => {\n\t\t\t\t\t\tonChange?.(date);\n\t\t\t\t\t\tsetOpen(false);\n\t\t\t\t\t}}\n\t\t\t\t\tcaptionLayout={captionLayout}\n\t\t\t\t\tstartMonth={startMonth}\n\t\t\t\t\tendMonth={endMonth}\n\t\t\t\t\tautoFocus\n\t\t\t\t/>\n\t\t\t</PopoverContent>\n\t\t</Popover>\n\t);\n}\nDatePicker.displayName = \"DatePicker\";\n\nexport { DatePicker };\nexport type { DatePickerProps };\n"]}
|
package/dist/deck.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/utils.ts","../src/artifacts/flashcard/flashcard.tsx","../src/artifacts/deck/deck.tsx"],"names":["React","jsx","jsxs"],"mappings":"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","file":"deck.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/**\n * Flashcard — front/back card with a 3D flip animation. Click, Enter, or\n * Space to flip. Pure CSS 3D transform, no animation peer required.\n *\n * Headless on content: pass any ReactNode for `front` and `back`. Pair\n * with Deck (artifacts/deck) for shuffle / next / prev / progress, or\n * with SpacedRepetition (artifacts/spaced-repetition) for confidence\n * rating after each reveal.\n *\n * @example\n * <Flashcard\n * front={<>What is the capital of France?</>}\n * back={<>Paris</>}\n * />\n *\n * <Flashcard\n * flipped={isFlipped}\n * onFlipChange={setFlipped}\n * front={term}\n * back={definition}\n * />\n */\nexport interface FlashcardProps extends Omit<React.HTMLAttributes<HTMLDivElement>, \"children\"> {\n\t/** Content of the front face. */\n\tfront: React.ReactNode;\n\t/** Content of the back face. */\n\tback: React.ReactNode;\n\t/** Uncontrolled initial flipped state. Default false. */\n\tdefaultFlipped?: boolean;\n\t/** Controlled flipped state. */\n\tflipped?: boolean;\n\t/** Fired with the new flipped value when the user toggles. */\n\tonFlipChange?: (flipped: boolean) => void;\n\t/** Pixel width. Default 360. */\n\twidth?: number;\n\t/** Pixel height. Default 240. */\n\theight?: number;\n\t/** Flip animation duration in ms. Default 500. Set to 0 to disable the animation entirely. */\n\tflipDurationMs?: number;\n}\n\nfunction Flashcard({\n\tfront,\n\tback,\n\tdefaultFlipped = false,\n\tflipped: flippedProp,\n\tonFlipChange,\n\twidth = 360,\n\theight = 240,\n\tflipDurationMs = 500,\n\tclassName,\n\t...rest\n}: FlashcardProps) {\n\tconst [internalFlipped, setInternalFlipped] = React.useState(defaultFlipped);\n\tconst isControlled = flippedProp !== undefined;\n\tconst flipped = isControlled ? flippedProp : internalFlipped;\n\n\tconst toggle = React.useCallback(() => {\n\t\tconst next = !flipped;\n\t\tif (!isControlled) setInternalFlipped(next);\n\t\tonFlipChange?.(next);\n\t}, [flipped, isControlled, onFlipChange]);\n\n\tconst handleKey = React.useCallback(\n\t\t(e: React.KeyboardEvent) => {\n\t\t\tif (e.key === \"Enter\" || e.key === \" \") {\n\t\t\t\te.preventDefault();\n\t\t\t\ttoggle();\n\t\t\t}\n\t\t},\n\t\t[toggle],\n\t);\n\n\treturn (\n\t\t<div\n\t\t\t{...rest}\n\t\t\tdata-hex-flashcard\n\t\t\tdata-flipped={flipped}\n\t\t\trole=\"button\"\n\t\t\ttabIndex={0}\n\t\t\taria-pressed={flipped}\n\t\t\taria-label={flipped ? \"Flashcard, back side. Activate to flip to front.\" : \"Flashcard, front side. Activate to reveal back.\"}\n\t\t\tonClick={toggle}\n\t\t\tonKeyDown={handleKey}\n\t\t\tclassName={cn(\n\t\t\t\t\"relative inline-block cursor-pointer select-none focus:outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\tstyle={{\n\t\t\t\twidth,\n\t\t\t\theight,\n\t\t\t\tperspective: 1000,\n\t\t\t}}\n\t\t>\n\t\t\t<div\n\t\t\t\tdata-hex-flashcard-inner\n\t\t\t\tclassName=\"relative h-full w-full transition-transform\"\n\t\t\t\tstyle={{\n\t\t\t\t\ttransformStyle: \"preserve-3d\",\n\t\t\t\t\ttransform: flipped ? \"rotateY(180deg)\" : \"rotateY(0deg)\",\n\t\t\t\t\ttransitionDuration: `${flipDurationMs}ms`,\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<div\n\t\t\t\t\tdata-hex-flashcard-face\n\t\t\t\t\tdata-side=\"front\"\n\t\t\t\t\tclassName=\"absolute inset-0 flex items-center justify-center rounded-lg border bg-card p-4 text-center text-card-foreground shadow-sm\"\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\tbackfaceVisibility: \"hidden\",\n\t\t\t\t\t\tWebkitBackfaceVisibility: \"hidden\",\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{front}\n\t\t\t\t</div>\n\t\t\t\t<div\n\t\t\t\t\tdata-hex-flashcard-face\n\t\t\t\t\tdata-side=\"back\"\n\t\t\t\t\tclassName=\"absolute inset-0 flex items-center justify-center rounded-lg border bg-card p-4 text-center text-card-foreground shadow-sm\"\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\tbackfaceVisibility: \"hidden\",\n\t\t\t\t\t\tWebkitBackfaceVisibility: \"hidden\",\n\t\t\t\t\t\ttransform: \"rotateY(180deg)\",\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{back}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nexport { Flashcard };\n","\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\nimport { Flashcard } from \"../flashcard/flashcard.js\";\n\n/**\n * Deck — a paged sequence of flashcards with optional shuffle, prev/next\n * navigation, a progress bar, and a slot for per-card SRS rating.\n * Composes [Flashcard] internally; consumers don't render Flashcard\n * themselves when they're inside a Deck.\n *\n * @example\n * <Deck\n * cards={[\n * { id: \"1\", front: \"Term 1\", back: \"Definition 1\" },\n * { id: \"2\", front: \"Term 2\", back: \"Definition 2\" },\n * ]}\n * shuffle\n * ratingSlot={(card) => (\n * <SpacedRepetition cardId={card.id} onRate={(rating) => save(rating, card.id)} />\n * )}\n * />\n */\nexport type DeckCard = {\n\tid: string;\n\tfront: React.ReactNode;\n\tback: React.ReactNode;\n};\n\nexport interface DeckProps extends Omit<React.HTMLAttributes<HTMLDivElement>, \"children\"> {\n\t/** Cards in order. */\n\tcards: DeckCard[];\n\t/** Initial shuffle. Default false (preserves order). */\n\tshuffle?: boolean;\n\t/** Optional render slot below the card; passed the current card. Useful for SpacedRepetition. */\n\tratingSlot?: (card: DeckCard) => React.ReactNode;\n\t/** Fired whenever the active card changes (after shuffle / prev / next). */\n\tonCardChange?: (index: number, card: DeckCard) => void;\n\t/** Pixel width of the inner Flashcard. Default 360. */\n\tcardWidth?: number;\n\t/** Pixel height of the inner Flashcard. Default 240. */\n\tcardHeight?: number;\n}\n\nfunction shuffleArray<T>(arr: T[]): T[] {\n\t// Fisher-Yates. Cheap and deterministic-shape (just non-deterministic\n\t// order on each call). Consumers wanting reproducibility wire their own\n\t// pre-shuffled array and pass `shuffle={false}`.\n\tconst out = arr.slice();\n\tfor (let i = out.length - 1; i > 0; i--) {\n\t\tconst j = Math.floor(Math.random() * (i + 1));\n\t\t[out[i], out[j]] = [out[j], out[i]];\n\t}\n\treturn out;\n}\n\nfunction Deck({\n\tcards,\n\tshuffle = false,\n\tratingSlot,\n\tonCardChange,\n\tcardWidth = 360,\n\tcardHeight = 240,\n\tclassName,\n\t...rest\n}: DeckProps) {\n\t// Order is recomputed only when `cards` identity OR `shuffle` flips —\n\t// not on every prev/next, so the user never gets re-shuffled mid-session.\n\tconst order = React.useMemo(() => (shuffle ? shuffleArray(cards) : cards.slice()), [cards, shuffle]);\n\tconst [index, setIndex] = React.useState(0);\n\tconst [flipped, setFlipped] = React.useState(false);\n\tconst onCardChangeRef = React.useRef(onCardChange);\n\tonCardChangeRef.current = onCardChange;\n\n\t// Reset to the first card when the order changes (cards swap, shuffle toggles).\n\tReact.useEffect(() => {\n\t\tsetIndex(0);\n\t\tsetFlipped(false);\n\t}, [order]);\n\n\tconst total = order.length;\n\tconst currentCard = order[index];\n\n\tconst goPrev = React.useCallback(() => {\n\t\tif (index === 0) return;\n\t\tconst next = index - 1;\n\t\tsetIndex(next);\n\t\tsetFlipped(false);\n\t\tconst card = order[next];\n\t\tif (card) onCardChangeRef.current?.(next, card);\n\t}, [index, order]);\n\n\tconst goNext = React.useCallback(() => {\n\t\tif (index >= total - 1) return;\n\t\tconst next = index + 1;\n\t\tsetIndex(next);\n\t\tsetFlipped(false);\n\t\tconst card = order[next];\n\t\tif (card) onCardChangeRef.current?.(next, card);\n\t}, [index, order, total]);\n\n\tif (total === 0) {\n\t\treturn (\n\t\t\t<div\n\t\t\t\t{...rest}\n\t\t\t\tdata-hex-deck\n\t\t\t\tdata-empty=\"true\"\n\t\t\t\tclassName={cn(\"rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground\", className)}\n\t\t\t>\n\t\t\t\tNo cards in this deck.\n\t\t\t</div>\n\t\t);\n\t}\n\n\tconst progressPercent = total > 0 ? ((index + 1) / total) * 100 : 0;\n\n\treturn (\n\t\t<div\n\t\t\t{...rest}\n\t\t\tdata-hex-deck\n\t\t\tdata-index={index}\n\t\t\tdata-total={total}\n\t\t\tclassName={cn(\"inline-flex flex-col items-center gap-4\", className)}\n\t\t>\n\t\t\t{currentCard ? (\n\t\t\t\t<Flashcard\n\t\t\t\t\tkey={currentCard.id}\n\t\t\t\t\tfront={currentCard.front}\n\t\t\t\t\tback={currentCard.back}\n\t\t\t\t\tflipped={flipped}\n\t\t\t\t\tonFlipChange={setFlipped}\n\t\t\t\t\twidth={cardWidth}\n\t\t\t\t\theight={cardHeight}\n\t\t\t\t/>\n\t\t\t) : null}\n\t\t\t<div data-hex-deck-controls className=\"flex w-full items-center gap-3\" style={{ width: cardWidth }}>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tdata-hex-deck-prev\n\t\t\t\t\tdisabled={index === 0}\n\t\t\t\t\tonClick={goPrev}\n\t\t\t\t\taria-label={`Previous card. Currently ${index + 1} of ${total}.`}\n\t\t\t\t\tclassName=\"inline-flex h-9 items-center justify-center rounded-md border bg-background px-3 text-sm font-medium transition-colors hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50 focus:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n\t\t\t\t>\n\t\t\t\t\tPrev\n\t\t\t\t</button>\n\t\t\t\t<div data-hex-deck-progress className=\"flex-1\" aria-hidden=\"true\">\n\t\t\t\t\t<div className=\"h-1.5 overflow-hidden rounded-full bg-muted\">\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclassName=\"h-full bg-primary transition-all\"\n\t\t\t\t\t\t\tstyle={{ width: `${progressPercent}%` }}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"mt-1 text-center text-xs text-muted-foreground\">\n\t\t\t\t\t\t{index + 1} / {total}\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tdata-hex-deck-next\n\t\t\t\t\tdisabled={index >= total - 1}\n\t\t\t\t\tonClick={goNext}\n\t\t\t\t\taria-label={`Next card. Currently ${index + 1} of ${total}.`}\n\t\t\t\t\tclassName=\"inline-flex h-9 items-center justify-center rounded-md border bg-background px-3 text-sm font-medium transition-colors hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50 focus:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n\t\t\t\t>\n\t\t\t\t\tNext\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t\t{ratingSlot && currentCard ? (\n\t\t\t\t<div data-hex-deck-rating-slot className=\"w-full\" style={{ width: cardWidth }}>\n\t\t\t\t\t{ratingSlot(currentCard)}\n\t\t\t\t</div>\n\t\t\t) : null}\n\t\t</div>\n\t);\n}\n\nexport { Deck };\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/artifacts/flashcard/flashcard.tsx","../src/artifacts/deck/deck.tsx"],"names":["React","jsx","jsxs"],"mappings":"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","file":"deck.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n\nconst SAFE_URL_SCHEMES = [\"http:\", \"https:\", \"mailto:\"] as const;\n\n/**\n * Allowlist a URL for use as an `<a href>` against untrusted input.\n *\n * Returns the raw string when it's `http(s):` / `mailto:` / a relative\n * URL (no scheme); returns `undefined` otherwise. Defends against\n * `javascript:` / `data:` / `vbscript:` injection from streamed model\n * output or third-party JSON payloads that flow into citation chips.\n *\n * Inside a Markdown render path, `rehype-sanitize` already strips\n * `javascript:` from inline-link hrefs — but it does NOT introspect\n * JSON nested inside attribute values (e.g. `<sources data='[…]'/>`),\n * so the components that consume that data must guard themselves.\n *\n * @param raw - The candidate URL, or `undefined` when none was supplied.\n * @returns The URL when safe to render, otherwise `undefined`.\n */\nexport function safeUrl(raw: string | undefined): string | undefined {\n\tif (raw === undefined || raw === \"\") return undefined;\n\t// Relative URLs have no scheme — `new URL(relative)` throws without a base,\n\t// so a thrown URL means either malformed input OR a relative path. Treat\n\t// \"throws + does not contain a colon\" as a relative path (safe).\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(raw);\n\t} catch {\n\t\treturn raw.includes(\":\") ? undefined : raw;\n\t}\n\treturn SAFE_URL_SCHEMES.some((scheme) => scheme === parsed.protocol) ? raw : undefined;\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/**\n * Flashcard — front/back card with a 3D flip animation. Click, Enter, or\n * Space to flip. Pure CSS 3D transform, no animation peer required.\n *\n * Headless on content: pass any ReactNode for `front` and `back`. Pair\n * with Deck (artifacts/deck) for shuffle / next / prev / progress, or\n * with SpacedRepetition (artifacts/spaced-repetition) for confidence\n * rating after each reveal.\n *\n * @example\n * <Flashcard\n * front={<>What is the capital of France?</>}\n * back={<>Paris</>}\n * />\n *\n * <Flashcard\n * flipped={isFlipped}\n * onFlipChange={setFlipped}\n * front={term}\n * back={definition}\n * />\n */\nexport interface FlashcardProps extends Omit<React.HTMLAttributes<HTMLDivElement>, \"children\"> {\n\t/** Content of the front face. */\n\tfront: React.ReactNode;\n\t/** Content of the back face. */\n\tback: React.ReactNode;\n\t/** Uncontrolled initial flipped state. Default false. */\n\tdefaultFlipped?: boolean;\n\t/** Controlled flipped state. */\n\tflipped?: boolean;\n\t/** Fired with the new flipped value when the user toggles. */\n\tonFlipChange?: (flipped: boolean) => void;\n\t/** Pixel width. Default 360. */\n\twidth?: number;\n\t/** Pixel height. Default 240. */\n\theight?: number;\n\t/** Flip animation duration in ms. Default 500. Set to 0 to disable the animation entirely. */\n\tflipDurationMs?: number;\n}\n\nfunction Flashcard({\n\tfront,\n\tback,\n\tdefaultFlipped = false,\n\tflipped: flippedProp,\n\tonFlipChange,\n\twidth = 360,\n\theight = 240,\n\tflipDurationMs = 500,\n\tclassName,\n\t...rest\n}: FlashcardProps) {\n\tconst [internalFlipped, setInternalFlipped] = React.useState(defaultFlipped);\n\tconst isControlled = flippedProp !== undefined;\n\tconst flipped = isControlled ? flippedProp : internalFlipped;\n\n\tconst toggle = React.useCallback(() => {\n\t\tconst next = !flipped;\n\t\tif (!isControlled) setInternalFlipped(next);\n\t\tonFlipChange?.(next);\n\t}, [flipped, isControlled, onFlipChange]);\n\n\tconst handleKey = React.useCallback(\n\t\t(e: React.KeyboardEvent) => {\n\t\t\tif (e.key === \"Enter\" || e.key === \" \") {\n\t\t\t\te.preventDefault();\n\t\t\t\ttoggle();\n\t\t\t}\n\t\t},\n\t\t[toggle],\n\t);\n\n\treturn (\n\t\t<div\n\t\t\t{...rest}\n\t\t\tdata-hex-flashcard\n\t\t\tdata-flipped={flipped}\n\t\t\trole=\"button\"\n\t\t\ttabIndex={0}\n\t\t\taria-pressed={flipped}\n\t\t\taria-label={flipped ? \"Flashcard, back side. Activate to flip to front.\" : \"Flashcard, front side. Activate to reveal back.\"}\n\t\t\tonClick={toggle}\n\t\t\tonKeyDown={handleKey}\n\t\t\tclassName={cn(\n\t\t\t\t\"relative inline-block cursor-pointer select-none focus:outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\tstyle={{\n\t\t\t\twidth,\n\t\t\t\theight,\n\t\t\t\tperspective: 1000,\n\t\t\t}}\n\t\t>\n\t\t\t<div\n\t\t\t\tdata-hex-flashcard-inner\n\t\t\t\tclassName=\"relative h-full w-full transition-transform\"\n\t\t\t\tstyle={{\n\t\t\t\t\ttransformStyle: \"preserve-3d\",\n\t\t\t\t\ttransform: flipped ? \"rotateY(180deg)\" : \"rotateY(0deg)\",\n\t\t\t\t\ttransitionDuration: `${flipDurationMs}ms`,\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<div\n\t\t\t\t\tdata-hex-flashcard-face\n\t\t\t\t\tdata-side=\"front\"\n\t\t\t\t\tclassName=\"absolute inset-0 flex items-center justify-center rounded-lg border bg-card p-4 text-center text-card-foreground shadow-sm\"\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\tbackfaceVisibility: \"hidden\",\n\t\t\t\t\t\tWebkitBackfaceVisibility: \"hidden\",\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{front}\n\t\t\t\t</div>\n\t\t\t\t<div\n\t\t\t\t\tdata-hex-flashcard-face\n\t\t\t\t\tdata-side=\"back\"\n\t\t\t\t\tclassName=\"absolute inset-0 flex items-center justify-center rounded-lg border bg-card p-4 text-center text-card-foreground shadow-sm\"\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\tbackfaceVisibility: \"hidden\",\n\t\t\t\t\t\tWebkitBackfaceVisibility: \"hidden\",\n\t\t\t\t\t\ttransform: \"rotateY(180deg)\",\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{back}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nexport { Flashcard };\n","\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\nimport { Flashcard } from \"../flashcard/flashcard.js\";\n\n/**\n * Deck — a paged sequence of flashcards with optional shuffle, prev/next\n * navigation, a progress bar, and a slot for per-card SRS rating.\n * Composes [Flashcard] internally; consumers don't render Flashcard\n * themselves when they're inside a Deck.\n *\n * @example\n * <Deck\n * cards={[\n * { id: \"1\", front: \"Term 1\", back: \"Definition 1\" },\n * { id: \"2\", front: \"Term 2\", back: \"Definition 2\" },\n * ]}\n * shuffle\n * ratingSlot={(card) => (\n * <SpacedRepetition cardId={card.id} onRate={(rating) => save(rating, card.id)} />\n * )}\n * />\n */\nexport type DeckCard = {\n\tid: string;\n\tfront: React.ReactNode;\n\tback: React.ReactNode;\n};\n\nexport interface DeckProps extends Omit<React.HTMLAttributes<HTMLDivElement>, \"children\"> {\n\t/** Cards in order. */\n\tcards: DeckCard[];\n\t/** Initial shuffle. Default false (preserves order). */\n\tshuffle?: boolean;\n\t/** Optional render slot below the card; passed the current card. Useful for SpacedRepetition. */\n\tratingSlot?: (card: DeckCard) => React.ReactNode;\n\t/** Fired whenever the active card changes (after shuffle / prev / next). */\n\tonCardChange?: (index: number, card: DeckCard) => void;\n\t/** Pixel width of the inner Flashcard. Default 360. */\n\tcardWidth?: number;\n\t/** Pixel height of the inner Flashcard. Default 240. */\n\tcardHeight?: number;\n}\n\nfunction shuffleArray<T>(arr: T[]): T[] {\n\t// Fisher-Yates. Cheap and deterministic-shape (just non-deterministic\n\t// order on each call). Consumers wanting reproducibility wire their own\n\t// pre-shuffled array and pass `shuffle={false}`.\n\tconst out = arr.slice();\n\tfor (let i = out.length - 1; i > 0; i--) {\n\t\tconst j = Math.floor(Math.random() * (i + 1));\n\t\t[out[i], out[j]] = [out[j], out[i]];\n\t}\n\treturn out;\n}\n\nfunction Deck({\n\tcards,\n\tshuffle = false,\n\tratingSlot,\n\tonCardChange,\n\tcardWidth = 360,\n\tcardHeight = 240,\n\tclassName,\n\t...rest\n}: DeckProps) {\n\t// Order is recomputed only when `cards` identity OR `shuffle` flips —\n\t// not on every prev/next, so the user never gets re-shuffled mid-session.\n\tconst order = React.useMemo(() => (shuffle ? shuffleArray(cards) : cards.slice()), [cards, shuffle]);\n\tconst [index, setIndex] = React.useState(0);\n\tconst [flipped, setFlipped] = React.useState(false);\n\tconst onCardChangeRef = React.useRef(onCardChange);\n\tonCardChangeRef.current = onCardChange;\n\n\t// Reset to the first card when the order changes (cards swap, shuffle toggles).\n\tReact.useEffect(() => {\n\t\tsetIndex(0);\n\t\tsetFlipped(false);\n\t}, [order]);\n\n\tconst total = order.length;\n\tconst currentCard = order[index];\n\n\tconst goPrev = React.useCallback(() => {\n\t\tif (index === 0) return;\n\t\tconst next = index - 1;\n\t\tsetIndex(next);\n\t\tsetFlipped(false);\n\t\tconst card = order[next];\n\t\tif (card) onCardChangeRef.current?.(next, card);\n\t}, [index, order]);\n\n\tconst goNext = React.useCallback(() => {\n\t\tif (index >= total - 1) return;\n\t\tconst next = index + 1;\n\t\tsetIndex(next);\n\t\tsetFlipped(false);\n\t\tconst card = order[next];\n\t\tif (card) onCardChangeRef.current?.(next, card);\n\t}, [index, order, total]);\n\n\tif (total === 0) {\n\t\treturn (\n\t\t\t<div\n\t\t\t\t{...rest}\n\t\t\t\tdata-hex-deck\n\t\t\t\tdata-empty=\"true\"\n\t\t\t\tclassName={cn(\"rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground\", className)}\n\t\t\t>\n\t\t\t\tNo cards in this deck.\n\t\t\t</div>\n\t\t);\n\t}\n\n\tconst progressPercent = total > 0 ? ((index + 1) / total) * 100 : 0;\n\n\treturn (\n\t\t<div\n\t\t\t{...rest}\n\t\t\tdata-hex-deck\n\t\t\tdata-index={index}\n\t\t\tdata-total={total}\n\t\t\tclassName={cn(\"inline-flex flex-col items-center gap-4\", className)}\n\t\t>\n\t\t\t{currentCard ? (\n\t\t\t\t<Flashcard\n\t\t\t\t\tkey={currentCard.id}\n\t\t\t\t\tfront={currentCard.front}\n\t\t\t\t\tback={currentCard.back}\n\t\t\t\t\tflipped={flipped}\n\t\t\t\t\tonFlipChange={setFlipped}\n\t\t\t\t\twidth={cardWidth}\n\t\t\t\t\theight={cardHeight}\n\t\t\t\t/>\n\t\t\t) : null}\n\t\t\t<div data-hex-deck-controls className=\"flex w-full items-center gap-3\" style={{ width: cardWidth }}>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tdata-hex-deck-prev\n\t\t\t\t\tdisabled={index === 0}\n\t\t\t\t\tonClick={goPrev}\n\t\t\t\t\taria-label={`Previous card. Currently ${index + 1} of ${total}.`}\n\t\t\t\t\tclassName=\"inline-flex h-9 items-center justify-center rounded-md border bg-background px-3 text-sm font-medium transition-colors hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50 focus:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n\t\t\t\t>\n\t\t\t\t\tPrev\n\t\t\t\t</button>\n\t\t\t\t<div data-hex-deck-progress className=\"flex-1\" aria-hidden=\"true\">\n\t\t\t\t\t<div className=\"h-1.5 overflow-hidden rounded-full bg-muted\">\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclassName=\"h-full bg-primary transition-all\"\n\t\t\t\t\t\t\tstyle={{ width: `${progressPercent}%` }}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"mt-1 text-center text-xs text-muted-foreground\">\n\t\t\t\t\t\t{index + 1} / {total}\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tdata-hex-deck-next\n\t\t\t\t\tdisabled={index >= total - 1}\n\t\t\t\t\tonClick={goNext}\n\t\t\t\t\taria-label={`Next card. Currently ${index + 1} of ${total}.`}\n\t\t\t\t\tclassName=\"inline-flex h-9 items-center justify-center rounded-md border bg-background px-3 text-sm font-medium transition-colors hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50 focus:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n\t\t\t\t>\n\t\t\t\t\tNext\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t\t{ratingSlot && currentCard ? (\n\t\t\t\t<div data-hex-deck-rating-slot className=\"w-full\" style={{ width: cardWidth }}>\n\t\t\t\t\t{ratingSlot(currentCard)}\n\t\t\t\t</div>\n\t\t\t) : null}\n\t\t</div>\n\t);\n}\n\nexport { Deck };\n"]}
|
package/dist/dendrogram.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/utils.ts","../src/artifacts/dendrogram/dendrogram.tsx"],"names":[],"mappings":"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","file":"dendrogram.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/**\n * Clustering tree where every leaf sits at the same depth, regardless of\n * branch length — the visual signature of taxonomies, phylogenetic trees,\n * and hierarchical-clustering output. Backed by d3-hierarchy's `cluster`\n * layout (distinct from `tree`, which packs leaves variably).\n *\n * Heavy peer: requires `d3-hierarchy` (~3 KB gzip).\n *\n * @example\n * <Dendrogram\n * root={{\n * id: \"root\", label: \"Animals\",\n * children: [\n * { id: \"mammals\", label: \"Mammals\", children: [\n * { id: \"cat\", label: \"Cat\" },\n * { id: \"dog\", label: \"Dog\" },\n * ]},\n * { id: \"birds\", label: \"Birds\", children: [{ id: \"robin\", label: \"Robin\" }] },\n * ],\n * }}\n * />\n */\nexport type DendrogramNode = {\n\tid: string;\n\tlabel: string;\n\tchildren?: DendrogramNode[];\n};\n\nexport interface DendrogramProps extends Omit<React.SVGAttributes<SVGSVGElement>, \"children\"> {\n\t/** Root of the hierarchy. */\n\troot: DendrogramNode;\n\t/** \"horizontal\" runs root-to-leaves left→right; \"vertical\" runs top→bottom. Default \"horizontal\". */\n\torientation?: \"horizontal\" | \"vertical\";\n\t/** \"step\" draws right-angle elbow links (taxonomy aesthetic); \"diagonal\" uses smooth Bezier. Default \"step\". */\n\tlinkShape?: \"step\" | \"diagonal\";\n\t/** Pixel width of the rendered SVG. Default 600. */\n\twidth?: number;\n\t/** Pixel height of the rendered SVG. Default 400. */\n\theight?: number;\n\t/** Fired when a leaf is clicked. */\n\tonLeafClick?: (node: DendrogramNode) => void;\n}\n\ninterface LaidOutNode {\n\tnode: DendrogramNode;\n\tx: number;\n\ty: number;\n\tdepth: number;\n\tisLeaf: boolean;\n}\n\ninterface LaidOutLink {\n\tsource: { x: number; y: number };\n\ttarget: { x: number; y: number };\n\tid: string;\n}\n\ntype D3HierarchyMod = typeof import(\"d3-hierarchy\");\n\nfunction Dendrogram({\n\troot,\n\torientation = \"horizontal\",\n\tlinkShape = \"step\",\n\twidth = 600,\n\theight = 400,\n\tonLeafClick,\n\tclassName,\n\t...rest\n}: DendrogramProps) {\n\tconst [d3h, setD3h] = React.useState<D3HierarchyMod | null>(null);\n\n\tReact.useEffect(() => {\n\t\tlet cancelled = false;\n\t\tvoid import(\"d3-hierarchy\").then((mod) => {\n\t\t\tif (!cancelled) setD3h(mod);\n\t\t});\n\t\treturn () => {\n\t\t\tcancelled = true;\n\t\t};\n\t}, []);\n\n\tif (!d3h) {\n\t\treturn (\n\t\t\t<div\n\t\t\t\tdata-hex-dendrogram-loading\n\t\t\t\taria-busy=\"true\"\n\t\t\t\tclassName={cn(\"inline-block bg-muted/20\", className)}\n\t\t\t\tstyle={{ width, height }}\n\t\t\t/>\n\t\t);\n\t}\n\n\tconst { nodes, links } = layout(d3h, root, orientation, width, height);\n\tconst leafCount = nodes.filter((n) => n.isLeaf).length;\n\tconst desc = `Dendrogram with ${leafCount} leaves, rooted at \"${root.label}\"`;\n\n\treturn (\n\t\t<svg\n\t\t\t{...rest}\n\t\t\tdata-hex-dendrogram\n\t\t\tdata-orientation={orientation}\n\t\t\tdata-link-shape={linkShape}\n\t\t\trole=\"img\"\n\t\t\twidth={width}\n\t\t\theight={height}\n\t\t\tviewBox={`0 0 ${width} ${height}`}\n\t\t\tclassName={cn(\"block\", className)}\n\t\t>\n\t\t\t<title>Dendrogram</title>\n\t\t\t<desc>{desc}</desc>\n\t\t\t<g data-hex-dendrogram-links>\n\t\t\t\t{links.map((l) => (\n\t\t\t\t\t<path\n\t\t\t\t\t\tkey={l.id}\n\t\t\t\t\t\td={linkPath(l, orientation, linkShape)}\n\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\tstroke=\"hsl(var(--muted-foreground))\"\n\t\t\t\t\t\tstrokeOpacity={0.8}\n\t\t\t\t\t\tstrokeWidth={1}\n\t\t\t\t\t/>\n\t\t\t\t))}\n\t\t\t</g>\n\t\t\t<g data-hex-dendrogram-nodes>\n\t\t\t\t{nodes.map((n) => (\n\t\t\t\t\t<g\n\t\t\t\t\t\tkey={n.node.id}\n\t\t\t\t\t\tdata-hex-dendrogram-node\n\t\t\t\t\t\tdata-leaf={n.isLeaf ? \"true\" : \"false\"}\n\t\t\t\t\t\tdata-depth={n.depth}\n\t\t\t\t\t\ttransform={`translate(${n.x},${n.y})`}\n\t\t\t\t\t\tstyle={n.isLeaf && onLeafClick ? { cursor: \"pointer\" } : undefined}\n\t\t\t\t\t\tonClick={n.isLeaf && onLeafClick ? () => onLeafClick(n.node) : undefined}\n\t\t\t\t\t>\n\t\t\t\t\t\t<circle\n\t\t\t\t\t\t\tr={n.isLeaf ? 3 : 2}\n\t\t\t\t\t\t\tfill={n.isLeaf ? \"hsl(var(--primary))\" : \"hsl(var(--muted-foreground))\"}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t{n.isLeaf ? (\n\t\t\t\t\t\t\t<text\n\t\t\t\t\t\t\t\tx={orientation === \"horizontal\" ? 6 : 0}\n\t\t\t\t\t\t\t\ty={orientation === \"horizontal\" ? 4 : 14}\n\t\t\t\t\t\t\t\ttextAnchor={orientation === \"horizontal\" ? \"start\" : \"middle\"}\n\t\t\t\t\t\t\t\tfontSize={11}\n\t\t\t\t\t\t\t\tfill=\"hsl(var(--foreground))\"\n\t\t\t\t\t\t\t\tstyle={{ paintOrder: \"stroke\" }}\n\t\t\t\t\t\t\t\tstroke=\"hsl(var(--background))\"\n\t\t\t\t\t\t\t\tstrokeWidth={3}\n\t\t\t\t\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{n.node.label}\n\t\t\t\t\t\t\t</text>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t</g>\n\t\t\t\t))}\n\t\t\t</g>\n\t\t</svg>\n\t);\n}\n\nfunction layout(\n\td3h: D3HierarchyMod,\n\troot: DendrogramNode,\n\torientation: \"horizontal\" | \"vertical\",\n\twidth: number,\n\theight: number,\n): { nodes: LaidOutNode[]; links: LaidOutLink[] } {\n\tconst hierarchy = d3h.hierarchy<DendrogramNode>(root);\n\tconst clusterFn = d3h.cluster<DendrogramNode>();\n\tif (orientation === \"horizontal\") {\n\t\tclusterFn.size([height - 32, width - 120]);\n\t} else {\n\t\tclusterFn.size([width - 32, height - 64]);\n\t}\n\t// cluster(hierarchy) returns HierarchyPointNode<T> with typed x/y.\n\tconst layoutRoot = clusterFn(hierarchy);\n\n\tconst nodes: LaidOutNode[] = [];\n\tlayoutRoot.each((d) => {\n\t\tconst isLeaf = !d.children || d.children.length === 0;\n\t\tif (orientation === \"horizontal\") {\n\t\t\tnodes.push({ node: d.data, x: d.y + 16, y: d.x + 16, depth: d.depth, isLeaf });\n\t\t} else {\n\t\t\tnodes.push({ node: d.data, x: d.x + 16, y: d.y + 16, depth: d.depth, isLeaf });\n\t\t}\n\t});\n\n\tconst links: LaidOutLink[] = layoutRoot.links().map((link, i) => {\n\t\tif (orientation === \"horizontal\") {\n\t\t\treturn {\n\t\t\t\tsource: { x: link.source.y + 16, y: link.source.x + 16 },\n\t\t\t\ttarget: { x: link.target.y + 16, y: link.target.x + 16 },\n\t\t\t\tid: `l-${i}`,\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tsource: { x: link.source.x + 16, y: link.source.y + 16 },\n\t\t\ttarget: { x: link.target.x + 16, y: link.target.y + 16 },\n\t\t\tid: `l-${i}`,\n\t\t};\n\t});\n\n\treturn { nodes, links };\n}\n\nfunction linkPath(\n\tlink: LaidOutLink,\n\torientation: \"horizontal\" | \"vertical\",\n\tlinkShape: \"step\" | \"diagonal\",\n): string {\n\tconst { source: s, target: t } = link;\n\tif (linkShape === \"step\") {\n\t\tif (orientation === \"horizontal\") {\n\t\t\treturn `M${s.x},${s.y} H${t.x} V${t.y}`;\n\t\t}\n\t\treturn `M${s.x},${s.y} V${t.y} H${t.x}`;\n\t}\n\tif (orientation === \"horizontal\") {\n\t\tconst mx = (s.x + t.x) / 2;\n\t\treturn `M${s.x},${s.y} C${mx},${s.y} ${mx},${t.y} ${t.x},${t.y}`;\n\t}\n\tconst my = (s.y + t.y) / 2;\n\treturn `M${s.x},${s.y} C${s.x},${my} ${t.x},${my} ${t.x},${t.y}`;\n}\n\nexport { Dendrogram };\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/artifacts/dendrogram/dendrogram.tsx"],"names":[],"mappings":";;;;;AAQO,SAAS,MAAM,MAAA,EAAsB;AAC3C,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC5B;ACsDA,SAAS,UAAA,CAAW;AAAA,EACnB,IAAA;AAAA,EACA,WAAA,GAAc,YAAA;AAAA,EACd,SAAA,GAAY,MAAA;AAAA,EACZ,KAAA,GAAQ,GAAA;AAAA,EACR,MAAA,GAAS,GAAA;AAAA,EACT,WAAA;AAAA,EACA,SAAA;AAAA,EACA,GAAG;AACJ,CAAA,EAAoB;AACnB,EAAA,MAAM,CAAC,GAAA,EAAK,MAAM,CAAA,GAAU,eAAgC,IAAI,CAAA;AAEhE,EAAM,gBAAU,MAAM;AACrB,IAAA,IAAI,SAAA,GAAY,KAAA;AAChB,IAAA,KAAK,OAAO,cAAc,CAAA,CAAE,IAAA,CAAK,CAAC,GAAA,KAAQ;AACzC,MAAA,IAAI,CAAC,SAAA,EAAW,MAAA,CAAO,GAAG,CAAA;AAAA,IAC3B,CAAC,CAAA;AACD,IAAA,OAAO,MAAM;AACZ,MAAA,SAAA,GAAY,IAAA;AAAA,IACb,CAAA;AAAA,EACD,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,IAAI,CAAC,GAAA,EAAK;AACT,IAAA,uBACC,GAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACA,6BAAA,EAA2B,IAAA;AAAA,QAC3B,WAAA,EAAU,MAAA;AAAA,QACV,SAAA,EAAW,EAAA,CAAG,0BAAA,EAA4B,SAAS,CAAA;AAAA,QACnD,KAAA,EAAO,EAAE,KAAA,EAAO,MAAA;AAAO;AAAA,KACxB;AAAA,EAEF;AAEA,EAAA,MAAM,EAAE,OAAO,KAAA,EAAM,GAAI,OAAO,GAAA,EAAK,IAAA,EAAM,WAAA,EAAa,KAAA,EAAO,MAAM,CAAA;AACrE,EAAA,MAAM,YAAY,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,MAAM,CAAA,CAAE,MAAA;AAChD,EAAA,MAAM,IAAA,GAAO,CAAA,gBAAA,EAAmB,SAAS,CAAA,oBAAA,EAAuB,KAAK,KAAK,CAAA,CAAA,CAAA;AAE1E,EAAA,uBACC,IAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,GAAG,IAAA;AAAA,MACJ,qBAAA,EAAmB,IAAA;AAAA,MACnB,kBAAA,EAAkB,WAAA;AAAA,MAClB,iBAAA,EAAiB,SAAA;AAAA,MACjB,IAAA,EAAK,KAAA;AAAA,MACL,KAAA;AAAA,MACA,MAAA;AAAA,MACA,OAAA,EAAS,CAAA,IAAA,EAAO,KAAK,CAAA,CAAA,EAAI,MAAM,CAAA,CAAA;AAAA,MAC/B,SAAA,EAAW,EAAA,CAAG,OAAA,EAAS,SAAS,CAAA;AAAA,MAEhC,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,WAAM,QAAA,EAAA,YAAA,EAAU,CAAA;AAAA,wBACjB,GAAA,CAAC,UAAM,QAAA,EAAA,IAAA,EAAK,CAAA;AAAA,4BACX,GAAA,EAAA,EAAE,2BAAA,EAAyB,MAC1B,QAAA,EAAA,KAAA,CAAM,GAAA,CAAI,CAAC,CAAA,qBACX,GAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YAEA,CAAA,EAAG,QAAA,CAAS,CAAA,EAAG,WAAA,EAAa,SAAS,CAAA;AAAA,YACrC,IAAA,EAAK,MAAA;AAAA,YACL,MAAA,EAAO,8BAAA;AAAA,YACP,aAAA,EAAe,GAAA;AAAA,YACf,WAAA,EAAa;AAAA,WAAA;AAAA,UALR,CAAA,CAAE;AAAA,SAOR,CAAA,EACF,CAAA;AAAA,4BACC,GAAA,EAAA,EAAE,2BAAA,EAAyB,MAC1B,QAAA,EAAA,KAAA,CAAM,GAAA,CAAI,CAAC,CAAA,qBACX,IAAA;AAAA,UAAC,GAAA;AAAA,UAAA;AAAA,YAEA,0BAAA,EAAwB,IAAA;AAAA,YACxB,WAAA,EAAW,CAAA,CAAE,MAAA,GAAS,MAAA,GAAS,OAAA;AAAA,YAC/B,cAAY,CAAA,CAAE,KAAA;AAAA,YACd,WAAW,CAAA,UAAA,EAAa,CAAA,CAAE,CAAC,CAAA,CAAA,EAAI,EAAE,CAAC,CAAA,CAAA,CAAA;AAAA,YAClC,OAAO,CAAA,CAAE,MAAA,IAAU,cAAc,EAAE,MAAA,EAAQ,WAAU,GAAI,MAAA;AAAA,YACzD,OAAA,EAAS,EAAE,MAAA,IAAU,WAAA,GAAc,MAAM,WAAA,CAAY,CAAA,CAAE,IAAI,CAAA,GAAI,MAAA;AAAA,YAE/D,QAAA,EAAA;AAAA,8BAAA,GAAA;AAAA,gBAAC,QAAA;AAAA,gBAAA;AAAA,kBACA,CAAA,EAAG,CAAA,CAAE,MAAA,GAAS,CAAA,GAAI,CAAA;AAAA,kBAClB,IAAA,EAAM,CAAA,CAAE,MAAA,GAAS,qBAAA,GAAwB;AAAA;AAAA,eAC1C;AAAA,cACC,EAAE,MAAA,mBACF,GAAA;AAAA,gBAAC,MAAA;AAAA,gBAAA;AAAA,kBACA,CAAA,EAAG,WAAA,KAAgB,YAAA,GAAe,CAAA,GAAI,CAAA;AAAA,kBACtC,CAAA,EAAG,WAAA,KAAgB,YAAA,GAAe,CAAA,GAAI,EAAA;AAAA,kBACtC,UAAA,EAAY,WAAA,KAAgB,YAAA,GAAe,OAAA,GAAU,QAAA;AAAA,kBACrD,QAAA,EAAU,EAAA;AAAA,kBACV,IAAA,EAAK,wBAAA;AAAA,kBACL,KAAA,EAAO,EAAE,UAAA,EAAY,QAAA,EAAS;AAAA,kBAC9B,MAAA,EAAO,wBAAA;AAAA,kBACP,WAAA,EAAa,CAAA;AAAA,kBACb,cAAA,EAAe,OAAA;AAAA,kBAEd,YAAE,IAAA,CAAK;AAAA;AAAA,eACT,GACG;AAAA;AAAA,WAAA;AAAA,UA1BC,EAAE,IAAA,CAAK;AAAA,SA4Bb,CAAA,EACF;AAAA;AAAA;AAAA,GACD;AAEF;AAEA,SAAS,MAAA,CACR,GAAA,EACA,IAAA,EACA,WAAA,EACA,OACA,MAAA,EACiD;AACjD,EAAA,MAAM,SAAA,GAAY,GAAA,CAAI,SAAA,CAA0B,IAAI,CAAA;AACpD,EAAA,MAAM,SAAA,GAAY,IAAI,OAAA,EAAwB;AAC9C,EAAA,IAAI,gBAAgB,YAAA,EAAc;AACjC,IAAA,SAAA,CAAU,KAAK,CAAC,MAAA,GAAS,EAAA,EAAI,KAAA,GAAQ,GAAG,CAAC,CAAA;AAAA,EAC1C,CAAA,MAAO;AACN,IAAA,SAAA,CAAU,KAAK,CAAC,KAAA,GAAQ,EAAA,EAAI,MAAA,GAAS,EAAE,CAAC,CAAA;AAAA,EACzC;AAEA,EAAA,MAAM,UAAA,GAAa,UAAU,SAAS,CAAA;AAEtC,EAAA,MAAM,QAAuB,EAAC;AAC9B,EAAA,UAAA,CAAW,IAAA,CAAK,CAAC,CAAA,KAAM;AACtB,IAAA,MAAM,SAAS,CAAC,CAAA,CAAE,QAAA,IAAY,CAAA,CAAE,SAAS,MAAA,KAAW,CAAA;AACpD,IAAA,IAAI,gBAAgB,YAAA,EAAc;AACjC,MAAA,KAAA,CAAM,KAAK,EAAE,IAAA,EAAM,CAAA,CAAE,IAAA,EAAM,GAAG,CAAA,CAAE,CAAA,GAAI,EAAA,EAAI,CAAA,EAAG,EAAE,CAAA,GAAI,EAAA,EAAI,OAAO,CAAA,CAAE,KAAA,EAAO,QAAQ,CAAA;AAAA,IAC9E,CAAA,MAAO;AACN,MAAA,KAAA,CAAM,KAAK,EAAE,IAAA,EAAM,CAAA,CAAE,IAAA,EAAM,GAAG,CAAA,CAAE,CAAA,GAAI,EAAA,EAAI,CAAA,EAAG,EAAE,CAAA,GAAI,EAAA,EAAI,OAAO,CAAA,CAAE,KAAA,EAAO,QAAQ,CAAA;AAAA,IAC9E;AAAA,EACD,CAAC,CAAA;AAED,EAAA,MAAM,QAAuB,UAAA,CAAW,KAAA,GAAQ,GAAA,CAAI,CAAC,MAAM,CAAA,KAAM;AAChE,IAAA,IAAI,gBAAgB,YAAA,EAAc;AACjC,MAAA,OAAO;AAAA,QACN,MAAA,EAAQ,EAAE,CAAA,EAAG,IAAA,CAAK,MAAA,CAAO,CAAA,GAAI,EAAA,EAAI,CAAA,EAAG,IAAA,CAAK,MAAA,CAAO,CAAA,GAAI,EAAA,EAAG;AAAA,QACvD,MAAA,EAAQ,EAAE,CAAA,EAAG,IAAA,CAAK,MAAA,CAAO,CAAA,GAAI,EAAA,EAAI,CAAA,EAAG,IAAA,CAAK,MAAA,CAAO,CAAA,GAAI,EAAA,EAAG;AAAA,QACvD,EAAA,EAAI,KAAK,CAAC,CAAA;AAAA,OACX;AAAA,IACD;AACA,IAAA,OAAO;AAAA,MACN,MAAA,EAAQ,EAAE,CAAA,EAAG,IAAA,CAAK,MAAA,CAAO,CAAA,GAAI,EAAA,EAAI,CAAA,EAAG,IAAA,CAAK,MAAA,CAAO,CAAA,GAAI,EAAA,EAAG;AAAA,MACvD,MAAA,EAAQ,EAAE,CAAA,EAAG,IAAA,CAAK,MAAA,CAAO,CAAA,GAAI,EAAA,EAAI,CAAA,EAAG,IAAA,CAAK,MAAA,CAAO,CAAA,GAAI,EAAA,EAAG;AAAA,MACvD,EAAA,EAAI,KAAK,CAAC,CAAA;AAAA,KACX;AAAA,EACD,CAAC,CAAA;AAED,EAAA,OAAO,EAAE,OAAO,KAAA,EAAM;AACvB;AAEA,SAAS,QAAA,CACR,IAAA,EACA,WAAA,EACA,SAAA,EACS;AACT,EAAA,MAAM,EAAE,MAAA,EAAQ,CAAA,EAAG,MAAA,EAAQ,GAAE,GAAI,IAAA;AACjC,EAAA,IAAI,cAAc,MAAA,EAAQ;AACzB,IAAA,IAAI,gBAAgB,YAAA,EAAc;AACjC,MAAA,OAAO,CAAA,CAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAA,EAAI,CAAA,CAAE,CAAC,CAAA,EAAA,EAAK,CAAA,CAAE,CAAC,CAAA,EAAA,EAAK,CAAA,CAAE,CAAC,CAAA,CAAA;AAAA,IACtC;AACA,IAAA,OAAO,CAAA,CAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAA,EAAI,CAAA,CAAE,CAAC,CAAA,EAAA,EAAK,CAAA,CAAE,CAAC,CAAA,EAAA,EAAK,CAAA,CAAE,CAAC,CAAA,CAAA;AAAA,EACtC;AACA,EAAA,IAAI,gBAAgB,YAAA,EAAc;AACjC,IAAA,MAAM,EAAA,GAAA,CAAM,CAAA,CAAE,CAAA,GAAI,CAAA,CAAE,CAAA,IAAK,CAAA;AACzB,IAAA,OAAO,CAAA,CAAA,EAAI,EAAE,CAAC,CAAA,CAAA,EAAI,EAAE,CAAC,CAAA,EAAA,EAAK,EAAE,CAAA,CAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAA,EAAI,EAAE,IAAI,CAAA,CAAE,CAAC,IAAI,CAAA,CAAE,CAAC,CAAA,CAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAA;AAAA,EAC/D;AACA,EAAA,MAAM,EAAA,GAAA,CAAM,CAAA,CAAE,CAAA,GAAI,CAAA,CAAE,CAAA,IAAK,CAAA;AACzB,EAAA,OAAO,CAAA,CAAA,EAAI,EAAE,CAAC,CAAA,CAAA,EAAI,EAAE,CAAC,CAAA,EAAA,EAAK,EAAE,CAAC,CAAA,CAAA,EAAI,EAAE,CAAA,CAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAA,EAAI,EAAE,IAAI,CAAA,CAAE,CAAC,CAAA,CAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAA;AAC/D","file":"dendrogram.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n\nconst SAFE_URL_SCHEMES = [\"http:\", \"https:\", \"mailto:\"] as const;\n\n/**\n * Allowlist a URL for use as an `<a href>` against untrusted input.\n *\n * Returns the raw string when it's `http(s):` / `mailto:` / a relative\n * URL (no scheme); returns `undefined` otherwise. Defends against\n * `javascript:` / `data:` / `vbscript:` injection from streamed model\n * output or third-party JSON payloads that flow into citation chips.\n *\n * Inside a Markdown render path, `rehype-sanitize` already strips\n * `javascript:` from inline-link hrefs — but it does NOT introspect\n * JSON nested inside attribute values (e.g. `<sources data='[…]'/>`),\n * so the components that consume that data must guard themselves.\n *\n * @param raw - The candidate URL, or `undefined` when none was supplied.\n * @returns The URL when safe to render, otherwise `undefined`.\n */\nexport function safeUrl(raw: string | undefined): string | undefined {\n\tif (raw === undefined || raw === \"\") return undefined;\n\t// Relative URLs have no scheme — `new URL(relative)` throws without a base,\n\t// so a thrown URL means either malformed input OR a relative path. Treat\n\t// \"throws + does not contain a colon\" as a relative path (safe).\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(raw);\n\t} catch {\n\t\treturn raw.includes(\":\") ? undefined : raw;\n\t}\n\treturn SAFE_URL_SCHEMES.some((scheme) => scheme === parsed.protocol) ? raw : undefined;\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/**\n * Clustering tree where every leaf sits at the same depth, regardless of\n * branch length — the visual signature of taxonomies, phylogenetic trees,\n * and hierarchical-clustering output. Backed by d3-hierarchy's `cluster`\n * layout (distinct from `tree`, which packs leaves variably).\n *\n * Heavy peer: requires `d3-hierarchy` (~3 KB gzip).\n *\n * @example\n * <Dendrogram\n * root={{\n * id: \"root\", label: \"Animals\",\n * children: [\n * { id: \"mammals\", label: \"Mammals\", children: [\n * { id: \"cat\", label: \"Cat\" },\n * { id: \"dog\", label: \"Dog\" },\n * ]},\n * { id: \"birds\", label: \"Birds\", children: [{ id: \"robin\", label: \"Robin\" }] },\n * ],\n * }}\n * />\n */\nexport type DendrogramNode = {\n\tid: string;\n\tlabel: string;\n\tchildren?: DendrogramNode[];\n};\n\nexport interface DendrogramProps extends Omit<React.SVGAttributes<SVGSVGElement>, \"children\"> {\n\t/** Root of the hierarchy. */\n\troot: DendrogramNode;\n\t/** \"horizontal\" runs root-to-leaves left→right; \"vertical\" runs top→bottom. Default \"horizontal\". */\n\torientation?: \"horizontal\" | \"vertical\";\n\t/** \"step\" draws right-angle elbow links (taxonomy aesthetic); \"diagonal\" uses smooth Bezier. Default \"step\". */\n\tlinkShape?: \"step\" | \"diagonal\";\n\t/** Pixel width of the rendered SVG. Default 600. */\n\twidth?: number;\n\t/** Pixel height of the rendered SVG. Default 400. */\n\theight?: number;\n\t/** Fired when a leaf is clicked. */\n\tonLeafClick?: (node: DendrogramNode) => void;\n}\n\ninterface LaidOutNode {\n\tnode: DendrogramNode;\n\tx: number;\n\ty: number;\n\tdepth: number;\n\tisLeaf: boolean;\n}\n\ninterface LaidOutLink {\n\tsource: { x: number; y: number };\n\ttarget: { x: number; y: number };\n\tid: string;\n}\n\ntype D3HierarchyMod = typeof import(\"d3-hierarchy\");\n\nfunction Dendrogram({\n\troot,\n\torientation = \"horizontal\",\n\tlinkShape = \"step\",\n\twidth = 600,\n\theight = 400,\n\tonLeafClick,\n\tclassName,\n\t...rest\n}: DendrogramProps) {\n\tconst [d3h, setD3h] = React.useState<D3HierarchyMod | null>(null);\n\n\tReact.useEffect(() => {\n\t\tlet cancelled = false;\n\t\tvoid import(\"d3-hierarchy\").then((mod) => {\n\t\t\tif (!cancelled) setD3h(mod);\n\t\t});\n\t\treturn () => {\n\t\t\tcancelled = true;\n\t\t};\n\t}, []);\n\n\tif (!d3h) {\n\t\treturn (\n\t\t\t<div\n\t\t\t\tdata-hex-dendrogram-loading\n\t\t\t\taria-busy=\"true\"\n\t\t\t\tclassName={cn(\"inline-block bg-muted/20\", className)}\n\t\t\t\tstyle={{ width, height }}\n\t\t\t/>\n\t\t);\n\t}\n\n\tconst { nodes, links } = layout(d3h, root, orientation, width, height);\n\tconst leafCount = nodes.filter((n) => n.isLeaf).length;\n\tconst desc = `Dendrogram with ${leafCount} leaves, rooted at \"${root.label}\"`;\n\n\treturn (\n\t\t<svg\n\t\t\t{...rest}\n\t\t\tdata-hex-dendrogram\n\t\t\tdata-orientation={orientation}\n\t\t\tdata-link-shape={linkShape}\n\t\t\trole=\"img\"\n\t\t\twidth={width}\n\t\t\theight={height}\n\t\t\tviewBox={`0 0 ${width} ${height}`}\n\t\t\tclassName={cn(\"block\", className)}\n\t\t>\n\t\t\t<title>Dendrogram</title>\n\t\t\t<desc>{desc}</desc>\n\t\t\t<g data-hex-dendrogram-links>\n\t\t\t\t{links.map((l) => (\n\t\t\t\t\t<path\n\t\t\t\t\t\tkey={l.id}\n\t\t\t\t\t\td={linkPath(l, orientation, linkShape)}\n\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\tstroke=\"hsl(var(--muted-foreground))\"\n\t\t\t\t\t\tstrokeOpacity={0.8}\n\t\t\t\t\t\tstrokeWidth={1}\n\t\t\t\t\t/>\n\t\t\t\t))}\n\t\t\t</g>\n\t\t\t<g data-hex-dendrogram-nodes>\n\t\t\t\t{nodes.map((n) => (\n\t\t\t\t\t<g\n\t\t\t\t\t\tkey={n.node.id}\n\t\t\t\t\t\tdata-hex-dendrogram-node\n\t\t\t\t\t\tdata-leaf={n.isLeaf ? \"true\" : \"false\"}\n\t\t\t\t\t\tdata-depth={n.depth}\n\t\t\t\t\t\ttransform={`translate(${n.x},${n.y})`}\n\t\t\t\t\t\tstyle={n.isLeaf && onLeafClick ? { cursor: \"pointer\" } : undefined}\n\t\t\t\t\t\tonClick={n.isLeaf && onLeafClick ? () => onLeafClick(n.node) : undefined}\n\t\t\t\t\t>\n\t\t\t\t\t\t<circle\n\t\t\t\t\t\t\tr={n.isLeaf ? 3 : 2}\n\t\t\t\t\t\t\tfill={n.isLeaf ? \"hsl(var(--primary))\" : \"hsl(var(--muted-foreground))\"}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t{n.isLeaf ? (\n\t\t\t\t\t\t\t<text\n\t\t\t\t\t\t\t\tx={orientation === \"horizontal\" ? 6 : 0}\n\t\t\t\t\t\t\t\ty={orientation === \"horizontal\" ? 4 : 14}\n\t\t\t\t\t\t\t\ttextAnchor={orientation === \"horizontal\" ? \"start\" : \"middle\"}\n\t\t\t\t\t\t\t\tfontSize={11}\n\t\t\t\t\t\t\t\tfill=\"hsl(var(--foreground))\"\n\t\t\t\t\t\t\t\tstyle={{ paintOrder: \"stroke\" }}\n\t\t\t\t\t\t\t\tstroke=\"hsl(var(--background))\"\n\t\t\t\t\t\t\t\tstrokeWidth={3}\n\t\t\t\t\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{n.node.label}\n\t\t\t\t\t\t\t</text>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t</g>\n\t\t\t\t))}\n\t\t\t</g>\n\t\t</svg>\n\t);\n}\n\nfunction layout(\n\td3h: D3HierarchyMod,\n\troot: DendrogramNode,\n\torientation: \"horizontal\" | \"vertical\",\n\twidth: number,\n\theight: number,\n): { nodes: LaidOutNode[]; links: LaidOutLink[] } {\n\tconst hierarchy = d3h.hierarchy<DendrogramNode>(root);\n\tconst clusterFn = d3h.cluster<DendrogramNode>();\n\tif (orientation === \"horizontal\") {\n\t\tclusterFn.size([height - 32, width - 120]);\n\t} else {\n\t\tclusterFn.size([width - 32, height - 64]);\n\t}\n\t// cluster(hierarchy) returns HierarchyPointNode<T> with typed x/y.\n\tconst layoutRoot = clusterFn(hierarchy);\n\n\tconst nodes: LaidOutNode[] = [];\n\tlayoutRoot.each((d) => {\n\t\tconst isLeaf = !d.children || d.children.length === 0;\n\t\tif (orientation === \"horizontal\") {\n\t\t\tnodes.push({ node: d.data, x: d.y + 16, y: d.x + 16, depth: d.depth, isLeaf });\n\t\t} else {\n\t\t\tnodes.push({ node: d.data, x: d.x + 16, y: d.y + 16, depth: d.depth, isLeaf });\n\t\t}\n\t});\n\n\tconst links: LaidOutLink[] = layoutRoot.links().map((link, i) => {\n\t\tif (orientation === \"horizontal\") {\n\t\t\treturn {\n\t\t\t\tsource: { x: link.source.y + 16, y: link.source.x + 16 },\n\t\t\t\ttarget: { x: link.target.y + 16, y: link.target.x + 16 },\n\t\t\t\tid: `l-${i}`,\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tsource: { x: link.source.x + 16, y: link.source.y + 16 },\n\t\t\ttarget: { x: link.target.x + 16, y: link.target.y + 16 },\n\t\t\tid: `l-${i}`,\n\t\t};\n\t});\n\n\treturn { nodes, links };\n}\n\nfunction linkPath(\n\tlink: LaidOutLink,\n\torientation: \"horizontal\" | \"vertical\",\n\tlinkShape: \"step\" | \"diagonal\",\n): string {\n\tconst { source: s, target: t } = link;\n\tif (linkShape === \"step\") {\n\t\tif (orientation === \"horizontal\") {\n\t\t\treturn `M${s.x},${s.y} H${t.x} V${t.y}`;\n\t\t}\n\t\treturn `M${s.x},${s.y} V${t.y} H${t.x}`;\n\t}\n\tif (orientation === \"horizontal\") {\n\t\tconst mx = (s.x + t.x) / 2;\n\t\treturn `M${s.x},${s.y} C${mx},${s.y} ${mx},${t.y} ${t.x},${t.y}`;\n\t}\n\tconst my = (s.y + t.y) / 2;\n\treturn `M${s.x},${s.y} C${s.x},${my} ${t.x},${my} ${t.x},${t.y}`;\n}\n\nexport { Dendrogram };\n"]}
|
package/dist/diagram.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/utils.ts","../src/ai/diagram/diagram.tsx"],"names":[],"mappings":";;;;;AAQO,SAAS,MAAM,MAAA,EAAsB;AAC3C,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC5B;ACyBA,SAAS,OAAA,CAAQ,EAAE,QAAA,EAAU,MAAA,EAAQ,KAAA,GAAQ,SAAA,EAAW,EAAA,EAAI,OAAA,EAAS,SAAA,EAAW,GAAG,IAAA,EAAK,EAAiB;AACxG,EAAA,MAAM,CAAC,GAAA,EAAK,MAAM,CAAA,GAAU,eAAiB,EAAE,CAAA;AAC/C,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAU,eAAwB,IAAI,CAAA;AAC5D,EAAA,MAAM,UAAA,GAAmB,aAAO,OAAO,CAAA;AACvC,EAAA,UAAA,CAAW,OAAA,GAAU,OAAA;AAMrB,EAAA,MAAM,UAAgB,KAAA,CAAA,KAAA,EAAM;AAC5B,EAAA,MAAM,WAAW,EAAA,IAAM,CAAA,YAAA,EAAe,QAAQ,OAAA,CAAQ,IAAA,EAAM,GAAG,CAAC,CAAA,CAAA;AAEhE,EAAM,gBAAU,MAAM;AACrB,IAAA,IAAI,SAAA,GAAY,KAAA;AAChB,IAAA,QAAA,CAAS,IAAI,CAAA;AACb,IAAA,KAAA,CAAM,YAAY;AACjB,MAAA,IAAI;AACH,QAAA,MAAM,EAAE,OAAA,EAAS,OAAA,EAAQ,GAAI,MAAM,OAAO,SAAS,CAAA;AACnD,QAAA,IAAI,SAAA,EAAW;AACf,QAAA,OAAA,CAAQ,WAAW,EAAE,WAAA,EAAa,OAAO,KAAA,EAAO,aAAA,EAAe,UAAU,CAAA;AACzE,QAAA,MAAM,EAAE,KAAK,QAAA,EAAS,GAAI,MAAM,OAAA,CAAQ,MAAA,CAAO,UAAU,MAAM,CAAA;AAC/D,QAAA,IAAI,CAAC,SAAA,EAAW,MAAA,CAAO,QAAQ,CAAA;AAAA,MAChC,SAAS,GAAA,EAAK;AACb,QAAA,MAAM,UAAU,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,OAAO,GAAG,CAAA;AAC/D,QAAA,IAAI,SAAA,EAAW;AACf,QAAA,QAAA,CAAS,OAAO,CAAA;AAChB,QAAA,UAAA,CAAW,UAAU,OAAO,CAAA;AAAA,MAC7B;AAAA,IACD,CAAA,GAAG;AACH,IAAA,OAAO,MAAM;AACZ,MAAA,SAAA,GAAY,IAAA;AAAA,IACb,CAAA;AAAA,EACD,CAAA,EAAG,CAAC,MAAA,EAAQ,KAAA,EAAO,QAAQ,CAAC,CAAA;AAE5B,EAAA,IAAI,KAAA,EAAO;AACV,IAAA,uBACC,IAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,GAAG,IAAA;AAAA,QACJ,wBAAA,EAAsB,IAAA;AAAA,QACtB,IAAA,EAAK,OAAA;AAAA,QACL,SAAA,EAAW,EAAA;AAAA,UACV,uFAAA;AAAA,UACA;AAAA,SACD;AAAA,QAEA,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,aAAA,EAAc,QAAA,EAAA,0BAAA,EAAwB,CAAA;AAAA,0BACrD,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,6CAAA,EAA+C,QAAA,EAAA,KAAA,EAAM;AAAA;AAAA;AAAA,KACrE;AAAA,EAEF;AAEA,EAAA,uBACC,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,GAAG,IAAA;AAAA,MACJ,kBAAA,EAAgB,IAAA;AAAA,MAChB,YAAA,EAAY,KAAA;AAAA,MACZ,SAAA,EAAW,EAAA,CAAG,mDAAA,EAAqD,SAAS,CAAA;AAAA,MAK5E,uBAAA,EAAyB,EAAE,MAAA,EAAQ,GAAA;AAAI;AAAA,GACxC;AAEF","file":"diagram.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/**\n * Render a Mermaid diagram from a source string. Useful for AI agent\n * outputs that emit flowcharts / sequence diagrams / class diagrams in\n * Markdown — pipe the code-fence body straight in.\n *\n * Heavy peer: requires `mermaid` (~700 KB gzip). The hex-core CLI's `add`\n * flow prompts before installing — this is the largest engine in the\n * AI Elements set, so the consumer should opt in deliberately.\n *\n * @example\n * <Diagram>{`flowchart LR\\n A --> B\\n B --> C`}</Diagram>\n *\n * <Diagram theme=\"dark\" id=\"agent-flow\">{mermaidSource}</Diagram>\n */\nexport interface DiagramProps extends Omit<React.HTMLAttributes<HTMLDivElement>, \"children\" | \"onError\"> {\n\t/** Mermaid source string. */\n\tchildren: string;\n\t/** Light or dark mermaid theme. Default \"default\" (light). */\n\ttheme?: \"default\" | \"dark\" | \"forest\" | \"neutral\";\n\t/** Stable ID for the rendered SVG. Required when multiple diagrams share a page; auto-generated when omitted. */\n\tid?: string;\n\t/** Called on parse/render failure with the engine's message. */\n\tonError?: (message: string) => void;\n}\n\n/**\n * Renders a Mermaid diagram from source.\n * @param props - Source string + theme + lifecycle callbacks\n * @returns A div containing the rendered SVG\n */\nfunction Diagram({ children: source, theme = \"default\", id, onError, className, ...rest }: DiagramProps) {\n\tconst [svg, setSvg] = React.useState<string>(\"\");\n\tconst [error, setError] = React.useState<string | null>(null);\n\tconst onErrorRef = React.useRef(onError);\n\tonErrorRef.current = onError;\n\n\t// useId is stable across SSR/hydration AND unique per component instance,\n\t// avoiding the module-singleton counter bug where two diagrams in\n\t// streamed AI output collide on mermaid's internal cache key. Mermaid\n\t// rejects \":\" in IDs (React's useId emits \":r0:\"-style) so strip it.\n\tconst reactId = React.useId();\n\tconst stableId = id ?? `hex-diagram-${reactId.replace(/:/g, \"-\")}`;\n\n\tReact.useEffect(() => {\n\t\tlet cancelled = false;\n\t\tsetError(null);\n\t\tvoid (async () => {\n\t\t\ttry {\n\t\t\t\tconst { default: mermaid } = await import(\"mermaid\");\n\t\t\t\tif (cancelled) return;\n\t\t\t\tmermaid.initialize({ startOnLoad: false, theme, securityLevel: \"strict\" });\n\t\t\t\tconst { svg: rendered } = await mermaid.render(stableId, source);\n\t\t\t\tif (!cancelled) setSvg(rendered);\n\t\t\t} catch (err) {\n\t\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\t\tif (cancelled) return;\n\t\t\t\tsetError(message);\n\t\t\t\tonErrorRef.current?.(message);\n\t\t\t}\n\t\t})();\n\t\treturn () => {\n\t\t\tcancelled = true;\n\t\t};\n\t}, [source, theme, stableId]);\n\n\tif (error) {\n\t\treturn (\n\t\t\t<div\n\t\t\t\t{...rest}\n\t\t\t\tdata-hex-diagram-error\n\t\t\t\trole=\"alert\"\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"rounded-md border border-destructive/40 bg-destructive/5 p-3 text-sm text-destructive\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t<div className=\"font-medium\">Diagram failed to render</div>\n\t\t\t\t<pre className=\"mt-1 whitespace-pre-wrap text-xs opacity-80\">{error}</pre>\n\t\t\t</div>\n\t\t);\n\t}\n\n\treturn (\n\t\t<div\n\t\t\t{...rest}\n\t\t\tdata-hex-diagram\n\t\t\tdata-theme={theme}\n\t\t\tclassName={cn(\"overflow-auto rounded-md border bg-background p-3\", className)}\n\t\t\t// dangerouslySetInnerHTML: mermaid sanitizes its own SVG output via\n\t\t\t// securityLevel=\"strict\" (no foreignObject, no script tags). Source\n\t\t\t// strings still come from the consumer — never from untrusted user\n\t\t\t// input without their own validation upstream.\n\t\t\tdangerouslySetInnerHTML={{ __html: svg }}\n\t\t/>\n\t);\n}\n\nexport { Diagram };\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/ai/diagram/diagram.tsx"],"names":[],"mappings":";;;;;AAQO,SAAS,MAAM,MAAA,EAAsB;AAC3C,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC5B;ACyBA,SAAS,OAAA,CAAQ,EAAE,QAAA,EAAU,MAAA,EAAQ,KAAA,GAAQ,SAAA,EAAW,EAAA,EAAI,OAAA,EAAS,SAAA,EAAW,GAAG,IAAA,EAAK,EAAiB;AACxG,EAAA,MAAM,CAAC,GAAA,EAAK,MAAM,CAAA,GAAU,eAAiB,EAAE,CAAA;AAC/C,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAU,eAAwB,IAAI,CAAA;AAC5D,EAAA,MAAM,UAAA,GAAmB,aAAO,OAAO,CAAA;AACvC,EAAA,UAAA,CAAW,OAAA,GAAU,OAAA;AAMrB,EAAA,MAAM,UAAgB,KAAA,CAAA,KAAA,EAAM;AAC5B,EAAA,MAAM,WAAW,EAAA,IAAM,CAAA,YAAA,EAAe,QAAQ,OAAA,CAAQ,IAAA,EAAM,GAAG,CAAC,CAAA,CAAA;AAEhE,EAAM,gBAAU,MAAM;AACrB,IAAA,IAAI,SAAA,GAAY,KAAA;AAChB,IAAA,QAAA,CAAS,IAAI,CAAA;AACb,IAAA,KAAA,CAAM,YAAY;AACjB,MAAA,IAAI;AACH,QAAA,MAAM,EAAE,OAAA,EAAS,OAAA,EAAQ,GAAI,MAAM,OAAO,SAAS,CAAA;AACnD,QAAA,IAAI,SAAA,EAAW;AACf,QAAA,OAAA,CAAQ,WAAW,EAAE,WAAA,EAAa,OAAO,KAAA,EAAO,aAAA,EAAe,UAAU,CAAA;AACzE,QAAA,MAAM,EAAE,KAAK,QAAA,EAAS,GAAI,MAAM,OAAA,CAAQ,MAAA,CAAO,UAAU,MAAM,CAAA;AAC/D,QAAA,IAAI,CAAC,SAAA,EAAW,MAAA,CAAO,QAAQ,CAAA;AAAA,MAChC,SAAS,GAAA,EAAK;AACb,QAAA,MAAM,UAAU,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,OAAO,GAAG,CAAA;AAC/D,QAAA,IAAI,SAAA,EAAW;AACf,QAAA,QAAA,CAAS,OAAO,CAAA;AAChB,QAAA,UAAA,CAAW,UAAU,OAAO,CAAA;AAAA,MAC7B;AAAA,IACD,CAAA,GAAG;AACH,IAAA,OAAO,MAAM;AACZ,MAAA,SAAA,GAAY,IAAA;AAAA,IACb,CAAA;AAAA,EACD,CAAA,EAAG,CAAC,MAAA,EAAQ,KAAA,EAAO,QAAQ,CAAC,CAAA;AAE5B,EAAA,IAAI,KAAA,EAAO;AACV,IAAA,uBACC,IAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,GAAG,IAAA;AAAA,QACJ,wBAAA,EAAsB,IAAA;AAAA,QACtB,IAAA,EAAK,OAAA;AAAA,QACL,SAAA,EAAW,EAAA;AAAA,UACV,uFAAA;AAAA,UACA;AAAA,SACD;AAAA,QAEA,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,aAAA,EAAc,QAAA,EAAA,0BAAA,EAAwB,CAAA;AAAA,0BACrD,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,6CAAA,EAA+C,QAAA,EAAA,KAAA,EAAM;AAAA;AAAA;AAAA,KACrE;AAAA,EAEF;AAEA,EAAA,uBACC,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,GAAG,IAAA;AAAA,MACJ,kBAAA,EAAgB,IAAA;AAAA,MAChB,YAAA,EAAY,KAAA;AAAA,MACZ,SAAA,EAAW,EAAA,CAAG,mDAAA,EAAqD,SAAS,CAAA;AAAA,MAK5E,uBAAA,EAAyB,EAAE,MAAA,EAAQ,GAAA;AAAI;AAAA,GACxC;AAEF","file":"diagram.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n\nconst SAFE_URL_SCHEMES = [\"http:\", \"https:\", \"mailto:\"] as const;\n\n/**\n * Allowlist a URL for use as an `<a href>` against untrusted input.\n *\n * Returns the raw string when it's `http(s):` / `mailto:` / a relative\n * URL (no scheme); returns `undefined` otherwise. Defends against\n * `javascript:` / `data:` / `vbscript:` injection from streamed model\n * output or third-party JSON payloads that flow into citation chips.\n *\n * Inside a Markdown render path, `rehype-sanitize` already strips\n * `javascript:` from inline-link hrefs — but it does NOT introspect\n * JSON nested inside attribute values (e.g. `<sources data='[…]'/>`),\n * so the components that consume that data must guard themselves.\n *\n * @param raw - The candidate URL, or `undefined` when none was supplied.\n * @returns The URL when safe to render, otherwise `undefined`.\n */\nexport function safeUrl(raw: string | undefined): string | undefined {\n\tif (raw === undefined || raw === \"\") return undefined;\n\t// Relative URLs have no scheme — `new URL(relative)` throws without a base,\n\t// so a thrown URL means either malformed input OR a relative path. Treat\n\t// \"throws + does not contain a colon\" as a relative path (safe).\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(raw);\n\t} catch {\n\t\treturn raw.includes(\":\") ? undefined : raw;\n\t}\n\treturn SAFE_URL_SCHEMES.some((scheme) => scheme === parsed.protocol) ? raw : undefined;\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/**\n * Render a Mermaid diagram from a source string. Useful for AI agent\n * outputs that emit flowcharts / sequence diagrams / class diagrams in\n * Markdown — pipe the code-fence body straight in.\n *\n * Heavy peer: requires `mermaid` (~700 KB gzip). The hex-core CLI's `add`\n * flow prompts before installing — this is the largest engine in the\n * AI Elements set, so the consumer should opt in deliberately.\n *\n * @example\n * <Diagram>{`flowchart LR\\n A --> B\\n B --> C`}</Diagram>\n *\n * <Diagram theme=\"dark\" id=\"agent-flow\">{mermaidSource}</Diagram>\n */\nexport interface DiagramProps extends Omit<React.HTMLAttributes<HTMLDivElement>, \"children\" | \"onError\"> {\n\t/** Mermaid source string. */\n\tchildren: string;\n\t/** Light or dark mermaid theme. Default \"default\" (light). */\n\ttheme?: \"default\" | \"dark\" | \"forest\" | \"neutral\";\n\t/** Stable ID for the rendered SVG. Required when multiple diagrams share a page; auto-generated when omitted. */\n\tid?: string;\n\t/** Called on parse/render failure with the engine's message. */\n\tonError?: (message: string) => void;\n}\n\n/**\n * Renders a Mermaid diagram from source.\n * @param props - Source string + theme + lifecycle callbacks\n * @returns A div containing the rendered SVG\n */\nfunction Diagram({ children: source, theme = \"default\", id, onError, className, ...rest }: DiagramProps) {\n\tconst [svg, setSvg] = React.useState<string>(\"\");\n\tconst [error, setError] = React.useState<string | null>(null);\n\tconst onErrorRef = React.useRef(onError);\n\tonErrorRef.current = onError;\n\n\t// useId is stable across SSR/hydration AND unique per component instance,\n\t// avoiding the module-singleton counter bug where two diagrams in\n\t// streamed AI output collide on mermaid's internal cache key. Mermaid\n\t// rejects \":\" in IDs (React's useId emits \":r0:\"-style) so strip it.\n\tconst reactId = React.useId();\n\tconst stableId = id ?? `hex-diagram-${reactId.replace(/:/g, \"-\")}`;\n\n\tReact.useEffect(() => {\n\t\tlet cancelled = false;\n\t\tsetError(null);\n\t\tvoid (async () => {\n\t\t\ttry {\n\t\t\t\tconst { default: mermaid } = await import(\"mermaid\");\n\t\t\t\tif (cancelled) return;\n\t\t\t\tmermaid.initialize({ startOnLoad: false, theme, securityLevel: \"strict\" });\n\t\t\t\tconst { svg: rendered } = await mermaid.render(stableId, source);\n\t\t\t\tif (!cancelled) setSvg(rendered);\n\t\t\t} catch (err) {\n\t\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\t\tif (cancelled) return;\n\t\t\t\tsetError(message);\n\t\t\t\tonErrorRef.current?.(message);\n\t\t\t}\n\t\t})();\n\t\treturn () => {\n\t\t\tcancelled = true;\n\t\t};\n\t}, [source, theme, stableId]);\n\n\tif (error) {\n\t\treturn (\n\t\t\t<div\n\t\t\t\t{...rest}\n\t\t\t\tdata-hex-diagram-error\n\t\t\t\trole=\"alert\"\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"rounded-md border border-destructive/40 bg-destructive/5 p-3 text-sm text-destructive\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t<div className=\"font-medium\">Diagram failed to render</div>\n\t\t\t\t<pre className=\"mt-1 whitespace-pre-wrap text-xs opacity-80\">{error}</pre>\n\t\t\t</div>\n\t\t);\n\t}\n\n\treturn (\n\t\t<div\n\t\t\t{...rest}\n\t\t\tdata-hex-diagram\n\t\t\tdata-theme={theme}\n\t\t\tclassName={cn(\"overflow-auto rounded-md border bg-background p-3\", className)}\n\t\t\t// dangerouslySetInnerHTML: mermaid sanitizes its own SVG output via\n\t\t\t// securityLevel=\"strict\" (no foreignObject, no script tags). Source\n\t\t\t// strings still come from the consumer — never from untrusted user\n\t\t\t// input without their own validation upstream.\n\t\t\tdangerouslySetInnerHTML={{ __html: svg }}\n\t\t/>\n\t);\n}\n\nexport { Diagram };\n"]}
|
package/dist/dialog.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/utils.ts","../src/components/dialog/dialog.tsx"],"names":[],"mappings":"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","file":"dialog.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n","\"use client\";\n\nimport * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/** Root container controlling open state of a modal dialog. */\nconst Dialog = DialogPrimitive.Root;\n\n/** The element (usually a button) that opens the dialog when clicked. */\nconst DialogTrigger = DialogPrimitive.Trigger;\n\n/** Portals the dialog overlay and content into the body. */\nconst DialogPortal = DialogPrimitive.Portal;\n\n/** Closes the dialog when rendered inside DialogContent. */\nconst DialogClose = DialogPrimitive.Close;\n\n/** Dimmed backdrop rendered behind the dialog content. */\nconst DialogOverlay = React.forwardRef<\n\tReact.ComponentRef<typeof DialogPrimitive.Overlay>,\n\tReact.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n\t<DialogPrimitive.Overlay\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"fixed inset-0 z-50 bg-background/80 backdrop-blur-sm\",\n\t\t\t\"data-[state=open]:animate-in data-[state=closed]:animate-out\",\n\t\t\t\"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nDialogOverlay.displayName = \"DialogOverlay\";\n\ninterface DialogContentProps\n\textends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> {\n\t/**\n\t * When `true` (the default), DialogContent caps its height at viewport-2rem\n\t * and renders children inside a padded inner scroll container. The Close\n\t * button stays anchored to the (non-scrolling) outer panel so it remains\n\t * visible even when the user scrolls long content.\n\t *\n\t * Pass `scrollable={false}` to opt out — useful when the consumer manages\n\t * its own scroll surface (e.g. CommandDialog defers scroll to cmdk's\n\t * internal CommandList).\n\t */\n\tscrollable?: boolean;\n}\n\n/** The dialog content panel, centered on the overlay. Includes a close button by default. */\nconst DialogContent = React.forwardRef<\n\tReact.ComponentRef<typeof DialogPrimitive.Content>,\n\tDialogContentProps\n>(({ className, children, scrollable = true, ...props }, ref) => (\n\t<DialogPortal>\n\t\t<DialogOverlay />\n\t\t<DialogPrimitive.Content\n\t\t\tref={ref}\n\t\t\tclassName={cn(\n\t\t\t\t\"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%]\",\n\t\t\t\tscrollable\n\t\t\t\t\t? \"max-h-[calc(100vh-2rem)] border border-foreground/[0.08] bg-background shadow-lg rounded-lg\"\n\t\t\t\t\t: \"gap-[var(--gap-md,1rem)] border border-foreground/[0.08] bg-background p-[var(--space-6,1.5rem)] shadow-lg rounded-lg\",\n\t\t\t\t\"duration-[var(--duration-normal,200ms)] data-[state=open]:animate-in data-[state=closed]:animate-out\",\n\t\t\t\t\"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n\t\t\t\t\"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t>\n\t\t\t{scrollable ? (\n\t\t\t\t<div className=\"grid gap-[var(--gap-md,1rem)] overflow-y-auto p-[var(--space-6,1.5rem)]\">\n\t\t\t\t\t{children}\n\t\t\t\t</div>\n\t\t\t) : (\n\t\t\t\tchildren\n\t\t\t)}\n\t\t\t<DialogPrimitive.Close\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"absolute right-4 top-4 z-10 rounded-sm opacity-70 ring-offset-background bg-background/80 backdrop-blur-sm\",\n\t\t\t\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out hover:opacity-100\",\n\t\t\t\t\t\"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n\t\t\t\t\t\"disabled:pointer-events-none\",\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t<svg\n\t\t\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\tfill=\"none\"\n\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\tstrokeWidth=\"2\"\n\t\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\t\tclassName=\"h-4 w-4\"\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t>\n\t\t\t\t\t<path d=\"M18 6 6 18\" />\n\t\t\t\t\t<path d=\"m6 6 12 12\" />\n\t\t\t\t</svg>\n\t\t\t\t<span className=\"sr-only\">Close</span>\n\t\t\t</DialogPrimitive.Close>\n\t\t</DialogPrimitive.Content>\n\t</DialogPortal>\n));\nDialogContent.displayName = \"DialogContent\";\n\nexport type { DialogContentProps };\n\n/**\n * Header container inside DialogContent; stacks title and description.\n * @returns A div wrapping title/description with vertical rhythm\n */\nfunction DialogHeader({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\"flex flex-col space-y-1.5 text-center sm:text-left\", className)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\n/**\n * Footer container inside DialogContent; aligns action buttons.\n * @returns A div that stacks buttons on mobile and right-aligns on desktop\n */\nfunction DialogFooter({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t\"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\n/** Accessible dialog title; Radix wires it to aria-labelledby automatically. */\nconst DialogTitle = React.forwardRef<\n\tReact.ComponentRef<typeof DialogPrimitive.Title>,\n\tReact.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>\n>(({ className, ...props }, ref) => (\n\t<DialogPrimitive.Title\n\t\tref={ref}\n\t\tclassName={cn(\"text-lg font-semibold leading-none tracking-tight\", className)}\n\t\t{...props}\n\t/>\n));\nDialogTitle.displayName = \"DialogTitle\";\n\n/** Accessible dialog description; Radix wires it to aria-describedby automatically. */\nconst DialogDescription = React.forwardRef<\n\tReact.ComponentRef<typeof DialogPrimitive.Description>,\n\tReact.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n\t<DialogPrimitive.Description\n\t\tref={ref}\n\t\tclassName={cn(\"text-sm text-muted-foreground\", className)}\n\t\t{...props}\n\t/>\n));\nDialogDescription.displayName = \"DialogDescription\";\n\nexport {\n\tDialog,\n\tDialogPortal,\n\tDialogOverlay,\n\tDialogTrigger,\n\tDialogClose,\n\tDialogContent,\n\tDialogHeader,\n\tDialogFooter,\n\tDialogTitle,\n\tDialogDescription,\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/components/dialog/dialog.tsx"],"names":[],"mappings":"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","file":"dialog.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n\nconst SAFE_URL_SCHEMES = [\"http:\", \"https:\", \"mailto:\"] as const;\n\n/**\n * Allowlist a URL for use as an `<a href>` against untrusted input.\n *\n * Returns the raw string when it's `http(s):` / `mailto:` / a relative\n * URL (no scheme); returns `undefined` otherwise. Defends against\n * `javascript:` / `data:` / `vbscript:` injection from streamed model\n * output or third-party JSON payloads that flow into citation chips.\n *\n * Inside a Markdown render path, `rehype-sanitize` already strips\n * `javascript:` from inline-link hrefs — but it does NOT introspect\n * JSON nested inside attribute values (e.g. `<sources data='[…]'/>`),\n * so the components that consume that data must guard themselves.\n *\n * @param raw - The candidate URL, or `undefined` when none was supplied.\n * @returns The URL when safe to render, otherwise `undefined`.\n */\nexport function safeUrl(raw: string | undefined): string | undefined {\n\tif (raw === undefined || raw === \"\") return undefined;\n\t// Relative URLs have no scheme — `new URL(relative)` throws without a base,\n\t// so a thrown URL means either malformed input OR a relative path. Treat\n\t// \"throws + does not contain a colon\" as a relative path (safe).\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(raw);\n\t} catch {\n\t\treturn raw.includes(\":\") ? undefined : raw;\n\t}\n\treturn SAFE_URL_SCHEMES.some((scheme) => scheme === parsed.protocol) ? raw : undefined;\n}\n","\"use client\";\n\nimport * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/** Root container controlling open state of a modal dialog. */\nconst Dialog = DialogPrimitive.Root;\n\n/** The element (usually a button) that opens the dialog when clicked. */\nconst DialogTrigger = DialogPrimitive.Trigger;\n\n/** Portals the dialog overlay and content into the body. */\nconst DialogPortal = DialogPrimitive.Portal;\n\n/** Closes the dialog when rendered inside DialogContent. */\nconst DialogClose = DialogPrimitive.Close;\n\n/** Dimmed backdrop rendered behind the dialog content. */\nconst DialogOverlay = React.forwardRef<\n\tReact.ComponentRef<typeof DialogPrimitive.Overlay>,\n\tReact.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n\t<DialogPrimitive.Overlay\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"fixed inset-0 z-50 bg-background/80 backdrop-blur-sm\",\n\t\t\t\"data-[state=open]:animate-in data-[state=closed]:animate-out\",\n\t\t\t\"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nDialogOverlay.displayName = \"DialogOverlay\";\n\ninterface DialogContentProps\n\textends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> {\n\t/**\n\t * When `true` (the default), DialogContent caps its height at viewport-2rem\n\t * and renders children inside a padded inner scroll container. The Close\n\t * button stays anchored to the (non-scrolling) outer panel so it remains\n\t * visible even when the user scrolls long content.\n\t *\n\t * Pass `scrollable={false}` to opt out — useful when the consumer manages\n\t * its own scroll surface (e.g. CommandDialog defers scroll to cmdk's\n\t * internal CommandList).\n\t */\n\tscrollable?: boolean;\n}\n\n/** The dialog content panel, centered on the overlay. Includes a close button by default. */\nconst DialogContent = React.forwardRef<\n\tReact.ComponentRef<typeof DialogPrimitive.Content>,\n\tDialogContentProps\n>(({ className, children, scrollable = true, ...props }, ref) => (\n\t<DialogPortal>\n\t\t<DialogOverlay />\n\t\t<DialogPrimitive.Content\n\t\t\tref={ref}\n\t\t\tclassName={cn(\n\t\t\t\t\"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%]\",\n\t\t\t\tscrollable\n\t\t\t\t\t? \"max-h-[calc(100vh-2rem)] border border-foreground/[0.08] bg-background shadow-lg rounded-lg\"\n\t\t\t\t\t: \"gap-[var(--gap-md,1rem)] border border-foreground/[0.08] bg-background p-[var(--space-6,1.5rem)] shadow-lg rounded-lg\",\n\t\t\t\t\"duration-[var(--duration-normal,200ms)] data-[state=open]:animate-in data-[state=closed]:animate-out\",\n\t\t\t\t\"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n\t\t\t\t\"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t>\n\t\t\t{scrollable ? (\n\t\t\t\t<div className=\"grid gap-[var(--gap-md,1rem)] overflow-y-auto p-[var(--space-6,1.5rem)]\">\n\t\t\t\t\t{children}\n\t\t\t\t</div>\n\t\t\t) : (\n\t\t\t\tchildren\n\t\t\t)}\n\t\t\t<DialogPrimitive.Close\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"absolute right-4 top-4 z-10 rounded-sm opacity-70 ring-offset-background bg-background/80 backdrop-blur-sm\",\n\t\t\t\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out hover:opacity-100\",\n\t\t\t\t\t\"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n\t\t\t\t\t\"disabled:pointer-events-none\",\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t<svg\n\t\t\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\tfill=\"none\"\n\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\tstrokeWidth=\"2\"\n\t\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\t\tclassName=\"h-4 w-4\"\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t>\n\t\t\t\t\t<path d=\"M18 6 6 18\" />\n\t\t\t\t\t<path d=\"m6 6 12 12\" />\n\t\t\t\t</svg>\n\t\t\t\t<span className=\"sr-only\">Close</span>\n\t\t\t</DialogPrimitive.Close>\n\t\t</DialogPrimitive.Content>\n\t</DialogPortal>\n));\nDialogContent.displayName = \"DialogContent\";\n\nexport type { DialogContentProps };\n\n/**\n * Header container inside DialogContent; stacks title and description.\n * @returns A div wrapping title/description with vertical rhythm\n */\nfunction DialogHeader({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\"flex flex-col space-y-1.5 text-center sm:text-left\", className)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\n/**\n * Footer container inside DialogContent; aligns action buttons.\n * @returns A div that stacks buttons on mobile and right-aligns on desktop\n */\nfunction DialogFooter({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t\"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\n/** Accessible dialog title; Radix wires it to aria-labelledby automatically. */\nconst DialogTitle = React.forwardRef<\n\tReact.ComponentRef<typeof DialogPrimitive.Title>,\n\tReact.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>\n>(({ className, ...props }, ref) => (\n\t<DialogPrimitive.Title\n\t\tref={ref}\n\t\tclassName={cn(\"text-lg font-semibold leading-none tracking-tight\", className)}\n\t\t{...props}\n\t/>\n));\nDialogTitle.displayName = \"DialogTitle\";\n\n/** Accessible dialog description; Radix wires it to aria-describedby automatically. */\nconst DialogDescription = React.forwardRef<\n\tReact.ComponentRef<typeof DialogPrimitive.Description>,\n\tReact.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n\t<DialogPrimitive.Description\n\t\tref={ref}\n\t\tclassName={cn(\"text-sm text-muted-foreground\", className)}\n\t\t{...props}\n\t/>\n));\nDialogDescription.displayName = \"DialogDescription\";\n\nexport {\n\tDialog,\n\tDialogPortal,\n\tDialogOverlay,\n\tDialogTrigger,\n\tDialogClose,\n\tDialogContent,\n\tDialogHeader,\n\tDialogFooter,\n\tDialogTitle,\n\tDialogDescription,\n};\n"]}
|
package/dist/drawer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/utils.ts","../src/components/drawer/drawer.tsx"],"names":["DrawerPrimitive"],"mappings":";;;;;;AAQO,SAAS,MAAM,MAAA,EAAsB;AAC3C,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC5B;ACEA,SAAS,OAAO,EAAE,qBAAA,GAAwB,IAAA,EAAM,GAAG,OAAM,EAAoB;AAC5E,EAAA,2BAAQA,QAAA,CAAgB,IAAA,EAAhB,EAAqB,qBAAA,EAA+C,GAAG,KAAA,EAAO,CAAA;AACvF;AACA,MAAA,CAAO,WAAA,GAAc,QAAA;AAGrB,IAAM,gBAAgBA,QAAA,CAAgB;AAGtC,IAAM,eAAeA,QAAA,CAAgB;AAGrC,IAAM,cAAcA,QAAA,CAAgB;AAGpC,IAAM,aAAA,GAAsB,iBAG1B,CAAC,EAAE,WAAW,GAAG,KAAA,IAAS,GAAA,qBAC3B,GAAA;AAAA,EAACA,QAAA,CAAgB,OAAA;AAAA,EAAhB;AAAA,IACA,GAAA;AAAA,IACA,SAAA,EAAW,EAAA;AAAA,MACV,sDAAA;AAAA,MACA;AAAA,KACD;AAAA,IACC,GAAG;AAAA;AACL,CACA;AACD,aAAA,CAAc,WAAA,GAAc,eAAA;AAG5B,IAAM,aAAA,GAAsB,KAAA,CAAA,UAAA,CAG1B,CAAC,EAAE,SAAA,EAAW,QAAA,EAAU,GAAG,KAAA,EAAM,EAAG,GAAA,qBACrC,IAAA,CAAC,YAAA,EAAA,EACA,QAAA,EAAA;AAAA,kBAAA,GAAA,CAAC,aAAA,EAAA,EAAc,CAAA;AAAA,kBACf,IAAA;AAAA,IAACA,QAAA,CAAgB,OAAA;AAAA,IAAhB;AAAA,MACA,GAAA;AAAA,MACA,SAAA,EAAW,EAAA;AAAA,QACV,yHAAA;AAAA,QACA;AAAA,OACD;AAAA,MACC,GAAG,KAAA;AAAA,MAEJ,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,sEAAA,EAAuE,aAAA,EAAY,MAAA,EAAO,CAAA;AAAA,QACxG;AAAA;AAAA;AAAA;AACF,CAAA,EACD,CACA;AACD,aAAA,CAAc,WAAA,GAAc,eAAA;AAM5B,SAAS,YAAA,CAAa,EAAE,SAAA,EAAW,GAAG,OAAM,EAAyC;AACpF,EAAA,uBACC,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACA,SAAA,EAAW,EAAA,CAAG,+DAAA,EAAiE,SAAS,CAAA;AAAA,MACvF,GAAG;AAAA;AAAA,GACL;AAEF;AAMA,SAAS,YAAA,CAAa,EAAE,SAAA,EAAW,GAAG,OAAM,EAAyC;AACpF,EAAA,uBAAO,GAAA,CAAC,SAAI,SAAA,EAAW,EAAA,CAAG,4EAA4E,SAAS,CAAA,EAAI,GAAG,KAAA,EAAO,CAAA;AAC9H;AAGA,IAAM,WAAA,GAAoB,iBAGxB,CAAC,EAAE,WAAW,GAAG,KAAA,IAAS,GAAA,qBAC3B,GAAA;AAAA,EAACA,QAAA,CAAgB,KAAA;AAAA,EAAhB;AAAA,IACA,GAAA;AAAA,IACA,SAAA,EAAW,EAAA,CAAG,mDAAA,EAAqD,SAAS,CAAA;AAAA,IAC3E,GAAG;AAAA;AACL,CACA;AACD,WAAA,CAAY,WAAA,GAAc,aAAA;AAG1B,IAAM,iBAAA,GAA0B,iBAG9B,CAAC,EAAE,WAAW,GAAG,KAAA,IAAS,GAAA,qBAC3B,GAAA;AAAA,EAACA,QAAA,CAAgB,WAAA;AAAA,EAAhB;AAAA,IACA,GAAA;AAAA,IACA,SAAA,EAAW,EAAA,CAAG,+BAAA,EAAiC,SAAS,CAAA;AAAA,IACvD,GAAG;AAAA;AACL,CACA;AACD,iBAAA,CAAkB,WAAA,GAAc,mBAAA","file":"drawer.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { Drawer as DrawerPrimitive } from \"vaul\";\nimport { cn } from \"../../lib/utils.js\";\n\ntype DrawerRootProps = React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Root>;\n\n/**\n * Root container for a bottom drawer (vaul). Manages open state, drag, and snap points.\n * @returns A drawer root that coordinates overlay, content, and dismiss behavior.\n */\nfunction Drawer({ shouldScaleBackground = true, ...props }: DrawerRootProps) {\n\treturn <DrawerPrimitive.Root shouldScaleBackground={shouldScaleBackground} {...props} />;\n}\nDrawer.displayName = \"Drawer\";\n\n/** The element that opens the drawer when clicked. */\nconst DrawerTrigger = DrawerPrimitive.Trigger;\n\n/** Portals drawer overlay and content into the body. */\nconst DrawerPortal = DrawerPrimitive.Portal;\n\n/** Closes the drawer when rendered inside DrawerContent. */\nconst DrawerClose = DrawerPrimitive.Close;\n\n/** Dimmed backdrop behind the drawer content. */\nconst DrawerOverlay = React.forwardRef<\n\tReact.ComponentRef<typeof DrawerPrimitive.Overlay>,\n\tReact.ComponentPropsWithoutRef<typeof DrawerPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n\t<DrawerPrimitive.Overlay\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"fixed inset-0 z-50 bg-background/80 backdrop-blur-sm\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nDrawerOverlay.displayName = \"DrawerOverlay\";\n\n/** The drawer content panel. Slides up from the bottom and can be dragged down to dismiss. */\nconst DrawerContent = React.forwardRef<\n\tReact.ComponentRef<typeof DrawerPrimitive.Content>,\n\tReact.ComponentPropsWithoutRef<typeof DrawerPrimitive.Content>\n>(({ className, children, ...props }, ref) => (\n\t<DrawerPortal>\n\t\t<DrawerOverlay />\n\t\t<DrawerPrimitive.Content\n\t\t\tref={ref}\n\t\t\tclassName={cn(\n\t\t\t\t\"fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border border-foreground/[0.08] bg-background\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t>\n\t\t\t<div className=\"mx-auto mt-[var(--space-4,1rem)] h-2 w-[100px] rounded-full bg-muted\" aria-hidden=\"true\" />\n\t\t\t{children}\n\t\t</DrawerPrimitive.Content>\n\t</DrawerPortal>\n));\nDrawerContent.displayName = \"DrawerContent\";\n\n/**\n * Header container inside DrawerContent; stacks title and description.\n * @returns A div with vertical rhythm.\n */\nfunction DrawerHeader({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\"grid gap-1.5 p-[var(--space-4,1rem)] text-center sm:text-left\", className)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\n/**\n * Footer container inside DrawerContent; stacks action buttons.\n * @returns A div that stacks buttons vertically with consistent gutters.\n */\nfunction DrawerFooter({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n\treturn <div className={cn(\"mt-auto flex flex-col gap-[var(--gap-sm,0.5rem)] p-[var(--space-4,1rem)]\", className)} {...props} />;\n}\n\n/** Accessible drawer title; vaul wires it to aria-labelledby automatically. */\nconst DrawerTitle = React.forwardRef<\n\tReact.ComponentRef<typeof DrawerPrimitive.Title>,\n\tReact.ComponentPropsWithoutRef<typeof DrawerPrimitive.Title>\n>(({ className, ...props }, ref) => (\n\t<DrawerPrimitive.Title\n\t\tref={ref}\n\t\tclassName={cn(\"text-lg font-semibold leading-none tracking-tight\", className)}\n\t\t{...props}\n\t/>\n));\nDrawerTitle.displayName = \"DrawerTitle\";\n\n/** Accessible drawer description; vaul wires it to aria-describedby automatically. */\nconst DrawerDescription = React.forwardRef<\n\tReact.ComponentRef<typeof DrawerPrimitive.Description>,\n\tReact.ComponentPropsWithoutRef<typeof DrawerPrimitive.Description>\n>(({ className, ...props }, ref) => (\n\t<DrawerPrimitive.Description\n\t\tref={ref}\n\t\tclassName={cn(\"text-sm text-muted-foreground\", className)}\n\t\t{...props}\n\t/>\n));\nDrawerDescription.displayName = \"DrawerDescription\";\n\nexport {\n\tDrawer,\n\tDrawerPortal,\n\tDrawerOverlay,\n\tDrawerTrigger,\n\tDrawerClose,\n\tDrawerContent,\n\tDrawerHeader,\n\tDrawerFooter,\n\tDrawerTitle,\n\tDrawerDescription,\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/components/drawer/drawer.tsx"],"names":["DrawerPrimitive"],"mappings":";;;;;;AAQO,SAAS,MAAM,MAAA,EAAsB;AAC3C,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC5B;ACEA,SAAS,OAAO,EAAE,qBAAA,GAAwB,IAAA,EAAM,GAAG,OAAM,EAAoB;AAC5E,EAAA,2BAAQA,QAAA,CAAgB,IAAA,EAAhB,EAAqB,qBAAA,EAA+C,GAAG,KAAA,EAAO,CAAA;AACvF;AACA,MAAA,CAAO,WAAA,GAAc,QAAA;AAGrB,IAAM,gBAAgBA,QAAA,CAAgB;AAGtC,IAAM,eAAeA,QAAA,CAAgB;AAGrC,IAAM,cAAcA,QAAA,CAAgB;AAGpC,IAAM,aAAA,GAAsB,iBAG1B,CAAC,EAAE,WAAW,GAAG,KAAA,IAAS,GAAA,qBAC3B,GAAA;AAAA,EAACA,QAAA,CAAgB,OAAA;AAAA,EAAhB;AAAA,IACA,GAAA;AAAA,IACA,SAAA,EAAW,EAAA;AAAA,MACV,sDAAA;AAAA,MACA;AAAA,KACD;AAAA,IACC,GAAG;AAAA;AACL,CACA;AACD,aAAA,CAAc,WAAA,GAAc,eAAA;AAG5B,IAAM,aAAA,GAAsB,KAAA,CAAA,UAAA,CAG1B,CAAC,EAAE,SAAA,EAAW,QAAA,EAAU,GAAG,KAAA,EAAM,EAAG,GAAA,qBACrC,IAAA,CAAC,YAAA,EAAA,EACA,QAAA,EAAA;AAAA,kBAAA,GAAA,CAAC,aAAA,EAAA,EAAc,CAAA;AAAA,kBACf,IAAA;AAAA,IAACA,QAAA,CAAgB,OAAA;AAAA,IAAhB;AAAA,MACA,GAAA;AAAA,MACA,SAAA,EAAW,EAAA;AAAA,QACV,yHAAA;AAAA,QACA;AAAA,OACD;AAAA,MACC,GAAG,KAAA;AAAA,MAEJ,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,sEAAA,EAAuE,aAAA,EAAY,MAAA,EAAO,CAAA;AAAA,QACxG;AAAA;AAAA;AAAA;AACF,CAAA,EACD,CACA;AACD,aAAA,CAAc,WAAA,GAAc,eAAA;AAM5B,SAAS,YAAA,CAAa,EAAE,SAAA,EAAW,GAAG,OAAM,EAAyC;AACpF,EAAA,uBACC,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACA,SAAA,EAAW,EAAA,CAAG,+DAAA,EAAiE,SAAS,CAAA;AAAA,MACvF,GAAG;AAAA;AAAA,GACL;AAEF;AAMA,SAAS,YAAA,CAAa,EAAE,SAAA,EAAW,GAAG,OAAM,EAAyC;AACpF,EAAA,uBAAO,GAAA,CAAC,SAAI,SAAA,EAAW,EAAA,CAAG,4EAA4E,SAAS,CAAA,EAAI,GAAG,KAAA,EAAO,CAAA;AAC9H;AAGA,IAAM,WAAA,GAAoB,iBAGxB,CAAC,EAAE,WAAW,GAAG,KAAA,IAAS,GAAA,qBAC3B,GAAA;AAAA,EAACA,QAAA,CAAgB,KAAA;AAAA,EAAhB;AAAA,IACA,GAAA;AAAA,IACA,SAAA,EAAW,EAAA,CAAG,mDAAA,EAAqD,SAAS,CAAA;AAAA,IAC3E,GAAG;AAAA;AACL,CACA;AACD,WAAA,CAAY,WAAA,GAAc,aAAA;AAG1B,IAAM,iBAAA,GAA0B,iBAG9B,CAAC,EAAE,WAAW,GAAG,KAAA,IAAS,GAAA,qBAC3B,GAAA;AAAA,EAACA,QAAA,CAAgB,WAAA;AAAA,EAAhB;AAAA,IACA,GAAA;AAAA,IACA,SAAA,EAAW,EAAA,CAAG,+BAAA,EAAiC,SAAS,CAAA;AAAA,IACvD,GAAG;AAAA;AACL,CACA;AACD,iBAAA,CAAkB,WAAA,GAAc,mBAAA","file":"drawer.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n\nconst SAFE_URL_SCHEMES = [\"http:\", \"https:\", \"mailto:\"] as const;\n\n/**\n * Allowlist a URL for use as an `<a href>` against untrusted input.\n *\n * Returns the raw string when it's `http(s):` / `mailto:` / a relative\n * URL (no scheme); returns `undefined` otherwise. Defends against\n * `javascript:` / `data:` / `vbscript:` injection from streamed model\n * output or third-party JSON payloads that flow into citation chips.\n *\n * Inside a Markdown render path, `rehype-sanitize` already strips\n * `javascript:` from inline-link hrefs — but it does NOT introspect\n * JSON nested inside attribute values (e.g. `<sources data='[…]'/>`),\n * so the components that consume that data must guard themselves.\n *\n * @param raw - The candidate URL, or `undefined` when none was supplied.\n * @returns The URL when safe to render, otherwise `undefined`.\n */\nexport function safeUrl(raw: string | undefined): string | undefined {\n\tif (raw === undefined || raw === \"\") return undefined;\n\t// Relative URLs have no scheme — `new URL(relative)` throws without a base,\n\t// so a thrown URL means either malformed input OR a relative path. Treat\n\t// \"throws + does not contain a colon\" as a relative path (safe).\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(raw);\n\t} catch {\n\t\treturn raw.includes(\":\") ? undefined : raw;\n\t}\n\treturn SAFE_URL_SCHEMES.some((scheme) => scheme === parsed.protocol) ? raw : undefined;\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { Drawer as DrawerPrimitive } from \"vaul\";\nimport { cn } from \"../../lib/utils.js\";\n\ntype DrawerRootProps = React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Root>;\n\n/**\n * Root container for a bottom drawer (vaul). Manages open state, drag, and snap points.\n * @returns A drawer root that coordinates overlay, content, and dismiss behavior.\n */\nfunction Drawer({ shouldScaleBackground = true, ...props }: DrawerRootProps) {\n\treturn <DrawerPrimitive.Root shouldScaleBackground={shouldScaleBackground} {...props} />;\n}\nDrawer.displayName = \"Drawer\";\n\n/** The element that opens the drawer when clicked. */\nconst DrawerTrigger = DrawerPrimitive.Trigger;\n\n/** Portals drawer overlay and content into the body. */\nconst DrawerPortal = DrawerPrimitive.Portal;\n\n/** Closes the drawer when rendered inside DrawerContent. */\nconst DrawerClose = DrawerPrimitive.Close;\n\n/** Dimmed backdrop behind the drawer content. */\nconst DrawerOverlay = React.forwardRef<\n\tReact.ComponentRef<typeof DrawerPrimitive.Overlay>,\n\tReact.ComponentPropsWithoutRef<typeof DrawerPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n\t<DrawerPrimitive.Overlay\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"fixed inset-0 z-50 bg-background/80 backdrop-blur-sm\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nDrawerOverlay.displayName = \"DrawerOverlay\";\n\n/** The drawer content panel. Slides up from the bottom and can be dragged down to dismiss. */\nconst DrawerContent = React.forwardRef<\n\tReact.ComponentRef<typeof DrawerPrimitive.Content>,\n\tReact.ComponentPropsWithoutRef<typeof DrawerPrimitive.Content>\n>(({ className, children, ...props }, ref) => (\n\t<DrawerPortal>\n\t\t<DrawerOverlay />\n\t\t<DrawerPrimitive.Content\n\t\t\tref={ref}\n\t\t\tclassName={cn(\n\t\t\t\t\"fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border border-foreground/[0.08] bg-background\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t>\n\t\t\t<div className=\"mx-auto mt-[var(--space-4,1rem)] h-2 w-[100px] rounded-full bg-muted\" aria-hidden=\"true\" />\n\t\t\t{children}\n\t\t</DrawerPrimitive.Content>\n\t</DrawerPortal>\n));\nDrawerContent.displayName = \"DrawerContent\";\n\n/**\n * Header container inside DrawerContent; stacks title and description.\n * @returns A div with vertical rhythm.\n */\nfunction DrawerHeader({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\"grid gap-1.5 p-[var(--space-4,1rem)] text-center sm:text-left\", className)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\n/**\n * Footer container inside DrawerContent; stacks action buttons.\n * @returns A div that stacks buttons vertically with consistent gutters.\n */\nfunction DrawerFooter({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n\treturn <div className={cn(\"mt-auto flex flex-col gap-[var(--gap-sm,0.5rem)] p-[var(--space-4,1rem)]\", className)} {...props} />;\n}\n\n/** Accessible drawer title; vaul wires it to aria-labelledby automatically. */\nconst DrawerTitle = React.forwardRef<\n\tReact.ComponentRef<typeof DrawerPrimitive.Title>,\n\tReact.ComponentPropsWithoutRef<typeof DrawerPrimitive.Title>\n>(({ className, ...props }, ref) => (\n\t<DrawerPrimitive.Title\n\t\tref={ref}\n\t\tclassName={cn(\"text-lg font-semibold leading-none tracking-tight\", className)}\n\t\t{...props}\n\t/>\n));\nDrawerTitle.displayName = \"DrawerTitle\";\n\n/** Accessible drawer description; vaul wires it to aria-describedby automatically. */\nconst DrawerDescription = React.forwardRef<\n\tReact.ComponentRef<typeof DrawerPrimitive.Description>,\n\tReact.ComponentPropsWithoutRef<typeof DrawerPrimitive.Description>\n>(({ className, ...props }, ref) => (\n\t<DrawerPrimitive.Description\n\t\tref={ref}\n\t\tclassName={cn(\"text-sm text-muted-foreground\", className)}\n\t\t{...props}\n\t/>\n));\nDrawerDescription.displayName = \"DrawerDescription\";\n\nexport {\n\tDrawer,\n\tDrawerPortal,\n\tDrawerOverlay,\n\tDrawerTrigger,\n\tDrawerClose,\n\tDrawerContent,\n\tDrawerHeader,\n\tDrawerFooter,\n\tDrawerTitle,\n\tDrawerDescription,\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/utils.ts","../src/components/dropdown-menu/dropdown-menu.tsx"],"names":[],"mappings":"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","file":"dropdown-menu.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n","\"use client\";\n\nimport * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/** Root container for a dropdown menu. */\nconst DropdownMenu = DropdownMenuPrimitive.Root;\n\n/** The element (button) that opens the dropdown. */\nconst DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;\n\n/** Groups related menu items for a11y. */\nconst DropdownMenuGroup = DropdownMenuPrimitive.Group;\n\n/** Portals dropdown content into the body. */\nconst DropdownMenuPortal = DropdownMenuPrimitive.Portal;\n\n/** Nested submenu root. */\nconst DropdownMenuSub = DropdownMenuPrimitive.Sub;\n\n/** Group for checkable radio items (one selected at a time). */\nconst DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;\n\n/** The visible dropdown panel. */\nconst DropdownMenuContent = React.forwardRef<\n\tReact.ComponentRef<typeof DropdownMenuPrimitive.Content>,\n\tReact.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>\n>(({ className, sideOffset = 4, ...props }, ref) => (\n\t<DropdownMenuPrimitive.Portal>\n\t\t<DropdownMenuPrimitive.Content\n\t\t\tref={ref}\n\t\t\tsideOffset={sideOffset}\n\t\t\tclassName={cn(\n\t\t\t\t\"z-50 min-w-[8rem] overflow-hidden rounded-md border border-foreground/[0.08] bg-popover p-[var(--space-1,0.25rem)] text-popover-foreground shadow-md\",\n\t\t\t\t\"data-[state=open]:animate-in data-[state=closed]:animate-out\",\n\t\t\t\t\"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n\t\t\t\t\"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95\",\n\t\t\t\t\"data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t</DropdownMenuPrimitive.Portal>\n));\nDropdownMenuContent.displayName = \"DropdownMenuContent\";\n\n/** A clickable menu item. */\nconst DropdownMenuItem = React.forwardRef<\n\tReact.ComponentRef<typeof DropdownMenuPrimitive.Item>,\n\tReact.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & { inset?: boolean }\n>(({ className, inset, ...props }, ref) => (\n\t<DropdownMenuPrimitive.Item\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"relative flex cursor-default select-none items-center gap-[var(--gap-sm,0.5rem)] rounded-sm px-[var(--space-2,0.5rem)] py-1.5 text-sm outline-none\",\n\t\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\"focus:bg-accent focus:text-accent-foreground\",\n\t\t\t\"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n\t\t\tinset && \"pl-[var(--space-8,2rem)]\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nDropdownMenuItem.displayName = \"DropdownMenuItem\";\n\n/** A menu item with a checkbox state. */\nconst DropdownMenuCheckboxItem = React.forwardRef<\n\tReact.ComponentRef<typeof DropdownMenuPrimitive.CheckboxItem>,\n\tReact.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>\n>(({ className, children, checked, ...props }, ref) => (\n\t<DropdownMenuPrimitive.CheckboxItem\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-[var(--space-8,2rem)] pr-[var(--space-2,0.5rem)] text-sm outline-none\",\n\t\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\"focus:bg-accent focus:text-accent-foreground\",\n\t\t\t\"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n\t\t\tclassName,\n\t\t)}\n\t\tchecked={checked}\n\t\t{...props}\n\t>\n\t\t<span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n\t\t\t<DropdownMenuPrimitive.ItemIndicator>\n\t\t\t\t<svg\n\t\t\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\tfill=\"none\"\n\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\tstrokeWidth=\"3\"\n\t\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\t\tclassName=\"h-4 w-4\"\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t>\n\t\t\t\t\t<polyline points=\"20 6 9 17 4 12\" />\n\t\t\t\t</svg>\n\t\t\t</DropdownMenuPrimitive.ItemIndicator>\n\t\t</span>\n\t\t{children}\n\t</DropdownMenuPrimitive.CheckboxItem>\n));\nDropdownMenuCheckboxItem.displayName = \"DropdownMenuCheckboxItem\";\n\n/** A menu item in a radio group. */\nconst DropdownMenuRadioItem = React.forwardRef<\n\tReact.ComponentRef<typeof DropdownMenuPrimitive.RadioItem>,\n\tReact.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>\n>(({ className, children, ...props }, ref) => (\n\t<DropdownMenuPrimitive.RadioItem\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-[var(--space-8,2rem)] pr-[var(--space-2,0.5rem)] text-sm outline-none\",\n\t\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\"focus:bg-accent focus:text-accent-foreground\",\n\t\t\t\"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t>\n\t\t<span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n\t\t\t<DropdownMenuPrimitive.ItemIndicator>\n\t\t\t\t<svg viewBox=\"0 0 24 24\" className=\"h-2 w-2 fill-current\" aria-hidden=\"true\">\n\t\t\t\t\t<circle cx=\"12\" cy=\"12\" r=\"10\" />\n\t\t\t\t</svg>\n\t\t\t</DropdownMenuPrimitive.ItemIndicator>\n\t\t</span>\n\t\t{children}\n\t</DropdownMenuPrimitive.RadioItem>\n));\nDropdownMenuRadioItem.displayName = \"DropdownMenuRadioItem\";\n\n/** A non-interactive section heading inside the menu. */\nconst DropdownMenuLabel = React.forwardRef<\n\tReact.ComponentRef<typeof DropdownMenuPrimitive.Label>,\n\tReact.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & { inset?: boolean }\n>(({ className, inset, ...props }, ref) => (\n\t<DropdownMenuPrimitive.Label\n\t\tref={ref}\n\t\tclassName={cn(\"px-[var(--space-2,0.5rem)] py-1.5 text-sm font-semibold\", inset && \"pl-[var(--space-8,2rem)]\", className)}\n\t\t{...props}\n\t/>\n));\nDropdownMenuLabel.displayName = \"DropdownMenuLabel\";\n\n/** Horizontal divider between menu items. */\nconst DropdownMenuSeparator = React.forwardRef<\n\tReact.ComponentRef<typeof DropdownMenuPrimitive.Separator>,\n\tReact.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n\t<DropdownMenuPrimitive.Separator\n\t\tref={ref}\n\t\tclassName={cn(\"-mx-[var(--space-1,0.25rem)] my-[var(--space-1,0.25rem)] h-px bg-foreground/[0.12]\", className)}\n\t\t{...props}\n\t/>\n));\nDropdownMenuSeparator.displayName = \"DropdownMenuSeparator\";\n\n/**\n * Right-aligned shortcut text (e.g. ⌘K) shown next to a menu item.\n * @returns A span with muted, tracked typography\n */\nfunction DropdownMenuShortcut({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) {\n\treturn (\n\t\t<span\n\t\t\tclassName={cn(\"ml-auto text-xs tracking-widest text-muted-foreground\", className)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nexport {\n\tDropdownMenu,\n\tDropdownMenuTrigger,\n\tDropdownMenuContent,\n\tDropdownMenuItem,\n\tDropdownMenuCheckboxItem,\n\tDropdownMenuRadioItem,\n\tDropdownMenuLabel,\n\tDropdownMenuSeparator,\n\tDropdownMenuShortcut,\n\tDropdownMenuGroup,\n\tDropdownMenuPortal,\n\tDropdownMenuSub,\n\tDropdownMenuRadioGroup,\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/components/dropdown-menu/dropdown-menu.tsx"],"names":[],"mappings":"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","file":"dropdown-menu.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n\nconst SAFE_URL_SCHEMES = [\"http:\", \"https:\", \"mailto:\"] as const;\n\n/**\n * Allowlist a URL for use as an `<a href>` against untrusted input.\n *\n * Returns the raw string when it's `http(s):` / `mailto:` / a relative\n * URL (no scheme); returns `undefined` otherwise. Defends against\n * `javascript:` / `data:` / `vbscript:` injection from streamed model\n * output or third-party JSON payloads that flow into citation chips.\n *\n * Inside a Markdown render path, `rehype-sanitize` already strips\n * `javascript:` from inline-link hrefs — but it does NOT introspect\n * JSON nested inside attribute values (e.g. `<sources data='[…]'/>`),\n * so the components that consume that data must guard themselves.\n *\n * @param raw - The candidate URL, or `undefined` when none was supplied.\n * @returns The URL when safe to render, otherwise `undefined`.\n */\nexport function safeUrl(raw: string | undefined): string | undefined {\n\tif (raw === undefined || raw === \"\") return undefined;\n\t// Relative URLs have no scheme — `new URL(relative)` throws without a base,\n\t// so a thrown URL means either malformed input OR a relative path. Treat\n\t// \"throws + does not contain a colon\" as a relative path (safe).\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(raw);\n\t} catch {\n\t\treturn raw.includes(\":\") ? undefined : raw;\n\t}\n\treturn SAFE_URL_SCHEMES.some((scheme) => scheme === parsed.protocol) ? raw : undefined;\n}\n","\"use client\";\n\nimport * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/** Root container for a dropdown menu. */\nconst DropdownMenu = DropdownMenuPrimitive.Root;\n\n/** The element (button) that opens the dropdown. */\nconst DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;\n\n/** Groups related menu items for a11y. */\nconst DropdownMenuGroup = DropdownMenuPrimitive.Group;\n\n/** Portals dropdown content into the body. */\nconst DropdownMenuPortal = DropdownMenuPrimitive.Portal;\n\n/** Nested submenu root. */\nconst DropdownMenuSub = DropdownMenuPrimitive.Sub;\n\n/** Group for checkable radio items (one selected at a time). */\nconst DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;\n\n/** The visible dropdown panel. */\nconst DropdownMenuContent = React.forwardRef<\n\tReact.ComponentRef<typeof DropdownMenuPrimitive.Content>,\n\tReact.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>\n>(({ className, sideOffset = 4, ...props }, ref) => (\n\t<DropdownMenuPrimitive.Portal>\n\t\t<DropdownMenuPrimitive.Content\n\t\t\tref={ref}\n\t\t\tsideOffset={sideOffset}\n\t\t\tclassName={cn(\n\t\t\t\t\"z-50 min-w-[8rem] overflow-hidden rounded-md border border-foreground/[0.08] bg-popover p-[var(--space-1,0.25rem)] text-popover-foreground shadow-md\",\n\t\t\t\t\"data-[state=open]:animate-in data-[state=closed]:animate-out\",\n\t\t\t\t\"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n\t\t\t\t\"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95\",\n\t\t\t\t\"data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t</DropdownMenuPrimitive.Portal>\n));\nDropdownMenuContent.displayName = \"DropdownMenuContent\";\n\n/** A clickable menu item. */\nconst DropdownMenuItem = React.forwardRef<\n\tReact.ComponentRef<typeof DropdownMenuPrimitive.Item>,\n\tReact.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & { inset?: boolean }\n>(({ className, inset, ...props }, ref) => (\n\t<DropdownMenuPrimitive.Item\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"relative flex cursor-default select-none items-center gap-[var(--gap-sm,0.5rem)] rounded-sm px-[var(--space-2,0.5rem)] py-1.5 text-sm outline-none\",\n\t\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\"focus:bg-accent focus:text-accent-foreground\",\n\t\t\t\"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n\t\t\tinset && \"pl-[var(--space-8,2rem)]\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nDropdownMenuItem.displayName = \"DropdownMenuItem\";\n\n/** A menu item with a checkbox state. */\nconst DropdownMenuCheckboxItem = React.forwardRef<\n\tReact.ComponentRef<typeof DropdownMenuPrimitive.CheckboxItem>,\n\tReact.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>\n>(({ className, children, checked, ...props }, ref) => (\n\t<DropdownMenuPrimitive.CheckboxItem\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-[var(--space-8,2rem)] pr-[var(--space-2,0.5rem)] text-sm outline-none\",\n\t\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\"focus:bg-accent focus:text-accent-foreground\",\n\t\t\t\"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n\t\t\tclassName,\n\t\t)}\n\t\tchecked={checked}\n\t\t{...props}\n\t>\n\t\t<span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n\t\t\t<DropdownMenuPrimitive.ItemIndicator>\n\t\t\t\t<svg\n\t\t\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\tfill=\"none\"\n\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\tstrokeWidth=\"3\"\n\t\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\t\tclassName=\"h-4 w-4\"\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t>\n\t\t\t\t\t<polyline points=\"20 6 9 17 4 12\" />\n\t\t\t\t</svg>\n\t\t\t</DropdownMenuPrimitive.ItemIndicator>\n\t\t</span>\n\t\t{children}\n\t</DropdownMenuPrimitive.CheckboxItem>\n));\nDropdownMenuCheckboxItem.displayName = \"DropdownMenuCheckboxItem\";\n\n/** A menu item in a radio group. */\nconst DropdownMenuRadioItem = React.forwardRef<\n\tReact.ComponentRef<typeof DropdownMenuPrimitive.RadioItem>,\n\tReact.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>\n>(({ className, children, ...props }, ref) => (\n\t<DropdownMenuPrimitive.RadioItem\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-[var(--space-8,2rem)] pr-[var(--space-2,0.5rem)] text-sm outline-none\",\n\t\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\"focus:bg-accent focus:text-accent-foreground\",\n\t\t\t\"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t>\n\t\t<span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n\t\t\t<DropdownMenuPrimitive.ItemIndicator>\n\t\t\t\t<svg viewBox=\"0 0 24 24\" className=\"h-2 w-2 fill-current\" aria-hidden=\"true\">\n\t\t\t\t\t<circle cx=\"12\" cy=\"12\" r=\"10\" />\n\t\t\t\t</svg>\n\t\t\t</DropdownMenuPrimitive.ItemIndicator>\n\t\t</span>\n\t\t{children}\n\t</DropdownMenuPrimitive.RadioItem>\n));\nDropdownMenuRadioItem.displayName = \"DropdownMenuRadioItem\";\n\n/** A non-interactive section heading inside the menu. */\nconst DropdownMenuLabel = React.forwardRef<\n\tReact.ComponentRef<typeof DropdownMenuPrimitive.Label>,\n\tReact.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & { inset?: boolean }\n>(({ className, inset, ...props }, ref) => (\n\t<DropdownMenuPrimitive.Label\n\t\tref={ref}\n\t\tclassName={cn(\"px-[var(--space-2,0.5rem)] py-1.5 text-sm font-semibold\", inset && \"pl-[var(--space-8,2rem)]\", className)}\n\t\t{...props}\n\t/>\n));\nDropdownMenuLabel.displayName = \"DropdownMenuLabel\";\n\n/** Horizontal divider between menu items. */\nconst DropdownMenuSeparator = React.forwardRef<\n\tReact.ComponentRef<typeof DropdownMenuPrimitive.Separator>,\n\tReact.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n\t<DropdownMenuPrimitive.Separator\n\t\tref={ref}\n\t\tclassName={cn(\"-mx-[var(--space-1,0.25rem)] my-[var(--space-1,0.25rem)] h-px bg-foreground/[0.12]\", className)}\n\t\t{...props}\n\t/>\n));\nDropdownMenuSeparator.displayName = \"DropdownMenuSeparator\";\n\n/**\n * Right-aligned shortcut text (e.g. ⌘K) shown next to a menu item.\n * @returns A span with muted, tracked typography\n */\nfunction DropdownMenuShortcut({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) {\n\treturn (\n\t\t<span\n\t\t\tclassName={cn(\"ml-auto text-xs tracking-widest text-muted-foreground\", className)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nexport {\n\tDropdownMenu,\n\tDropdownMenuTrigger,\n\tDropdownMenuContent,\n\tDropdownMenuItem,\n\tDropdownMenuCheckboxItem,\n\tDropdownMenuRadioItem,\n\tDropdownMenuLabel,\n\tDropdownMenuSeparator,\n\tDropdownMenuShortcut,\n\tDropdownMenuGroup,\n\tDropdownMenuPortal,\n\tDropdownMenuSub,\n\tDropdownMenuRadioGroup,\n};\n"]}
|
package/dist/dropzone.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/utils.ts","../src/components/dropzone/dropzone.tsx"],"names":[],"mappings":"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","file":"dropzone.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\ninterface DropzoneProps\n\textends Omit<\n\t\tReact.HTMLAttributes<HTMLDivElement>,\n\t\t\"onChange\" | \"onDrop\" | \"children\"\n\t> {\n\t/** Fired with the accepted file list every time the user picks or drops files. */\n\tonFilesSelected?: (files: File[]) => void;\n\t/**\n\t * Fired when files are dropped/picked but ALL of them are filtered out by\n\t * `accept` / `maxSize` / `maxFiles`. Useful for surfacing \"file too large\"\n\t * or \"wrong type\" toasts to the user. Receives the rejected File[].\n\t */\n\tonFilesRejected?: (files: File[]) => void;\n\t/** `accept` attribute forwarded to the hidden file input (e.g. \"image/*\", \".csv\"). */\n\taccept?: string;\n\t/** Allow multiple files. Default true. */\n\tmultiple?: boolean;\n\t/** Maximum total file count (after dedupe). Excess files are dropped silently — surface in your handler. */\n\tmaxFiles?: number;\n\t/** Maximum size per file in bytes. Files over the cap are filtered before onFilesSelected fires. */\n\tmaxSize?: number;\n\t/** Disable interaction. */\n\tdisabled?: boolean;\n\t/** Optional render override for the dropzone body. Receives drag state. */\n\tchildren?: React.ReactNode | ((state: DropzoneRenderState) => React.ReactNode);\n\t/** Required accessible name for the drop area. */\n\t\"aria-label\": string;\n}\n\ninterface DropzoneRenderState {\n\tisDragOver: boolean;\n\tisDisabled: boolean;\n\topenFileDialog: () => void;\n}\n\n/** Apply `accept` / `maxSize` / `maxFiles` filters before emitting to onFilesSelected. */\nfunction filterFiles(\n\tfiles: FileList | File[],\n\t{ accept, maxSize, maxFiles }: { accept?: string; maxSize?: number; maxFiles?: number },\n): File[] {\n\tconst list = Array.from(files);\n\tconst acceptList = accept\n\t\t? accept\n\t\t\t\t.split(\",\")\n\t\t\t\t.map((s) => s.trim())\n\t\t\t\t.filter(Boolean)\n\t\t: undefined;\n\n\tconst matchAccept = (file: File): boolean => {\n\t\tif (!acceptList) return true;\n\t\treturn acceptList.some((entry) => {\n\t\t\tif (entry.startsWith(\".\")) {\n\t\t\t\treturn file.name.toLowerCase().endsWith(entry.toLowerCase());\n\t\t\t}\n\t\t\tif (entry.endsWith(\"/*\")) {\n\t\t\t\tconst prefix = entry.slice(0, -1); // \"image/\"\n\t\t\t\treturn file.type.startsWith(prefix);\n\t\t\t}\n\t\t\treturn file.type === entry;\n\t\t});\n\t};\n\n\tconst sized =\n\t\ttypeof maxSize === \"number\" ? list.filter((f) => f.size <= maxSize) : list;\n\tconst accepted = sized.filter(matchAccept);\n\tif (typeof maxFiles === \"number\") return accepted.slice(0, maxFiles);\n\treturn accepted;\n}\n\n/**\n * Drag-and-drop file input built on the native HTML5 drag-drop API plus a\n * visually-hidden (sr-only) `<input type=\"file\">` for screen-reader and\n * keyboard access.\n *\n * Two interaction surfaces:\n * - The visible drop area is a `role=\"button\"` div with `tabIndex=0` and the\n * required `aria-label`. Click, Enter, or Space proxies through to click the\n * hidden input, opening the system file dialog.\n * - The hidden input itself remains in the accessibility tree (sr-only, NOT\n * `aria-hidden`) so AT-driven file pickers can find it directly.\n *\n * Pass `children` as a node (default placeholder) or a function receiving\n * `{ isDragOver, isDisabled, openFileDialog }` for full layout control.\n * @returns A drop area + hidden file input pair that yields a File[].\n */\nfunction Dropzone({\n\tonFilesSelected,\n\tonFilesRejected,\n\taccept,\n\tmultiple = true,\n\tmaxFiles,\n\tmaxSize,\n\tdisabled = false,\n\tchildren,\n\tclassName,\n\t\"aria-label\": ariaLabel,\n\t...rest\n}: DropzoneProps) {\n\tconst inputRef = React.useRef<HTMLInputElement>(null);\n\tconst [isDragOver, setIsDragOver] = React.useState(false);\n\tconst dragCounter = React.useRef(0);\n\n\tconst emit = React.useCallback(\n\t\t(files: FileList | File[] | null | undefined) => {\n\t\t\tif (!files || disabled) return;\n\t\t\tconst all = Array.from(files);\n\t\t\tif (all.length === 0) return;\n\t\t\tconst accepted = filterFiles(all, { accept, maxSize, maxFiles });\n\t\t\tif (accepted.length === 0) {\n\t\t\t\tonFilesRejected?.(all);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst finalAccepted = !multiple ? accepted.slice(0, 1) : accepted;\n\t\t\tconst rejected = all.filter((f) => !finalAccepted.includes(f));\n\t\t\tonFilesSelected?.(finalAccepted);\n\t\t\tif (rejected.length > 0) onFilesRejected?.(rejected);\n\t\t},\n\t\t[\n\t\t\taccept,\n\t\t\tdisabled,\n\t\t\tmaxFiles,\n\t\t\tmaxSize,\n\t\t\tmultiple,\n\t\t\tonFilesSelected,\n\t\t\tonFilesRejected,\n\t\t],\n\t);\n\n\t/*\n\t * Reset the drag counter + isDragOver when the user cancels a drag outside\n\t * the dropzone (Esc, drag off the page, switch tab). Without this, the\n\t * counter can stay >0 and the dropzone gets stuck in its hover style.\n\t */\n\tReact.useEffect(() => {\n\t\tconst reset = () => {\n\t\t\tdragCounter.current = 0;\n\t\t\tsetIsDragOver(false);\n\t\t};\n\t\twindow.addEventListener(\"dragend\", reset);\n\t\twindow.addEventListener(\"drop\", reset);\n\t\treturn () => {\n\t\t\twindow.removeEventListener(\"dragend\", reset);\n\t\t\twindow.removeEventListener(\"drop\", reset);\n\t\t};\n\t}, []);\n\n\tconst openFileDialog = React.useCallback(() => {\n\t\tif (disabled) return;\n\t\tinputRef.current?.click();\n\t}, [disabled]);\n\n\tconst handleDragEnter = (e: React.DragEvent<HTMLDivElement>) => {\n\t\tif (disabled) return;\n\t\te.preventDefault();\n\t\tdragCounter.current += 1;\n\t\tif (e.dataTransfer.types.includes(\"Files\")) setIsDragOver(true);\n\t};\n\tconst handleDragOver = (e: React.DragEvent<HTMLDivElement>) => {\n\t\tif (disabled) return;\n\t\te.preventDefault();\n\t\te.dataTransfer.dropEffect = \"copy\";\n\t};\n\tconst handleDragLeave = (e: React.DragEvent<HTMLDivElement>) => {\n\t\tif (disabled) return;\n\t\te.preventDefault();\n\t\tdragCounter.current = Math.max(0, dragCounter.current - 1);\n\t\tif (dragCounter.current === 0) setIsDragOver(false);\n\t};\n\tconst handleDrop = (e: React.DragEvent<HTMLDivElement>) => {\n\t\tif (disabled) return;\n\t\te.preventDefault();\n\t\tdragCounter.current = 0;\n\t\tsetIsDragOver(false);\n\t\temit(e.dataTransfer.files);\n\t};\n\tconst handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n\t\tif (disabled) return;\n\t\tif (e.key === \"Enter\" || e.key === \" \") {\n\t\t\te.preventDefault();\n\t\t\topenFileDialog();\n\t\t}\n\t};\n\n\tconst renderState: DropzoneRenderState = {\n\t\tisDragOver,\n\t\tisDisabled: disabled,\n\t\topenFileDialog,\n\t};\n\n\treturn (\n\t\t<>\n\t\t\t<div\n\t\t\t\trole=\"button\"\n\t\t\t\ttabIndex={disabled ? -1 : 0}\n\t\t\t\taria-label={ariaLabel}\n\t\t\t\taria-disabled={disabled || undefined}\n\t\t\t\tdata-drag-over={isDragOver || undefined}\n\t\t\t\tonClick={openFileDialog}\n\t\t\t\tonKeyDown={handleKeyDown}\n\t\t\t\tonDragEnter={handleDragEnter}\n\t\t\t\tonDragOver={handleDragOver}\n\t\t\t\tonDragLeave={handleDragLeave}\n\t\t\t\tonDrop={handleDrop}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"flex w-full cursor-pointer select-none flex-col items-center justify-center gap-[var(--space-2,0.5rem)] rounded-md border-2 border-dashed border-input bg-background px-[var(--space-6,1.5rem)] py-[var(--space-8,2rem)] text-center text-sm transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\t\t\"hover:bg-accent hover:text-accent-foreground\",\n\t\t\t\t\t\"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n\t\t\t\t\tisDragOver && \"border-primary bg-accent text-accent-foreground\",\n\t\t\t\t\tdisabled && \"pointer-events-none opacity-50\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\t{...rest}\n\t\t\t>\n\t\t\t\t{typeof children === \"function\"\n\t\t\t\t\t? children(renderState)\n\t\t\t\t\t: (children ?? (\n\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t<svg\n\t\t\t\t\t\t\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t\t\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\t\t\t\tstrokeWidth=\"2\"\n\t\t\t\t\t\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\t\t\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\t\t\t\t\t\tclassName=\"h-6 w-6 text-muted-foreground\"\n\t\t\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\" />\n\t\t\t\t\t\t\t\t\t<polyline points=\"17 8 12 3 7 8\" />\n\t\t\t\t\t\t\t\t\t<line x1=\"12\" y1=\"3\" x2=\"12\" y2=\"15\" />\n\t\t\t\t\t\t\t\t</svg>\n\t\t\t\t\t\t\t\t<span className=\"font-medium\">\n\t\t\t\t\t\t\t\t\t{isDragOver ? \"Drop files to upload\" : \"Drag files here or click to browse\"}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t{accept ? (\n\t\t\t\t\t\t\t\t\t<span className=\"text-xs text-muted-foreground\">{accept}</span>\n\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t))}\n\t\t\t</div>\n\t\t\t{/*\n\t\t\t * Input lives OUTSIDE the role=\"button\" container to satisfy axe\n\t\t\t * nested-interactive. It is aria-hidden (outer button is the AT\n\t\t\t * surface) and clicked programmatically via inputRef.current?.click().\n\t\t\t */}\n\t\t\t<input\n\t\t\t\tref={inputRef}\n\t\t\t\ttype=\"file\"\n\t\t\t\taccept={accept}\n\t\t\t\tmultiple={multiple}\n\t\t\t\tdisabled={disabled}\n\t\t\t\taria-hidden=\"true\"\n\t\t\t\ttabIndex={-1}\n\t\t\t\tclassName=\"sr-only\"\n\t\t\t\tonChange={(e) => {\n\t\t\t\t\temit(e.target.files);\n\t\t\t\t\t// Reset so picking the same file twice still fires onChange\n\t\t\t\t\te.target.value = \"\";\n\t\t\t\t}}\n\t\t\t/>\n\t\t</>\n\t);\n}\nDropzone.displayName = \"Dropzone\";\n\nexport { Dropzone };\nexport type { DropzoneProps, DropzoneRenderState };\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/components/dropzone/dropzone.tsx"],"names":[],"mappings":"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","file":"dropzone.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n\nconst SAFE_URL_SCHEMES = [\"http:\", \"https:\", \"mailto:\"] as const;\n\n/**\n * Allowlist a URL for use as an `<a href>` against untrusted input.\n *\n * Returns the raw string when it's `http(s):` / `mailto:` / a relative\n * URL (no scheme); returns `undefined` otherwise. Defends against\n * `javascript:` / `data:` / `vbscript:` injection from streamed model\n * output or third-party JSON payloads that flow into citation chips.\n *\n * Inside a Markdown render path, `rehype-sanitize` already strips\n * `javascript:` from inline-link hrefs — but it does NOT introspect\n * JSON nested inside attribute values (e.g. `<sources data='[…]'/>`),\n * so the components that consume that data must guard themselves.\n *\n * @param raw - The candidate URL, or `undefined` when none was supplied.\n * @returns The URL when safe to render, otherwise `undefined`.\n */\nexport function safeUrl(raw: string | undefined): string | undefined {\n\tif (raw === undefined || raw === \"\") return undefined;\n\t// Relative URLs have no scheme — `new URL(relative)` throws without a base,\n\t// so a thrown URL means either malformed input OR a relative path. Treat\n\t// \"throws + does not contain a colon\" as a relative path (safe).\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(raw);\n\t} catch {\n\t\treturn raw.includes(\":\") ? undefined : raw;\n\t}\n\treturn SAFE_URL_SCHEMES.some((scheme) => scheme === parsed.protocol) ? raw : undefined;\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\ninterface DropzoneProps\n\textends Omit<\n\t\tReact.HTMLAttributes<HTMLDivElement>,\n\t\t\"onChange\" | \"onDrop\" | \"children\"\n\t> {\n\t/** Fired with the accepted file list every time the user picks or drops files. */\n\tonFilesSelected?: (files: File[]) => void;\n\t/**\n\t * Fired when files are dropped/picked but ALL of them are filtered out by\n\t * `accept` / `maxSize` / `maxFiles`. Useful for surfacing \"file too large\"\n\t * or \"wrong type\" toasts to the user. Receives the rejected File[].\n\t */\n\tonFilesRejected?: (files: File[]) => void;\n\t/** `accept` attribute forwarded to the hidden file input (e.g. \"image/*\", \".csv\"). */\n\taccept?: string;\n\t/** Allow multiple files. Default true. */\n\tmultiple?: boolean;\n\t/** Maximum total file count (after dedupe). Excess files are dropped silently — surface in your handler. */\n\tmaxFiles?: number;\n\t/** Maximum size per file in bytes. Files over the cap are filtered before onFilesSelected fires. */\n\tmaxSize?: number;\n\t/** Disable interaction. */\n\tdisabled?: boolean;\n\t/** Optional render override for the dropzone body. Receives drag state. */\n\tchildren?: React.ReactNode | ((state: DropzoneRenderState) => React.ReactNode);\n\t/** Required accessible name for the drop area. */\n\t\"aria-label\": string;\n}\n\ninterface DropzoneRenderState {\n\tisDragOver: boolean;\n\tisDisabled: boolean;\n\topenFileDialog: () => void;\n}\n\n/** Apply `accept` / `maxSize` / `maxFiles` filters before emitting to onFilesSelected. */\nfunction filterFiles(\n\tfiles: FileList | File[],\n\t{ accept, maxSize, maxFiles }: { accept?: string; maxSize?: number; maxFiles?: number },\n): File[] {\n\tconst list = Array.from(files);\n\tconst acceptList = accept\n\t\t? accept\n\t\t\t\t.split(\",\")\n\t\t\t\t.map((s) => s.trim())\n\t\t\t\t.filter(Boolean)\n\t\t: undefined;\n\n\tconst matchAccept = (file: File): boolean => {\n\t\tif (!acceptList) return true;\n\t\treturn acceptList.some((entry) => {\n\t\t\tif (entry.startsWith(\".\")) {\n\t\t\t\treturn file.name.toLowerCase().endsWith(entry.toLowerCase());\n\t\t\t}\n\t\t\tif (entry.endsWith(\"/*\")) {\n\t\t\t\tconst prefix = entry.slice(0, -1); // \"image/\"\n\t\t\t\treturn file.type.startsWith(prefix);\n\t\t\t}\n\t\t\treturn file.type === entry;\n\t\t});\n\t};\n\n\tconst sized =\n\t\ttypeof maxSize === \"number\" ? list.filter((f) => f.size <= maxSize) : list;\n\tconst accepted = sized.filter(matchAccept);\n\tif (typeof maxFiles === \"number\") return accepted.slice(0, maxFiles);\n\treturn accepted;\n}\n\n/**\n * Drag-and-drop file input built on the native HTML5 drag-drop API plus a\n * visually-hidden (sr-only) `<input type=\"file\">` for screen-reader and\n * keyboard access.\n *\n * Two interaction surfaces:\n * - The visible drop area is a `role=\"button\"` div with `tabIndex=0` and the\n * required `aria-label`. Click, Enter, or Space proxies through to click the\n * hidden input, opening the system file dialog.\n * - The hidden input itself remains in the accessibility tree (sr-only, NOT\n * `aria-hidden`) so AT-driven file pickers can find it directly.\n *\n * Pass `children` as a node (default placeholder) or a function receiving\n * `{ isDragOver, isDisabled, openFileDialog }` for full layout control.\n * @returns A drop area + hidden file input pair that yields a File[].\n */\nfunction Dropzone({\n\tonFilesSelected,\n\tonFilesRejected,\n\taccept,\n\tmultiple = true,\n\tmaxFiles,\n\tmaxSize,\n\tdisabled = false,\n\tchildren,\n\tclassName,\n\t\"aria-label\": ariaLabel,\n\t...rest\n}: DropzoneProps) {\n\tconst inputRef = React.useRef<HTMLInputElement>(null);\n\tconst [isDragOver, setIsDragOver] = React.useState(false);\n\tconst dragCounter = React.useRef(0);\n\n\tconst emit = React.useCallback(\n\t\t(files: FileList | File[] | null | undefined) => {\n\t\t\tif (!files || disabled) return;\n\t\t\tconst all = Array.from(files);\n\t\t\tif (all.length === 0) return;\n\t\t\tconst accepted = filterFiles(all, { accept, maxSize, maxFiles });\n\t\t\tif (accepted.length === 0) {\n\t\t\t\tonFilesRejected?.(all);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst finalAccepted = !multiple ? accepted.slice(0, 1) : accepted;\n\t\t\tconst rejected = all.filter((f) => !finalAccepted.includes(f));\n\t\t\tonFilesSelected?.(finalAccepted);\n\t\t\tif (rejected.length > 0) onFilesRejected?.(rejected);\n\t\t},\n\t\t[\n\t\t\taccept,\n\t\t\tdisabled,\n\t\t\tmaxFiles,\n\t\t\tmaxSize,\n\t\t\tmultiple,\n\t\t\tonFilesSelected,\n\t\t\tonFilesRejected,\n\t\t],\n\t);\n\n\t/*\n\t * Reset the drag counter + isDragOver when the user cancels a drag outside\n\t * the dropzone (Esc, drag off the page, switch tab). Without this, the\n\t * counter can stay >0 and the dropzone gets stuck in its hover style.\n\t */\n\tReact.useEffect(() => {\n\t\tconst reset = () => {\n\t\t\tdragCounter.current = 0;\n\t\t\tsetIsDragOver(false);\n\t\t};\n\t\twindow.addEventListener(\"dragend\", reset);\n\t\twindow.addEventListener(\"drop\", reset);\n\t\treturn () => {\n\t\t\twindow.removeEventListener(\"dragend\", reset);\n\t\t\twindow.removeEventListener(\"drop\", reset);\n\t\t};\n\t}, []);\n\n\tconst openFileDialog = React.useCallback(() => {\n\t\tif (disabled) return;\n\t\tinputRef.current?.click();\n\t}, [disabled]);\n\n\tconst handleDragEnter = (e: React.DragEvent<HTMLDivElement>) => {\n\t\tif (disabled) return;\n\t\te.preventDefault();\n\t\tdragCounter.current += 1;\n\t\tif (e.dataTransfer.types.includes(\"Files\")) setIsDragOver(true);\n\t};\n\tconst handleDragOver = (e: React.DragEvent<HTMLDivElement>) => {\n\t\tif (disabled) return;\n\t\te.preventDefault();\n\t\te.dataTransfer.dropEffect = \"copy\";\n\t};\n\tconst handleDragLeave = (e: React.DragEvent<HTMLDivElement>) => {\n\t\tif (disabled) return;\n\t\te.preventDefault();\n\t\tdragCounter.current = Math.max(0, dragCounter.current - 1);\n\t\tif (dragCounter.current === 0) setIsDragOver(false);\n\t};\n\tconst handleDrop = (e: React.DragEvent<HTMLDivElement>) => {\n\t\tif (disabled) return;\n\t\te.preventDefault();\n\t\tdragCounter.current = 0;\n\t\tsetIsDragOver(false);\n\t\temit(e.dataTransfer.files);\n\t};\n\tconst handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n\t\tif (disabled) return;\n\t\tif (e.key === \"Enter\" || e.key === \" \") {\n\t\t\te.preventDefault();\n\t\t\topenFileDialog();\n\t\t}\n\t};\n\n\tconst renderState: DropzoneRenderState = {\n\t\tisDragOver,\n\t\tisDisabled: disabled,\n\t\topenFileDialog,\n\t};\n\n\treturn (\n\t\t<>\n\t\t\t<div\n\t\t\t\trole=\"button\"\n\t\t\t\ttabIndex={disabled ? -1 : 0}\n\t\t\t\taria-label={ariaLabel}\n\t\t\t\taria-disabled={disabled || undefined}\n\t\t\t\tdata-drag-over={isDragOver || undefined}\n\t\t\t\tonClick={openFileDialog}\n\t\t\t\tonKeyDown={handleKeyDown}\n\t\t\t\tonDragEnter={handleDragEnter}\n\t\t\t\tonDragOver={handleDragOver}\n\t\t\t\tonDragLeave={handleDragLeave}\n\t\t\t\tonDrop={handleDrop}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"flex w-full cursor-pointer select-none flex-col items-center justify-center gap-[var(--space-2,0.5rem)] rounded-md border-2 border-dashed border-input bg-background px-[var(--space-6,1.5rem)] py-[var(--space-8,2rem)] text-center text-sm transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\t\t\"hover:bg-accent hover:text-accent-foreground\",\n\t\t\t\t\t\"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n\t\t\t\t\tisDragOver && \"border-primary bg-accent text-accent-foreground\",\n\t\t\t\t\tdisabled && \"pointer-events-none opacity-50\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\t{...rest}\n\t\t\t>\n\t\t\t\t{typeof children === \"function\"\n\t\t\t\t\t? children(renderState)\n\t\t\t\t\t: (children ?? (\n\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t<svg\n\t\t\t\t\t\t\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t\t\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\t\t\t\tstrokeWidth=\"2\"\n\t\t\t\t\t\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\t\t\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\t\t\t\t\t\tclassName=\"h-6 w-6 text-muted-foreground\"\n\t\t\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\" />\n\t\t\t\t\t\t\t\t\t<polyline points=\"17 8 12 3 7 8\" />\n\t\t\t\t\t\t\t\t\t<line x1=\"12\" y1=\"3\" x2=\"12\" y2=\"15\" />\n\t\t\t\t\t\t\t\t</svg>\n\t\t\t\t\t\t\t\t<span className=\"font-medium\">\n\t\t\t\t\t\t\t\t\t{isDragOver ? \"Drop files to upload\" : \"Drag files here or click to browse\"}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t{accept ? (\n\t\t\t\t\t\t\t\t\t<span className=\"text-xs text-muted-foreground\">{accept}</span>\n\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t))}\n\t\t\t</div>\n\t\t\t{/*\n\t\t\t * Input lives OUTSIDE the role=\"button\" container to satisfy axe\n\t\t\t * nested-interactive. It is aria-hidden (outer button is the AT\n\t\t\t * surface) and clicked programmatically via inputRef.current?.click().\n\t\t\t */}\n\t\t\t<input\n\t\t\t\tref={inputRef}\n\t\t\t\ttype=\"file\"\n\t\t\t\taccept={accept}\n\t\t\t\tmultiple={multiple}\n\t\t\t\tdisabled={disabled}\n\t\t\t\taria-hidden=\"true\"\n\t\t\t\ttabIndex={-1}\n\t\t\t\tclassName=\"sr-only\"\n\t\t\t\tonChange={(e) => {\n\t\t\t\t\temit(e.target.files);\n\t\t\t\t\t// Reset so picking the same file twice still fires onChange\n\t\t\t\t\te.target.value = \"\";\n\t\t\t\t}}\n\t\t\t/>\n\t\t</>\n\t);\n}\nDropzone.displayName = \"Dropzone\";\n\nexport { Dropzone };\nexport type { DropzoneProps, DropzoneRenderState };\n"]}
|