@devalok/shilp-sutra 0.49.3 → 0.49.4
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/_chunks/badge-group.js.map +1 -1
- package/dist/_chunks/block-shell.js.map +1 -1
- package/dist/_chunks/chart-container.js.map +1 -1
- package/dist/_chunks/chat.js.map +1 -1
- package/dist/_chunks/colors.js.map +1 -1
- package/dist/_chunks/document-preview.js.map +1 -1
- package/dist/_chunks/emoji-suggestion.js.map +1 -1
- package/dist/_chunks/emoji.js +2 -2
- package/dist/_chunks/emoji.js.map +1 -1
- package/dist/_chunks/field-state.js.map +1 -1
- package/dist/_chunks/grid-lines.js.map +1 -1
- package/dist/_chunks/image-preview.js.map +1 -1
- package/dist/_chunks/keybinding.js.map +1 -1
- package/dist/_chunks/link-context.js.map +1 -1
- package/dist/_chunks/mention-suggestion.js.map +1 -1
- package/dist/_chunks/motion-provider.js.map +1 -1
- package/dist/_chunks/normalize-icon.js.map +1 -1
- package/dist/_chunks/oauth-button.js.map +1 -1
- package/dist/_chunks/popover.js.map +1 -1
- package/dist/_chunks/primitives.js +1123 -1153
- package/dist/_chunks/primitives.js.map +1 -1
- package/dist/_chunks/shared.js.map +1 -1
- package/dist/_chunks/success.js.map +1 -1
- package/dist/_chunks/tiptap.js +4283 -3460
- package/dist/_chunks/tiptap.js.map +1 -1
- package/dist/_chunks/tooltip.js.map +1 -1
- package/dist/_chunks/tree-view.js +1 -1
- package/dist/_chunks/tree-view.js.map +1 -1
- package/dist/_chunks/use-calendar.js.map +1 -1
- package/dist/_chunks/use-controllable-open.js.map +1 -1
- package/dist/_chunks/vendor-client.js +86 -59
- package/dist/_chunks/vendor-client.js.map +1 -1
- package/dist/_chunks/vendor-utils.js +555 -513
- package/dist/_chunks/vendor-utils.js.map +1 -1
- package/dist/ai/ai-command-provider.d.ts +1 -1
- package/dist/ai/ai-command-provider.d.ts.map +1 -1
- package/dist/ai/ai-command-provider.js.map +1 -1
- package/dist/ai/block-renderer.js.map +1 -1
- package/dist/ai/blocks/block-shell.d.ts +1 -1
- package/dist/ai/blocks/block-shell.d.ts.map +1 -1
- package/dist/ai/blocks/block-table.d.ts +1 -1
- package/dist/ai/blocks/block-table.d.ts.map +1 -1
- package/dist/ai/blocks/confirm.d.ts +1 -1
- package/dist/ai/blocks/confirm.d.ts.map +1 -1
- package/dist/ai/blocks/divider.d.ts +1 -1
- package/dist/ai/blocks/divider.d.ts.map +1 -1
- package/dist/ai/blocks/error.d.ts +1 -1
- package/dist/ai/blocks/error.d.ts.map +1 -1
- package/dist/ai/blocks/error.js.map +1 -1
- package/dist/ai/blocks/info.d.ts +1 -1
- package/dist/ai/blocks/info.d.ts.map +1 -1
- package/dist/ai/blocks/loading.d.ts +1 -1
- package/dist/ai/blocks/loading.d.ts.map +1 -1
- package/dist/ai/blocks/stat-row.d.ts +1 -1
- package/dist/ai/blocks/stat-row.d.ts.map +1 -1
- package/dist/ai/blocks/success.d.ts +1 -1
- package/dist/ai/blocks/success.d.ts.map +1 -1
- package/dist/ai/blocks/text.d.ts +1 -1
- package/dist/ai/blocks/text.d.ts.map +1 -1
- package/dist/ai/blocks/text.js.map +1 -1
- package/dist/ai/command-bar.js.map +1 -1
- package/dist/ai/conversation.js.map +1 -1
- package/dist/ai/devadoot-icon.d.ts +1 -1
- package/dist/ai/devadoot-icon.d.ts.map +1 -1
- package/dist/ai/index.js.map +1 -1
- package/dist/composed/activity-feed.js.map +1 -1
- package/dist/composed/avatar-group.js.map +1 -1
- package/dist/composed/bulk-action-bar.js.map +1 -1
- package/dist/composed/command-palette.js.map +1 -1
- package/dist/composed/confirm-dialog.js.map +1 -1
- package/dist/composed/content-card.js.map +1 -1
- package/dist/composed/date-picker/index.js.map +1 -1
- package/dist/composed/deadline-indicator.js.map +1 -1
- package/dist/composed/emoji-picker.d.ts +2 -2
- package/dist/composed/emoji-picker.d.ts.map +1 -1
- package/dist/composed/emoji-picker.js.map +1 -1
- package/dist/composed/empty-state.js.map +1 -1
- package/dist/composed/error-boundary.d.ts +1 -1
- package/dist/composed/error-boundary.js.map +1 -1
- package/dist/composed/extensions/emoji-node.js.map +1 -1
- package/dist/composed/file-preview/audio-preview.d.ts +2 -1
- package/dist/composed/file-preview/audio-preview.d.ts.map +1 -1
- package/dist/composed/file-preview/document-preview.d.ts +2 -1
- package/dist/composed/file-preview/document-preview.d.ts.map +1 -1
- package/dist/composed/file-preview/embed-preview.d.ts +2 -1
- package/dist/composed/file-preview/embed-preview.d.ts.map +1 -1
- package/dist/composed/file-preview/image-preview.d.ts +2 -1
- package/dist/composed/file-preview/image-preview.d.ts.map +1 -1
- package/dist/composed/file-preview/shared.d.ts +5 -5
- package/dist/composed/file-preview/shared.d.ts.map +1 -1
- package/dist/composed/file-preview/video-preview.d.ts +2 -1
- package/dist/composed/file-preview/video-preview.d.ts.map +1 -1
- package/dist/composed/file-preview.d.ts +1 -1
- package/dist/composed/file-preview.d.ts.map +1 -1
- package/dist/composed/file-preview.js.map +1 -1
- package/dist/composed/filter-bar.d.ts +2 -2
- package/dist/composed/filter-bar.d.ts.map +1 -1
- package/dist/composed/filter-bar.js.map +1 -1
- package/dist/composed/form-section.js.map +1 -1
- package/dist/composed/global-loading.js.map +1 -1
- package/dist/composed/inline-edit.js.map +1 -1
- package/dist/composed/lib/string-utils.js.map +1 -1
- package/dist/composed/loading-skeleton.js.map +1 -1
- package/dist/composed/markdown-viewer.js.map +1 -1
- package/dist/composed/master-detail.d.ts +3 -3
- package/dist/composed/master-detail.d.ts.map +1 -1
- package/dist/composed/master-detail.js.map +1 -1
- package/dist/composed/member-picker.js.map +1 -1
- package/dist/composed/multi-select-popover.js.map +1 -1
- package/dist/composed/page-header.js.map +1 -1
- package/dist/composed/page-skeletons.js.map +1 -1
- package/dist/composed/priority-indicator.js.map +1 -1
- package/dist/composed/responsive-modal.js +8 -4
- package/dist/composed/responsive-modal.js.map +1 -1
- package/dist/composed/rich-chat-input/attachment-strip.d.ts +2 -1
- package/dist/composed/rich-chat-input/attachment-strip.d.ts.map +1 -1
- package/dist/composed/rich-chat-input/chat-toolbar.d.ts +17 -17
- package/dist/composed/rich-chat-input/chat-toolbar.d.ts.map +1 -1
- package/dist/composed/rich-chat-input/recording-overlay.d.ts +2 -1
- package/dist/composed/rich-chat-input/recording-overlay.d.ts.map +1 -1
- package/dist/composed/rich-chat-input/reply-banner.d.ts +2 -1
- package/dist/composed/rich-chat-input/reply-banner.d.ts.map +1 -1
- package/dist/composed/rich-chat-input/schedule-send.d.ts +4 -3
- package/dist/composed/rich-chat-input/schedule-send.d.ts.map +1 -1
- package/dist/composed/rich-chat-input.js +2 -1
- package/dist/composed/rich-chat-input.js.map +1 -1
- package/dist/composed/rich-text-editor.js +2 -1
- package/dist/composed/rich-text-editor.js.map +1 -1
- package/dist/composed/schedule-view.js.map +1 -1
- package/dist/composed/simple-tooltip.js.map +1 -1
- package/dist/composed/status-badge.js.map +1 -1
- package/dist/hooks/use-color-mode.js +2 -1
- package/dist/hooks/use-color-mode.js.map +1 -1
- package/dist/hooks/use-mobile.js.map +1 -1
- package/dist/hooks/use-touch-device.js.map +1 -1
- package/dist/hooks/use-viewport-height.js.map +1 -1
- package/dist/motion/index.js.map +1 -1
- package/dist/motion/motion-provider.d.ts +1 -1
- package/dist/motion/motion-provider.d.ts.map +1 -1
- package/dist/motion/primitives-index.js.map +1 -1
- package/dist/shell/app-command-palette.js.map +1 -1
- package/dist/shell/bottom-navbar.js.map +1 -1
- package/dist/shell/command-registry.d.ts +1 -1
- package/dist/shell/command-registry.d.ts.map +1 -1
- package/dist/shell/command-registry.js.map +1 -1
- package/dist/shell/notification-center.js.map +1 -1
- package/dist/shell/notification-preferences.js.map +1 -1
- package/dist/shell/sidebar.js.map +1 -1
- package/dist/shell/top-bar.js.map +1 -1
- package/dist/ui/accordion.js.map +1 -1
- package/dist/ui/alert-dialog.js.map +1 -1
- package/dist/ui/alert.js.map +1 -1
- package/dist/ui/aspect-ratio.js.map +1 -1
- package/dist/ui/autocomplete.js.map +1 -1
- package/dist/ui/avatar.d.ts +1 -1
- package/dist/ui/avatar.js.map +1 -1
- package/dist/ui/badge-group.d.ts +1 -1
- package/dist/ui/badge-group.d.ts.map +1 -1
- package/dist/ui/badge-indicator.d.ts +1 -1
- package/dist/ui/badge-indicator.d.ts.map +1 -1
- package/dist/ui/badge-indicator.js.map +1 -1
- package/dist/ui/banner.js.map +1 -1
- package/dist/ui/breadcrumb.d.ts +2 -2
- package/dist/ui/breadcrumb.js.map +1 -1
- package/dist/ui/button-group.js.map +1 -1
- package/dist/ui/button-processing.d.ts +2 -1
- package/dist/ui/button-processing.d.ts.map +1 -1
- package/dist/ui/button-processing.js.map +1 -1
- package/dist/ui/button.js.map +1 -1
- package/dist/ui/card.js +1 -1
- package/dist/ui/card.js.map +1 -1
- package/dist/ui/charts/_internal/axes.d.ts +2 -1
- package/dist/ui/charts/_internal/axes.d.ts.map +1 -1
- package/dist/ui/charts/_internal/grid-lines.d.ts +2 -1
- package/dist/ui/charts/_internal/grid-lines.d.ts.map +1 -1
- package/dist/ui/charts/_internal/legend.d.ts +2 -1
- package/dist/ui/charts/_internal/legend.d.ts.map +1 -1
- package/dist/ui/charts/_internal/tooltip.d.ts +1 -1
- package/dist/ui/charts/_internal/tooltip.d.ts.map +1 -1
- package/dist/ui/charts/area-chart.js.map +1 -1
- package/dist/ui/charts/bar-chart.js.map +1 -1
- package/dist/ui/charts/gauge-chart.js.map +1 -1
- package/dist/ui/charts/line-chart.js.map +1 -1
- package/dist/ui/charts/pie-chart.js.map +1 -1
- package/dist/ui/charts/radar-chart.js.map +1 -1
- package/dist/ui/charts/sparkline.js +2 -2
- package/dist/ui/charts/sparkline.js.map +1 -1
- package/dist/ui/chat/date-separator.d.ts +2 -1
- package/dist/ui/chat/date-separator.d.ts.map +1 -1
- package/dist/ui/chat/message.d.ts +8 -8
- package/dist/ui/chat/message.d.ts.map +1 -1
- package/dist/ui/chat/typing-indicator.d.ts +2 -1
- package/dist/ui/chat/typing-indicator.d.ts.map +1 -1
- package/dist/ui/chat/unread-separator.d.ts +2 -1
- package/dist/ui/chat/unread-separator.d.ts.map +1 -1
- package/dist/ui/checkbox.js.map +1 -1
- package/dist/ui/code.js.map +1 -1
- package/dist/ui/collapsible.js.map +1 -1
- package/dist/ui/color-input.js.map +1 -1
- package/dist/ui/color-swatch.js.map +1 -1
- package/dist/ui/combobox.js +15 -6
- package/dist/ui/combobox.js.map +1 -1
- package/dist/ui/container.js.map +1 -1
- package/dist/ui/context-menu.d.ts +2 -2
- package/dist/ui/context-menu.js.map +1 -1
- package/dist/ui/data-table-body.d.ts +1 -1
- package/dist/ui/data-table-body.d.ts.map +1 -1
- package/dist/ui/data-table-body.js +1 -1
- package/dist/ui/data-table-body.js.map +1 -1
- package/dist/ui/data-table-bulk-actions.d.ts +2 -1
- package/dist/ui/data-table-bulk-actions.d.ts.map +1 -1
- package/dist/ui/data-table-bulk-actions.js.map +1 -1
- package/dist/ui/data-table-card.d.ts +1 -1
- package/dist/ui/data-table-card.d.ts.map +1 -1
- package/dist/ui/data-table-card.js.map +1 -1
- package/dist/ui/data-table-context.d.ts +1 -1
- package/dist/ui/data-table-context.d.ts.map +1 -1
- package/dist/ui/data-table-context.js.map +1 -1
- package/dist/ui/data-table-header.d.ts +2 -1
- package/dist/ui/data-table-header.d.ts.map +1 -1
- package/dist/ui/data-table-header.js.map +1 -1
- package/dist/ui/data-table-pagination.d.ts +2 -1
- package/dist/ui/data-table-pagination.d.ts.map +1 -1
- package/dist/ui/data-table-pagination.js.map +1 -1
- package/dist/ui/data-table-toolbar.d.ts +1 -1
- package/dist/ui/data-table-toolbar.d.ts.map +1 -1
- package/dist/ui/data-table-toolbar.js.map +1 -1
- package/dist/ui/data-table.d.ts +1 -1
- package/dist/ui/data-table.d.ts.map +1 -1
- package/dist/ui/data-table.js.map +1 -1
- package/dist/ui/devalok-grain.d.ts +2 -1
- package/dist/ui/devalok-grain.d.ts.map +1 -1
- package/dist/ui/devalok-grain.js.map +1 -1
- package/dist/ui/dialog.js.map +1 -1
- package/dist/ui/dot.js +1 -1
- package/dist/ui/dot.js.map +1 -1
- package/dist/ui/dropdown-menu.d.ts +1 -1
- package/dist/ui/dropdown-menu.js.map +1 -1
- package/dist/ui/file-upload.js.map +1 -1
- package/dist/ui/form.js.map +1 -1
- package/dist/ui/hover-card.js.map +1 -1
- package/dist/ui/icon-button.js.map +1 -1
- package/dist/ui/icon-context.d.ts +1 -1
- package/dist/ui/icon-context.d.ts.map +1 -1
- package/dist/ui/icon-context.js.map +1 -1
- package/dist/ui/icon-group.js.map +1 -1
- package/dist/ui/icon.js.map +1 -1
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/input-otp.js.map +1 -1
- package/dist/ui/input.js.map +1 -1
- package/dist/ui/label.js.map +1 -1
- package/dist/ui/lib/bottom-sheet.d.ts +1 -1
- package/dist/ui/lib/bottom-sheet.d.ts.map +1 -1
- package/dist/ui/lib/date-utils.js.map +1 -1
- package/dist/ui/lib/link-context.d.ts +1 -1
- package/dist/ui/lib/link-context.d.ts.map +1 -1
- package/dist/ui/lib/motion.js.map +1 -1
- package/dist/ui/lib/utils.js.map +1 -1
- package/dist/ui/link.js.map +1 -1
- package/dist/ui/menubar.d.ts +1 -1
- package/dist/ui/menubar.js.map +1 -1
- package/dist/ui/navigation-menu.js +14 -9
- package/dist/ui/navigation-menu.js.map +1 -1
- package/dist/ui/number-input.js.map +1 -1
- package/dist/ui/pagination.js.map +1 -1
- package/dist/ui/progress-ring.js.map +1 -1
- package/dist/ui/progress.js.map +1 -1
- package/dist/ui/radio.js.map +1 -1
- package/dist/ui/search-input.js.map +1 -1
- package/dist/ui/segmented-control.js.map +1 -1
- package/dist/ui/select.js.map +1 -1
- package/dist/ui/separator.js.map +1 -1
- package/dist/ui/sheet.js.map +1 -1
- package/dist/ui/sidebar.js +1 -1
- package/dist/ui/sidebar.js.map +1 -1
- package/dist/ui/skeleton.js.map +1 -1
- package/dist/ui/slider.js.map +1 -1
- package/dist/ui/spinner.js.map +1 -1
- package/dist/ui/split-button.js.map +1 -1
- package/dist/ui/stack.js.map +1 -1
- package/dist/ui/stat-card.js.map +1 -1
- package/dist/ui/stat-flash.d.ts +2 -1
- package/dist/ui/stat-flash.d.ts.map +1 -1
- package/dist/ui/stat-flash.js +1 -1
- package/dist/ui/stat-flash.js.map +1 -1
- package/dist/ui/stepper.d.ts +1 -1
- package/dist/ui/stepper.d.ts.map +1 -1
- package/dist/ui/stepper.js +1 -1
- package/dist/ui/stepper.js.map +1 -1
- package/dist/ui/surface.js.map +1 -1
- package/dist/ui/switch.d.ts +1 -1
- package/dist/ui/switch.js.map +1 -1
- package/dist/ui/table-row-link.js.map +1 -1
- package/dist/ui/table.js.map +1 -1
- package/dist/ui/tabs.js.map +1 -1
- package/dist/ui/text.js.map +1 -1
- package/dist/ui/textarea.js.map +1 -1
- package/dist/ui/toast-registry.js.map +1 -1
- package/dist/ui/toast.d.ts +4 -4
- package/dist/ui/toast.d.ts.map +1 -1
- package/dist/ui/toast.js +5 -3
- package/dist/ui/toast.js.map +1 -1
- package/dist/ui/toaster.js.map +1 -1
- package/dist/ui/toggle-group.js.map +1 -1
- package/dist/ui/toggle.js.map +1 -1
- package/dist/ui/tooltip.js.map +1 -1
- package/dist/ui/truncated-text.js.map +1 -1
- package/dist/ui/visually-hidden.js.map +1 -1
- package/llms.txt +1 -1
- package/mcp-manifest.json +1 -1
- package/package.json +21 -21
- package/skill/SKILL.md +1 -1
- package/skill/references/components.md +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"badge-group.js","names":[],"sources":["../../src/ui/badge.tsx","../../src/ui/badge-group.tsx"],"sourcesContent":["'use client'\n\nimport { Slot } from '@primitives/react-slot'\nimport { IconCheck, IconX } from '@tabler/icons-react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { AnimatePresence, motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { Dot } from './dot'\nimport { Icon } from './icon'\nimport type { IconInput } from './lib/icon-input'\nimport { durations,springs } from './lib/motion'\nimport { normalizeIcon } from './lib/normalize-icon'\nimport { cn } from './lib/utils'\n\n// ── Color map — single source of truth for all badge color × variant combos ──\nconst colorMap = {\n default: { bg: 'bg-surface-raised-hover', fg: 'text-surface-fg-muted', border: 'border-surface-border-strong', solid: 'bg-neutral-5', solidFg: 'text-surface-fg' },\n accent: { bg: 'bg-accent-3', fg: 'text-accent-11', border: 'border-accent-7', solid: 'bg-accent-9', solidFg: 'text-accent-fg' },\n error: { bg: 'bg-error-3', fg: 'text-error-11', border: 'border-error-7', solid: 'bg-error-9', solidFg: 'text-error-fg' },\n success: { bg: 'bg-success-3', fg: 'text-success-11', border: 'border-success-7', solid: 'bg-success-9', solidFg: 'text-success-fg' },\n warning: { bg: 'bg-warning-3', fg: 'text-warning-11', border: 'border-warning-7', solid: 'bg-warning-9', solidFg: 'text-warning-fg' },\n info: { bg: 'bg-info-3', fg: 'text-info-11', border: 'border-info-7', solid: 'bg-info-9', solidFg: 'text-info-fg' },\n neutral: { bg: 'bg-surface-raised-hover', fg: 'text-surface-fg-muted', border: 'border-surface-border-strong', solid: 'bg-neutral-5', solidFg: 'text-surface-fg' },\n teal: { bg: 'bg-category-teal-3', fg: 'text-category-teal-11', border: 'border-category-teal-7', solid: 'bg-category-teal-9', solidFg: 'text-white' },\n amber: { bg: 'bg-category-amber-3', fg: 'text-category-amber-11', border: 'border-category-amber-7', solid: 'bg-category-amber-9', solidFg: 'text-white' },\n slate: { bg: 'bg-category-slate-3', fg: 'text-category-slate-11', border: 'border-category-slate-7', solid: 'bg-category-slate-9', solidFg: 'text-white' },\n indigo: { bg: 'bg-category-indigo-3', fg: 'text-category-indigo-11', border: 'border-category-indigo-7', solid: 'bg-category-indigo-9', solidFg: 'text-white' },\n cyan: { bg: 'bg-category-cyan-3', fg: 'text-category-cyan-11', border: 'border-category-cyan-7', solid: 'bg-category-cyan-9', solidFg: 'text-white' },\n orange: { bg: 'bg-category-orange-3', fg: 'text-category-orange-11', border: 'border-category-orange-7', solid: 'bg-category-orange-9', solidFg: 'text-white' },\n emerald: { bg: 'bg-category-emerald-3', fg: 'text-category-emerald-11', border: 'border-category-emerald-7', solid: 'bg-category-emerald-9', solidFg: 'text-white' },\n} as const\n\ntype BadgeColor = keyof typeof colorMap | 'custom'\n\n/** Derive color classes for a given variant + color pair */\nfunction getColorClasses(variant: 'subtle' | 'solid' | 'outline' | 'soft', color: BadgeColor): string {\n if (color === 'custom') return ''\n const c = colorMap[color]\n switch (variant) {\n case 'subtle': return cn(c.bg, c.fg, c.border)\n case 'solid': return cn(c.solid, c.solidFg, 'border-transparent')\n case 'outline': return cn('bg-transparent', c.fg, c.border)\n case 'soft': return cn(c.bg, c.fg, 'border-transparent')\n }\n}\n\nconst badgeVariants = cva(\n 'relative inline-flex items-center rounded-pill font-sans font-medium overflow-hidden isolate transition-[color,background-color,border-color,padding] duration-fast-02 ease-productive-standard select-none [&>span:not([data-grain])]:relative [&>span:not([data-grain])]:z-[2]',\n {\n variants: {\n variant: {\n subtle: 'border',\n solid: 'border border-transparent',\n outline: 'border',\n soft: 'border border-transparent',\n },\n size: {\n xs: 'h-4 px-ds-02b text-ds-xs gap-ds-02',\n sm: 'h-5 px-ds-03 text-ds-xs gap-ds-02',\n md: 'h-6 px-2.5 text-ds-xs gap-ds-02b', /* px-2.5=10px — no exact DS token */\n lg: 'h-7 px-ds-04 text-ds-sm gap-ds-02b',\n },\n },\n defaultVariants: {\n variant: 'subtle',\n size: 'md',\n },\n },\n)\n\n/** Icon sizing per badge size */\nconst iconSizeMap: Record<string, string> = {\n xs: '[&>svg]:h-2.5 [&>svg]:w-2.5',\n sm: '[&>svg]:h-3 [&>svg]:w-3',\n md: '[&>svg]:h-3 [&>svg]:w-3',\n lg: '[&>svg]:h-3.5 [&>svg]:w-3.5',\n}\n\n/** Reduced left padding when leading content (icon/dot/selected) is present */\nconst paddingLeftWithIcon: Record<string, string> = {\n xs: 'pl-ds-02',\n sm: 'pl-ds-02b',\n md: 'pl-ds-03',\n lg: 'pl-2.5', /* 10px — no exact DS token */\n}\n\n/** Reduced right padding when trailing content (dismiss/endIcon) is present */\nconst paddingRightWithTrailing: Record<string, string> = {\n xs: 'pr-ds-01',\n sm: 'pr-ds-02',\n md: 'pr-ds-02',\n lg: 'pr-ds-02b',\n}\n\n/**\n * Badge — a compact inline label with a two-axis variant system.\n *\n * **Two axes:**\n * - `variant` controls **visual style**: `\"subtle\"` | `\"solid\"` | `\"outline\"` | `\"soft\"`\n * - `color` controls **semantic intent/category**: 16 built-in colors + `\"custom\"` (CSS variable)\n *\n * **Interactive:** Pass `onClick` to make it a button. Pass `selected` for toggle state.\n * **Dismissible:** Pass `onDismiss` to show a dismiss button.\n * **Custom colors:** Set `color=\"custom\"` and CSS variable `--badge-color` on a parent or via `style`.\n * For light custom colors on solid variant, set `--badge-fg-color` to a dark value.\n *\n * @example\n * <Badge color=\"success\">Active</Badge>\n *\n * @example\n * <Badge variant=\"solid\" size=\"sm\" dot>3 new</Badge>\n *\n * @example\n * <Badge color=\"custom\" style={{ '--badge-color': '#8b5cf6' } as React.CSSProperties}>\n * Custom\n * </Badge>\n */\ninterface BadgeProps\n extends Omit<React.HTMLAttributes<HTMLElement>, 'color'>,\n VariantProps<typeof badgeVariants> {\n /** Semantic intent or category color. Use `\"custom\"` with `--badge-color` CSS variable. */\n color?: BadgeColor\n asChild?: boolean\n startIcon?: IconInput\n endIcon?: IconInput\n dot?: boolean\n /** Pulse the status dot (opt-in; static by default). @default false */\n dotPulse?: boolean\n onDismiss?: () => void\n selected?: boolean\n disabled?: boolean\n maxWidth?: number\n /**\n * Truncate children with ellipsis when they overflow the badge width.\n * Use with a fixed width (e.g. `className=\"w-20\"`) or `maxWidth` for\n * constrained pill badges. Always adds a title tooltip on the full text.\n */\n truncate?: boolean\n circle?: boolean\n}\n\nconst Badge = React.forwardRef<HTMLElement, BadgeProps>(\n (\n {\n className,\n variant,\n color,\n size,\n asChild,\n startIcon,\n endIcon,\n dot,\n dotPulse,\n onDismiss,\n onClick,\n selected,\n disabled,\n maxWidth,\n truncate,\n circle,\n children,\n style,\n ...props\n },\n ref,\n ) => {\n const resolvedVariant = variant ?? 'subtle'\n const resolvedColor = color ?? 'default'\n const resolvedSize = size ?? 'md'\n\n // When both onClick + onDismiss, use div with role=\"button\" to avoid nested <button>\n const Comp = asChild\n ? Slot\n : onClick && onDismiss\n ? 'div'\n : onClick\n ? 'button'\n : 'span'\n\n // Custom color inline styles via CSS variable\n const customStyles =\n resolvedColor === 'custom'\n ? {\n ...(resolvedVariant === 'subtle' && {\n backgroundColor: 'color-mix(in oklch, var(--badge-color) 15%, transparent)',\n color: 'var(--badge-color)',\n borderColor: 'color-mix(in oklch, var(--badge-color) 40%, transparent)',\n }),\n ...(resolvedVariant === 'solid' && {\n backgroundColor: 'var(--badge-color)',\n color: 'var(--badge-fg-color, white)',\n borderColor: 'transparent',\n }),\n ...(resolvedVariant === 'outline' && {\n backgroundColor: 'transparent',\n color: 'var(--badge-color)',\n borderColor: 'color-mix(in oklch, var(--badge-color) 50%, transparent)',\n }),\n ...(resolvedVariant === 'soft' && {\n backgroundColor: 'color-mix(in oklch, var(--badge-color) 12%, transparent)',\n color: 'var(--badge-color)',\n borderColor: 'transparent',\n }),\n }\n : undefined\n\n // Keyboard handler for div[role=\"button\"] (onClick + onDismiss case)\n const handleKeyDown =\n onClick && onDismiss\n ? (e: React.KeyboardEvent<HTMLElement>) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n if (!disabled) onClick(e as unknown as React.MouseEvent<HTMLElement>)\n }\n props.onKeyDown?.(e)\n }\n : props.onKeyDown\n\n const hasLeading = !!(dot || startIcon || (onClick && selected && !startIcon && !dot))\n const hasTrailing = !!(onDismiss || endIcon)\n\n return (\n <Comp\n ref={ref as React.Ref<never>}\n className={cn(\n badgeVariants({ variant: resolvedVariant, size: resolvedSize }),\n getColorClasses(resolvedVariant, resolvedColor),\n hasLeading && paddingLeftWithIcon[resolvedSize],\n hasTrailing && paddingRightWithTrailing[resolvedSize],\n onClick &&\n 'cursor-pointer hover:brightness-[0.97] focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-1 transition-[color,background-color,border-color,transform,filter] duration-moderate-01 ease-productive-exit hover:duration-fast-02 hover:ease-productive-entrance active:scale-[0.95] active:brightness-[0.92] active:duration-[0ms]',\n selected && 'ring-1 ring-current/20 transition-shadow duration-fast-02',\n disabled && 'opacity-action-disabled pointer-events-none saturate-[0.3]',\n circle && 'justify-center px-0 aspect-square',\n className,\n )}\n style={{ ...style, ...customStyles, ...(maxWidth ? { maxWidth } : undefined) }}\n onClick={disabled ? undefined : (onClick as React.MouseEventHandler<HTMLElement>)}\n onKeyDown={handleKeyDown}\n {...(Comp === 'button' && { type: 'button' as const })}\n {...(Comp === 'button' && disabled ? { disabled: true } : {})}\n {...(Comp === 'div' && onClick ? { role: 'button' as const, tabIndex: 0 } : {})}\n {...props}\n >\n {/* Dot indicator — animated entrance, uses the shared <Dot> (current colour + pulse) */}\n <AnimatePresence>\n {dot && (\n <motion.span\n key=\"dot\"\n initial={{ scale: 0 }}\n animate={{ scale: 1 }}\n exit={{ scale: 0 }}\n transition={springs.snappy}\n className=\"inline-flex shrink-0\"\n >\n <Dot color=\"current\" size=\"sm\" pulse={dotPulse} />\n </motion.span>\n )}\n </AnimatePresence>\n\n {/* Selected check icon — always mounted for interactive badges */}\n {onClick && !startIcon && !dot && (\n <motion.span\n initial={false}\n animate={selected\n ? { opacity: 1, scale: 1, width: 'auto', marginRight: 0 }\n : { opacity: 0, scale: 0.5, width: 0, marginRight: -4 }\n }\n transition={{ type: 'tween', duration: durations.moderate01, ease: [0.2, 0, 0.38, 0.9] }} /* ease-productive-standard */\n className=\"inline-flex shrink-0 overflow-hidden\"\n aria-hidden={!selected}\n >\n <Icon icon={IconCheck} size=\"xs\" />\n </motion.span>\n )}\n\n {/* Start icon */}\n {startIcon && (\n <span className={cn('shrink-0', iconSizeMap[resolvedSize])}>{normalizeIcon(startIcon)}</span>\n )}\n\n {/* Children — with optional truncation */}\n {truncate || maxWidth ? (\n <span\n className=\"truncate\"\n title={typeof children === 'string' ? children : undefined}\n >\n {children}\n </span>\n ) : (\n children\n )}\n\n {/* End icon */}\n {endIcon && (\n <span className={cn('shrink-0', iconSizeMap[resolvedSize])}>{normalizeIcon(endIcon)}</span>\n )}\n\n {/* Dismiss button */}\n {onDismiss && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation()\n onDismiss()\n }}\n className={cn(\n 'shrink-0 rounded-pill text-current/60 hover:text-current hover:bg-current/10 transition-colors focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-accent-9',\n resolvedSize === 'xs'\n ? 'p-0 -mr-0.5 min-w-ds-05 min-h-ds-05'\n : 'p-px',\n )}\n aria-label={\n `Remove ${typeof children === 'string' ? children : ''}`.trim() || 'Remove'\n }\n >\n <Icon icon={IconX} size=\"xs\" />\n </button>\n )}\n </Comp>\n )\n },\n)\nBadge.displayName = 'Badge'\n\nimport { BadgeGroup } from './badge-group'\nimport { BadgeIndicator } from './badge-indicator'\n\nconst BadgeCompound = Object.assign(Badge, {\n Indicator: BadgeIndicator,\n Group: BadgeGroup,\n})\n\nexport { BadgeCompound as Badge, type BadgeColor,type BadgeProps, badgeVariants }\n","'use client'\n\nimport * as React from 'react'\n\nimport { Badge, type BadgeProps } from './badge'\nimport { cn } from './lib/utils'\n\nconst GAP_CLASSES = {\n tight: 'gap-1',\n default: 'gap-1.5',\n loose: 'gap-2',\n} as const\n\nexport interface BadgeGroupProps {\n max?: number\n gap?: keyof typeof GAP_CLASSES\n size?: BadgeProps['size']\n onOverflowClick?: () => void\n className?: string\n children: React.ReactNode\n}\n\nexport function BadgeGroup({\n max,\n gap = 'default',\n size,\n onOverflowClick,\n className,\n children,\n}: BadgeGroupProps) {\n const childArray = React.Children.toArray(children)\n const total = childArray.length\n const hasOverflow = max !== undefined && total > max\n const visible = hasOverflow ? childArray.slice(0, max) : childArray\n const overflowCount = hasOverflow ? total - max! : 0\n\n return (\n <div className={cn('flex flex-wrap items-center', GAP_CLASSES[gap], className)}>\n {visible}\n {hasOverflow && (\n // With onClick, Badge renders a real, keyboard-reachable <button>; add a\n // label since \"+N\" alone isn't descriptive to a screen reader.\n <Badge\n variant=\"outline\"\n color=\"neutral\"\n size={size ?? 'sm'}\n onClick={onOverflowClick}\n aria-label={onOverflowClick ? `Show ${overflowCount} more` : undefined}\n >\n +{overflowCount}\n </Badge>\n )}\n </div>\n )\n}\n\nBadgeGroup.displayName = 'BadgeGroup'\n"],"mappings":";;;;;;;;;;;;;AAgBA,IAAM,IAAW;CACf,SAAS;EAAE,IAAI;EAA2B,IAAI;EAAyB,QAAQ;EAAgC,OAAO;EAAgB,SAAS;EAAmB;CAClK,QAAS;EAAE,IAAI;EAAgB,IAAI;EAAmB,QAAQ;EAAoB,OAAO;EAAgB,SAAS;EAAkB;CACpI,OAAS;EAAE,IAAI;EAAgB,IAAI;EAAmB,QAAQ;EAAoB,OAAO;EAAgB,SAAS;EAAiB;CACnI,SAAS;EAAE,IAAI;EAAgB,IAAI;EAAmB,QAAQ;EAAoB,OAAO;EAAgB,SAAS;EAAmB;CACrI,SAAS;EAAE,IAAI;EAAgB,IAAI;EAAmB,QAAQ;EAAoB,OAAO;EAAgB,SAAS;EAAmB;CACrI,MAAS;EAAE,IAAI;EAAgB,IAAI;EAAmB,QAAQ;EAAoB,OAAO;EAAgB,SAAS;EAAgB;CAClI,SAAS;EAAE,IAAI;EAA2B,IAAI;EAAyB,QAAQ;EAAgC,OAAO;EAAgB,SAAS;EAAmB;CAClK,MAAS;EAAE,IAAI;EAAyB,IAAI;EAA4B,QAAQ;EAA6B,OAAO;EAAyB,SAAS;EAAc;CACpK,OAAS;EAAE,IAAI;EAAyB,IAAI;EAA4B,QAAQ;EAA6B,OAAO;EAAyB,SAAS;EAAc;CACpK,OAAS;EAAE,IAAI;EAAyB,IAAI;EAA4B,QAAQ;EAA6B,OAAO;EAAyB,SAAS;EAAc;CACpK,QAAS;EAAE,IAAI;EAAyB,IAAI;EAA4B,QAAQ;EAA6B,OAAO;EAAyB,SAAS;EAAc;CACpK,MAAS;EAAE,IAAI;EAAyB,IAAI;EAA4B,QAAQ;EAA6B,OAAO;EAAyB,SAAS;EAAc;CACpK,QAAS;EAAE,IAAI;EAAyB,IAAI;EAA4B,QAAQ;EAA6B,OAAO;EAAyB,SAAS;EAAc;CACpK,SAAS;EAAE,IAAI;EAAyB,IAAI;EAA4B,QAAQ;EAA6B,OAAO;EAAyB,SAAS;EAAc;CACrK;AAKD,SAAS,EAAgB,GAAkD,GAA2B;AACpG,KAAI,MAAU,SAAU,QAAO;CAC/B,IAAM,IAAI,EAAS;AACnB,SAAQ,GAAR;EACE,KAAK,SAAW,QAAO,EAAG,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO;EAC/C,KAAK,QAAW,QAAO,EAAG,EAAE,OAAO,EAAE,SAAS,qBAAqB;EACnE,KAAK,UAAW,QAAO,EAAG,kBAAkB,EAAE,IAAI,EAAE,OAAO;EAC3D,KAAK,OAAW,QAAO,EAAG,EAAE,IAAI,EAAE,IAAI,qBAAqB;;;AAI/D,IAAM,IAAgB,EACpB,oRACA;CACE,UAAU;EACR,SAAS;GACP,QAAQ;GACR,OAAO;GACP,SAAS;GACT,MAAM;GACP;EACD,MAAM;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACL;EACF;CACD,iBAAiB;EACf,SAAS;EACT,MAAM;EACP;CACF,CACF,EAGK,IAAsC;CAC1C,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACL,EAGK,IAA8C;CAClD,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACL,EAGK,IAAmD;CACvD,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACL,EAiDK,IAAQ,EAAM,YAEhB,EACE,cACA,YACA,UACA,SACA,YACA,cACA,YACA,QACA,aACA,cACA,YACA,aACA,aACA,aACA,aACA,WACA,aACA,UACA,GAAG,KAEL,MACG;CACH,IAAM,IAAkB,KAAW,UAC7B,IAAgB,KAAS,WACzB,IAAe,KAAQ,MAGvB,IAAO,IACT,IACA,KAAW,IACT,QACA,IACE,WACA,QAGF,IACJ,MAAkB,WACd;EACE,GAAI,MAAoB,YAAY;GAClC,iBAAiB;GACjB,OAAO;GACP,aAAa;GACd;EACD,GAAI,MAAoB,WAAW;GACjC,iBAAiB;GACjB,OAAO;GACP,aAAa;GACd;EACD,GAAI,MAAoB,aAAa;GACnC,iBAAiB;GACjB,OAAO;GACP,aAAa;GACd;EACD,GAAI,MAAoB,UAAU;GAChC,iBAAiB;GACjB,OAAO;GACP,aAAa;GACd;EACF,GACD,KAAA,GAGA,IACJ,KAAW,KACN,MAAwC;AAKvC,GAJI,EAAE,QAAQ,WAAW,EAAE,QAAQ,SACjC,EAAE,gBAAgB,EACb,KAAU,EAAQ,EAA8C,GAEvE,EAAM,YAAY,EAAE;KAEtB,EAAM,WAEN,IAAa,CAAC,EAAE,KAAO,KAAc,KAAW,KAAY,CAAC,KAAa,CAAC,IAC3E,IAAc,CAAC,EAAE,KAAa;AAEpC,QACE,kBAAC,GAAD;EACO;EACL,WAAW,EACT,EAAc;GAAE,SAAS;GAAiB,MAAM;GAAc,CAAC,EAC/D,EAAgB,GAAiB,EAAc,EAC/C,KAAc,EAAoB,IAClC,KAAe,EAAyB,IACxC,KACE,yXACF,KAAY,6DACZ,KAAY,8DACZ,KAAU,qCACV,EACD;EACD,OAAO;GAAE,GAAG;GAAO,GAAG;GAAc,GAAI,IAAW,EAAE,aAAU,GAAG,KAAA;GAAY;EAC9E,SAAS,IAAW,KAAA,IAAa;EACjC,WAAW;EACX,GAAK,MAAS,YAAY,EAAE,MAAM,UAAmB;EACrD,GAAK,MAAS,YAAY,IAAW,EAAE,UAAU,IAAM,GAAG,EAAE;EAC5D,GAAK,MAAS,SAAS,IAAU;GAAE,MAAM;GAAmB,UAAU;GAAG,GAAG,EAAE;EAC9E,GAAI;YApBN;GAuBE,kBAAC,GAAD,EAAA,UACG,KACC,kBAAC,EAAO,MAAR;IAEE,SAAS,EAAE,OAAO,GAAG;IACrB,SAAS,EAAE,OAAO,GAAG;IACrB,MAAM,EAAE,OAAO,GAAG;IAClB,YAAY,EAAQ;IACpB,WAAU;cAEV,kBAAC,GAAD;KAAK,OAAM;KAAU,MAAK;KAAK,OAAO;KAAY,CAAA;IACtC,EARR,MAQQ,EAEA,CAAA;GAGjB,KAAW,CAAC,KAAa,CAAC,KACzB,kBAAC,EAAO,MAAR;IACE,SAAS;IACT,SAAS,IACL;KAAE,SAAS;KAAG,OAAO;KAAG,OAAO;KAAQ,aAAa;KAAG,GACvD;KAAE,SAAS;KAAG,OAAO;KAAK,OAAO;KAAG,aAAa;KAAI;IAEzD,YAAY;KAAE,MAAM;KAAS,UAAU,EAAU;KAAY,MAAM;MAAC;MAAK;MAAG;MAAM;MAAI;KAAE;IACxF,WAAU;IACV,eAAa,CAAC;cAEd,kBAAC,GAAD;KAAM,MAAM;KAAW,MAAK;KAAO,CAAA;IACvB,CAAA;GAIf,KACC,kBAAC,QAAD;IAAM,WAAW,EAAG,YAAY,EAAY,GAAc;cAAG,EAAc,EAAU;IAAQ,CAAA;GAI9F,KAAY,IACX,kBAAC,QAAD;IACE,WAAU;IACV,OAAO,OAAO,KAAa,WAAW,IAAW,KAAA;IAEhD;IACI,CAAA,GAEP;GAID,KACC,kBAAC,QAAD;IAAM,WAAW,EAAG,YAAY,EAAY,GAAc;cAAG,EAAc,EAAQ;IAAQ,CAAA;GAI5F,KACC,kBAAC,UAAD;IACE,MAAK;IACL,UAAU,MAAM;AAEd,KADA,EAAE,iBAAiB,EACnB,GAAW;;IAEb,WAAW,EACT,gLACA,MAAiB,OACb,wCACA,OACL;IACD,cACE,UAAU,OAAO,KAAa,WAAW,IAAW,KAAK,MAAM,IAAI;cAGrE,kBAAC,GAAD;KAAM,MAAM;KAAO,MAAK;KAAO,CAAA;IACxB,CAAA;GAEN;;EAGZ;AACD,EAAM,cAAc;AAKpB,IAAM,IAAgB,OAAO,OAAO,GAAO;CACzC,WAAW;CACX,OAAO;CACR,CAAC,ECrUI,IAAc;CAClB,OAAO;CACP,SAAS;CACT,OAAO;CACR;AAWD,SAAgB,EAAW,EACzB,QACA,SAAM,WACN,SACA,oBACA,cACA,eACkB;CAClB,IAAM,IAAa,EAAM,SAAS,QAAQ,EAAS,EAC7C,IAAQ,EAAW,QACnB,IAAc,MAAQ,KAAA,KAAa,IAAQ,GAC3C,IAAU,IAAc,EAAW,MAAM,GAAG,EAAI,GAAG,GACnD,IAAgB,IAAc,IAAQ,IAAO;AAEnD,QACE,kBAAC,OAAD;EAAK,WAAW,EAAG,+BAA+B,EAAY,IAAM,EAAU;YAA9E,CACG,GACA,KAGC,kBAAC,GAAD;GACE,SAAQ;GACR,OAAM;GACN,MAAM,KAAQ;GACd,SAAS;GACT,cAAY,IAAkB,QAAQ,EAAc,SAAS,KAAA;aAL/D,CAMC,KACG,EACI;KAEN;;;AAIV,EAAW,cAAc"}
|
|
1
|
+
{"version":3,"file":"badge-group.js","names":[],"sources":["../../src/ui/badge.tsx","../../src/ui/badge-group.tsx"],"sourcesContent":["'use client'\n\nimport { Slot } from '@primitives/react-slot'\nimport { IconCheck, IconX } from '@tabler/icons-react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { AnimatePresence, motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { Dot } from './dot'\nimport { Icon } from './icon'\nimport type { IconInput } from './lib/icon-input'\nimport { durations,springs } from './lib/motion'\nimport { normalizeIcon } from './lib/normalize-icon'\nimport { cn } from './lib/utils'\n\n// ── Color map — single source of truth for all badge color × variant combos ──\nconst colorMap = {\n default: { bg: 'bg-surface-raised-hover', fg: 'text-surface-fg-muted', border: 'border-surface-border-strong', solid: 'bg-neutral-5', solidFg: 'text-surface-fg' },\n accent: { bg: 'bg-accent-3', fg: 'text-accent-11', border: 'border-accent-7', solid: 'bg-accent-9', solidFg: 'text-accent-fg' },\n error: { bg: 'bg-error-3', fg: 'text-error-11', border: 'border-error-7', solid: 'bg-error-9', solidFg: 'text-error-fg' },\n success: { bg: 'bg-success-3', fg: 'text-success-11', border: 'border-success-7', solid: 'bg-success-9', solidFg: 'text-success-fg' },\n warning: { bg: 'bg-warning-3', fg: 'text-warning-11', border: 'border-warning-7', solid: 'bg-warning-9', solidFg: 'text-warning-fg' },\n info: { bg: 'bg-info-3', fg: 'text-info-11', border: 'border-info-7', solid: 'bg-info-9', solidFg: 'text-info-fg' },\n neutral: { bg: 'bg-surface-raised-hover', fg: 'text-surface-fg-muted', border: 'border-surface-border-strong', solid: 'bg-neutral-5', solidFg: 'text-surface-fg' },\n teal: { bg: 'bg-category-teal-3', fg: 'text-category-teal-11', border: 'border-category-teal-7', solid: 'bg-category-teal-9', solidFg: 'text-white' },\n amber: { bg: 'bg-category-amber-3', fg: 'text-category-amber-11', border: 'border-category-amber-7', solid: 'bg-category-amber-9', solidFg: 'text-white' },\n slate: { bg: 'bg-category-slate-3', fg: 'text-category-slate-11', border: 'border-category-slate-7', solid: 'bg-category-slate-9', solidFg: 'text-white' },\n indigo: { bg: 'bg-category-indigo-3', fg: 'text-category-indigo-11', border: 'border-category-indigo-7', solid: 'bg-category-indigo-9', solidFg: 'text-white' },\n cyan: { bg: 'bg-category-cyan-3', fg: 'text-category-cyan-11', border: 'border-category-cyan-7', solid: 'bg-category-cyan-9', solidFg: 'text-white' },\n orange: { bg: 'bg-category-orange-3', fg: 'text-category-orange-11', border: 'border-category-orange-7', solid: 'bg-category-orange-9', solidFg: 'text-white' },\n emerald: { bg: 'bg-category-emerald-3', fg: 'text-category-emerald-11', border: 'border-category-emerald-7', solid: 'bg-category-emerald-9', solidFg: 'text-white' },\n} as const\n\ntype BadgeColor = keyof typeof colorMap | 'custom'\n\n/** Derive color classes for a given variant + color pair */\nfunction getColorClasses(variant: 'subtle' | 'solid' | 'outline' | 'soft', color: BadgeColor): string {\n if (color === 'custom') return ''\n const c = colorMap[color]\n switch (variant) {\n case 'subtle': return cn(c.bg, c.fg, c.border)\n case 'solid': return cn(c.solid, c.solidFg, 'border-transparent')\n case 'outline': return cn('bg-transparent', c.fg, c.border)\n case 'soft': return cn(c.bg, c.fg, 'border-transparent')\n }\n}\n\nconst badgeVariants = cva(\n 'relative inline-flex items-center rounded-pill font-sans font-medium overflow-hidden isolate transition-[color,background-color,border-color,padding] duration-fast-02 ease-productive-standard select-none [&>span:not([data-grain])]:relative [&>span:not([data-grain])]:z-[2]',\n {\n variants: {\n variant: {\n subtle: 'border',\n solid: 'border border-transparent',\n outline: 'border',\n soft: 'border border-transparent',\n },\n size: {\n xs: 'h-4 px-ds-02b text-ds-xs gap-ds-02',\n sm: 'h-5 px-ds-03 text-ds-xs gap-ds-02',\n md: 'h-6 px-2.5 text-ds-xs gap-ds-02b', /* px-2.5=10px — no exact DS token */\n lg: 'h-7 px-ds-04 text-ds-sm gap-ds-02b',\n },\n },\n defaultVariants: {\n variant: 'subtle',\n size: 'md',\n },\n },\n)\n\n/** Icon sizing per badge size */\nconst iconSizeMap: Record<string, string> = {\n xs: '[&>svg]:h-2.5 [&>svg]:w-2.5',\n sm: '[&>svg]:h-3 [&>svg]:w-3',\n md: '[&>svg]:h-3 [&>svg]:w-3',\n lg: '[&>svg]:h-3.5 [&>svg]:w-3.5',\n}\n\n/** Reduced left padding when leading content (icon/dot/selected) is present */\nconst paddingLeftWithIcon: Record<string, string> = {\n xs: 'pl-ds-02',\n sm: 'pl-ds-02b',\n md: 'pl-ds-03',\n lg: 'pl-2.5', /* 10px — no exact DS token */\n}\n\n/** Reduced right padding when trailing content (dismiss/endIcon) is present */\nconst paddingRightWithTrailing: Record<string, string> = {\n xs: 'pr-ds-01',\n sm: 'pr-ds-02',\n md: 'pr-ds-02',\n lg: 'pr-ds-02b',\n}\n\n/**\n * Badge — a compact inline label with a two-axis variant system.\n *\n * **Two axes:**\n * - `variant` controls **visual style**: `\"subtle\"` | `\"solid\"` | `\"outline\"` | `\"soft\"`\n * - `color` controls **semantic intent/category**: 16 built-in colors + `\"custom\"` (CSS variable)\n *\n * **Interactive:** Pass `onClick` to make it a button. Pass `selected` for toggle state.\n * **Dismissible:** Pass `onDismiss` to show a dismiss button.\n * **Custom colors:** Set `color=\"custom\"` and CSS variable `--badge-color` on a parent or via `style`.\n * For light custom colors on solid variant, set `--badge-fg-color` to a dark value.\n *\n * @example\n * <Badge color=\"success\">Active</Badge>\n *\n * @example\n * <Badge variant=\"solid\" size=\"sm\" dot>3 new</Badge>\n *\n * @example\n * <Badge color=\"custom\" style={{ '--badge-color': '#8b5cf6' } as React.CSSProperties}>\n * Custom\n * </Badge>\n */\ninterface BadgeProps\n extends Omit<React.HTMLAttributes<HTMLElement>, 'color'>,\n VariantProps<typeof badgeVariants> {\n /** Semantic intent or category color. Use `\"custom\"` with `--badge-color` CSS variable. */\n color?: BadgeColor\n asChild?: boolean\n startIcon?: IconInput\n endIcon?: IconInput\n dot?: boolean\n /** Pulse the status dot (opt-in; static by default). @default false */\n dotPulse?: boolean\n onDismiss?: () => void\n selected?: boolean\n disabled?: boolean\n maxWidth?: number\n /**\n * Truncate children with ellipsis when they overflow the badge width.\n * Use with a fixed width (e.g. `className=\"w-20\"`) or `maxWidth` for\n * constrained pill badges. Always adds a title tooltip on the full text.\n */\n truncate?: boolean\n circle?: boolean\n}\n\nconst Badge = React.forwardRef<HTMLElement, BadgeProps>(\n (\n {\n className,\n variant,\n color,\n size,\n asChild,\n startIcon,\n endIcon,\n dot,\n dotPulse,\n onDismiss,\n onClick,\n selected,\n disabled,\n maxWidth,\n truncate,\n circle,\n children,\n style,\n ...props\n },\n ref,\n ) => {\n const resolvedVariant = variant ?? 'subtle'\n const resolvedColor = color ?? 'default'\n const resolvedSize = size ?? 'md'\n\n // When both onClick + onDismiss, use div with role=\"button\" to avoid nested <button>\n const Comp = asChild\n ? Slot\n : onClick && onDismiss\n ? 'div'\n : onClick\n ? 'button'\n : 'span'\n\n // Custom color inline styles via CSS variable\n const customStyles =\n resolvedColor === 'custom'\n ? {\n ...(resolvedVariant === 'subtle' && {\n backgroundColor: 'color-mix(in oklch, var(--badge-color) 15%, transparent)',\n color: 'var(--badge-color)',\n borderColor: 'color-mix(in oklch, var(--badge-color) 40%, transparent)',\n }),\n ...(resolvedVariant === 'solid' && {\n backgroundColor: 'var(--badge-color)',\n color: 'var(--badge-fg-color, white)',\n borderColor: 'transparent',\n }),\n ...(resolvedVariant === 'outline' && {\n backgroundColor: 'transparent',\n color: 'var(--badge-color)',\n borderColor: 'color-mix(in oklch, var(--badge-color) 50%, transparent)',\n }),\n ...(resolvedVariant === 'soft' && {\n backgroundColor: 'color-mix(in oklch, var(--badge-color) 12%, transparent)',\n color: 'var(--badge-color)',\n borderColor: 'transparent',\n }),\n }\n : undefined\n\n // Keyboard handler for div[role=\"button\"] (onClick + onDismiss case)\n const handleKeyDown =\n onClick && onDismiss\n ? (e: React.KeyboardEvent<HTMLElement>) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n if (!disabled) onClick(e as unknown as React.MouseEvent<HTMLElement>)\n }\n props.onKeyDown?.(e)\n }\n : props.onKeyDown\n\n const hasLeading = !!(dot || startIcon || (onClick && selected && !startIcon && !dot))\n const hasTrailing = !!(onDismiss || endIcon)\n\n return (\n <Comp\n ref={ref as React.Ref<never>}\n className={cn(\n badgeVariants({ variant: resolvedVariant, size: resolvedSize }),\n getColorClasses(resolvedVariant, resolvedColor),\n hasLeading && paddingLeftWithIcon[resolvedSize],\n hasTrailing && paddingRightWithTrailing[resolvedSize],\n onClick &&\n 'cursor-pointer hover:brightness-[0.97] focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-1 transition-[color,background-color,border-color,transform,filter] duration-moderate-01 ease-productive-exit hover:duration-fast-02 hover:ease-productive-entrance active:scale-[0.95] active:brightness-[0.92] active:duration-[0ms]',\n selected && 'ring-1 ring-current/20 transition-shadow duration-fast-02',\n disabled && 'opacity-action-disabled pointer-events-none saturate-[0.3]',\n circle && 'justify-center px-0 aspect-square',\n className,\n )}\n style={{ ...style, ...customStyles, ...(maxWidth ? { maxWidth } : undefined) }}\n onClick={disabled ? undefined : (onClick as React.MouseEventHandler<HTMLElement>)}\n onKeyDown={handleKeyDown}\n {...(Comp === 'button' && { type: 'button' as const })}\n {...(Comp === 'button' && disabled ? { disabled: true } : {})}\n {...(Comp === 'div' && onClick ? { role: 'button' as const, tabIndex: 0 } : {})}\n {...props}\n >\n {/* Dot indicator — animated entrance, uses the shared <Dot> (current colour + pulse) */}\n <AnimatePresence>\n {dot && (\n <motion.span\n key=\"dot\"\n initial={{ scale: 0 }}\n animate={{ scale: 1 }}\n exit={{ scale: 0 }}\n transition={springs.snappy}\n className=\"inline-flex shrink-0\"\n >\n <Dot color=\"current\" size=\"sm\" pulse={dotPulse} />\n </motion.span>\n )}\n </AnimatePresence>\n\n {/* Selected check icon — always mounted for interactive badges */}\n {onClick && !startIcon && !dot && (\n <motion.span\n initial={false}\n animate={selected\n ? { opacity: 1, scale: 1, width: 'auto', marginRight: 0 }\n : { opacity: 0, scale: 0.5, width: 0, marginRight: -4 }\n }\n transition={{ type: 'tween', duration: durations.moderate01, ease: [0.2, 0, 0.38, 0.9] }} /* ease-productive-standard */\n className=\"inline-flex shrink-0 overflow-hidden\"\n aria-hidden={!selected}\n >\n <Icon icon={IconCheck} size=\"xs\" />\n </motion.span>\n )}\n\n {/* Start icon */}\n {startIcon && (\n <span className={cn('shrink-0', iconSizeMap[resolvedSize])}>{normalizeIcon(startIcon)}</span>\n )}\n\n {/* Children — with optional truncation */}\n {truncate || maxWidth ? (\n <span\n className=\"truncate\"\n title={typeof children === 'string' ? children : undefined}\n >\n {children}\n </span>\n ) : (\n children\n )}\n\n {/* End icon */}\n {endIcon && (\n <span className={cn('shrink-0', iconSizeMap[resolvedSize])}>{normalizeIcon(endIcon)}</span>\n )}\n\n {/* Dismiss button */}\n {onDismiss && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation()\n onDismiss()\n }}\n className={cn(\n 'shrink-0 rounded-pill text-current/60 hover:text-current hover:bg-current/10 transition-colors focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-accent-9',\n resolvedSize === 'xs'\n ? 'p-0 -mr-0.5 min-w-ds-05 min-h-ds-05'\n : 'p-px',\n )}\n aria-label={\n `Remove ${typeof children === 'string' ? children : ''}`.trim() || 'Remove'\n }\n >\n <Icon icon={IconX} size=\"xs\" />\n </button>\n )}\n </Comp>\n )\n },\n)\nBadge.displayName = 'Badge'\n\nimport { BadgeGroup } from './badge-group'\nimport { BadgeIndicator } from './badge-indicator'\n\nconst BadgeCompound = Object.assign(Badge, {\n Indicator: BadgeIndicator,\n Group: BadgeGroup,\n})\n\nexport { BadgeCompound as Badge, type BadgeColor,type BadgeProps, badgeVariants }\n","'use client'\n\nimport * as React from 'react'\n\nimport { Badge, type BadgeProps } from './badge'\nimport { cn } from './lib/utils'\n\nconst GAP_CLASSES = {\n tight: 'gap-1',\n default: 'gap-1.5',\n loose: 'gap-2',\n} as const\n\nexport interface BadgeGroupProps {\n max?: number\n gap?: keyof typeof GAP_CLASSES\n size?: BadgeProps['size']\n onOverflowClick?: () => void\n className?: string\n children: React.ReactNode\n}\n\nexport function BadgeGroup({\n max,\n gap = 'default',\n size,\n onOverflowClick,\n className,\n children,\n}: BadgeGroupProps) {\n const childArray = React.Children.toArray(children)\n const total = childArray.length\n const hasOverflow = max !== undefined && total > max\n const visible = hasOverflow ? childArray.slice(0, max) : childArray\n const overflowCount = hasOverflow ? total - max! : 0\n\n return (\n <div className={cn('flex flex-wrap items-center', GAP_CLASSES[gap], className)}>\n {visible}\n {hasOverflow && (\n // With onClick, Badge renders a real, keyboard-reachable <button>; add a\n // label since \"+N\" alone isn't descriptive to a screen reader.\n <Badge\n variant=\"outline\"\n color=\"neutral\"\n size={size ?? 'sm'}\n onClick={onOverflowClick}\n aria-label={onOverflowClick ? `Show ${overflowCount} more` : undefined}\n >\n +{overflowCount}\n </Badge>\n )}\n </div>\n )\n}\n\nBadgeGroup.displayName = 'BadgeGroup'\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block-shell.js","names":[],"sources":["../../src/ai/blocks/block-shell.tsx"],"sourcesContent":["'use client'\n\nimport { IconAlertTriangle } from '@tabler/icons-react'\nimport * as React from 'react'\n\nimport { Icon } from '../../ui/icon'\nimport { cn } from '../../ui/lib/utils'\n\nexport interface BlockShellProps {\n confidence?: 'high' | 'medium' | 'low'\n className?: string\n children: React.ReactNode\n}\n\n/**\n * Shared wrapper for AI block renderers. Owns the low-confidence treatment so it\n * lives in ONE place instead of a copy-pasted rail across every block.\n *\n * Low confidence = a faint warning wash (`bg-warning-2`, the DS \"Subtle\n * background\" step) + a \"Low confidence\" chip pinned top-right. NOT a colored\n * left rail (the AI tell removed from Card in v0.44.0). `pt-ds-07` reserves\n * clearance so the chip never overlaps content in prose/table blocks.\n */\nconst BlockShell = React.memo(function BlockShell({\n confidence,\n className,\n children,\n}: BlockShellProps) {\n const low = confidence === 'low'\n return (\n <div\n data-confidence={confidence}\n className={cn(\n low && 'relative rounded-surface bg-warning-2 p-ds-04 pt-ds-07',\n className,\n )}\n >\n {low && (\n <span className=\"absolute right-ds-03 top-ds-03 inline-flex items-center gap-1 rounded-pill bg-warning-3 px-ds-02 py-px text-ds-xs font-semibold text-warning-11\">\n <Icon icon={IconAlertTriangle} size=\"xs\" aria-hidden />\n Low confidence\n </span>\n )}\n {children}\n </div>\n )\n})\n\nBlockShell.displayName = 'BlockShell'\n\nexport { BlockShell }\n"],"mappings":";;;;;;AAuBA,IAAM,IAAa,EAAM,KAAK,SAAoB,EAChD,eACA,cACA,eACkB;CAClB,IAAM,IAAM,MAAe;
|
|
1
|
+
{"version":3,"file":"block-shell.js","names":[],"sources":["../../src/ai/blocks/block-shell.tsx"],"sourcesContent":["'use client'\n\nimport { IconAlertTriangle } from '@tabler/icons-react'\nimport * as React from 'react'\n\nimport { Icon } from '../../ui/icon'\nimport { cn } from '../../ui/lib/utils'\n\nexport interface BlockShellProps {\n confidence?: 'high' | 'medium' | 'low'\n className?: string\n children: React.ReactNode\n}\n\n/**\n * Shared wrapper for AI block renderers. Owns the low-confidence treatment so it\n * lives in ONE place instead of a copy-pasted rail across every block.\n *\n * Low confidence = a faint warning wash (`bg-warning-2`, the DS \"Subtle\n * background\" step) + a \"Low confidence\" chip pinned top-right. NOT a colored\n * left rail (the AI tell removed from Card in v0.44.0). `pt-ds-07` reserves\n * clearance so the chip never overlaps content in prose/table blocks.\n */\nconst BlockShell = React.memo(function BlockShell({\n confidence,\n className,\n children,\n}: BlockShellProps) {\n const low = confidence === 'low'\n return (\n <div\n data-confidence={confidence}\n className={cn(\n low && 'relative rounded-surface bg-warning-2 p-ds-04 pt-ds-07',\n className,\n )}\n >\n {low && (\n <span className=\"absolute right-ds-03 top-ds-03 inline-flex items-center gap-1 rounded-pill bg-warning-3 px-ds-02 py-px text-ds-xs font-semibold text-warning-11\">\n <Icon icon={IconAlertTriangle} size=\"xs\" aria-hidden />\n Low confidence\n </span>\n )}\n {children}\n </div>\n )\n})\n\nBlockShell.displayName = 'BlockShell'\n\nexport { BlockShell }\n"],"mappings":";;;;;;AAuBA,IAAM,IAAa,EAAM,KAAK,SAAoB,EAChD,eACA,cACA,eACkB;CAClB,IAAM,IAAM,MAAe;CAC3B,OACE,kBAAC,OAAD;EACE,mBAAiB;EACjB,WAAW,EACT,KAAO,0DACP,CACF;YALF,CAOG,KACC,kBAAC,QAAD;GAAM,WAAU;aAAhB,CACE,kBAAC,GAAD;IAAM,MAAM;IAAmB,MAAK;IAAK,eAAA;GAAa,CAAA,GAAC,gBAEnD;MAEP,CACE;;AAET,CAAC;AAED,EAAW,cAAc"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chart-container.js","names":[],"sources":["../../src/ui/charts/_internal/types.ts","../../src/ui/charts/chart-container.tsx"],"sourcesContent":["export interface ChartMargin {\n top: number\n right: number\n bottom: number\n left: number\n}\n\nexport const DEFAULT_MARGIN: ChartMargin = {\n top: 20,\n right: 20,\n bottom: 40,\n left: 50,\n}\n\nexport interface DataPoint {\n [key: string]: string | number | Date\n}\n\nexport interface Series {\n key: string\n label: string\n color?: string\n}\n\nexport type ChartColor =\n | 'chart-1'\n | 'chart-2'\n | 'chart-3'\n | 'chart-4'\n | 'chart-5'\n | 'chart-6'\n | 'chart-7'\n | 'chart-8'\n","'use client'\n\nimport * as React from 'react'\nimport { useEffect,useRef, useState } from 'react'\n\nimport { cn } from '../lib/utils'\nimport type { ChartMargin } from './_internal/types'\nimport { DEFAULT_MARGIN } from './_internal/types'\n\nexport interface ChartContainerProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> {\n /** Fixed height in pixels */\n height?: number\n /** Chart margins */\n margin?: Partial<ChartMargin>\n className?: string\n /** Accessible label for the chart SVG */\n ariaLabel?: string\n /** Accessible description for screen readers — summarize key data points */\n ariaDescription?: string\n /** Render function receiving inner dimensions (width/height minus margins) */\n children: (dimensions: {\n width: number\n height: number\n margin: ChartMargin\n }) => React.ReactNode\n}\n\nexport const ChartContainer = React.forwardRef<HTMLDivElement, ChartContainerProps>(\n (\n {\n height = 300,\n margin: marginOverride,\n className,\n ariaLabel = 'Chart',\n ariaDescription,\n children,\n ...props\n },\n ref,\n ) => {\n const containerRef = useRef<HTMLDivElement>(null)\n const [width, setWidth] = useState(0)\n\n const margin = { ...DEFAULT_MARGIN, ...marginOverride }\n\n useEffect(() => {\n if (!containerRef.current) return\n const observer = new ResizeObserver((entries) => {\n const entry = entries[0]\n if (entry) setWidth(entry.contentRect.width)\n })\n observer.observe(containerRef.current)\n return () => observer.disconnect()\n }, [])\n\n const innerWidth = Math.max(0, width - margin.left - margin.right)\n const innerHeight = Math.max(0, height - margin.top - margin.bottom)\n\n return (\n <div\n ref={(node) => {\n (containerRef as React.MutableRefObject<HTMLDivElement | null>).current = node\n if (typeof ref === 'function') ref(node)\n else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = node\n }}\n className={cn('relative w-full', className)}\n {...props}\n >\n {width > 0 && (\n <svg width={width} height={height} role=\"img\" aria-label={ariaLabel}>\n {ariaDescription && <desc>{ariaDescription}</desc>}\n <g transform={`translate(${margin.left},${margin.top})`}>\n {children({ width: innerWidth, height: innerHeight, margin })}\n </g>\n </svg>\n )}\n </div>\n )\n },\n)\nChartContainer.displayName = 'ChartContainer'\n"],"mappings":";;;;;AAOA,IAAa,IAA8B;CACzC,KAAK;CACL,OAAO;CACP,QAAQ;CACR,MAAM;
|
|
1
|
+
{"version":3,"file":"chart-container.js","names":[],"sources":["../../src/ui/charts/_internal/types.ts","../../src/ui/charts/chart-container.tsx"],"sourcesContent":["export interface ChartMargin {\n top: number\n right: number\n bottom: number\n left: number\n}\n\nexport const DEFAULT_MARGIN: ChartMargin = {\n top: 20,\n right: 20,\n bottom: 40,\n left: 50,\n}\n\nexport interface DataPoint {\n [key: string]: string | number | Date\n}\n\nexport interface Series {\n key: string\n label: string\n color?: string\n}\n\nexport type ChartColor =\n | 'chart-1'\n | 'chart-2'\n | 'chart-3'\n | 'chart-4'\n | 'chart-5'\n | 'chart-6'\n | 'chart-7'\n | 'chart-8'\n","'use client'\n\nimport * as React from 'react'\nimport { useEffect,useRef, useState } from 'react'\n\nimport { cn } from '../lib/utils'\nimport type { ChartMargin } from './_internal/types'\nimport { DEFAULT_MARGIN } from './_internal/types'\n\nexport interface ChartContainerProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> {\n /** Fixed height in pixels */\n height?: number\n /** Chart margins */\n margin?: Partial<ChartMargin>\n className?: string\n /** Accessible label for the chart SVG */\n ariaLabel?: string\n /** Accessible description for screen readers — summarize key data points */\n ariaDescription?: string\n /** Render function receiving inner dimensions (width/height minus margins) */\n children: (dimensions: {\n width: number\n height: number\n margin: ChartMargin\n }) => React.ReactNode\n}\n\nexport const ChartContainer = React.forwardRef<HTMLDivElement, ChartContainerProps>(\n (\n {\n height = 300,\n margin: marginOverride,\n className,\n ariaLabel = 'Chart',\n ariaDescription,\n children,\n ...props\n },\n ref,\n ) => {\n const containerRef = useRef<HTMLDivElement>(null)\n const [width, setWidth] = useState(0)\n\n const margin = { ...DEFAULT_MARGIN, ...marginOverride }\n\n useEffect(() => {\n if (!containerRef.current) return\n const observer = new ResizeObserver((entries) => {\n const entry = entries[0]\n if (entry) setWidth(entry.contentRect.width)\n })\n observer.observe(containerRef.current)\n return () => observer.disconnect()\n }, [])\n\n const innerWidth = Math.max(0, width - margin.left - margin.right)\n const innerHeight = Math.max(0, height - margin.top - margin.bottom)\n\n return (\n <div\n ref={(node) => {\n (containerRef as React.MutableRefObject<HTMLDivElement | null>).current = node\n if (typeof ref === 'function') ref(node)\n else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = node\n }}\n className={cn('relative w-full', className)}\n {...props}\n >\n {width > 0 && (\n <svg width={width} height={height} role=\"img\" aria-label={ariaLabel}>\n {ariaDescription && <desc>{ariaDescription}</desc>}\n <g transform={`translate(${margin.left},${margin.top})`}>\n {children({ width: innerWidth, height: innerHeight, margin })}\n </g>\n </svg>\n )}\n </div>\n )\n },\n)\nChartContainer.displayName = 'ChartContainer'\n"],"mappings":";;;;;AAOA,IAAa,IAA8B;CACzC,KAAK;CACL,OAAO;CACP,QAAQ;CACR,MAAM;AACR,GCea,IAAiB,EAAM,YAEhC,EACE,YAAS,KACT,QAAQ,GACR,cACA,eAAY,SACZ,oBACA,aACA,GAAG,KAEL,MACG;CACL,IAAM,IAAe,EAAuB,IAAI,GAC1C,CAAC,GAAO,KAAY,EAAS,CAAC,GAE9B,IAAS;EAAE,GAAG;EAAgB,GAAG;CAAe;CAEtD,QAAgB;EACd,IAAI,CAAC,EAAa,SAAS;EAC3B,IAAM,IAAW,IAAI,gBAAgB,MAAY;GAC/C,IAAM,IAAQ,EAAQ;GACtB,AAAI,KAAO,EAAS,EAAM,YAAY,KAAK;EAC7C,CAAC;EAED,OADA,EAAS,QAAQ,EAAa,OAAO,SACxB,EAAS,WAAW;CACnC,GAAG,CAAC,CAAC;CAEL,IAAM,IAAa,KAAK,IAAI,GAAG,IAAQ,EAAO,OAAO,EAAO,KAAK,GAC3D,IAAc,KAAK,IAAI,GAAG,IAAS,EAAO,MAAM,EAAO,MAAM;CAEnE,OACE,kBAAC,OAAD;EACE,MAAM,MAAS;GAEb,AADA,EAAgE,UAAU,GACtE,OAAO,KAAQ,aAAY,EAAI,CAAI,IAC9B,MAAK,EAAuD,UAAU;EACjF;EACA,WAAW,EAAG,mBAAmB,CAAS;EAC1C,GAAI;YAEH,IAAQ,KACP,kBAAC,OAAD;GAAY;GAAe;GAAQ,MAAK;GAAM,cAAY;aAA1D,CACG,KAAmB,kBAAC,QAAD,EAAA,UAAO,EAAsB,CAAA,GACjD,kBAAC,KAAD;IAAG,WAAW,aAAa,EAAO,KAAK,GAAG,EAAO,IAAI;cAClD,EAAS;KAAE,OAAO;KAAY,QAAQ;KAAa;IAAO,CAAC;GAC3D,CAAA,CACA;;CAEJ,CAAA;AAEP,CACF;AACA,EAAe,cAAc"}
|
package/dist/_chunks/chat.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat.js","names":[],"sources":["../../src/ui/chat/date-separator.tsx","../../src/ui/chat/message.tsx","../../src/ui/chat/message-input.tsx","../../src/ui/chat/message-list.tsx","../../src/ui/chat/system-message.tsx","../../src/ui/chat/typing-indicator.tsx","../../src/ui/chat/unread-separator.tsx"],"sourcesContent":["import * as React from 'react'\n\nimport { cn } from '../lib/utils'\n\nexport interface DateSeparatorProps {\n date: Date | string\n format?: (date: Date) => string\n className?: string\n}\n\nfunction defaultFormat(date: Date): string {\n const now = new Date()\n const today = new Date(now.getFullYear(), now.getMonth(), now.getDate())\n const target = new Date(date.getFullYear(), date.getMonth(), date.getDate())\n const diffMs = today.getTime() - target.getTime()\n const diffDays = Math.round(diffMs / (1000 * 60 * 60 * 24))\n\n if (diffDays === 0) return 'Today'\n if (diffDays === 1) return 'Yesterday'\n\n const month = date.toLocaleString('en-US', { month: 'short' })\n const day = date.getDate()\n\n if (date.getFullYear() !== now.getFullYear()) {\n return `${month} ${day}, ${date.getFullYear()}`\n }\n\n return `${month} ${day}`\n}\n\nfunction DateSeparator({ date, format, className }: DateSeparatorProps) {\n const d = typeof date === 'string' ? new Date(date) : date\n const label = format ? format(d) : defaultFormat(d)\n\n return (\n <div className={cn('flex items-center gap-ds-03 py-ds-03', className)}>\n <div className=\"flex-1 border-t border-surface-border-subtle\" />\n <span className=\"text-ds-xs font-medium text-surface-fg-subtle/50 uppercase tracking-wider\">\n {label}\n </span>\n <div className=\"flex-1 border-t border-surface-border-subtle\" />\n </div>\n )\n}\nDateSeparator.displayName = 'DateSeparator'\n\nexport { DateSeparator }\n","'use client'\n\nimport { IconTrash } from '@tabler/icons-react'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { Avatar, AvatarFallback,AvatarImage } from '../avatar'\nimport { Icon } from '../icon'\nimport { IconProvider } from '../icon-context'\nimport type { IconInput } from '../lib/icon-input'\nimport { MENTION_TOKEN_CLASS } from '../lib/mention'\nimport { motionProps,springs } from '../lib/motion'\nimport { normalizeIcon } from '../lib/normalize-icon'\nimport { cn } from '../lib/utils'\nimport { Textarea } from '../textarea'\nimport { Tooltip, TooltipContent,TooltipTrigger } from '../tooltip'\n\n// ── Context ──────────────────────────────────────────────────────────────\n\ninterface MessageContextValue {\n variant: 'flat' | 'bubble'\n placement: 'start' | 'end'\n grouped: boolean\n highlight?: 'mention' | 'internal'\n}\n\nconst MessageContext = React.createContext<MessageContextValue>({\n variant: 'flat',\n placement: 'start',\n grouped: false,\n})\n\nfunction useMessageContext() {\n return React.useContext(MessageContext)\n}\n\n// ── Root ─────────────────────────────────────────────────────────────────\n\nexport interface MessageProps extends React.HTMLAttributes<HTMLDivElement> {\n children: React.ReactNode\n variant?: 'flat' | 'bubble'\n placement?: 'start' | 'end'\n highlight?: 'mention' | 'internal'\n grouped?: boolean\n deleted?: boolean\n deletedText?: string\n}\n\nconst MessageRoot = React.forwardRef<HTMLDivElement, MessageProps>(\n (\n {\n children,\n variant = 'flat',\n placement = 'start',\n highlight,\n grouped = false,\n deleted = false,\n deletedText = 'This message was deleted',\n className,\n ...props\n },\n ref,\n ) => {\n const ctx = React.useMemo<MessageContextValue>(\n () => ({ variant, placement, grouped, highlight }),\n [variant, placement, grouped, highlight],\n )\n\n if (deleted) {\n return (\n <motion.div\n ref={ref}\n initial={{ y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n transition={springs.snappy}\n className={cn(\n 'flex items-center gap-ds-02 py-ds-02 text-ds-xs text-surface-fg-subtle/50 italic',\n className,\n )}\n {...motionProps(props)}\n >\n <Icon icon={IconTrash} size=\"xs\" />\n {deletedText}\n </motion.div>\n )\n }\n\n if (variant === 'bubble') {\n return (\n <MessageContext.Provider value={ctx}>\n <motion.div\n ref={ref}\n data-highlight={highlight}\n initial={{ y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n transition={springs.snappy}\n className={cn(\n 'group/message relative flex',\n placement === 'end' ? 'justify-end' : 'justify-start',\n // mention is carried by the styled in-content @token (see MENTION_TOKEN_CLASS), not a row tint/rail\n MENTION_TOKEN_CLASS,\n highlight === 'internal' && 'bg-warning-2/50 rounded-control-inner',\n className,\n )}\n {...motionProps(props)}\n >\n <div\n className={cn(\n 'max-w-[85%] rounded-bubble px-ds-04 py-ds-03',\n placement === 'end'\n ? 'bg-accent-3 text-surface-fg'\n : 'bg-surface-raised text-surface-fg',\n )}\n >\n {children}\n </div>\n </motion.div>\n </MessageContext.Provider>\n )\n }\n\n // flat variant (default)\n return (\n <MessageContext.Provider value={ctx}>\n <motion.div\n ref={ref}\n data-highlight={highlight}\n initial={{ y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n transition={springs.snappy}\n className={cn(\n 'group/message relative flex gap-ds-04',\n grouped && '-mt-ds-01',\n // mention is carried by the styled in-content @token (see MENTION_TOKEN_CLASS), not a row rail/tint\n MENTION_TOKEN_CLASS,\n highlight === 'internal' && 'bg-warning-2/50 rounded-control-inner',\n className,\n )}\n {...motionProps(props)}\n >\n {children}\n </motion.div>\n </MessageContext.Provider>\n )\n },\n)\nMessageRoot.displayName = 'Message'\n\n// ── Avatar ───────────────────────────────────────────────────────────────\n\nexport interface MessageAvatarProps {\n src?: string | null\n fallback?: string\n icon?: IconInput\n size?: 'sm' | 'md'\n children?: React.ReactNode\n}\n\nfunction MessageAvatar({\n src,\n fallback,\n icon,\n size = 'md',\n children,\n}: MessageAvatarProps) {\n const { grouped } = useMessageContext()\n\n const sizeClass = size === 'sm' ? 'w-5' : 'w-6'\n const heightClass = size === 'sm' ? 'h-5' : 'h-6'\n\n if (grouped) {\n return <div className={cn(sizeClass, heightClass, 'shrink-0')} />\n }\n\n if (children) {\n return (\n <div className={cn(sizeClass, 'shrink-0 flex items-start')}>\n {children}\n </div>\n )\n }\n\n if (icon) {\n return (\n <div\n className={cn(\n sizeClass,\n size === 'sm' ? 'h-5' : 'h-6',\n 'shrink-0 flex items-center justify-center rounded-pill bg-surface-raised-hover',\n )}\n >\n <IconProvider size={size === 'sm' ? 'xs' : 'sm'}>{normalizeIcon(icon)}</IconProvider>\n </div>\n )\n }\n\n return (\n <div className={cn(sizeClass, 'shrink-0')}>\n <Avatar size={size === 'sm' ? 'xs' : 'sm'}>\n {src && <AvatarImage src={src} alt={fallback ?? ''} />}\n <AvatarFallback>{fallback ?? ''}</AvatarFallback>\n </Avatar>\n </div>\n )\n}\nMessageAvatar.displayName = 'Message.Avatar'\n\n// ── Content ──────────────────────────────────────────────────────────────\n\nexport interface MessageContentProps extends React.HTMLAttributes<HTMLDivElement> {\n children: React.ReactNode\n}\n\nfunction MessageContent({ children, className, ...props }: MessageContentProps) {\n return (\n <div className={cn('min-w-0 flex-1 flex flex-col gap-ds-02', className)} {...props}>\n {children}\n </div>\n )\n}\nMessageContent.displayName = 'Message.Content'\n\n// ── Author ───────────────────────────────────────────────────────────────\n\nexport interface MessageAuthorProps {\n name: string\n badge?: React.ReactNode\n timestamp?: Date\n formattedTimestamp?: string\n timestampFormat?: (date: Date) => string\n}\n\nfunction defaultTimestampFormat(date: Date): string {\n return date.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' })\n}\n\nfunction MessageAuthor({\n name,\n badge,\n timestamp,\n formattedTimestamp,\n timestampFormat = defaultTimestampFormat,\n}: MessageAuthorProps) {\n const { grouped } = useMessageContext()\n\n if (grouped) return null\n\n const timeStr = formattedTimestamp\n ?? (timestamp ? timestampFormat(timestamp) : undefined)\n\n return (\n <div className=\"flex items-baseline gap-ds-02\">\n <span className=\"font-semibold text-ds-md text-surface-fg\">{name}</span>\n {badge}\n {timeStr && (\n <span className=\"text-ds-sm text-surface-fg-subtle/50\">{timeStr}</span>\n )}\n </div>\n )\n}\nMessageAuthor.displayName = 'Message.Author'\n\n// ── Body ─────────────────────────────────────────────────────────────────\n\nexport interface MessageBodyProps extends React.HTMLAttributes<HTMLDivElement> {\n children: React.ReactNode\n}\n\nfunction MessageBody({ children, className, ...props }: MessageBodyProps) {\n return (\n <div\n className={cn(\n 'text-ds-md leading-relaxed text-surface-fg whitespace-pre-wrap',\n className,\n )}\n {...props}\n >\n {children}\n </div>\n )\n}\nMessageBody.displayName = 'Message.Body'\n\n// ── EditableBody ─────────────────────────────────────────────────────────\n\nexport interface MessageEditableBodyProps {\n content: string\n onSave: (newContent: string) => void\n onCancel?: () => void\n canEdit?: boolean\n renderContent?: (content: string) => React.ReactNode\n}\n\nfunction MessageEditableBody({\n content,\n onSave,\n onCancel,\n canEdit = false,\n renderContent,\n}: MessageEditableBodyProps) {\n const [isEditing, setIsEditing] = React.useState(false)\n const [editDraft, setEditDraft] = React.useState(content)\n const textareaRef = React.useRef<HTMLTextAreaElement>(null)\n\n React.useEffect(() => {\n if (isEditing && textareaRef.current) {\n textareaRef.current.focus()\n textareaRef.current.select()\n }\n }, [isEditing])\n\n const handleStartEdit = React.useCallback(() => {\n if (!canEdit) return\n setEditDraft(content)\n setIsEditing(true)\n }, [canEdit, content])\n\n const handleSave = React.useCallback(() => {\n const trimmed = editDraft.trim()\n if (trimmed && trimmed !== content) {\n onSave(trimmed)\n }\n setIsEditing(false)\n }, [editDraft, content, onSave])\n\n const handleCancel = React.useCallback(() => {\n setIsEditing(false)\n setEditDraft(content)\n onCancel?.()\n }, [content, onCancel])\n\n const handleKeyDown = React.useCallback(\n (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault()\n handleSave()\n } else if (e.key === 'Escape') {\n e.preventDefault()\n handleCancel()\n }\n },\n [handleSave, handleCancel],\n )\n\n if (isEditing) {\n return (\n <div className=\"text-ds-md leading-relaxed\">\n <Textarea\n ref={textareaRef}\n value={editDraft}\n onChange={(e) => setEditDraft(e.target.value)}\n onKeyDown={handleKeyDown}\n onBlur={handleSave}\n // compact inline-edit overrides on top of the Textarea base\n className=\"resize-none rounded-control-inner bg-surface-raised-hover px-ds-02 py-ds-01 text-ds-md leading-relaxed\"\n rows={2}\n />\n <div className=\"mt-ds-01 text-ds-xs text-surface-fg-subtle/50\">\n Enter to save · Escape to cancel\n </div>\n </div>\n )\n }\n\n return (\n <div\n className={cn(\n 'text-ds-md leading-relaxed text-surface-fg whitespace-pre-wrap',\n canEdit && 'cursor-pointer hover:bg-surface-raised-hover rounded-control-inner transition-colors',\n )}\n onClick={handleStartEdit}\n role={canEdit ? 'button' : undefined}\n tabIndex={canEdit ? 0 : undefined}\n onKeyDown={\n canEdit\n ? (e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n handleStartEdit()\n }\n }\n : undefined\n }\n >\n {renderContent ? renderContent(content) : content}\n </div>\n )\n}\nMessageEditableBody.displayName = 'Message.EditableBody'\n\n// ── Reactions ────────────────────────────────────────────────────────────\n\nexport interface MessageReactionsProps {\n reactions: { emoji: string; count: number; reacted: boolean }[]\n onReact: (emoji: string) => void\n}\n\nfunction MessageReactions({ reactions, onReact }: MessageReactionsProps) {\n if (reactions.length === 0) return null\n\n return (\n <div className=\"flex flex-wrap gap-ds-02 mt-ds-03\">\n {reactions.map((r) => (\n <button\n key={r.emoji}\n type=\"button\"\n onClick={() => onReact(r.emoji)}\n aria-label={`${r.emoji} ${r.count} reaction${r.count !== 1 ? 's' : ''}${r.reacted ? ', you reacted' : ''}`}\n className={cn(\n 'inline-flex items-center gap-ds-01 rounded-pill px-ds-02 py-ds-01 text-ds-xs transition-colors',\n r.reacted\n ? 'bg-accent-3 ring-1 ring-accent-6'\n : 'bg-surface-raised-hover hover:bg-surface-raised-active',\n )}\n >\n <span>{r.emoji}</span>\n <span>{r.count}</span>\n </button>\n ))}\n </div>\n )\n}\nMessageReactions.displayName = 'Message.Reactions'\n\n// ── Actions (floating toolbar) ───────────────────────────────────────────\n\nexport interface MessageActionsProps {\n children: React.ReactNode\n delay?: number\n}\n\nfunction MessageActions({ children, delay = 100 }: MessageActionsProps) {\n return (\n <div\n className={cn(\n 'absolute -top-2 right-0 z-10',\n 'flex items-center gap-ds-01 rounded-control bg-surface-raised px-ds-01 py-ds-01 shadow-raised',\n 'opacity-0 group-hover/message:opacity-100 group-focus-within/message:opacity-100 transition-opacity duration-150',\n )}\n style={{ transitionDelay: `${delay}ms` }}\n >\n {children}\n </div>\n )\n}\nMessageActions.displayName = 'Message.Actions'\n\n// ── Action (single icon button) ──────────────────────────────────────────\n\nexport interface MessageActionProps {\n icon: IconInput\n label: string\n onClick: () => void\n variant?: 'default' | 'danger'\n}\n\nfunction MessageAction({\n icon,\n label,\n onClick,\n variant = 'default',\n}: MessageActionProps) {\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n onClick={onClick}\n aria-label={label}\n className={cn(\n 'p-ds-02 rounded-control-inner transition-colors',\n variant === 'default' &&\n 'text-surface-fg-subtle hover:text-surface-fg hover:bg-surface-raised-hover',\n variant === 'danger' &&\n 'text-surface-fg-subtle hover:text-error-11 hover:bg-surface-raised-hover',\n )}\n >\n <IconProvider size=\"xs\">{normalizeIcon(icon)}</IconProvider>\n </button>\n </TooltipTrigger>\n <TooltipContent>{label}</TooltipContent>\n </Tooltip>\n )\n}\nMessageAction.displayName = 'Message.Action'\n\n// ── Compound Export ──────────────────────────────────────────────────────\n\nexport const Message = Object.assign(MessageRoot, {\n Avatar: MessageAvatar,\n Content: MessageContent,\n Author: MessageAuthor,\n Body: MessageBody,\n EditableBody: MessageEditableBody,\n Reactions: MessageReactions,\n Actions: MessageActions,\n Action: MessageAction,\n})\n\nexport {\n type MessageContextValue,\n useMessageContext,\n}\n","'use client'\n\nimport { IconSend, IconSquare } from '@tabler/icons-react'\nimport * as React from 'react'\n\nimport { Button } from '../button'\nimport { Icon } from '../icon'\nimport { cn } from '../lib/utils'\n\nexport interface MessageInputProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onSubmit'> {\n onSubmit: (text: string) => void\n placeholder?: string\n disabled?: boolean\n isStreaming?: boolean\n onCancel?: () => void\n leadingSlot?: React.ReactNode\n trailingSlot?: React.ReactNode\n disclaimer?: string\n sendIcon?: React.ReactNode\n}\n\nconst MessageInput = React.forwardRef<HTMLDivElement, MessageInputProps>(\n (\n {\n onSubmit,\n placeholder = 'Type a message...',\n disabled = false,\n isStreaming = false,\n onCancel,\n leadingSlot,\n trailingSlot,\n disclaimer,\n sendIcon,\n className,\n ...props\n },\n ref,\n ) => {\n const [text, setText] = React.useState('')\n const textareaRef = React.useRef<HTMLTextAreaElement>(null)\n\n const resize = React.useCallback(() => {\n const el = textareaRef.current\n if (!el) return\n el.style.height = 'auto'\n el.style.height = `${Math.min(el.scrollHeight, 160)}px`\n }, [])\n\n const handleChange = React.useCallback(\n (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n setText(e.target.value)\n resize()\n },\n [resize],\n )\n\n const handleSend = React.useCallback(() => {\n const trimmed = text.trim()\n if (!trimmed || isStreaming) return\n onSubmit(trimmed)\n setText('')\n // Reset height after clearing\n if (textareaRef.current) {\n textareaRef.current.style.height = 'auto'\n }\n }, [text, isStreaming, onSubmit])\n\n const handleKeyDown = React.useCallback(\n (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault()\n if (!isStreaming) {\n handleSend()\n }\n }\n },\n [isStreaming, handleSend],\n )\n\n const isEmpty = text.trim().length === 0\n\n return (\n <div\n ref={ref}\n className={cn(\n 'border-t border-surface-border-subtle px-ds-05 py-ds-04',\n className,\n )}\n {...props}\n >\n <div className=\"flex items-end gap-ds-02 rounded-overlay-lg border border-surface-border bg-surface-base p-ds-03\">\n {leadingSlot}\n <textarea\n ref={textareaRef}\n value={text}\n onChange={handleChange}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n aria-label={placeholder || 'Type a message'}\n disabled={disabled}\n rows={1}\n className=\"flex-1 resize-none bg-transparent px-ds-02 py-ds-01 text-ds-sm text-surface-fg placeholder:text-surface-fg-subtle/50 focus:outline-hidden disabled:opacity-50\"\n style={{ maxHeight: 160 }}\n />\n {isStreaming ? (\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n color=\"error\"\n onClick={onCancel}\n aria-label=\"Stop\"\n >\n <Icon icon={IconSquare} size=\"sm\" />\n </Button>\n ) : (\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n onClick={handleSend}\n disabled={isEmpty || disabled}\n aria-label=\"Send\"\n >\n {sendIcon ?? <Icon icon={IconSend} size=\"sm\" />}\n </Button>\n )}\n {trailingSlot}\n </div>\n {disclaimer && (\n <p className=\"mt-ds-02 text-center text-ds-xs text-surface-fg-subtle/50\">\n {disclaimer}\n </p>\n )}\n </div>\n )\n },\n)\nMessageInput.displayName = 'MessageInput'\n\nexport { MessageInput }\n","'use client'\n\nimport { AnimatePresence,motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { tweens } from '../lib/motion'\nimport { cn } from '../lib/utils'\nimport { Spinner } from '../spinner'\n\nexport interface MessageListProps extends React.HTMLAttributes<HTMLDivElement> {\n children: React.ReactNode\n /** Auto-scroll to bottom when new content arrives (default true) */\n autoScroll?: boolean\n /** Number of new messages to show in the floating pill */\n newMessageCount?: number\n /** Called when user clicks the \"N new\" pill */\n onScrollToBottom?: () => void\n /** Called when user scrolls near the top — triggers load-more */\n onLoadMore?: () => void\n /** Whether more messages are currently being loaded */\n loadingMore?: boolean\n /** Content to render when there are no children */\n emptySlot?: React.ReactNode\n /** Custom scroll-to-bottom button (unused slot for future override) */\n scrollToBottomSlot?: React.ReactNode\n /** Content rendered above the scroll container (e.g. channel name) */\n headerSlot?: React.ReactNode\n}\n\nconst MessageList = React.forwardRef<HTMLDivElement, MessageListProps>(\n (\n {\n children,\n autoScroll = true,\n newMessageCount = 0,\n onScrollToBottom,\n onLoadMore,\n loadingMore = false,\n emptySlot,\n scrollToBottomSlot,\n headerSlot,\n className,\n ...props\n },\n ref,\n ) => {\n const scrollRef = React.useRef<HTMLDivElement>(null)\n const isAtBottomRef = React.useRef(true)\n const [isAtBottom, setIsAtBottom] = React.useState(true)\n const loadingMoreRef = React.useRef(false)\n const prevScrollHeightRef = React.useRef(0)\n\n const isEmpty = React.Children.count(children) === 0 && !loadingMore\n\n // ── Scroll handler ────────────────────────────────────────────\n const handleScroll = React.useCallback(() => {\n const el = scrollRef.current\n if (!el) return\n\n const atBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 40\n isAtBottomRef.current = atBottom\n setIsAtBottom(atBottom)\n\n // Load more when near top\n if (el.scrollTop < 100 && onLoadMore && !loadingMoreRef.current) {\n loadingMoreRef.current = true\n prevScrollHeightRef.current = el.scrollHeight\n onLoadMore()\n }\n }, [onLoadMore])\n\n // ── Auto-scroll to bottom when children change ────────────────\n React.useLayoutEffect(() => {\n const el = scrollRef.current\n if (!el) return\n\n // Scroll preservation after load-more\n if (loadingMoreRef.current) {\n const newScrollHeight = el.scrollHeight\n el.scrollTop = newScrollHeight - prevScrollHeightRef.current\n loadingMoreRef.current = false\n return\n }\n\n // Auto-scroll if user was at bottom\n if (autoScroll && isAtBottomRef.current) {\n el.scrollTo({ top: el.scrollHeight, behavior: 'smooth' })\n }\n }, [children, autoScroll])\n\n // ── Reset loading flag when loadingMore goes false ──────────\n React.useEffect(() => {\n if (!loadingMore) {\n loadingMoreRef.current = false\n }\n }, [loadingMore])\n\n // ── \"N new\" pill visibility ───────────────────────────────────\n const showNewPill = newMessageCount > 0 && !isAtBottom\n\n const handleScrollToBottom = React.useCallback(() => {\n const el = scrollRef.current\n if (el) {\n el.scrollTo({ top: el.scrollHeight, behavior: 'smooth' })\n }\n onScrollToBottom?.()\n }, [onScrollToBottom])\n\n return (\n <div\n ref={ref}\n className={cn('relative flex flex-1 flex-col overflow-hidden', className)}\n {...props}\n >\n {headerSlot}\n <div\n ref={scrollRef}\n role=\"log\"\n aria-live=\"polite\"\n aria-relevant=\"additions\"\n className=\"flex-1 overflow-y-auto px-ds-05 py-ds-04\"\n style={{\n scrollbarWidth: 'thin',\n scrollbarColor: 'var(--color-surface-border) transparent',\n }}\n onScroll={handleScroll}\n >\n {loadingMore && (\n <div className=\"flex justify-center py-ds-03\">\n <Spinner size=\"sm\" />\n </div>\n )}\n {isEmpty ? (\n emptySlot\n ) : (\n <div className=\"flex flex-col gap-ds-04\">\n <AnimatePresence initial={false}>{children}</AnimatePresence>\n </div>\n )}\n </div>\n\n {/* \"N new\" floating pill */}\n <AnimatePresence>\n {showNewPill && (\n <motion.button\n initial={{ opacity: 0, y: 10 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: 10 }}\n transition={tweens.fade}\n onClick={handleScrollToBottom}\n className=\"absolute bottom-ds-04 left-1/2 z-10 -translate-x-1/2 rounded-pill bg-accent-9 px-ds-04 py-ds-02 text-ds-xs font-medium text-accent-fg shadow-raised transition-colors hover:bg-accent-10\"\n >\n {newMessageCount} new\n </motion.button>\n )}\n </AnimatePresence>\n </div>\n )\n },\n)\nMessageList.displayName = 'MessageList'\n\nexport { MessageList }\n","'use client'\n\nimport { IconAlertCircle } from '@tabler/icons-react'\nimport * as React from 'react'\n\nimport { Icon } from '../icon'\nimport { IconProvider } from '../icon-context'\nimport type { IconInput } from '../lib/icon-input'\nimport { normalizeIcon } from '../lib/normalize-icon'\nimport { cn } from '../lib/utils'\n\nexport interface SystemMessageProps extends React.HTMLAttributes<HTMLDivElement> {\n icon?: IconInput\n timestamp?: string\n variant?: 'event' | 'alert'\n children: React.ReactNode\n}\n\nfunction formatTime(ts: string): string {\n return new Date(ts).toLocaleTimeString('en-US', {\n hour: 'numeric',\n minute: '2-digit',\n })\n}\n\nconst SystemMessage = React.forwardRef<HTMLDivElement, SystemMessageProps>(\n ({ icon, timestamp, variant = 'event', children, className, ...props }, ref) => {\n if (variant === 'alert') {\n return (\n <div\n ref={ref}\n role=\"alert\"\n className={cn('flex justify-center', className)}\n {...props}\n >\n <div className=\"flex items-center gap-ds-03 rounded-surface bg-error-3 px-ds-04 py-ds-03\">\n <IconProvider size=\"sm\">{normalizeIcon(icon) ?? <Icon icon={IconAlertCircle} />}</IconProvider>\n <span className=\"text-ds-sm text-error-11\">{children}</span>\n {timestamp && (\n <span className=\"text-ds-sm text-error-11/60\">\n {formatTime(timestamp)}\n </span>\n )}\n </div>\n </div>\n )\n }\n\n // event variant (default)\n return (\n <div\n ref={ref}\n className={cn(\n 'flex items-center gap-ds-02 rounded-control-inner bg-surface-raised-hover/30 px-ds-02 py-ds-01 -mx-ds-02 text-ds-sm text-surface-fg-subtle/60',\n className,\n )}\n {...props}\n >\n <IconProvider size=\"xs\">{normalizeIcon(icon)}</IconProvider>\n <span className=\"flex-1\">{children}</span>\n {timestamp && <span>{formatTime(timestamp)}</span>}\n </div>\n )\n },\n)\nSystemMessage.displayName = 'SystemMessage'\n\nexport { SystemMessage }\n","'use client'\n\nimport { AnimatePresence,motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { cn } from '../lib/utils'\n\nexport interface TypingIndicatorProps {\n users: { name: string; image?: string }[]\n className?: string\n}\n\nfunction formatTypingText(users: { name: string }[]): string {\n if (users.length === 1) return `${users[0].name} is typing...`\n if (users.length === 2) return `${users[0].name} and ${users[1].name} are typing...`\n return 'Several people are typing...'\n}\n\nfunction TypingIndicator({ users, className }: TypingIndicatorProps) {\n return (\n <div className={cn('min-h-ds-06 px-ds-05', className)} role=\"status\" aria-live=\"polite\">\n <AnimatePresence>\n {users.length > 0 && (\n <motion.div\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n className=\"flex items-center gap-ds-02 text-ds-xs text-surface-fg-subtle\"\n >\n <span className=\"flex items-center gap-ds-01\">\n {[0, 1, 2].map((i) => (\n <motion.span\n key={i}\n className=\"h-1 w-1 rounded-pill bg-surface-fg-subtle\"\n animate={{ y: [0, -3, 0] }}\n transition={{\n duration: 0.5,\n repeat: Infinity,\n delay: i * 0.15,\n }}\n />\n ))}\n </span>\n <span>{formatTypingText(users)}</span>\n </motion.div>\n )}\n </AnimatePresence>\n </div>\n )\n}\nTypingIndicator.displayName = 'TypingIndicator'\n\nexport { TypingIndicator }\n","import * as React from 'react'\n\nimport { cn } from '../lib/utils'\n\nexport interface UnreadSeparatorProps {\n label?: string\n count?: number\n className?: string\n}\n\nfunction UnreadSeparator({\n label = 'NEW',\n count,\n className,\n}: UnreadSeparatorProps) {\n return (\n <div className={cn('relative flex items-center py-ds-02', className)}>\n <div className=\"flex-1 border-t-2 border-accent-7\" />\n <span className=\"px-ds-03 text-ds-xs font-semibold text-accent-11\">\n {count ? `${count} ${label}` : label}\n </span>\n <div className=\"flex-1 border-t-2 border-accent-7\" />\n </div>\n )\n}\nUnreadSeparator.displayName = 'UnreadSeparator'\n\nexport { UnreadSeparator }\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"chat.js","names":[],"sources":["../../src/ui/chat/date-separator.tsx","../../src/ui/chat/message.tsx","../../src/ui/chat/message-input.tsx","../../src/ui/chat/message-list.tsx","../../src/ui/chat/system-message.tsx","../../src/ui/chat/typing-indicator.tsx","../../src/ui/chat/unread-separator.tsx"],"sourcesContent":["import * as React from 'react'\n\nimport { cn } from '../lib/utils'\n\nexport interface DateSeparatorProps {\n date: Date | string\n format?: (date: Date) => string\n className?: string\n}\n\nfunction defaultFormat(date: Date): string {\n const now = new Date()\n const today = new Date(now.getFullYear(), now.getMonth(), now.getDate())\n const target = new Date(date.getFullYear(), date.getMonth(), date.getDate())\n const diffMs = today.getTime() - target.getTime()\n const diffDays = Math.round(diffMs / (1000 * 60 * 60 * 24))\n\n if (diffDays === 0) return 'Today'\n if (diffDays === 1) return 'Yesterday'\n\n const month = date.toLocaleString('en-US', { month: 'short' })\n const day = date.getDate()\n\n if (date.getFullYear() !== now.getFullYear()) {\n return `${month} ${day}, ${date.getFullYear()}`\n }\n\n return `${month} ${day}`\n}\n\nfunction DateSeparator({ date, format, className }: DateSeparatorProps) {\n const d = typeof date === 'string' ? new Date(date) : date\n const label = format ? format(d) : defaultFormat(d)\n\n return (\n <div className={cn('flex items-center gap-ds-03 py-ds-03', className)}>\n <div className=\"flex-1 border-t border-surface-border-subtle\" />\n <span className=\"text-ds-xs font-medium text-surface-fg-subtle/50 uppercase tracking-wider\">\n {label}\n </span>\n <div className=\"flex-1 border-t border-surface-border-subtle\" />\n </div>\n )\n}\nDateSeparator.displayName = 'DateSeparator'\n\nexport { DateSeparator }\n","'use client'\n\nimport { IconTrash } from '@tabler/icons-react'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { Avatar, AvatarFallback,AvatarImage } from '../avatar'\nimport { Icon } from '../icon'\nimport { IconProvider } from '../icon-context'\nimport type { IconInput } from '../lib/icon-input'\nimport { MENTION_TOKEN_CLASS } from '../lib/mention'\nimport { motionProps,springs } from '../lib/motion'\nimport { normalizeIcon } from '../lib/normalize-icon'\nimport { cn } from '../lib/utils'\nimport { Textarea } from '../textarea'\nimport { Tooltip, TooltipContent,TooltipTrigger } from '../tooltip'\n\n// ── Context ──────────────────────────────────────────────────────────────\n\ninterface MessageContextValue {\n variant: 'flat' | 'bubble'\n placement: 'start' | 'end'\n grouped: boolean\n highlight?: 'mention' | 'internal'\n}\n\nconst MessageContext = React.createContext<MessageContextValue>({\n variant: 'flat',\n placement: 'start',\n grouped: false,\n})\n\nfunction useMessageContext() {\n return React.useContext(MessageContext)\n}\n\n// ── Root ─────────────────────────────────────────────────────────────────\n\nexport interface MessageProps extends React.HTMLAttributes<HTMLDivElement> {\n children: React.ReactNode\n variant?: 'flat' | 'bubble'\n placement?: 'start' | 'end'\n highlight?: 'mention' | 'internal'\n grouped?: boolean\n deleted?: boolean\n deletedText?: string\n}\n\nconst MessageRoot = React.forwardRef<HTMLDivElement, MessageProps>(\n (\n {\n children,\n variant = 'flat',\n placement = 'start',\n highlight,\n grouped = false,\n deleted = false,\n deletedText = 'This message was deleted',\n className,\n ...props\n },\n ref,\n ) => {\n const ctx = React.useMemo<MessageContextValue>(\n () => ({ variant, placement, grouped, highlight }),\n [variant, placement, grouped, highlight],\n )\n\n if (deleted) {\n return (\n <motion.div\n ref={ref}\n initial={{ y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n transition={springs.snappy}\n className={cn(\n 'flex items-center gap-ds-02 py-ds-02 text-ds-xs text-surface-fg-subtle/50 italic',\n className,\n )}\n {...motionProps(props)}\n >\n <Icon icon={IconTrash} size=\"xs\" />\n {deletedText}\n </motion.div>\n )\n }\n\n if (variant === 'bubble') {\n return (\n <MessageContext.Provider value={ctx}>\n <motion.div\n ref={ref}\n data-highlight={highlight}\n initial={{ y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n transition={springs.snappy}\n className={cn(\n 'group/message relative flex',\n placement === 'end' ? 'justify-end' : 'justify-start',\n // mention is carried by the styled in-content @token (see MENTION_TOKEN_CLASS), not a row tint/rail\n MENTION_TOKEN_CLASS,\n highlight === 'internal' && 'bg-warning-2/50 rounded-control-inner',\n className,\n )}\n {...motionProps(props)}\n >\n <div\n className={cn(\n 'max-w-[85%] rounded-bubble px-ds-04 py-ds-03',\n placement === 'end'\n ? 'bg-accent-3 text-surface-fg'\n : 'bg-surface-raised text-surface-fg',\n )}\n >\n {children}\n </div>\n </motion.div>\n </MessageContext.Provider>\n )\n }\n\n // flat variant (default)\n return (\n <MessageContext.Provider value={ctx}>\n <motion.div\n ref={ref}\n data-highlight={highlight}\n initial={{ y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n transition={springs.snappy}\n className={cn(\n 'group/message relative flex gap-ds-04',\n grouped && '-mt-ds-01',\n // mention is carried by the styled in-content @token (see MENTION_TOKEN_CLASS), not a row rail/tint\n MENTION_TOKEN_CLASS,\n highlight === 'internal' && 'bg-warning-2/50 rounded-control-inner',\n className,\n )}\n {...motionProps(props)}\n >\n {children}\n </motion.div>\n </MessageContext.Provider>\n )\n },\n)\nMessageRoot.displayName = 'Message'\n\n// ── Avatar ───────────────────────────────────────────────────────────────\n\nexport interface MessageAvatarProps {\n src?: string | null\n fallback?: string\n icon?: IconInput\n size?: 'sm' | 'md'\n children?: React.ReactNode\n}\n\nfunction MessageAvatar({\n src,\n fallback,\n icon,\n size = 'md',\n children,\n}: MessageAvatarProps) {\n const { grouped } = useMessageContext()\n\n const sizeClass = size === 'sm' ? 'w-5' : 'w-6'\n const heightClass = size === 'sm' ? 'h-5' : 'h-6'\n\n if (grouped) {\n return <div className={cn(sizeClass, heightClass, 'shrink-0')} />\n }\n\n if (children) {\n return (\n <div className={cn(sizeClass, 'shrink-0 flex items-start')}>\n {children}\n </div>\n )\n }\n\n if (icon) {\n return (\n <div\n className={cn(\n sizeClass,\n size === 'sm' ? 'h-5' : 'h-6',\n 'shrink-0 flex items-center justify-center rounded-pill bg-surface-raised-hover',\n )}\n >\n <IconProvider size={size === 'sm' ? 'xs' : 'sm'}>{normalizeIcon(icon)}</IconProvider>\n </div>\n )\n }\n\n return (\n <div className={cn(sizeClass, 'shrink-0')}>\n <Avatar size={size === 'sm' ? 'xs' : 'sm'}>\n {src && <AvatarImage src={src} alt={fallback ?? ''} />}\n <AvatarFallback>{fallback ?? ''}</AvatarFallback>\n </Avatar>\n </div>\n )\n}\nMessageAvatar.displayName = 'Message.Avatar'\n\n// ── Content ──────────────────────────────────────────────────────────────\n\nexport interface MessageContentProps extends React.HTMLAttributes<HTMLDivElement> {\n children: React.ReactNode\n}\n\nfunction MessageContent({ children, className, ...props }: MessageContentProps) {\n return (\n <div className={cn('min-w-0 flex-1 flex flex-col gap-ds-02', className)} {...props}>\n {children}\n </div>\n )\n}\nMessageContent.displayName = 'Message.Content'\n\n// ── Author ───────────────────────────────────────────────────────────────\n\nexport interface MessageAuthorProps {\n name: string\n badge?: React.ReactNode\n timestamp?: Date\n formattedTimestamp?: string\n timestampFormat?: (date: Date) => string\n}\n\nfunction defaultTimestampFormat(date: Date): string {\n return date.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' })\n}\n\nfunction MessageAuthor({\n name,\n badge,\n timestamp,\n formattedTimestamp,\n timestampFormat = defaultTimestampFormat,\n}: MessageAuthorProps) {\n const { grouped } = useMessageContext()\n\n if (grouped) return null\n\n const timeStr = formattedTimestamp\n ?? (timestamp ? timestampFormat(timestamp) : undefined)\n\n return (\n <div className=\"flex items-baseline gap-ds-02\">\n <span className=\"font-semibold text-ds-md text-surface-fg\">{name}</span>\n {badge}\n {timeStr && (\n <span className=\"text-ds-sm text-surface-fg-subtle/50\">{timeStr}</span>\n )}\n </div>\n )\n}\nMessageAuthor.displayName = 'Message.Author'\n\n// ── Body ─────────────────────────────────────────────────────────────────\n\nexport interface MessageBodyProps extends React.HTMLAttributes<HTMLDivElement> {\n children: React.ReactNode\n}\n\nfunction MessageBody({ children, className, ...props }: MessageBodyProps) {\n return (\n <div\n className={cn(\n 'text-ds-md leading-relaxed text-surface-fg whitespace-pre-wrap',\n className,\n )}\n {...props}\n >\n {children}\n </div>\n )\n}\nMessageBody.displayName = 'Message.Body'\n\n// ── EditableBody ─────────────────────────────────────────────────────────\n\nexport interface MessageEditableBodyProps {\n content: string\n onSave: (newContent: string) => void\n onCancel?: () => void\n canEdit?: boolean\n renderContent?: (content: string) => React.ReactNode\n}\n\nfunction MessageEditableBody({\n content,\n onSave,\n onCancel,\n canEdit = false,\n renderContent,\n}: MessageEditableBodyProps) {\n const [isEditing, setIsEditing] = React.useState(false)\n const [editDraft, setEditDraft] = React.useState(content)\n const textareaRef = React.useRef<HTMLTextAreaElement>(null)\n\n React.useEffect(() => {\n if (isEditing && textareaRef.current) {\n textareaRef.current.focus()\n textareaRef.current.select()\n }\n }, [isEditing])\n\n const handleStartEdit = React.useCallback(() => {\n if (!canEdit) return\n setEditDraft(content)\n setIsEditing(true)\n }, [canEdit, content])\n\n const handleSave = React.useCallback(() => {\n const trimmed = editDraft.trim()\n if (trimmed && trimmed !== content) {\n onSave(trimmed)\n }\n setIsEditing(false)\n }, [editDraft, content, onSave])\n\n const handleCancel = React.useCallback(() => {\n setIsEditing(false)\n setEditDraft(content)\n onCancel?.()\n }, [content, onCancel])\n\n const handleKeyDown = React.useCallback(\n (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault()\n handleSave()\n } else if (e.key === 'Escape') {\n e.preventDefault()\n handleCancel()\n }\n },\n [handleSave, handleCancel],\n )\n\n if (isEditing) {\n return (\n <div className=\"text-ds-md leading-relaxed\">\n <Textarea\n ref={textareaRef}\n value={editDraft}\n onChange={(e) => setEditDraft(e.target.value)}\n onKeyDown={handleKeyDown}\n onBlur={handleSave}\n // compact inline-edit overrides on top of the Textarea base\n className=\"resize-none rounded-control-inner bg-surface-raised-hover px-ds-02 py-ds-01 text-ds-md leading-relaxed\"\n rows={2}\n />\n <div className=\"mt-ds-01 text-ds-xs text-surface-fg-subtle/50\">\n Enter to save · Escape to cancel\n </div>\n </div>\n )\n }\n\n return (\n <div\n className={cn(\n 'text-ds-md leading-relaxed text-surface-fg whitespace-pre-wrap',\n canEdit && 'cursor-pointer hover:bg-surface-raised-hover rounded-control-inner transition-colors',\n )}\n onClick={handleStartEdit}\n role={canEdit ? 'button' : undefined}\n tabIndex={canEdit ? 0 : undefined}\n onKeyDown={\n canEdit\n ? (e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n handleStartEdit()\n }\n }\n : undefined\n }\n >\n {renderContent ? renderContent(content) : content}\n </div>\n )\n}\nMessageEditableBody.displayName = 'Message.EditableBody'\n\n// ── Reactions ────────────────────────────────────────────────────────────\n\nexport interface MessageReactionsProps {\n reactions: { emoji: string; count: number; reacted: boolean }[]\n onReact: (emoji: string) => void\n}\n\nfunction MessageReactions({ reactions, onReact }: MessageReactionsProps) {\n if (reactions.length === 0) return null\n\n return (\n <div className=\"flex flex-wrap gap-ds-02 mt-ds-03\">\n {reactions.map((r) => (\n <button\n key={r.emoji}\n type=\"button\"\n onClick={() => onReact(r.emoji)}\n aria-label={`${r.emoji} ${r.count} reaction${r.count !== 1 ? 's' : ''}${r.reacted ? ', you reacted' : ''}`}\n className={cn(\n 'inline-flex items-center gap-ds-01 rounded-pill px-ds-02 py-ds-01 text-ds-xs transition-colors',\n r.reacted\n ? 'bg-accent-3 ring-1 ring-accent-6'\n : 'bg-surface-raised-hover hover:bg-surface-raised-active',\n )}\n >\n <span>{r.emoji}</span>\n <span>{r.count}</span>\n </button>\n ))}\n </div>\n )\n}\nMessageReactions.displayName = 'Message.Reactions'\n\n// ── Actions (floating toolbar) ───────────────────────────────────────────\n\nexport interface MessageActionsProps {\n children: React.ReactNode\n delay?: number\n}\n\nfunction MessageActions({ children, delay = 100 }: MessageActionsProps) {\n return (\n <div\n className={cn(\n 'absolute -top-2 right-0 z-10',\n 'flex items-center gap-ds-01 rounded-control bg-surface-raised px-ds-01 py-ds-01 shadow-raised',\n 'opacity-0 group-hover/message:opacity-100 group-focus-within/message:opacity-100 transition-opacity duration-150',\n )}\n style={{ transitionDelay: `${delay}ms` }}\n >\n {children}\n </div>\n )\n}\nMessageActions.displayName = 'Message.Actions'\n\n// ── Action (single icon button) ──────────────────────────────────────────\n\nexport interface MessageActionProps {\n icon: IconInput\n label: string\n onClick: () => void\n variant?: 'default' | 'danger'\n}\n\nfunction MessageAction({\n icon,\n label,\n onClick,\n variant = 'default',\n}: MessageActionProps) {\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n onClick={onClick}\n aria-label={label}\n className={cn(\n 'p-ds-02 rounded-control-inner transition-colors',\n variant === 'default' &&\n 'text-surface-fg-subtle hover:text-surface-fg hover:bg-surface-raised-hover',\n variant === 'danger' &&\n 'text-surface-fg-subtle hover:text-error-11 hover:bg-surface-raised-hover',\n )}\n >\n <IconProvider size=\"xs\">{normalizeIcon(icon)}</IconProvider>\n </button>\n </TooltipTrigger>\n <TooltipContent>{label}</TooltipContent>\n </Tooltip>\n )\n}\nMessageAction.displayName = 'Message.Action'\n\n// ── Compound Export ──────────────────────────────────────────────────────\n\nexport const Message = Object.assign(MessageRoot, {\n Avatar: MessageAvatar,\n Content: MessageContent,\n Author: MessageAuthor,\n Body: MessageBody,\n EditableBody: MessageEditableBody,\n Reactions: MessageReactions,\n Actions: MessageActions,\n Action: MessageAction,\n})\n\nexport {\n type MessageContextValue,\n useMessageContext,\n}\n","'use client'\n\nimport { IconSend, IconSquare } from '@tabler/icons-react'\nimport * as React from 'react'\n\nimport { Button } from '../button'\nimport { Icon } from '../icon'\nimport { cn } from '../lib/utils'\n\nexport interface MessageInputProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onSubmit'> {\n onSubmit: (text: string) => void\n placeholder?: string\n disabled?: boolean\n isStreaming?: boolean\n onCancel?: () => void\n leadingSlot?: React.ReactNode\n trailingSlot?: React.ReactNode\n disclaimer?: string\n sendIcon?: React.ReactNode\n}\n\nconst MessageInput = React.forwardRef<HTMLDivElement, MessageInputProps>(\n (\n {\n onSubmit,\n placeholder = 'Type a message...',\n disabled = false,\n isStreaming = false,\n onCancel,\n leadingSlot,\n trailingSlot,\n disclaimer,\n sendIcon,\n className,\n ...props\n },\n ref,\n ) => {\n const [text, setText] = React.useState('')\n const textareaRef = React.useRef<HTMLTextAreaElement>(null)\n\n const resize = React.useCallback(() => {\n const el = textareaRef.current\n if (!el) return\n el.style.height = 'auto'\n el.style.height = `${Math.min(el.scrollHeight, 160)}px`\n }, [])\n\n const handleChange = React.useCallback(\n (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n setText(e.target.value)\n resize()\n },\n [resize],\n )\n\n const handleSend = React.useCallback(() => {\n const trimmed = text.trim()\n if (!trimmed || isStreaming) return\n onSubmit(trimmed)\n setText('')\n // Reset height after clearing\n if (textareaRef.current) {\n textareaRef.current.style.height = 'auto'\n }\n }, [text, isStreaming, onSubmit])\n\n const handleKeyDown = React.useCallback(\n (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault()\n if (!isStreaming) {\n handleSend()\n }\n }\n },\n [isStreaming, handleSend],\n )\n\n const isEmpty = text.trim().length === 0\n\n return (\n <div\n ref={ref}\n className={cn(\n 'border-t border-surface-border-subtle px-ds-05 py-ds-04',\n className,\n )}\n {...props}\n >\n <div className=\"flex items-end gap-ds-02 rounded-overlay-lg border border-surface-border bg-surface-base p-ds-03\">\n {leadingSlot}\n <textarea\n ref={textareaRef}\n value={text}\n onChange={handleChange}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n aria-label={placeholder || 'Type a message'}\n disabled={disabled}\n rows={1}\n className=\"flex-1 resize-none bg-transparent px-ds-02 py-ds-01 text-ds-sm text-surface-fg placeholder:text-surface-fg-subtle/50 focus:outline-hidden disabled:opacity-50\"\n style={{ maxHeight: 160 }}\n />\n {isStreaming ? (\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n color=\"error\"\n onClick={onCancel}\n aria-label=\"Stop\"\n >\n <Icon icon={IconSquare} size=\"sm\" />\n </Button>\n ) : (\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n onClick={handleSend}\n disabled={isEmpty || disabled}\n aria-label=\"Send\"\n >\n {sendIcon ?? <Icon icon={IconSend} size=\"sm\" />}\n </Button>\n )}\n {trailingSlot}\n </div>\n {disclaimer && (\n <p className=\"mt-ds-02 text-center text-ds-xs text-surface-fg-subtle/50\">\n {disclaimer}\n </p>\n )}\n </div>\n )\n },\n)\nMessageInput.displayName = 'MessageInput'\n\nexport { MessageInput }\n","'use client'\n\nimport { AnimatePresence,motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { tweens } from '../lib/motion'\nimport { cn } from '../lib/utils'\nimport { Spinner } from '../spinner'\n\nexport interface MessageListProps extends React.HTMLAttributes<HTMLDivElement> {\n children: React.ReactNode\n /** Auto-scroll to bottom when new content arrives (default true) */\n autoScroll?: boolean\n /** Number of new messages to show in the floating pill */\n newMessageCount?: number\n /** Called when user clicks the \"N new\" pill */\n onScrollToBottom?: () => void\n /** Called when user scrolls near the top — triggers load-more */\n onLoadMore?: () => void\n /** Whether more messages are currently being loaded */\n loadingMore?: boolean\n /** Content to render when there are no children */\n emptySlot?: React.ReactNode\n /** Custom scroll-to-bottom button (unused slot for future override) */\n scrollToBottomSlot?: React.ReactNode\n /** Content rendered above the scroll container (e.g. channel name) */\n headerSlot?: React.ReactNode\n}\n\nconst MessageList = React.forwardRef<HTMLDivElement, MessageListProps>(\n (\n {\n children,\n autoScroll = true,\n newMessageCount = 0,\n onScrollToBottom,\n onLoadMore,\n loadingMore = false,\n emptySlot,\n scrollToBottomSlot,\n headerSlot,\n className,\n ...props\n },\n ref,\n ) => {\n const scrollRef = React.useRef<HTMLDivElement>(null)\n const isAtBottomRef = React.useRef(true)\n const [isAtBottom, setIsAtBottom] = React.useState(true)\n const loadingMoreRef = React.useRef(false)\n const prevScrollHeightRef = React.useRef(0)\n\n const isEmpty = React.Children.count(children) === 0 && !loadingMore\n\n // ── Scroll handler ────────────────────────────────────────────\n const handleScroll = React.useCallback(() => {\n const el = scrollRef.current\n if (!el) return\n\n const atBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 40\n isAtBottomRef.current = atBottom\n setIsAtBottom(atBottom)\n\n // Load more when near top\n if (el.scrollTop < 100 && onLoadMore && !loadingMoreRef.current) {\n loadingMoreRef.current = true\n prevScrollHeightRef.current = el.scrollHeight\n onLoadMore()\n }\n }, [onLoadMore])\n\n // ── Auto-scroll to bottom when children change ────────────────\n React.useLayoutEffect(() => {\n const el = scrollRef.current\n if (!el) return\n\n // Scroll preservation after load-more\n if (loadingMoreRef.current) {\n const newScrollHeight = el.scrollHeight\n el.scrollTop = newScrollHeight - prevScrollHeightRef.current\n loadingMoreRef.current = false\n return\n }\n\n // Auto-scroll if user was at bottom\n if (autoScroll && isAtBottomRef.current) {\n el.scrollTo({ top: el.scrollHeight, behavior: 'smooth' })\n }\n }, [children, autoScroll])\n\n // ── Reset loading flag when loadingMore goes false ──────────\n React.useEffect(() => {\n if (!loadingMore) {\n loadingMoreRef.current = false\n }\n }, [loadingMore])\n\n // ── \"N new\" pill visibility ───────────────────────────────────\n const showNewPill = newMessageCount > 0 && !isAtBottom\n\n const handleScrollToBottom = React.useCallback(() => {\n const el = scrollRef.current\n if (el) {\n el.scrollTo({ top: el.scrollHeight, behavior: 'smooth' })\n }\n onScrollToBottom?.()\n }, [onScrollToBottom])\n\n return (\n <div\n ref={ref}\n className={cn('relative flex flex-1 flex-col overflow-hidden', className)}\n {...props}\n >\n {headerSlot}\n <div\n ref={scrollRef}\n role=\"log\"\n aria-live=\"polite\"\n aria-relevant=\"additions\"\n className=\"flex-1 overflow-y-auto px-ds-05 py-ds-04\"\n style={{\n scrollbarWidth: 'thin',\n scrollbarColor: 'var(--color-surface-border) transparent',\n }}\n onScroll={handleScroll}\n >\n {loadingMore && (\n <div className=\"flex justify-center py-ds-03\">\n <Spinner size=\"sm\" />\n </div>\n )}\n {isEmpty ? (\n emptySlot\n ) : (\n <div className=\"flex flex-col gap-ds-04\">\n <AnimatePresence initial={false}>{children}</AnimatePresence>\n </div>\n )}\n </div>\n\n {/* \"N new\" floating pill */}\n <AnimatePresence>\n {showNewPill && (\n <motion.button\n initial={{ opacity: 0, y: 10 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: 10 }}\n transition={tweens.fade}\n onClick={handleScrollToBottom}\n className=\"absolute bottom-ds-04 left-1/2 z-10 -translate-x-1/2 rounded-pill bg-accent-9 px-ds-04 py-ds-02 text-ds-xs font-medium text-accent-fg shadow-raised transition-colors hover:bg-accent-10\"\n >\n {newMessageCount} new\n </motion.button>\n )}\n </AnimatePresence>\n </div>\n )\n },\n)\nMessageList.displayName = 'MessageList'\n\nexport { MessageList }\n","'use client'\n\nimport { IconAlertCircle } from '@tabler/icons-react'\nimport * as React from 'react'\n\nimport { Icon } from '../icon'\nimport { IconProvider } from '../icon-context'\nimport type { IconInput } from '../lib/icon-input'\nimport { normalizeIcon } from '../lib/normalize-icon'\nimport { cn } from '../lib/utils'\n\nexport interface SystemMessageProps extends React.HTMLAttributes<HTMLDivElement> {\n icon?: IconInput\n timestamp?: string\n variant?: 'event' | 'alert'\n children: React.ReactNode\n}\n\nfunction formatTime(ts: string): string {\n return new Date(ts).toLocaleTimeString('en-US', {\n hour: 'numeric',\n minute: '2-digit',\n })\n}\n\nconst SystemMessage = React.forwardRef<HTMLDivElement, SystemMessageProps>(\n ({ icon, timestamp, variant = 'event', children, className, ...props }, ref) => {\n if (variant === 'alert') {\n return (\n <div\n ref={ref}\n role=\"alert\"\n className={cn('flex justify-center', className)}\n {...props}\n >\n <div className=\"flex items-center gap-ds-03 rounded-surface bg-error-3 px-ds-04 py-ds-03\">\n <IconProvider size=\"sm\">{normalizeIcon(icon) ?? <Icon icon={IconAlertCircle} />}</IconProvider>\n <span className=\"text-ds-sm text-error-11\">{children}</span>\n {timestamp && (\n <span className=\"text-ds-sm text-error-11/60\">\n {formatTime(timestamp)}\n </span>\n )}\n </div>\n </div>\n )\n }\n\n // event variant (default)\n return (\n <div\n ref={ref}\n className={cn(\n 'flex items-center gap-ds-02 rounded-control-inner bg-surface-raised-hover/30 px-ds-02 py-ds-01 -mx-ds-02 text-ds-sm text-surface-fg-subtle/60',\n className,\n )}\n {...props}\n >\n <IconProvider size=\"xs\">{normalizeIcon(icon)}</IconProvider>\n <span className=\"flex-1\">{children}</span>\n {timestamp && <span>{formatTime(timestamp)}</span>}\n </div>\n )\n },\n)\nSystemMessage.displayName = 'SystemMessage'\n\nexport { SystemMessage }\n","'use client'\n\nimport { AnimatePresence,motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { cn } from '../lib/utils'\n\nexport interface TypingIndicatorProps {\n users: { name: string; image?: string }[]\n className?: string\n}\n\nfunction formatTypingText(users: { name: string }[]): string {\n if (users.length === 1) return `${users[0].name} is typing...`\n if (users.length === 2) return `${users[0].name} and ${users[1].name} are typing...`\n return 'Several people are typing...'\n}\n\nfunction TypingIndicator({ users, className }: TypingIndicatorProps) {\n return (\n <div className={cn('min-h-ds-06 px-ds-05', className)} role=\"status\" aria-live=\"polite\">\n <AnimatePresence>\n {users.length > 0 && (\n <motion.div\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n className=\"flex items-center gap-ds-02 text-ds-xs text-surface-fg-subtle\"\n >\n <span className=\"flex items-center gap-ds-01\">\n {[0, 1, 2].map((i) => (\n <motion.span\n key={i}\n className=\"h-1 w-1 rounded-pill bg-surface-fg-subtle\"\n animate={{ y: [0, -3, 0] }}\n transition={{\n duration: 0.5,\n repeat: Infinity,\n delay: i * 0.15,\n }}\n />\n ))}\n </span>\n <span>{formatTypingText(users)}</span>\n </motion.div>\n )}\n </AnimatePresence>\n </div>\n )\n}\nTypingIndicator.displayName = 'TypingIndicator'\n\nexport { TypingIndicator }\n","import * as React from 'react'\n\nimport { cn } from '../lib/utils'\n\nexport interface UnreadSeparatorProps {\n label?: string\n count?: number\n className?: string\n}\n\nfunction UnreadSeparator({\n label = 'NEW',\n count,\n className,\n}: UnreadSeparatorProps) {\n return (\n <div className={cn('relative flex items-center py-ds-02', className)}>\n <div className=\"flex-1 border-t-2 border-accent-7\" />\n <span className=\"px-ds-03 text-ds-xs font-semibold text-accent-11\">\n {count ? `${count} ${label}` : label}\n </span>\n <div className=\"flex-1 border-t-2 border-accent-7\" />\n </div>\n )\n}\nUnreadSeparator.displayName = 'UnreadSeparator'\n\nexport { UnreadSeparator }\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"colors.js","names":[],"sources":["../../src/ui/charts/_internal/animation.ts","../../src/ui/charts/_internal/colors.ts"],"sourcesContent":["'use client'\n\nimport { useMotion } from '../../../motion/motion-provider'\n\n/** Hook to detect reduced-motion preference via MotionProvider context */\nexport function useReducedMotion(): boolean {\n const { reducedMotion } = useMotion()\n return reducedMotion\n}\n\n/** Get transition duration respecting reduced motion preference */\nexport function getTransitionDuration(reducedMotion: boolean, duration = 300): number {\n return reducedMotion ? 0 : duration\n}\n","import type { ChartColor } from './types'\n\nconst CHART_COLORS: ChartColor[] = [\n 'chart-1',\n 'chart-2',\n 'chart-3',\n 'chart-4',\n 'chart-5',\n 'chart-6',\n 'chart-7',\n 'chart-8',\n]\n\n/** Get CSS variable reference for a chart color token */\nexport function getChartColor(color: ChartColor): string {\n return `var(--${color})`\n}\n\n/** Get an array of chart color CSS variable references, cycling if needed */\nexport function getChartColors(count: number): string[] {\n return Array.from({ length: count }, (_, i) =>\n getChartColor(CHART_COLORS[i % CHART_COLORS.length]),\n )\n}\n\n/** Resolve a color prop — if it's a ChartColor token name, convert to var(); otherwise pass through */\nexport function resolveColor(color: string | ChartColor | undefined, index: number = 0): string {\n if (!color) return getChartColor(CHART_COLORS[index % CHART_COLORS.length])\n if ((CHART_COLORS as string[]).includes(color)) return getChartColor(color as ChartColor)\n return color // pass through raw CSS color\n}\n"],"mappings":";;AAKA,SAAgB,IAA4B;CAC1C,IAAM,EAAE,qBAAkB,
|
|
1
|
+
{"version":3,"file":"colors.js","names":[],"sources":["../../src/ui/charts/_internal/animation.ts","../../src/ui/charts/_internal/colors.ts"],"sourcesContent":["'use client'\n\nimport { useMotion } from '../../../motion/motion-provider'\n\n/** Hook to detect reduced-motion preference via MotionProvider context */\nexport function useReducedMotion(): boolean {\n const { reducedMotion } = useMotion()\n return reducedMotion\n}\n\n/** Get transition duration respecting reduced motion preference */\nexport function getTransitionDuration(reducedMotion: boolean, duration = 300): number {\n return reducedMotion ? 0 : duration\n}\n","import type { ChartColor } from './types'\n\nconst CHART_COLORS: ChartColor[] = [\n 'chart-1',\n 'chart-2',\n 'chart-3',\n 'chart-4',\n 'chart-5',\n 'chart-6',\n 'chart-7',\n 'chart-8',\n]\n\n/** Get CSS variable reference for a chart color token */\nexport function getChartColor(color: ChartColor): string {\n return `var(--${color})`\n}\n\n/** Get an array of chart color CSS variable references, cycling if needed */\nexport function getChartColors(count: number): string[] {\n return Array.from({ length: count }, (_, i) =>\n getChartColor(CHART_COLORS[i % CHART_COLORS.length]),\n )\n}\n\n/** Resolve a color prop — if it's a ChartColor token name, convert to var(); otherwise pass through */\nexport function resolveColor(color: string | ChartColor | undefined, index: number = 0): string {\n if (!color) return getChartColor(CHART_COLORS[index % CHART_COLORS.length])\n if ((CHART_COLORS as string[]).includes(color)) return getChartColor(color as ChartColor)\n return color // pass through raw CSS color\n}\n"],"mappings":";;AAKA,SAAgB,IAA4B;CAC1C,IAAM,EAAE,qBAAkB,EAAU;CACpC,OAAO;AACT;AAGA,SAAgB,EAAsB,GAAwB,IAAW,KAAa;CACpF,OAAO,IAAgB,IAAI;AAC7B;;;ACXA,IAAM,IAA6B;CACjC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAGA,SAAgB,EAAc,GAA2B;CACvD,OAAO,SAAS,EAAM;AACxB;AAUA,SAAgB,EAAa,GAAwC,IAAgB,GAAW;CAG9F,OAFK,IACA,EAA0B,SAAS,CAAK,IAAU,EAAc,CAAmB,IACjF,IAFY,EAAc,EAAa,IAAQ,EAAa,OAAO;AAG5E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document-preview.js","names":[],"sources":["../../src/composed/file-preview/document-preview.tsx"],"sourcesContent":["'use client'\n\nimport { IconChevronLeft, IconChevronRight } from '@tabler/icons-react'\nimport { AnimatePresence,motion } from 'framer-motion'\nimport * as React from 'react'\nimport { Document, Page, pdfjs } from 'react-pdf'\n\nimport { Button } from '../../ui/button'\nimport { Icon } from '../../ui/icon'\nimport { tweens } from '../../ui/lib/motion'\nimport { Skeleton } from '../../ui/skeleton'\nimport { ErrorFallback, Toolbar } from './shared'\n\n// ============================================================\n// PDF Preview — Adobe/Google Drive style\n// ============================================================\n\nexport default function DocumentPreview({ url, initialPage, onError }: { url: string; initialPage: number; onError?: (msg: string) => void }) {\n React.useEffect(() => {\n pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.mjs`\n }, [])\n\n const [numPages, setNumPages] = React.useState(0)\n const [page, setPage] = React.useState(initialPage)\n const [pageInput, setPageInput] = React.useState(String(initialPage))\n const [error, setError] = React.useState(false)\n const containerRef = React.useRef<HTMLDivElement>(null)\n const [hovered, setHovered] = React.useState(false)\n\n // Sync page input when page changes via buttons\n React.useEffect(() => { setPageInput(String(page)) }, [page])\n\n // Keyboard nav — scoped to container focus/hover\n React.useEffect(() => {\n function handleKey(e: KeyboardEvent) {\n const el = containerRef.current\n if (!el) return\n const hasFocus = el.contains(document.activeElement)\n if (!hasFocus && !hovered) return\n\n if (e.key === 'ArrowRight' || e.key === 'ArrowDown') {\n e.preventDefault()\n setPage((p) => Math.min(numPages, p + 1))\n } else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') {\n e.preventDefault()\n setPage((p) => Math.max(1, p - 1))\n }\n }\n document.addEventListener('keydown', handleKey)\n return () => document.removeEventListener('keydown', handleKey)\n }, [numPages, hovered])\n\n function handlePageInputSubmit(e: React.KeyboardEvent) {\n if (e.key === 'Enter') {\n const n = parseInt(pageInput, 10)\n if (n >= 1 && n <= numPages) setPage(n)\n else setPageInput(String(page))\n }\n }\n\n if (error) return <ErrorFallback message=\"Could not load PDF\" url={url} />\n\n return (\n <div\n ref={containerRef}\n className=\"flex flex-col items-center gap-ds-03\"\n onMouseEnter={() => setHovered(true)}\n onMouseLeave={() => setHovered(false)}\n tabIndex={-1}\n >\n <div className=\"overflow-auto max-h-[70vh] rounded-control bg-surface-sunken border border-surface-border\">\n <Document\n file={url}\n onLoadSuccess={({ numPages: n }) => setNumPages(n)}\n onLoadError={() => { setError(true); onError?.('PDF failed to load') }}\n loading={<Skeleton className=\"h-[500px] w-[400px]\" />}\n error={<ErrorFallback message=\"Failed to load PDF\" url={url} />}\n >\n <AnimatePresence mode=\"wait\">\n <motion.div\n key={page}\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={tweens.fade}\n >\n <Page pageNumber={page} renderTextLayer={false} renderAnnotationLayer={false} />\n </motion.div>\n </AnimatePresence>\n </Document>\n </div>\n\n {numPages > 0 && (\n <Toolbar>\n <Button variant=\"ghost\" size=\"icon-xs\" onClick={() => setPage((p) => Math.max(1, p - 1))} disabled={page <= 1} aria-label=\"Previous page (←)\" title=\"Previous page\">\n <Icon icon={IconChevronLeft} size=\"sm\" />\n </Button>\n <div className=\"flex items-center gap-ds-01 text-ds-xs text-surface-fg-muted\">\n <input\n type=\"text\"\n value={pageInput}\n onChange={(e) => setPageInput(e.target.value)}\n onKeyDown={handlePageInputSubmit}\n onBlur={() => setPageInput(String(page))}\n className=\"w-8 bg-transparent text-center font-mono text-surface-fg outline-hidden focus:bg-surface-raised-hover rounded-control-inner\"\n aria-label=\"Page number\"\n />\n <span>/ {numPages}</span>\n </div>\n <Button variant=\"ghost\" size=\"icon-xs\" onClick={() => setPage((p) => Math.min(numPages, p + 1))} disabled={page >= numPages} aria-label=\"Next page (→)\" title=\"Next page\">\n <Icon icon={IconChevronRight} size=\"sm\" />\n </Button>\n </Toolbar>\n )}\n </div>\n )\n}\n"],"mappings":";;;;;;;;;;;AAiBA,SAAwB,EAAgB,EAAE,QAAK,gBAAa,cAAkF;
|
|
1
|
+
{"version":3,"file":"document-preview.js","names":[],"sources":["../../src/composed/file-preview/document-preview.tsx"],"sourcesContent":["'use client'\n\nimport { IconChevronLeft, IconChevronRight } from '@tabler/icons-react'\nimport { AnimatePresence,motion } from 'framer-motion'\nimport * as React from 'react'\nimport { Document, Page, pdfjs } from 'react-pdf'\n\nimport { Button } from '../../ui/button'\nimport { Icon } from '../../ui/icon'\nimport { tweens } from '../../ui/lib/motion'\nimport { Skeleton } from '../../ui/skeleton'\nimport { ErrorFallback, Toolbar } from './shared'\n\n// ============================================================\n// PDF Preview — Adobe/Google Drive style\n// ============================================================\n\nexport default function DocumentPreview({ url, initialPage, onError }: { url: string; initialPage: number; onError?: (msg: string) => void }) {\n React.useEffect(() => {\n pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.mjs`\n }, [])\n\n const [numPages, setNumPages] = React.useState(0)\n const [page, setPage] = React.useState(initialPage)\n const [pageInput, setPageInput] = React.useState(String(initialPage))\n const [error, setError] = React.useState(false)\n const containerRef = React.useRef<HTMLDivElement>(null)\n const [hovered, setHovered] = React.useState(false)\n\n // Sync page input when page changes via buttons\n React.useEffect(() => { setPageInput(String(page)) }, [page])\n\n // Keyboard nav — scoped to container focus/hover\n React.useEffect(() => {\n function handleKey(e: KeyboardEvent) {\n const el = containerRef.current\n if (!el) return\n const hasFocus = el.contains(document.activeElement)\n if (!hasFocus && !hovered) return\n\n if (e.key === 'ArrowRight' || e.key === 'ArrowDown') {\n e.preventDefault()\n setPage((p) => Math.min(numPages, p + 1))\n } else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') {\n e.preventDefault()\n setPage((p) => Math.max(1, p - 1))\n }\n }\n document.addEventListener('keydown', handleKey)\n return () => document.removeEventListener('keydown', handleKey)\n }, [numPages, hovered])\n\n function handlePageInputSubmit(e: React.KeyboardEvent) {\n if (e.key === 'Enter') {\n const n = parseInt(pageInput, 10)\n if (n >= 1 && n <= numPages) setPage(n)\n else setPageInput(String(page))\n }\n }\n\n if (error) return <ErrorFallback message=\"Could not load PDF\" url={url} />\n\n return (\n <div\n ref={containerRef}\n className=\"flex flex-col items-center gap-ds-03\"\n onMouseEnter={() => setHovered(true)}\n onMouseLeave={() => setHovered(false)}\n tabIndex={-1}\n >\n <div className=\"overflow-auto max-h-[70vh] rounded-control bg-surface-sunken border border-surface-border\">\n <Document\n file={url}\n onLoadSuccess={({ numPages: n }) => setNumPages(n)}\n onLoadError={() => { setError(true); onError?.('PDF failed to load') }}\n loading={<Skeleton className=\"h-[500px] w-[400px]\" />}\n error={<ErrorFallback message=\"Failed to load PDF\" url={url} />}\n >\n <AnimatePresence mode=\"wait\">\n <motion.div\n key={page}\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={tweens.fade}\n >\n <Page pageNumber={page} renderTextLayer={false} renderAnnotationLayer={false} />\n </motion.div>\n </AnimatePresence>\n </Document>\n </div>\n\n {numPages > 0 && (\n <Toolbar>\n <Button variant=\"ghost\" size=\"icon-xs\" onClick={() => setPage((p) => Math.max(1, p - 1))} disabled={page <= 1} aria-label=\"Previous page (←)\" title=\"Previous page\">\n <Icon icon={IconChevronLeft} size=\"sm\" />\n </Button>\n <div className=\"flex items-center gap-ds-01 text-ds-xs text-surface-fg-muted\">\n <input\n type=\"text\"\n value={pageInput}\n onChange={(e) => setPageInput(e.target.value)}\n onKeyDown={handlePageInputSubmit}\n onBlur={() => setPageInput(String(page))}\n className=\"w-8 bg-transparent text-center font-mono text-surface-fg outline-hidden focus:bg-surface-raised-hover rounded-control-inner\"\n aria-label=\"Page number\"\n />\n <span>/ {numPages}</span>\n </div>\n <Button variant=\"ghost\" size=\"icon-xs\" onClick={() => setPage((p) => Math.min(numPages, p + 1))} disabled={page >= numPages} aria-label=\"Next page (→)\" title=\"Next page\">\n <Icon icon={IconChevronRight} size=\"sm\" />\n </Button>\n </Toolbar>\n )}\n </div>\n )\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"emoji-suggestion.js","names":[],"sources":["../../src/composed/extensions/emoji-data.ts","../../src/composed/extensions/emoji-suggestion.tsx"],"sourcesContent":["// Emoji dataset for the editors' `:shortcode:` autocomplete. Sources\n// `@emoji-mart/data` — a pure-JSON package with NO react peer, so it is\n// unaffected by the React-19 peer issue that drove the picker off\n// `@emoji-mart/react` (→ frimousse). Native-only since that migration: no\n// spritesheet coordinates, no per-art-style loaders.\n\ninterface EmojiSkin {\n native: string\n}\n\ninterface EmojiEntry {\n id: string\n name: string\n keywords?: string[]\n skins: EmojiSkin[]\n}\n\nexport interface EmojiDataset {\n emojis: Record<string, EmojiEntry>\n}\n\nexport interface ResolvedEmoji {\n id: string\n name: string\n native: string\n}\n\nlet cachedData: EmojiDataset | null = null\n\nexport async function loadEmojiData(): Promise<EmojiDataset> {\n if (cachedData) return cachedData\n const mod = await import('@emoji-mart/data')\n cachedData = ((mod as { default?: EmojiDataset }).default ?? mod) as EmojiDataset\n return cachedData\n}\n\nfunction resolve(entry: EmojiEntry): ResolvedEmoji {\n return { id: entry.id, name: entry.name, native: entry.skins[0]?.native ?? '' }\n}\n\nexport function searchEmoji(data: EmojiDataset, query: string, limit = 8): ResolvedEmoji[] {\n const entries = Object.values(data.emojis)\n if (!query) return entries.slice(0, limit).map(resolve)\n const q = query.toLowerCase()\n const results: ResolvedEmoji[] = []\n for (const e of entries) {\n if (results.length >= limit) break\n if (\n e.id.includes(q) ||\n e.name.toLowerCase().includes(q) ||\n e.keywords?.some((k) => k.includes(q))\n ) {\n results.push(resolve(e))\n }\n }\n return results\n}\n","import { Extension } from '@tiptap/core'\nimport Suggestion, { type SuggestionKeyDownProps,type SuggestionProps } from '@tiptap/suggestion'\nimport { PluginKey } from 'prosemirror-state'\nimport * as React from 'react'\nimport { createRoot, type Root } from 'react-dom/client'\n\nimport { cn } from '../../ui/lib/utils'\nimport { loadEmojiData, type ResolvedEmoji, searchEmoji } from './emoji-data'\n\n// Re-export for external consumers\nexport type { ResolvedEmoji as EmojiSuggestionItem }\n\n// Native-only since the frimousse migration.\nfunction EmojiImage({ emoji, size = '1.2em' }: { emoji: ResolvedEmoji; size?: string }) {\n return <span style={{ fontSize: size }}>{emoji.native}</span>\n}\n\ninterface EmojiListRef {\n onKeyDown: (props: SuggestionKeyDownProps) => boolean\n}\n\ninterface EmojiListProps {\n items: ResolvedEmoji[]\n command: (item: ResolvedEmoji) => void\n}\n\nconst EmojiList = React.forwardRef<EmojiListRef, EmojiListProps>(\n ({ items, command }, ref) => {\n const [selectedIndex, setSelectedIndex] = React.useState(0)\n\n React.useEffect(() => setSelectedIndex(0), [items])\n\n React.useImperativeHandle(ref, () => ({\n onKeyDown: ({ event }: SuggestionKeyDownProps) => {\n if (event.key === 'ArrowUp') {\n setSelectedIndex((i) => (i + items.length - 1) % items.length)\n return true\n }\n if (event.key === 'ArrowDown') {\n setSelectedIndex((i) => (i + 1) % items.length)\n return true\n }\n if (event.key === 'Enter') {\n if (items[selectedIndex]) command(items[selectedIndex])\n return true\n }\n return false\n },\n }))\n\n if (!items.length) return null\n\n return (\n <div role=\"listbox\" aria-label=\"Emoji suggestions\" className=\"z-popover max-h-[200px] overflow-x-hidden overflow-y-auto rounded-control bg-surface-overlay shadow-raised-hover\">\n {items.map((item, index) => (\n <button\n key={item.id}\n type=\"button\"\n role=\"option\"\n aria-selected={index === selectedIndex}\n onClick={() => command(item)}\n className={cn(\n 'flex w-full items-center gap-ds-03 px-ds-04 py-ds-02b text-left text-ds-sm',\n index === selectedIndex ? 'bg-surface-raised text-surface-fg' : 'text-surface-fg-muted hover:bg-surface-raised',\n )}\n >\n <EmojiImage emoji={item} size=\"1.25em\" />\n <span className=\"truncate\">:{item.id}:</span>\n </button>\n ))}\n </div>\n )\n },\n)\nEmojiList.displayName = 'EmojiList'\n\nfunction createEmojiSuggestionRenderer() {\n return () => {\n let root: Root | null = null\n let container: HTMLDivElement | null = null\n let componentRef: EmojiListRef | null = null\n\n return {\n onStart: (props: SuggestionProps<ResolvedEmoji>) => {\n container = document.createElement('div')\n container.style.position = 'absolute'\n container.style.zIndex = '1400'\n const rect = props.clientRect?.()\n if (rect) {\n container.style.left = `${rect.left}px`\n container.style.top = `${rect.bottom + 4}px`\n }\n document.body.appendChild(container)\n root = createRoot(container)\n root.render(\n <EmojiList\n ref={(r) => { componentRef = r }}\n items={props.items as ResolvedEmoji[]}\n command={(item) => props.command(item)}\n />,\n )\n },\n\n onUpdate: (props: SuggestionProps<ResolvedEmoji>) => {\n if (!root || !container) return\n const rect = props.clientRect?.()\n if (rect) {\n container.style.left = `${rect.left}px`\n container.style.top = `${rect.bottom + 4}px`\n }\n root.render(\n <EmojiList\n ref={(r) => { componentRef = r }}\n items={props.items as ResolvedEmoji[]}\n command={(item) => props.command(item)}\n />,\n )\n },\n\n onKeyDown: (props: SuggestionKeyDownProps) => {\n if (props.event.key === 'Escape') {\n if (container) {\n root?.unmount()\n container.remove()\n container = null\n root = null\n }\n return true\n }\n return componentRef?.onKeyDown(props) ?? false\n },\n\n onExit: () => {\n if (container) {\n root?.unmount()\n container.remove()\n container = null\n root = null\n }\n },\n }\n }\n}\n\n/** Factory: returns the configured `:shortcode:` emoji suggestion extension. */\nexport function createEmojiSuggestion() {\n return Extension.create({\n name: 'emojiSuggestion',\n\n addProseMirrorPlugins() {\n return [\n Suggestion({\n pluginKey: new PluginKey('emojiSuggestion'),\n editor: this.editor,\n char: ':',\n items: async ({ query }) => {\n const data = await loadEmojiData()\n return searchEmoji(data, query, 8)\n },\n command: ({ editor, range, props: item }) => {\n const emoji = item as ResolvedEmoji\n editor\n .chain()\n .focus()\n .deleteRange(range)\n .insertContent({\n type: 'emojiNode',\n attrs: { id: emoji.id, native: emoji.native },\n })\n .run()\n },\n render: createEmojiSuggestionRenderer(),\n }),\n ]\n },\n })\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"emoji-suggestion.js","names":[],"sources":["../../src/composed/extensions/emoji-data.ts","../../src/composed/extensions/emoji-suggestion.tsx"],"sourcesContent":["// Emoji dataset for the editors' `:shortcode:` autocomplete. Sources\n// `@emoji-mart/data` — a pure-JSON package with NO react peer, so it is\n// unaffected by the React-19 peer issue that drove the picker off\n// `@emoji-mart/react` (→ frimousse). Native-only since that migration: no\n// spritesheet coordinates, no per-art-style loaders.\n\ninterface EmojiSkin {\n native: string\n}\n\ninterface EmojiEntry {\n id: string\n name: string\n keywords?: string[]\n skins: EmojiSkin[]\n}\n\nexport interface EmojiDataset {\n emojis: Record<string, EmojiEntry>\n}\n\nexport interface ResolvedEmoji {\n id: string\n name: string\n native: string\n}\n\nlet cachedData: EmojiDataset | null = null\n\nexport async function loadEmojiData(): Promise<EmojiDataset> {\n if (cachedData) return cachedData\n const mod = await import('@emoji-mart/data')\n cachedData = ((mod as { default?: EmojiDataset }).default ?? mod) as EmojiDataset\n return cachedData\n}\n\nfunction resolve(entry: EmojiEntry): ResolvedEmoji {\n return { id: entry.id, name: entry.name, native: entry.skins[0]?.native ?? '' }\n}\n\nexport function searchEmoji(data: EmojiDataset, query: string, limit = 8): ResolvedEmoji[] {\n const entries = Object.values(data.emojis)\n if (!query) return entries.slice(0, limit).map(resolve)\n const q = query.toLowerCase()\n const results: ResolvedEmoji[] = []\n for (const e of entries) {\n if (results.length >= limit) break\n if (\n e.id.includes(q) ||\n e.name.toLowerCase().includes(q) ||\n e.keywords?.some((k) => k.includes(q))\n ) {\n results.push(resolve(e))\n }\n }\n return results\n}\n","import { Extension } from '@tiptap/core'\nimport Suggestion, { type SuggestionKeyDownProps,type SuggestionProps } from '@tiptap/suggestion'\nimport { PluginKey } from 'prosemirror-state'\nimport * as React from 'react'\nimport { createRoot, type Root } from 'react-dom/client'\n\nimport { cn } from '../../ui/lib/utils'\nimport { loadEmojiData, type ResolvedEmoji, searchEmoji } from './emoji-data'\n\n// Re-export for external consumers\nexport type { ResolvedEmoji as EmojiSuggestionItem }\n\n// Native-only since the frimousse migration.\nfunction EmojiImage({ emoji, size = '1.2em' }: { emoji: ResolvedEmoji; size?: string }) {\n return <span style={{ fontSize: size }}>{emoji.native}</span>\n}\n\ninterface EmojiListRef {\n onKeyDown: (props: SuggestionKeyDownProps) => boolean\n}\n\ninterface EmojiListProps {\n items: ResolvedEmoji[]\n command: (item: ResolvedEmoji) => void\n}\n\nconst EmojiList = React.forwardRef<EmojiListRef, EmojiListProps>(\n ({ items, command }, ref) => {\n const [selectedIndex, setSelectedIndex] = React.useState(0)\n\n React.useEffect(() => setSelectedIndex(0), [items])\n\n React.useImperativeHandle(ref, () => ({\n onKeyDown: ({ event }: SuggestionKeyDownProps) => {\n if (event.key === 'ArrowUp') {\n setSelectedIndex((i) => (i + items.length - 1) % items.length)\n return true\n }\n if (event.key === 'ArrowDown') {\n setSelectedIndex((i) => (i + 1) % items.length)\n return true\n }\n if (event.key === 'Enter') {\n if (items[selectedIndex]) command(items[selectedIndex])\n return true\n }\n return false\n },\n }))\n\n if (!items.length) return null\n\n return (\n <div role=\"listbox\" aria-label=\"Emoji suggestions\" className=\"z-popover max-h-[200px] overflow-x-hidden overflow-y-auto rounded-control bg-surface-overlay shadow-raised-hover\">\n {items.map((item, index) => (\n <button\n key={item.id}\n type=\"button\"\n role=\"option\"\n aria-selected={index === selectedIndex}\n onClick={() => command(item)}\n className={cn(\n 'flex w-full items-center gap-ds-03 px-ds-04 py-ds-02b text-left text-ds-sm',\n index === selectedIndex ? 'bg-surface-raised text-surface-fg' : 'text-surface-fg-muted hover:bg-surface-raised',\n )}\n >\n <EmojiImage emoji={item} size=\"1.25em\" />\n <span className=\"truncate\">:{item.id}:</span>\n </button>\n ))}\n </div>\n )\n },\n)\nEmojiList.displayName = 'EmojiList'\n\nfunction createEmojiSuggestionRenderer() {\n return () => {\n let root: Root | null = null\n let container: HTMLDivElement | null = null\n let componentRef: EmojiListRef | null = null\n\n return {\n onStart: (props: SuggestionProps<ResolvedEmoji>) => {\n container = document.createElement('div')\n container.style.position = 'absolute'\n container.style.zIndex = '1400'\n const rect = props.clientRect?.()\n if (rect) {\n container.style.left = `${rect.left}px`\n container.style.top = `${rect.bottom + 4}px`\n }\n document.body.appendChild(container)\n root = createRoot(container)\n root.render(\n <EmojiList\n ref={(r) => { componentRef = r }}\n items={props.items as ResolvedEmoji[]}\n command={(item) => props.command(item)}\n />,\n )\n },\n\n onUpdate: (props: SuggestionProps<ResolvedEmoji>) => {\n if (!root || !container) return\n const rect = props.clientRect?.()\n if (rect) {\n container.style.left = `${rect.left}px`\n container.style.top = `${rect.bottom + 4}px`\n }\n root.render(\n <EmojiList\n ref={(r) => { componentRef = r }}\n items={props.items as ResolvedEmoji[]}\n command={(item) => props.command(item)}\n />,\n )\n },\n\n onKeyDown: (props: SuggestionKeyDownProps) => {\n if (props.event.key === 'Escape') {\n if (container) {\n root?.unmount()\n container.remove()\n container = null\n root = null\n }\n return true\n }\n return componentRef?.onKeyDown(props) ?? false\n },\n\n onExit: () => {\n if (container) {\n root?.unmount()\n container.remove()\n container = null\n root = null\n }\n },\n }\n }\n}\n\n/** Factory: returns the configured `:shortcode:` emoji suggestion extension. */\nexport function createEmojiSuggestion() {\n return Extension.create({\n name: 'emojiSuggestion',\n\n addProseMirrorPlugins() {\n return [\n Suggestion({\n pluginKey: new PluginKey('emojiSuggestion'),\n editor: this.editor,\n char: ':',\n items: async ({ query }) => {\n const data = await loadEmojiData()\n return searchEmoji(data, query, 8)\n },\n command: ({ editor, range, props: item }) => {\n const emoji = item as ResolvedEmoji\n editor\n .chain()\n .focus()\n .deleteRange(range)\n .insertContent({\n type: 'emojiNode',\n attrs: { id: emoji.id, native: emoji.native },\n })\n .run()\n },\n render: createEmojiSuggestionRenderer(),\n }),\n ]\n },\n })\n}\n"],"mappings":";;;;;;AA2BA,IAAI,IAAkC;AAEtC,eAAsB,IAAuC;CAC3D,IAAI,GAAY,OAAO;CACvB,IAAM,IAAM,MAAM,OAAO,aAAA,CAAA,MAAA,MAAA,EAAA,cAAA;CAEzB,OADA,IAAe,EAAmC,WAAW,GACtD;AACT;AAEA,SAAS,EAAQ,GAAkC;CACjD,OAAO;EAAE,IAAI,EAAM;EAAI,MAAM,EAAM;EAAM,QAAQ,EAAM,MAAM,EAAE,EAAE,UAAU;CAAG;AAChF;AAEA,SAAgB,EAAY,GAAoB,GAAe,IAAQ,GAAoB;CACzF,IAAM,IAAU,OAAO,OAAO,EAAK,MAAM;CACzC,IAAI,CAAC,GAAO,OAAO,EAAQ,MAAM,GAAG,CAAK,CAAC,CAAC,IAAI,CAAO;CACtD,IAAM,IAAI,EAAM,YAAY,GACtB,IAA2B,CAAC;CAClC,KAAK,IAAM,KAAK,GAAS;EACvB,IAAI,EAAQ,UAAU,GAAO;EAC7B,CACE,EAAE,GAAG,SAAS,CAAC,KACf,EAAE,KAAK,YAAY,CAAC,CAAC,SAAS,CAAC,KAC/B,EAAE,UAAU,MAAM,MAAM,EAAE,SAAS,CAAC,CAAC,MAErC,EAAQ,KAAK,EAAQ,CAAC,CAAC;CAE3B;CACA,OAAO;AACT;;;AC3CA,SAAS,EAAW,EAAE,UAAO,UAAO,WAAoD;CACtF,OAAO,kBAAC,QAAD;EAAM,OAAO,EAAE,UAAU,EAAK;YAAI,EAAM;CAAa,CAAA;AAC9D;AAWA,IAAM,IAAY,EAAM,YACrB,EAAE,UAAO,cAAW,MAAQ;CAC3B,IAAM,CAAC,GAAe,KAAoB,EAAM,SAAS,CAAC;CAwB1D,OAtBA,EAAM,gBAAgB,EAAiB,CAAC,GAAG,CAAC,CAAK,CAAC,GAElD,EAAM,oBAAoB,UAAY,EACpC,YAAY,EAAE,eACR,EAAM,QAAQ,aAChB,GAAkB,OAAO,IAAI,EAAM,SAAS,KAAK,EAAM,MAAM,GACtD,MAEL,EAAM,QAAQ,eAChB,GAAkB,OAAO,IAAI,KAAK,EAAM,MAAM,GACvC,MAEL,EAAM,QAAQ,WACZ,EAAM,MAAgB,EAAQ,EAAM,EAAc,GAC/C,MAEF,GAEX,EAAE,GAEG,EAAM,SAGT,kBAAC,OAAD;EAAK,MAAK;EAAU,cAAW;EAAoB,WAAU;YAC1D,EAAM,KAAK,GAAM,MAChB,kBAAC,UAAD;GAEE,MAAK;GACL,MAAK;GACL,iBAAe,MAAU;GACzB,eAAe,EAAQ,CAAI;GAC3B,WAAW,EACT,8EACA,MAAU,IAAgB,sCAAsC,+CAClE;aATF,CAWE,kBAAC,GAAD;IAAY,OAAO;IAAM,MAAK;GAAU,CAAA,GACxC,kBAAC,QAAD;IAAM,WAAU;cAAhB;KAA2B;KAAE,EAAK;KAAG;IAAO;KACtC;KAZD,EAAK,EAYJ,CACT;CACE,CAAA,IApBmB;AAsB5B,CACF;AACA,EAAU,cAAc;AAExB,SAAS,IAAgC;CACvC,aAAa;EACX,IAAI,IAAoB,MACpB,IAAmC,MACnC,IAAoC;EAExC,OAAO;GACL,UAAU,MAA0C;IAGlD,AAFA,IAAY,SAAS,cAAc,KAAK,GACxC,EAAU,MAAM,WAAW,YAC3B,EAAU,MAAM,SAAS;IACzB,IAAM,IAAO,EAAM,aAAa;IAOhC,AANI,MACF,EAAU,MAAM,OAAO,GAAG,EAAK,KAAK,KACpC,EAAU,MAAM,MAAM,GAAG,EAAK,SAAS,EAAE,MAE3C,SAAS,KAAK,YAAY,CAAS,GACnC,IAAO,EAAW,CAAS,GAC3B,EAAK,OACH,kBAAC,GAAD;KACE,MAAM,MAAM;MAAE,IAAe;KAAE;KAC/B,OAAO,EAAM;KACb,UAAU,MAAS,EAAM,QAAQ,CAAI;IACtC,CAAA,CACH;GACF;GAEA,WAAW,MAA0C;IACnD,IAAI,CAAC,KAAQ,CAAC,GAAW;IACzB,IAAM,IAAO,EAAM,aAAa;IAKhC,AAJI,MACF,EAAU,MAAM,OAAO,GAAG,EAAK,KAAK,KACpC,EAAU,MAAM,MAAM,GAAG,EAAK,SAAS,EAAE,MAE3C,EAAK,OACH,kBAAC,GAAD;KACE,MAAM,MAAM;MAAE,IAAe;KAAE;KAC/B,OAAO,EAAM;KACb,UAAU,MAAS,EAAM,QAAQ,CAAI;IACtC,CAAA,CACH;GACF;GAEA,YAAY,MACN,EAAM,MAAM,QAAQ,YAClB,MACF,GAAM,QAAQ,GACd,EAAU,OAAO,GACjB,IAAY,MACZ,IAAO,OAEF,MAEF,GAAc,UAAU,CAAK,KAAK;GAG3C,cAAc;IACZ,AAAI,MACF,GAAM,QAAQ,GACd,EAAU,OAAO,GACjB,IAAY,MACZ,IAAO;GAEX;EACF;CACF;AACF;AAGA,SAAgB,IAAwB;CACtC,OAAO,EAAU,OAAO;EACtB,MAAM;EAEN,wBAAwB;GACtB,OAAO,CACL,EAAW;IACT,WAAW,IAAI,EAAU,iBAAiB;IAC1C,QAAQ,KAAK;IACb,MAAM;IACN,OAAO,OAAO,EAAE,eAEP,EAAY,MADA,EAAc,GACR,GAAO,CAAC;IAEnC,UAAU,EAAE,WAAQ,UAAO,OAAO,QAAW;KAC3C,IAAM,IAAQ;KACd,EACG,MAAM,CAAC,CACP,MAAM,CAAC,CACP,YAAY,CAAK,CAAC,CAClB,cAAc;MACb,MAAM;MACN,OAAO;OAAE,IAAI,EAAM;OAAI,QAAQ,EAAM;MAAO;KAC9C,CAAC,CAAC,CACD,IAAI;IACT;IACA,QAAQ,EAA8B;GACxC,CAAC,CACH;EACF;CACF,CAAC;AACH"}
|