@devalok/shilp-sutra 0.49.5 → 0.51.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +12 -4
- package/MIGRATION.md +12 -0
- package/dist/_chunks/badge-group.js +4 -4
- package/dist/_chunks/badge-group.js.map +1 -1
- package/dist/_chunks/block-shell.js +1 -1
- package/dist/_chunks/block-shell.js.map +1 -1
- package/dist/_chunks/chat.js +18 -18
- package/dist/_chunks/chat.js.map +1 -1
- package/dist/_chunks/document-preview.js +1 -1
- package/dist/_chunks/document-preview.js.map +1 -1
- package/dist/_chunks/emoji-suggestion.js +1 -1
- package/dist/_chunks/emoji-suggestion.js.map +1 -1
- package/dist/_chunks/grid-lines.js +2 -2
- package/dist/_chunks/grid-lines.js.map +1 -1
- package/dist/_chunks/image-preview.js +1 -1
- package/dist/_chunks/image-preview.js.map +1 -1
- package/dist/_chunks/mention-suggestion.js +2 -2
- package/dist/_chunks/mention-suggestion.js.map +1 -1
- package/dist/_chunks/oauth-button.js +8 -8
- package/dist/_chunks/oauth-button.js.map +1 -1
- package/dist/_chunks/shared.js +2 -2
- package/dist/_chunks/shared.js.map +1 -1
- package/dist/_chunks/success.js +5 -5
- package/dist/_chunks/success.js.map +1 -1
- package/dist/_chunks/tiptap.js +3956 -1796
- package/dist/_chunks/tiptap.js.map +1 -1
- package/dist/_chunks/tooltip.js +2 -2
- package/dist/_chunks/tooltip.js.map +1 -1
- package/dist/_chunks/tree-view.js +2 -2
- package/dist/_chunks/tree-view.js.map +1 -1
- package/dist/_chunks/use-calendar.js +3 -3
- package/dist/_chunks/use-calendar.js.map +1 -1
- package/dist/ai/block-renderer.js +1 -1
- package/dist/ai/block-renderer.js.map +1 -1
- package/dist/ai/blocks/error.js +1 -1
- package/dist/ai/blocks/error.js.map +1 -1
- package/dist/ai/command-bar.js +15 -15
- package/dist/ai/command-bar.js.map +1 -1
- package/dist/ai/conversation.js +6 -6
- package/dist/ai/conversation.js.map +1 -1
- package/dist/composed/activity-feed.js +4 -4
- package/dist/composed/activity-feed.js.map +1 -1
- package/dist/composed/avatar-group.js +6 -6
- package/dist/composed/avatar-group.js.map +1 -1
- package/dist/composed/bulk-action-bar.js +1 -1
- package/dist/composed/bulk-action-bar.js.map +1 -1
- package/dist/composed/command-palette.js +12 -12
- package/dist/composed/command-palette.js.map +1 -1
- package/dist/composed/content-card.js +1 -1
- package/dist/composed/content-card.js.map +1 -1
- package/dist/composed/date-picker/index.js +17 -17
- package/dist/composed/date-picker/index.js.map +1 -1
- package/dist/composed/deadline-indicator.js +2 -2
- package/dist/composed/deadline-indicator.js.map +1 -1
- package/dist/composed/diff.d.ts +108 -0
- package/dist/composed/diff.d.ts.map +1 -0
- package/dist/composed/diff.js +1004 -0
- package/dist/composed/diff.js.map +1 -0
- package/dist/composed/emoji-picker.js +6 -6
- package/dist/composed/emoji-picker.js.map +1 -1
- package/dist/composed/empty-state.js +2 -2
- package/dist/composed/empty-state.js.map +1 -1
- package/dist/composed/error-boundary.js +6 -6
- package/dist/composed/error-boundary.js.map +1 -1
- package/dist/composed/file-preview.js +5 -5
- package/dist/composed/file-preview.js.map +1 -1
- package/dist/composed/filter-bar.js +3 -3
- package/dist/composed/filter-bar.js.map +1 -1
- package/dist/composed/form-section.js +2 -2
- package/dist/composed/form-section.js.map +1 -1
- package/dist/composed/inline-edit.d.ts +1 -1
- package/dist/composed/inline-edit.d.ts.map +1 -1
- package/dist/composed/inline-edit.js.map +1 -1
- package/dist/composed/loading-skeleton.js +3 -3
- package/dist/composed/loading-skeleton.js.map +1 -1
- package/dist/composed/markdown-viewer.js +11 -11
- package/dist/composed/markdown-viewer.js.map +1 -1
- package/dist/composed/master-detail.js +1 -1
- package/dist/composed/master-detail.js.map +1 -1
- package/dist/composed/member-picker.js +2 -2
- package/dist/composed/member-picker.js.map +1 -1
- package/dist/composed/multi-select-popover.js +5 -5
- package/dist/composed/multi-select-popover.js.map +1 -1
- package/dist/composed/page-header.js +3 -3
- package/dist/composed/page-header.js.map +1 -1
- package/dist/composed/page-skeletons.js +4 -4
- package/dist/composed/page-skeletons.js.map +1 -1
- package/dist/composed/priority-indicator.js +1 -1
- package/dist/composed/priority-indicator.js.map +1 -1
- package/dist/composed/responsive-modal.js +2 -2
- package/dist/composed/responsive-modal.js.map +1 -1
- package/dist/composed/rich-chat-input.js +27 -27
- package/dist/composed/rich-chat-input.js.map +1 -1
- package/dist/composed/rich-text-editor.d.ts +81 -6
- package/dist/composed/rich-text-editor.d.ts.map +1 -1
- package/dist/composed/rich-text-editor.js +365 -210
- package/dist/composed/rich-text-editor.js.map +1 -1
- package/dist/composed/schedule-view.js +4 -4
- package/dist/composed/schedule-view.js.map +1 -1
- package/dist/shell/bottom-navbar.js +4 -4
- package/dist/shell/bottom-navbar.js.map +1 -1
- package/dist/shell/notification-center.js +13 -13
- package/dist/shell/notification-center.js.map +1 -1
- package/dist/shell/notification-preferences.js +10 -10
- package/dist/shell/notification-preferences.js.map +1 -1
- package/dist/shell/sidebar.js +9 -9
- package/dist/shell/sidebar.js.map +1 -1
- package/dist/shell/top-bar.js +8 -8
- package/dist/shell/top-bar.js.map +1 -1
- package/dist/tokens/semantic.css +6 -1
- package/dist/tokens/typography-semantic.css +6 -6
- package/dist/tokens/utilities.css +8 -0
- package/dist/ui/accordion.js +2 -2
- package/dist/ui/accordion.js.map +1 -1
- package/dist/ui/alert-dialog.js +4 -4
- package/dist/ui/alert-dialog.js.map +1 -1
- package/dist/ui/alert.js +1 -1
- package/dist/ui/alert.js.map +1 -1
- package/dist/ui/autocomplete.js +3 -3
- package/dist/ui/autocomplete.js.map +1 -1
- package/dist/ui/avatar.js +5 -5
- package/dist/ui/avatar.js.map +1 -1
- package/dist/ui/banner.js +1 -1
- package/dist/ui/banner.js.map +1 -1
- package/dist/ui/breadcrumb.js +1 -1
- package/dist/ui/breadcrumb.js.map +1 -1
- package/dist/ui/button.js +7 -7
- package/dist/ui/button.js.map +1 -1
- package/dist/ui/card.d.ts +6 -5
- package/dist/ui/card.d.ts.map +1 -1
- package/dist/ui/card.js +2 -2
- package/dist/ui/card.js.map +1 -1
- package/dist/ui/charts/gauge-chart.js +2 -2
- package/dist/ui/charts/gauge-chart.js.map +1 -1
- package/dist/ui/charts/pie-chart.js +1 -1
- package/dist/ui/charts/pie-chart.js.map +1 -1
- package/dist/ui/charts/radar-chart.d.ts +19 -1
- package/dist/ui/charts/radar-chart.d.ts.map +1 -1
- package/dist/ui/charts/radar-chart.js +80 -42
- package/dist/ui/charts/radar-chart.js.map +1 -1
- package/dist/ui/code.js +2 -2
- package/dist/ui/code.js.map +1 -1
- package/dist/ui/color-input.js +9 -9
- package/dist/ui/color-input.js.map +1 -1
- package/dist/ui/combobox.js +16 -16
- package/dist/ui/combobox.js.map +1 -1
- package/dist/ui/context-menu.js +6 -6
- package/dist/ui/context-menu.js.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.js +1 -1
- package/dist/ui/data-table-bulk-actions.js.map +1 -1
- package/dist/ui/data-table-card.js +1 -1
- package/dist/ui/data-table-card.js.map +1 -1
- package/dist/ui/data-table-header.js +1 -1
- package/dist/ui/data-table-header.js.map +1 -1
- package/dist/ui/data-table-pagination.js +3 -3
- package/dist/ui/data-table-pagination.js.map +1 -1
- package/dist/ui/data-table-toolbar.js +1 -1
- package/dist/ui/data-table-toolbar.js.map +1 -1
- package/dist/ui/data-table.js +1 -1
- package/dist/ui/data-table.js.map +1 -1
- package/dist/ui/dialog.js +2 -2
- package/dist/ui/dialog.js.map +1 -1
- package/dist/ui/dot.js +4 -4
- package/dist/ui/dot.js.map +1 -1
- package/dist/ui/dropdown-menu.js +6 -6
- package/dist/ui/dropdown-menu.js.map +1 -1
- package/dist/ui/file-upload.js +5 -5
- package/dist/ui/file-upload.js.map +1 -1
- package/dist/ui/form.js +1 -1
- package/dist/ui/form.js.map +1 -1
- package/dist/ui/input-otp.d.ts.map +1 -1
- package/dist/ui/input-otp.js +3 -3
- package/dist/ui/input-otp.js.map +1 -1
- package/dist/ui/input.js +8 -8
- package/dist/ui/input.js.map +1 -1
- package/dist/ui/label.js +1 -1
- package/dist/ui/label.js.map +1 -1
- package/dist/ui/lib/utils.d.ts.map +1 -1
- package/dist/ui/lib/utils.js +42 -13
- package/dist/ui/lib/utils.js.map +1 -1
- package/dist/ui/menubar.js +7 -7
- package/dist/ui/menubar.js.map +1 -1
- package/dist/ui/navigation-menu.js +1 -1
- package/dist/ui/navigation-menu.js.map +1 -1
- package/dist/ui/number-input.js +4 -4
- package/dist/ui/number-input.js.map +1 -1
- package/dist/ui/pagination.js +1 -1
- package/dist/ui/pagination.js.map +1 -1
- package/dist/ui/progress-ring.js +3 -3
- package/dist/ui/progress-ring.js.map +1 -1
- package/dist/ui/progress.js +2 -2
- package/dist/ui/progress.js.map +1 -1
- package/dist/ui/segmented-control.js +3 -3
- package/dist/ui/segmented-control.js.map +1 -1
- package/dist/ui/select.js +6 -6
- package/dist/ui/select.js.map +1 -1
- package/dist/ui/sheet.js +2 -2
- package/dist/ui/sheet.js.map +1 -1
- package/dist/ui/sidebar.js +7 -7
- package/dist/ui/sidebar.js.map +1 -1
- package/dist/ui/split-button.js +6 -6
- package/dist/ui/split-button.js.map +1 -1
- package/dist/ui/stat-card.d.ts +4 -4
- package/dist/ui/stat-card.d.ts.map +1 -1
- package/dist/ui/stat-card.js +7 -7
- package/dist/ui/stat-card.js.map +1 -1
- package/dist/ui/stepper.js +3 -3
- package/dist/ui/stepper.js.map +1 -1
- package/dist/ui/table.js +3 -3
- package/dist/ui/table.js.map +1 -1
- package/dist/ui/tabs.js +3 -3
- package/dist/ui/tabs.js.map +1 -1
- package/dist/ui/text.d.ts.map +1 -1
- package/dist/ui/text.js.map +1 -1
- package/dist/ui/textarea.js +4 -4
- package/dist/ui/textarea.js.map +1 -1
- package/dist/ui/toast.js +11 -11
- package/dist/ui/toast.js.map +1 -1
- package/dist/ui/toggle.js +3 -3
- package/dist/ui/toggle.js.map +1 -1
- package/dist/ui/tooltip.js +1 -1
- package/dist/ui/tooltip.js.map +1 -1
- package/docs/components/composed/diff.md +50 -0
- package/docs/components/ui/stat-card.md +1 -1
- package/llms.txt +2 -1
- package/make-kit/components/card.md +4 -4
- package/mcp-manifest.json +146 -2
- package/package.json +8 -1
- package/skill/SKILL.md +1 -1
- package/skill/references/components.md +2 -1
package/AGENTS.md
CHANGED
|
@@ -43,13 +43,14 @@ Read these local files. Your training data is outdated and will hallucinate APIs
|
|
|
43
43
|
### MCP tools
|
|
44
44
|
|
|
45
45
|
<!-- BEGIN:mcp-tools --><!-- generated by scripts/generate-tool-list.mjs — do not edit by hand -->
|
|
46
|
-
|
|
46
|
+
_13 tools (source: `packages/mcp-server/src/index.mjs`):_
|
|
47
47
|
|
|
48
48
|
**Reference:**
|
|
49
49
|
- `find_component` — Search shilp-sutra components by keyword (authoritative component index).
|
|
50
50
|
- `get_component` — Authoritative, version-exact reference for one component: props/variants/defaults as JSON, usage rules, examples, composition (compound parts,…
|
|
51
51
|
- `get_setup` — Framework install recipe (vite, next-app-router, next-pages, remix, astro, tanstack-start) or guides (customize-brand, server-components, troubleshoot,…
|
|
52
52
|
- `get_tokens` — Design-token reference (color, spacing, typography, radius, shadow, motion, z) as JSON.
|
|
53
|
+
- `how_to_use` — START HERE if new to this MCP.
|
|
53
54
|
- `search_docs` — Full-text search across component docs and recipes for patterns and guidance the other tools don't slice (e.g. "focus ring", "dark mode toggle").
|
|
54
55
|
- `upgrade` — Structured breaking changes + migration pointers between two shilp-sutra versions.
|
|
55
56
|
|
|
@@ -59,6 +60,9 @@ _11 tools (source: `packages/mcp-server/src/index.mjs`):_
|
|
|
59
60
|
- `validate_snippet` — Pre-write linter.
|
|
60
61
|
- `verify_setup` — Post-install gate.
|
|
61
62
|
|
|
63
|
+
**Quality:**
|
|
64
|
+
- `check_slop` — Pre-emit DESIGN-QUALITY gate (complements validate_snippet, which checks correctness).
|
|
65
|
+
|
|
62
66
|
**Write:**
|
|
63
67
|
- `report_issue` — File a bug report, feature request, suggestion, or docs-gap on the shilp-sutra repo when you hit a wall using the design system.
|
|
64
68
|
<!-- END:mcp-tools -->
|
|
@@ -176,12 +180,16 @@ Set up shilp-sutra theming for this project via the Themer.
|
|
|
176
180
|
My brand: <hex OR archetype name>
|
|
177
181
|
|
|
178
182
|
Steps:
|
|
179
|
-
1. Map my brand input to query params
|
|
183
|
+
1. Map my brand input to query params. The endpoint accepts ONLY these — pick the case that fits:
|
|
184
|
+
- Archetype name → `archetype=<name>`
|
|
185
|
+
- A hex color → CONVERT the hex to OKLCH first, then pass `hue=<0-360>&chroma=<0.10-0.20>` (numeric). There is NO `hex` or `color` param — passing one is silently ignored and you get the default devalok theme (wrong color, no error). Example: `#D33163` → hue 8, chroma 0.198 → `hue=8&chroma=0.198`.
|
|
186
|
+
- Nothing given → `archetype=devalok`
|
|
180
187
|
2. Fetch GET https://shilp-sutra.devalok.in/themer/result.json?<params>
|
|
181
188
|
Response: { archetype, density, shape, motion, hue, chroma, css, pasteAfter, pasteLocation, doNotPasteInside }
|
|
182
|
-
|
|
189
|
+
Sanity-check the echoed `hue`/`chroma` in the response match what you sent — if they came back null, your params didn't parse.
|
|
190
|
+
3. Paste the response `css` field AFTER the line in `pasteAfter` in the project's global stylesheet. Not inside any `@layer`. Paste it verbatim, unmodified.
|
|
183
191
|
4. If @devalok/shilp-sutra isn't installed, install it first per the matching install-<framework>.md recipe.
|
|
184
|
-
5. Verify with a Button or Card on any page — radius + accent should match https://shilp-sutra.devalok.in/themer/result?<params>.
|
|
192
|
+
5. Verify with a Button or Card on any page — radius + accent should match https://shilp-sutra.devalok.in/themer/result?<params>. If the accent DIDN'T change, the override was dropped at build: check the pasted block sits at the stylesheet top level (not inside `@layer`) and the build log has no CSS-parse warning near it.
|
|
185
193
|
````
|
|
186
194
|
|
|
187
195
|
When the user has already been to the Themer, they may paste a *filled-in* version with the JSON URL pre-built — skip step 1, go straight to fetch.
|
package/MIGRATION.md
CHANGED
|
@@ -4,6 +4,18 @@ This page indexes all breaking changes across `@devalok/shilp-sutra` versions. F
|
|
|
4
4
|
|
|
5
5
|
> **Upgrading from < 0.36?** Start here, then read each intermediate version section. Breaking changes stack — skipping versions means stacking migrations.
|
|
6
6
|
|
|
7
|
+
## v0.51.0 — additive (no migration required)
|
|
8
|
+
|
|
9
|
+
Nothing breaks at the TypeScript level; this release is additive.
|
|
10
|
+
|
|
11
|
+
> Auto-stubbed by `version-packages` so the release audit's MIGRATION-section gate can't block. If any behavioral or visual change needs consumer action, replace this stub with the specifics on the Version Packages PR before publishing.
|
|
12
|
+
|
|
13
|
+
## v0.50.0 — additive (no migration required)
|
|
14
|
+
|
|
15
|
+
Nothing breaks at the TypeScript level; this release is additive.
|
|
16
|
+
|
|
17
|
+
> Auto-stubbed by `version-packages` so the release audit's MIGRATION-section gate can't block. If any behavioral or visual change needs consumer action, replace this stub with the specifics on the Version Packages PR before publishing.
|
|
18
|
+
|
|
7
19
|
## v0.49.0 — breaking changes (review before release)
|
|
8
20
|
|
|
9
21
|
> ⚠️ Auto-stubbed by `version-packages`. This version has breaking entries in BREAKING.json. **Expand each into before→after migration steps on the Version Packages PR before publishing.**
|
|
@@ -131,10 +131,10 @@ var v = r("relative inline-flex items-center rounded-pill font-sans font-medium
|
|
|
131
131
|
soft: "border border-transparent"
|
|
132
132
|
},
|
|
133
133
|
size: {
|
|
134
|
-
xs: "h-4 px-ds-02b text-
|
|
135
|
-
sm: "h-5 px-ds-03 text-
|
|
136
|
-
md: "h-6 px-2.5 text-
|
|
137
|
-
lg: "h-7 px-ds-04 text-
|
|
134
|
+
xs: "h-4 px-ds-02b text-body-xs gap-ds-02",
|
|
135
|
+
sm: "h-5 px-ds-03 text-body-xs gap-ds-02",
|
|
136
|
+
md: "h-6 px-2.5 text-body-xs gap-ds-02b",
|
|
137
|
+
lg: "h-7 px-ds-04 text-body-sm gap-ds-02b"
|
|
138
138
|
}
|
|
139
139
|
},
|
|
140
140
|
defaultVariants: {
|
|
@@ -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 extends React.HTMLAttributes<HTMLDivElement> {\n max?: number\n gap?: keyof typeof GAP_CLASSES\n size?: BadgeProps['size']\n onOverflowClick?: () => void\n children: React.ReactNode\n}\n\nexport const BadgeGroup = React.forwardRef<HTMLDivElement, BadgeGroupProps>(function BadgeGroup(\n { max, gap = 'default', size, onOverflowClick, className, children, ...rest },\n ref,\n) {\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\n ref={ref}\n className={cn('flex flex-wrap items-center', GAP_CLASSES[gap], className)}\n {...rest}\n >\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
|
+
{"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-body-xs gap-ds-02',\n sm: 'h-5 px-ds-03 text-body-xs gap-ds-02',\n md: 'h-6 px-2.5 text-body-xs gap-ds-02b', /* px-2.5=10px — no exact DS token */\n lg: 'h-7 px-ds-04 text-body-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 extends React.HTMLAttributes<HTMLDivElement> {\n max?: number\n gap?: keyof typeof GAP_CLASSES\n size?: BadgeProps['size']\n onOverflowClick?: () => void\n children: React.ReactNode\n}\n\nexport const BadgeGroup = React.forwardRef<HTMLDivElement, BadgeGroupProps>(function BadgeGroup(\n { max, gap = 'default', size, onOverflowClick, className, children, ...rest },\n ref,\n) {\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\n ref={ref}\n className={cn('flex flex-wrap items-center', GAP_CLASSES[gap], className)}\n {...rest}\n >\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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"}
|
|
@@ -11,7 +11,7 @@ var o = n.memo(function({ confidence: n, className: o, children: s }) {
|
|
|
11
11
|
"data-confidence": n,
|
|
12
12
|
className: e(c && "relative rounded-surface bg-warning-2 p-ds-04 pt-ds-07", o),
|
|
13
13
|
children: [c && /* @__PURE__ */ i("span", {
|
|
14
|
-
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-
|
|
14
|
+
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-body-xs font-semibold text-warning-11",
|
|
15
15
|
children: [/* @__PURE__ */ r(t, {
|
|
16
16
|
icon: a,
|
|
17
17
|
size: "xs",
|
|
@@ -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-
|
|
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-body-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"}
|
package/dist/_chunks/chat.js
CHANGED
|
@@ -29,7 +29,7 @@ function D({ date: e, format: t, className: n }) {
|
|
|
29
29
|
children: [
|
|
30
30
|
/* @__PURE__ */ v("div", { className: "flex-1 border-t border-surface-border-subtle" }),
|
|
31
31
|
/* @__PURE__ */ v("span", {
|
|
32
|
-
className: "text-
|
|
32
|
+
className: "text-label-xs font-medium text-surface-fg-subtle/50 uppercase tracking-wider",
|
|
33
33
|
children: a
|
|
34
34
|
}),
|
|
35
35
|
/* @__PURE__ */ v("div", { className: "flex-1 border-t border-surface-border-subtle" })
|
|
@@ -67,7 +67,7 @@ var A = _.forwardRef(({ children: e, variant: r = "flat", placement: a = "start"
|
|
|
67
67
|
y: 0
|
|
68
68
|
},
|
|
69
69
|
transition: n.snappy,
|
|
70
|
-
className: i("flex items-center gap-ds-02 py-ds-02 text-
|
|
70
|
+
className: i("flex items-center gap-ds-02 py-ds-02 text-caption text-surface-fg-subtle/50 italic", d),
|
|
71
71
|
...t(f),
|
|
72
72
|
children: [/* @__PURE__ */ v(o, {
|
|
73
73
|
icon: C,
|
|
@@ -154,12 +154,12 @@ function P({ name: e, badge: t, timestamp: n, formattedTimestamp: r, timestampFo
|
|
|
154
154
|
className: "flex items-baseline gap-ds-02",
|
|
155
155
|
children: [
|
|
156
156
|
/* @__PURE__ */ v("span", {
|
|
157
|
-
className: "font-semibold text-
|
|
157
|
+
className: "font-semibold text-body-md text-surface-fg",
|
|
158
158
|
children: e
|
|
159
159
|
}),
|
|
160
160
|
t,
|
|
161
161
|
o && /* @__PURE__ */ v("span", {
|
|
162
|
-
className: "text-
|
|
162
|
+
className: "text-body-sm text-surface-fg-subtle/50",
|
|
163
163
|
children: o
|
|
164
164
|
})
|
|
165
165
|
]
|
|
@@ -168,7 +168,7 @@ function P({ name: e, badge: t, timestamp: n, formattedTimestamp: r, timestampFo
|
|
|
168
168
|
P.displayName = "Message.Author";
|
|
169
169
|
function F({ children: e, className: t, ...n }) {
|
|
170
170
|
return /* @__PURE__ */ v("div", {
|
|
171
|
-
className: i("text-
|
|
171
|
+
className: i("text-body-md leading-relaxed text-surface-fg whitespace-pre-wrap", t),
|
|
172
172
|
...n,
|
|
173
173
|
children: e
|
|
174
174
|
});
|
|
@@ -194,21 +194,21 @@ function I({ content: e, onSave: t, onCancel: n, canEdit: r = !1, renderContent:
|
|
|
194
194
|
e.key === "Enter" && !e.shiftKey ? (e.preventDefault(), p()) : e.key === "Escape" && (e.preventDefault(), m());
|
|
195
195
|
}, [p, m]);
|
|
196
196
|
return o ? /* @__PURE__ */ y("div", {
|
|
197
|
-
className: "text-
|
|
197
|
+
className: "text-body-md leading-relaxed",
|
|
198
198
|
children: [/* @__PURE__ */ v(f, {
|
|
199
199
|
ref: u,
|
|
200
200
|
value: c,
|
|
201
201
|
onChange: (e) => l(e.target.value),
|
|
202
202
|
onKeyDown: h,
|
|
203
203
|
onBlur: p,
|
|
204
|
-
className: "resize-none rounded-control-inner bg-surface-raised-hover px-ds-02 py-ds-01 text-
|
|
204
|
+
className: "resize-none rounded-control-inner bg-surface-raised-hover px-ds-02 py-ds-01 text-body-md leading-relaxed",
|
|
205
205
|
rows: 2
|
|
206
206
|
}), /* @__PURE__ */ v("div", {
|
|
207
|
-
className: "mt-ds-01 text-
|
|
207
|
+
className: "mt-ds-01 text-caption text-surface-fg-subtle/50",
|
|
208
208
|
children: "Enter to save · Escape to cancel"
|
|
209
209
|
})]
|
|
210
210
|
}) : /* @__PURE__ */ v("div", {
|
|
211
|
-
className: i("text-
|
|
211
|
+
className: i("text-body-md leading-relaxed text-surface-fg whitespace-pre-wrap", r && "cursor-pointer hover:bg-surface-raised-hover rounded-control-inner transition-colors"),
|
|
212
212
|
onClick: d,
|
|
213
213
|
role: r ? "button" : void 0,
|
|
214
214
|
tabIndex: r ? 0 : void 0,
|
|
@@ -226,7 +226,7 @@ function L({ reactions: e, onReact: t }) {
|
|
|
226
226
|
type: "button",
|
|
227
227
|
onClick: () => t(e.emoji),
|
|
228
228
|
"aria-label": `${e.emoji} ${e.count} reaction${e.count === 1 ? "" : "s"}${e.reacted ? ", you reacted" : ""}`,
|
|
229
|
-
className: i("inline-flex items-center gap-ds-01 rounded-pill px-ds-02 py-ds-01 text-
|
|
229
|
+
className: i("inline-flex items-center gap-ds-01 rounded-pill px-ds-02 py-ds-01 text-body-xs transition-colors", e.reacted ? "bg-accent-3 ring-1 ring-accent-6" : "bg-surface-raised-hover hover:bg-surface-raised-active"),
|
|
230
230
|
children: [/* @__PURE__ */ v("span", { children: e.emoji }), /* @__PURE__ */ v("span", { children: e.count })]
|
|
231
231
|
}, e.emoji))
|
|
232
232
|
});
|
|
@@ -298,7 +298,7 @@ var B = Object.assign(A, {
|
|
|
298
298
|
"aria-label": t || "Type a message",
|
|
299
299
|
disabled: n,
|
|
300
300
|
rows: 1,
|
|
301
|
-
className: "flex-1 resize-none bg-transparent px-ds-02 py-ds-01 text-
|
|
301
|
+
className: "flex-1 resize-none bg-transparent px-ds-02 py-ds-01 text-body-sm text-surface-fg placeholder:text-surface-fg-subtle/50 focus:outline-hidden disabled:opacity-50",
|
|
302
302
|
style: { maxHeight: 160 }
|
|
303
303
|
}),
|
|
304
304
|
r ? /* @__PURE__ */ v(d, {
|
|
@@ -325,7 +325,7 @@ var B = Object.assign(A, {
|
|
|
325
325
|
c
|
|
326
326
|
]
|
|
327
327
|
}), l && /* @__PURE__ */ v("p", {
|
|
328
|
-
className: "mt-ds-02 text-center text-
|
|
328
|
+
className: "mt-ds-02 text-center text-caption text-surface-fg-subtle/50",
|
|
329
329
|
children: l
|
|
330
330
|
})]
|
|
331
331
|
});
|
|
@@ -405,7 +405,7 @@ var H = _.forwardRef(({ children: e, autoScroll: t = !0, newMessageCount: n = 0,
|
|
|
405
405
|
},
|
|
406
406
|
transition: r.fade,
|
|
407
407
|
onClick: k,
|
|
408
|
-
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-
|
|
408
|
+
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-body-xs font-medium text-accent-fg shadow-raised transition-colors hover:bg-accent-10",
|
|
409
409
|
children: [n, " new"]
|
|
410
410
|
}) })
|
|
411
411
|
]
|
|
@@ -433,18 +433,18 @@ var W = _.forwardRef(({ icon: t, timestamp: n, variant: r = "event", children: a
|
|
|
433
433
|
children: u(t) ?? /* @__PURE__ */ v(o, { icon: b })
|
|
434
434
|
}),
|
|
435
435
|
/* @__PURE__ */ v("span", {
|
|
436
|
-
className: "text-
|
|
436
|
+
className: "text-body-sm text-error-11",
|
|
437
437
|
children: a
|
|
438
438
|
}),
|
|
439
439
|
n && /* @__PURE__ */ v("span", {
|
|
440
|
-
className: "text-
|
|
440
|
+
className: "text-body-sm text-error-11/60",
|
|
441
441
|
children: U(n)
|
|
442
442
|
})
|
|
443
443
|
]
|
|
444
444
|
})
|
|
445
445
|
}) : /* @__PURE__ */ y("div", {
|
|
446
446
|
ref: l,
|
|
447
|
-
className: i("flex items-center gap-ds-02 rounded-control-inner bg-surface-raised-hover/30 px-ds-02 py-ds-01 -mx-ds-02 text-
|
|
447
|
+
className: i("flex items-center gap-ds-02 rounded-control-inner bg-surface-raised-hover/30 px-ds-02 py-ds-01 -mx-ds-02 text-body-sm text-surface-fg-subtle/60", s),
|
|
448
448
|
...c,
|
|
449
449
|
children: [
|
|
450
450
|
/* @__PURE__ */ v(e, {
|
|
@@ -473,7 +473,7 @@ function K({ users: e, className: t }) {
|
|
|
473
473
|
initial: { opacity: 0 },
|
|
474
474
|
animate: { opacity: 1 },
|
|
475
475
|
exit: { opacity: 0 },
|
|
476
|
-
className: "flex items-center gap-ds-02 text-
|
|
476
|
+
className: "flex items-center gap-ds-02 text-caption text-surface-fg-subtle",
|
|
477
477
|
children: [/* @__PURE__ */ v("span", {
|
|
478
478
|
className: "flex items-center gap-ds-01",
|
|
479
479
|
children: [
|
|
@@ -506,7 +506,7 @@ function q({ label: e = "NEW", count: t, className: n }) {
|
|
|
506
506
|
children: [
|
|
507
507
|
/* @__PURE__ */ v("div", { className: "flex-1 border-t-2 border-accent-7" }),
|
|
508
508
|
/* @__PURE__ */ v("span", {
|
|
509
|
-
className: "px-ds-03 text-
|
|
509
|
+
className: "px-ds-03 text-body-xs font-semibold text-accent-11",
|
|
510
510
|
children: t ? `${t} ${e}` : e
|
|
511
511
|
}),
|
|
512
512
|
/* @__PURE__ */ v("div", { className: "flex-1 border-t-2 border-accent-7" })
|
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-label-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-caption 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-body-md text-surface-fg\">{name}</span>\n {badge}\n {timeStr && (\n <span className=\"text-body-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-body-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-body-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-body-md leading-relaxed\"\n rows={2}\n />\n <div className=\"mt-ds-01 text-caption 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-body-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-body-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-body-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-caption 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-body-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-body-sm text-error-11\">{children}</span>\n {timestamp && (\n <span className=\"text-body-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-body-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-caption 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-body-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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"}
|
|
@@ -81,7 +81,7 @@ function g({ url: g, initialPage: _, onError: v }) {
|
|
|
81
81
|
})
|
|
82
82
|
}),
|
|
83
83
|
/* @__PURE__ */ c("div", {
|
|
84
|
-
className: "flex items-center gap-ds-01 text-
|
|
84
|
+
className: "flex items-center gap-ds-01 text-caption text-surface-fg-muted",
|
|
85
85
|
children: [/* @__PURE__ */ s("input", {
|
|
86
86
|
type: "text",
|
|
87
87
|
value: C,
|