@devalok/shilp-sutra 0.44.0 → 0.45.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 +13 -11
- package/BREAKING.json +209 -27
- package/MIGRATION.md +34 -0
- package/README.md +12 -0
- package/dist/_chunks/badge-group.js +1 -0
- package/dist/_chunks/badge-group.js.map +1 -1
- package/dist/_chunks/block-shell.js +25 -0
- package/dist/_chunks/block-shell.js.map +1 -0
- package/dist/_chunks/chat.js +4 -2
- package/dist/_chunks/chat.js.map +1 -1
- package/dist/_chunks/document-preview.js +1 -1
- package/dist/_chunks/image-preview.js +4 -4
- package/dist/_chunks/shared.js +65 -78
- package/dist/_chunks/shared.js.map +1 -1
- package/dist/_chunks/success.js +108 -106
- package/dist/_chunks/success.js.map +1 -1
- package/dist/ai/blocks/block-shell.d.ts +19 -0
- package/dist/ai/blocks/block-shell.d.ts.map +1 -0
- package/dist/ai/blocks/block-table.d.ts.map +1 -1
- package/dist/ai/blocks/confirm.d.ts.map +1 -1
- package/dist/ai/blocks/error.d.ts.map +1 -1
- package/dist/ai/blocks/error.js +5 -5
- package/dist/ai/blocks/error.js.map +1 -1
- package/dist/ai/blocks/success.d.ts.map +1 -1
- package/dist/ai/blocks/text.d.ts.map +1 -1
- package/dist/ai/blocks/text.js +4 -3
- package/dist/ai/blocks/text.js.map +1 -1
- package/dist/composed/activity-feed.d.ts.map +1 -1
- package/dist/composed/activity-feed.js +14 -12
- package/dist/composed/activity-feed.js.map +1 -1
- package/dist/composed/file-preview/audio-preview.d.ts.map +1 -1
- package/dist/composed/file-preview/shared.d.ts +10 -0
- package/dist/composed/file-preview/shared.d.ts.map +1 -1
- package/dist/composed/file-preview/video-preview.d.ts.map +1 -1
- package/dist/composed/file-preview.js +149 -188
- package/dist/composed/file-preview.js.map +1 -1
- package/dist/composed/master-detail.d.ts.map +1 -1
- package/dist/composed/master-detail.js +13 -4
- package/dist/composed/master-detail.js.map +1 -1
- package/dist/composed/schedule-view.d.ts.map +1 -1
- package/dist/composed/schedule-view.js +52 -39
- package/dist/composed/schedule-view.js.map +1 -1
- package/dist/shell/notification-preferences.d.ts.map +1 -1
- package/dist/shell/notification-preferences.js +115 -114
- package/dist/shell/notification-preferences.js.map +1 -1
- package/dist/ui/badge-group.d.ts.map +1 -1
- package/dist/ui/card.d.ts +66 -16
- package/dist/ui/card.d.ts.map +1 -1
- package/dist/ui/card.js +85 -60
- package/dist/ui/card.js.map +1 -1
- package/dist/ui/chat/message.d.ts.map +1 -1
- package/dist/ui/color-input.d.ts.map +1 -1
- package/dist/ui/color-input.js +18 -18
- package/dist/ui/color-input.js.map +1 -1
- package/dist/ui/data-table-body.d.ts.map +1 -1
- package/dist/ui/data-table-body.js +94 -64
- package/dist/ui/data-table-body.js.map +1 -1
- package/dist/ui/data-table-card.d.ts.map +1 -1
- package/dist/ui/data-table-card.js +50 -43
- package/dist/ui/data-table-card.js.map +1 -1
- package/dist/ui/data-table-context.d.ts +0 -4
- package/dist/ui/data-table-context.d.ts.map +1 -1
- package/dist/ui/data-table-context.js +8 -12
- package/dist/ui/data-table-context.js.map +1 -1
- package/dist/ui/data-table-header.d.ts.map +1 -1
- package/dist/ui/data-table-header.js +2 -2
- package/dist/ui/data-table-header.js.map +1 -1
- package/dist/ui/data-table.d.ts.map +1 -1
- package/dist/ui/data-table.js +185 -182
- package/dist/ui/data-table.js.map +1 -1
- package/dist/ui/index.d.ts +3 -2
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +59 -58
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/segmented-control.js +4 -4
- package/dist/ui/segmented-control.js.map +1 -1
- package/dist/ui/separator.d.ts +6 -5
- package/dist/ui/separator.d.ts.map +1 -1
- package/dist/ui/separator.js +7 -10
- package/dist/ui/separator.js.map +1 -1
- package/dist/ui/split-button.d.ts.map +1 -1
- package/dist/ui/split-button.js +62 -129
- package/dist/ui/split-button.js.map +1 -1
- package/dist/ui/stat-card.d.ts +7 -0
- package/dist/ui/stat-card.d.ts.map +1 -1
- package/dist/ui/stat-card.js +144 -126
- package/dist/ui/stat-card.js.map +1 -1
- package/dist/ui/table-row-link.d.ts +45 -0
- package/dist/ui/table-row-link.d.ts.map +1 -0
- package/dist/ui/table-row-link.js +16 -0
- package/dist/ui/table-row-link.js.map +1 -0
- package/dist/ui/table.d.ts +49 -5
- package/dist/ui/table.d.ts.map +1 -1
- package/dist/ui/table.js +39 -29
- package/dist/ui/table.js.map +1 -1
- package/dist/ui/toast-types.d.ts +10 -0
- package/dist/ui/toast-types.d.ts.map +1 -1
- package/dist/ui/toast.d.ts +6 -2
- package/dist/ui/toast.d.ts.map +1 -1
- package/dist/ui/toast.js +56 -54
- package/dist/ui/toast.js.map +1 -1
- package/docs/components/composed/content-card.md +2 -0
- package/docs/components/ui/button.md +3 -3
- package/docs/components/ui/card.md +27 -10
- package/docs/components/ui/color-input.md +2 -2
- package/docs/components/ui/data-table.md +8 -1
- package/docs/components/ui/segmented-control.md +2 -2
- package/docs/components/ui/separator.md +3 -1
- package/docs/components/ui/split-button.md +3 -0
- package/docs/components/ui/stat-card.md +10 -2
- package/docs/components/ui/table-row-link.md +41 -0
- package/docs/components/ui/table.md +69 -0
- package/docs/components/ui/toast.md +10 -6
- package/docs/recipes/install-next-app-router.md +1 -1
- package/docs/recipes/troubleshoot.md +1 -1
- package/llms.txt +159 -781
- package/make-kit/components/card.md +54 -16
- package/make-kit/components/table.md +45 -7
- package/make-kit/foundations/spacing.md +3 -1
- package/make-kit/foundations/surfaces.md +1 -1
- package/mcp-manifest.json +12349 -0
- package/mcp-manifest.schema.json +232 -0
- package/package.json +8 -3
- package/skill/README.md +0 -1
- package/skill/SKILL.md +9 -8
- package/skill/references/components.md +159 -781
- package/skill/references/setup-next-app-router.md +1 -1
- package/skill/references/troubleshoot.md +1 -1
- package/llms-full.txt +0 -7198
- package/llms-quick.txt +0 -251
- package/skill/references/components-full.md +0 -7200
package/AGENTS.md
CHANGED
|
@@ -18,22 +18,24 @@ If you are a human, read [README.md](./README.md) instead.
|
|
|
18
18
|
|
|
19
19
|
<!-- BEGIN:shilp-sutra-agent-rules -->
|
|
20
20
|
|
|
21
|
-
##
|
|
21
|
+
## How to get details, in priority order
|
|
22
22
|
|
|
23
|
-
1.
|
|
24
|
-
2. **`packages/core/llms.txt`** —
|
|
25
|
-
3. **`packages/core/docs/
|
|
26
|
-
4. **`packages/core/
|
|
27
|
-
5. **`packages/core/docs/recipes
|
|
28
|
-
6. **`
|
|
23
|
+
1. **shilp-sutra MCP** (if connected) — version-exact answers as JSON, cheapest on context: `find_component(query)`, `get_component(name, sections?)`, `get_tokens(category)`, `get_setup(framework)`, `upgrade(from, to)`, `search_docs(query)`. Always pass the consumer's installed version (from `node_modules/@devalok/shilp-sutra/package.json`) as `version`.
|
|
24
|
+
2. **`packages/core/llms.txt`** — the ~3K-token router: what exists + where to get detail. Load this by default; it is deliberately tiny.
|
|
25
|
+
3. **`packages/core/docs/components/<tier>/<name>.md`** — single-component doc (~3K tokens: props, examples, composability, gotchas). Read ONLY the components you're using — never bulk-read the directory or concatenate these.
|
|
26
|
+
4. **`packages/core/mcp-manifest.json`** — everything machine-readable (props, tokens, composition; react-docgen shape). Prefer targeted reads over prose when you need structured data without the MCP.
|
|
27
|
+
5. **`packages/core/docs/recipes/<framework>.md`** — copy-paste install + setup for the user's framework.
|
|
28
|
+
6. **`packages/core/docs/recipes/upgrading.md`** + **`MIGRATION.md`** — read BOTH before any version bump. See the hard constraint below.
|
|
29
|
+
7. **`node_modules/@devalok/shilp-sutra/BREAKING.json`** — machine-readable manifest of every breaking change per version (moves, type narrowings, removals, renames). Read this programmatically when planning an upgrade — schema in `BREAKING.schema.json`. Lets you answer "does my code import any of these moved symbols?" without parsing CHANGELOG prose.
|
|
30
|
+
|
|
31
|
+
(`llms-full.txt` and `llms-quick.txt` were removed in 0.45 — the router + per-component docs + manifest replaced them. Do not look for them.)
|
|
29
32
|
|
|
30
33
|
When the package is installed in a consumer project, the same files live at:
|
|
31
34
|
|
|
32
|
-
- `node_modules/@devalok/shilp-sutra/llms-quick.txt`
|
|
33
35
|
- `node_modules/@devalok/shilp-sutra/llms.txt`
|
|
34
|
-
- `node_modules/@devalok/shilp-sutra/llms-full.txt`
|
|
35
|
-
- `node_modules/@devalok/shilp-sutra/docs/recipes/`
|
|
36
36
|
- `node_modules/@devalok/shilp-sutra/docs/components/`
|
|
37
|
+
- `node_modules/@devalok/shilp-sutra/mcp-manifest.json`
|
|
38
|
+
- `node_modules/@devalok/shilp-sutra/docs/recipes/`
|
|
37
39
|
|
|
38
40
|
Read these local files. Your training data is outdated and will hallucinate APIs that do not exist in the installed version.
|
|
39
41
|
|
|
@@ -72,7 +74,7 @@ If the framework is not in the table, fall back to **`install-vite.md`** (closes
|
|
|
72
74
|
- **Per-component imports keep RSC fast AND avoid peer-dep cliffs.** `@devalok/shilp-sutra/ui/text` is server-safe and pulls only its own peers. The barrel `@devalok/shilp-sutra/ui` re-exports every component — including ones with hard peer-dep requirements (e.g. `input-otp`) — so it forces those peers to be installed even when you never render those components. With all peers installed the barrel also works in RSC (Next 16 honours each per-component `"use client"`), but the client bundle is larger than necessary. Prefer per-component imports for new code; existing barrel usage is not an emergency.
|
|
73
75
|
- **Spacing tokens use the `--spacing-ds-*` namespace** (utilities like `p-ds-04`, `gap-ds-03`). Tailwind 4's default numeric scale (`p-4`, `gap-2`) **coexists by design** — both are valid. Pick `p-ds-*` when the value should track DS theme changes (a card's internal padding, a form row's gap); pick `p-N` for one-off layout values (a hero section's vertical breathing room). Do NOT mass-codemod `p-4` → `p-ds-04` — that is not what the package authors did. Typography composites use `text-ds-body-md`, etc.
|
|
74
76
|
- **Bare `shadow` is dead in Tailwind 4.** Use `shadow-raised`, `shadow-overlay`, `shadow-floating`.
|
|
75
|
-
- **Do not invent variant names.** Variant names live in CVA source. Grep `packages/core/src/ui/<component>.tsx` or check `
|
|
77
|
+
- **Do not invent variant names.** Variant names live in CVA source. Grep `packages/core/src/ui/<component>.tsx` or check the component's `props` entry in `mcp-manifest.json` for the authoritative list.
|
|
76
78
|
- **Default to `variant="soft"`** over `variant="outline"` for non-primary Button actions.
|
|
77
79
|
|
|
78
80
|
## Spacing cadence (when building layouts — forms, settings, login, anything with vertical rhythm)
|
package/BREAKING.json
CHANGED
|
@@ -6,33 +6,195 @@
|
|
|
6
6
|
"summary": "Barrel peer-cliff cleanup — 12 symbol families removed from /ui, /composed, /ai barrels (per-component subpath only). Icon API unification narrows the `icon` prop on 14 components from React.ReactNode to IconInput.",
|
|
7
7
|
"migrationDoc": "MIGRATION.md#v0400--barrel-peer-cliff-cleanup--icon-api-unification",
|
|
8
8
|
"moved": [
|
|
9
|
-
{
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
{
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
{
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
{
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
9
|
+
{
|
|
10
|
+
"symbol": "Toaster",
|
|
11
|
+
"from": "@devalok/shilp-sutra/ui",
|
|
12
|
+
"to": "@devalok/shilp-sutra/ui/toaster",
|
|
13
|
+
"peer": "sonner",
|
|
14
|
+
"eslintRule": "prefer-per-component-import"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"symbol": "toast",
|
|
18
|
+
"from": "@devalok/shilp-sutra/ui",
|
|
19
|
+
"to": "@devalok/shilp-sutra/ui/toast",
|
|
20
|
+
"peer": "sonner",
|
|
21
|
+
"eslintRule": "prefer-per-component-import"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"symbol": "InputOTP",
|
|
25
|
+
"from": "@devalok/shilp-sutra/ui",
|
|
26
|
+
"to": "@devalok/shilp-sutra/ui/input-otp",
|
|
27
|
+
"peer": "input-otp",
|
|
28
|
+
"eslintRule": "prefer-per-component-import"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"symbol": "DatePicker",
|
|
32
|
+
"from": "@devalok/shilp-sutra/composed",
|
|
33
|
+
"to": "@devalok/shilp-sutra/composed/date-picker",
|
|
34
|
+
"peer": "date-fns",
|
|
35
|
+
"eslintRule": "prefer-per-component-import"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"symbol": "DateRangePicker",
|
|
39
|
+
"from": "@devalok/shilp-sutra/composed",
|
|
40
|
+
"to": "@devalok/shilp-sutra/composed/date-picker",
|
|
41
|
+
"peer": "date-fns",
|
|
42
|
+
"eslintRule": "prefer-per-component-import"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"symbol": "DateTimePicker",
|
|
46
|
+
"from": "@devalok/shilp-sutra/composed",
|
|
47
|
+
"to": "@devalok/shilp-sutra/composed/date-picker",
|
|
48
|
+
"peer": "date-fns",
|
|
49
|
+
"eslintRule": "prefer-per-component-import"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"symbol": "TimePicker",
|
|
53
|
+
"from": "@devalok/shilp-sutra/composed",
|
|
54
|
+
"to": "@devalok/shilp-sutra/composed/date-picker",
|
|
55
|
+
"peer": "date-fns",
|
|
56
|
+
"eslintRule": "prefer-per-component-import"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"symbol": "CalendarGrid",
|
|
60
|
+
"from": "@devalok/shilp-sutra/composed",
|
|
61
|
+
"to": "@devalok/shilp-sutra/composed/date-picker",
|
|
62
|
+
"peer": "date-fns",
|
|
63
|
+
"eslintRule": "prefer-per-component-import"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"symbol": "MonthPicker",
|
|
67
|
+
"from": "@devalok/shilp-sutra/composed",
|
|
68
|
+
"to": "@devalok/shilp-sutra/composed/date-picker",
|
|
69
|
+
"peer": "date-fns",
|
|
70
|
+
"eslintRule": "prefer-per-component-import"
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"symbol": "YearPicker",
|
|
74
|
+
"from": "@devalok/shilp-sutra/composed",
|
|
75
|
+
"to": "@devalok/shilp-sutra/composed/date-picker",
|
|
76
|
+
"peer": "date-fns",
|
|
77
|
+
"eslintRule": "prefer-per-component-import"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"symbol": "Presets",
|
|
81
|
+
"from": "@devalok/shilp-sutra/composed",
|
|
82
|
+
"to": "@devalok/shilp-sutra/composed/date-picker",
|
|
83
|
+
"peer": "date-fns",
|
|
84
|
+
"eslintRule": "prefer-per-component-import"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"symbol": "useCalendar",
|
|
88
|
+
"from": "@devalok/shilp-sutra/composed",
|
|
89
|
+
"to": "@devalok/shilp-sutra/composed/date-picker",
|
|
90
|
+
"peer": "date-fns",
|
|
91
|
+
"eslintRule": "prefer-per-component-import"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"symbol": "EmojiPicker",
|
|
95
|
+
"from": "@devalok/shilp-sutra/composed",
|
|
96
|
+
"to": "@devalok/shilp-sutra/composed/emoji-picker",
|
|
97
|
+
"peer": "@emoji-mart/data",
|
|
98
|
+
"eslintRule": "prefer-per-component-import"
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"symbol": "EmojiPickerPopover",
|
|
102
|
+
"from": "@devalok/shilp-sutra/composed",
|
|
103
|
+
"to": "@devalok/shilp-sutra/composed/emoji-picker",
|
|
104
|
+
"peer": "@emoji-mart/data",
|
|
105
|
+
"eslintRule": "prefer-per-component-import"
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"symbol": "EmojiNode",
|
|
109
|
+
"from": "@devalok/shilp-sutra/composed",
|
|
110
|
+
"to": "@devalok/shilp-sutra/composed/extensions/emoji-node",
|
|
111
|
+
"peer": "@tiptap/react",
|
|
112
|
+
"eslintRule": "prefer-per-component-import"
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"symbol": "createEmojiSuggestion",
|
|
116
|
+
"from": "@devalok/shilp-sutra/composed",
|
|
117
|
+
"to": "@devalok/shilp-sutra/composed/extensions/emoji-suggestion",
|
|
118
|
+
"peer": "@tiptap/react",
|
|
119
|
+
"eslintRule": "prefer-per-component-import"
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"symbol": "FilePreview",
|
|
123
|
+
"from": "@devalok/shilp-sutra/composed",
|
|
124
|
+
"to": "@devalok/shilp-sutra/composed/file-preview",
|
|
125
|
+
"peer": "react-pdf",
|
|
126
|
+
"eslintRule": "prefer-per-component-import"
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
"symbol": "MarkdownViewer",
|
|
130
|
+
"from": "@devalok/shilp-sutra/composed",
|
|
131
|
+
"to": "@devalok/shilp-sutra/composed/markdown-viewer",
|
|
132
|
+
"peer": "react-markdown",
|
|
133
|
+
"eslintRule": "prefer-per-component-import"
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"symbol": "RichTextEditor",
|
|
137
|
+
"from": "@devalok/shilp-sutra/composed",
|
|
138
|
+
"to": "@devalok/shilp-sutra/composed/rich-text-editor",
|
|
139
|
+
"peer": "@tiptap/react",
|
|
140
|
+
"eslintRule": "prefer-per-component-import"
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
"symbol": "RichTextViewer",
|
|
144
|
+
"from": "@devalok/shilp-sutra/composed",
|
|
145
|
+
"to": "@devalok/shilp-sutra/composed/rich-text-editor",
|
|
146
|
+
"peer": "@tiptap/react",
|
|
147
|
+
"eslintRule": "prefer-per-component-import"
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
"symbol": "RichChatInput",
|
|
151
|
+
"from": "@devalok/shilp-sutra/composed",
|
|
152
|
+
"to": "@devalok/shilp-sutra/composed/rich-chat-input",
|
|
153
|
+
"peer": "@tiptap/react",
|
|
154
|
+
"eslintRule": "prefer-per-component-import"
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"symbol": "AudioPlayer",
|
|
158
|
+
"from": "@devalok/shilp-sutra/composed",
|
|
159
|
+
"to": "@devalok/shilp-sutra/composed/rich-chat-input",
|
|
160
|
+
"peer": "@tiptap/react",
|
|
161
|
+
"eslintRule": "prefer-per-component-import"
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
"symbol": "AudioWaveform",
|
|
165
|
+
"from": "@devalok/shilp-sutra/composed",
|
|
166
|
+
"to": "@devalok/shilp-sutra/composed/rich-chat-input",
|
|
167
|
+
"peer": "@tiptap/react",
|
|
168
|
+
"eslintRule": "prefer-per-component-import"
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
"symbol": "useVoiceRecorder",
|
|
172
|
+
"from": "@devalok/shilp-sutra/composed",
|
|
173
|
+
"to": "@devalok/shilp-sutra/composed/rich-chat-input",
|
|
174
|
+
"peer": "@tiptap/react",
|
|
175
|
+
"eslintRule": "prefer-per-component-import"
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
"symbol": "BlockRenderer",
|
|
179
|
+
"from": "@devalok/shilp-sutra/ai",
|
|
180
|
+
"to": "@devalok/shilp-sutra/ai/block-renderer",
|
|
181
|
+
"peer": "react-markdown",
|
|
182
|
+
"eslintRule": "prefer-per-component-import"
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
"symbol": "ErrorBlock",
|
|
186
|
+
"from": "@devalok/shilp-sutra/ai/blocks",
|
|
187
|
+
"to": "@devalok/shilp-sutra/ai/blocks/error",
|
|
188
|
+
"peer": "react-markdown",
|
|
189
|
+
"eslintRule": "prefer-per-component-import"
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"symbol": "TextBlock",
|
|
193
|
+
"from": "@devalok/shilp-sutra/ai/blocks",
|
|
194
|
+
"to": "@devalok/shilp-sutra/ai/blocks/text",
|
|
195
|
+
"peer": "react-markdown",
|
|
196
|
+
"eslintRule": "prefer-per-component-import"
|
|
197
|
+
}
|
|
36
198
|
],
|
|
37
199
|
"narrowed": [
|
|
38
200
|
{
|
|
@@ -61,6 +223,26 @@
|
|
|
61
223
|
"fix": "Retype the icon source from React.ReactNode to React.ReactElement (or import the IconInput type). Build-time only; runtime JSX is unaffected."
|
|
62
224
|
}
|
|
63
225
|
]
|
|
226
|
+
},
|
|
227
|
+
"0.45.0": {
|
|
228
|
+
"summary": "AI doc surface: llms-full.txt and llms-quick.txt removed from the tarball. Replaced by the hosted MCP (https://shilp-sutra.devalok.in/mcp), the llms.txt router, per-component docs, and mcp-manifest.json. No TypeScript-level breaks.",
|
|
229
|
+
"migrationDoc": "MIGRATION.md#v0450--card-spacing-variable-table-overhaul-ai-docs-switch-to-mcp",
|
|
230
|
+
"removed": [
|
|
231
|
+
{
|
|
232
|
+
"symbol": "llms-full.txt",
|
|
233
|
+
"where": "npm tarball root",
|
|
234
|
+
"replacement": "mcp-manifest.json + docs/components/<tier>/<name>.md (or the hosted MCP get_component tool)"
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
"symbol": "llms-quick.txt",
|
|
238
|
+
"where": "npm tarball root",
|
|
239
|
+
"replacement": "llms.txt (now a ~2.5K-token router)"
|
|
240
|
+
}
|
|
241
|
+
],
|
|
242
|
+
"notes": [
|
|
243
|
+
"New hosted MCP at https://shilp-sutra.devalok.in/mcp — six read-only tools, version param on every tool; upgrade(from,to) accepts pre-0.45 versions.",
|
|
244
|
+
"New mcp-manifest.json ships at the package root (schema: mcp-manifest.schema.json)."
|
|
245
|
+
]
|
|
64
246
|
}
|
|
65
247
|
}
|
|
66
248
|
}
|
package/MIGRATION.md
CHANGED
|
@@ -4,6 +4,40 @@ 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.45.0 — Card spacing variable, table overhaul, AI docs switch to MCP
|
|
8
|
+
|
|
9
|
+
Nothing breaks at the TypeScript level. One doc-surface removal + two visual things to check after upgrade:
|
|
10
|
+
|
|
11
|
+
### REMOVED: `llms-full.txt` and `llms-quick.txt` (AI doc surface)
|
|
12
|
+
|
|
13
|
+
The concatenated doc dumps no longer ship in the tarball. Replacements, in priority order:
|
|
14
|
+
|
|
15
|
+
1. **Hosted MCP** (new): `claude mcp add --transport http shilp-sutra https://shilp-sutra.devalok.in/mcp` — six tools (`find_component`, `get_component`, `get_tokens`, `get_setup`, `upgrade`, `search_docs`), every one takes a `version` param; pass your installed version for version-exact answers.
|
|
16
|
+
2. `llms.txt` — now a ~2.5K-token router (what exists + where to get detail), not a cheatsheet.
|
|
17
|
+
3. `docs/components/<tier>/<name>.md` — per-component reference (~3K tokens each), unchanged.
|
|
18
|
+
4. `mcp-manifest.json` (new, package root) — all props/tokens/composition as JSON (react-docgen shape, schema in `mcp-manifest.schema.json`).
|
|
19
|
+
|
|
20
|
+
Anything that read the removed file paths (custom agent rules, scripts, editor doc references) must switch to one of the above.
|
|
21
|
+
|
|
22
|
+
### Visual: table rows tighten
|
|
23
|
+
|
|
24
|
+
Standard density rows go from ~53px to ~37px (comfortable ~85px → ~45px) — the density map was re-benchmarked against Carbon/Radix/Polaris. If a screen depended on the old airy rows, pass `density="comfortable"`. Rows also regain their hairline separators (they had been silently lost) and row hover is now actually visible on cards.
|
|
25
|
+
|
|
26
|
+
### CSS selectors targeting Card/Table internals
|
|
27
|
+
|
|
28
|
+
Card's per-size literal classes (`px-ds-05b` on slots, `top-ds-05b` on CardAction) are gone — spacing now flows through `--card-spacing`/`--card-gap` CSS variables. Consumer `className` overrides via tw-merge keep working; only hand-written CSS selectors targeting the old class names need to move to the variables:
|
|
29
|
+
|
|
30
|
+
```diff
|
|
31
|
+
- .my-card .px-ds-05b { … }
|
|
32
|
+
+ .my-card { --card-spacing: 24px; }
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Table cells similarly moved from `py-ds-03 px-ds-03` literals to `py-(--table-py) px-ds-04` + `--table-edge` on first/last cells.
|
|
36
|
+
|
|
37
|
+
### New APIs (additive)
|
|
38
|
+
|
|
39
|
+
`CardBleed`, `CardSection`, `Card orientation="horizontal"`, `StatCard size`, `Table density/striped`, `TableCell/TableHead numeric`, `TableRowActions`, `TableRowLink` (`ui/table-row-link`). StatCard's `footer` now renders behind a full-width rule instead of an inset border — purely visual.
|
|
40
|
+
|
|
7
41
|
## v0.44.0 — Card system: gap-model, corner slots, truncation primitive
|
|
8
42
|
|
|
9
43
|
Three breaking changes (`Card` `accent`/`accentColor` removed, `StatCard` `surface` → `variant`, `ContentCard` deprecated). Everything else is additive.
|
package/README.md
CHANGED
|
@@ -43,6 +43,18 @@ import { Button } from '@devalok/shilp-sutra/ui/button'
|
|
|
43
43
|
|
|
44
44
|
No `tailwind.config.ts` required from us. Your own plugins or content globs go in `globals.css` via TW4 directives (`@plugin`, `@source`, `@theme`).
|
|
45
45
|
|
|
46
|
+
## AI Agents & MCP
|
|
47
|
+
|
|
48
|
+
Live docs MCP — version-exact component/token/migration answers for any MCP-capable agent:
|
|
49
|
+
|
|
50
|
+
```sh
|
|
51
|
+
claude mcp add --transport http shilp-sutra https://shilp-sutra.devalok.in/mcp
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Six read-only tools: `find_component`, `get_component`, `get_tokens`, `get_setup`, `upgrade`, `search_docs`. Every tool takes a `version` param — pass your installed version (from `node_modules/@devalok/shilp-sutra/package.json`) so answers match your prop surface exactly.
|
|
55
|
+
|
|
56
|
+
Without MCP: `llms.txt` (router) → `docs/components/<tier>/<name>.md` (per-component) → `mcp-manifest.json` (all props/tokens/composition as JSON). Full contract in `AGENTS.md`.
|
|
57
|
+
|
|
46
58
|
## Peer Dependencies
|
|
47
59
|
|
|
48
60
|
### Required
|
|
@@ -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, useReducedMotion } from 'framer-motion'\nimport * as React from 'react'\n\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 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 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 prefersReducedMotion = useReducedMotion()\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 + continuous 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=\"relative inline-flex h-1.5 w-1.5 shrink-0\"\n aria-hidden=\"true\"\n >\n <motion.span\n className=\"absolute inset-0 rounded-pill bg-current\"\n animate={prefersReducedMotion ? undefined : { scale: [1, 2.5], opacity: [0.35, 0] }}\n transition={prefersReducedMotion ? { duration: 0 } : { repeat: Infinity, repeatDelay: 0.3, duration: 1.2, ease: [0, 0, 0.58, 1] }}\n />\n <span className=\"relative h-1.5 w-1.5 rounded-pill bg-current\" />\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-[16px] min-h-[16px]'\n : 'p-px',\n )}\n aria-label={\n `Remove ${typeof children === 'string' ? children : ''}`.trim() || 'Remove'\n }\n >\n <Icon icon={IconX} size=\"xs\" />\n </button>\n )}\n </Comp>\n )\n },\n)\nBadge.displayName = 'Badge'\n\nimport { BadgeGroup } from './badge-group'\nimport { BadgeIndicator } from './badge-indicator'\n\nconst BadgeCompound = Object.assign(Badge, {\n Indicator: BadgeIndicator,\n Group: BadgeGroup,\n})\n\nexport { BadgeCompound as Badge, type BadgeColor,type BadgeProps, badgeVariants }\n","'use client'\n\nimport * as React from 'react'\n\nimport { Badge, type BadgeProps } from './badge'\nimport { cn } from './lib/utils'\n\nconst GAP_CLASSES = {\n tight: 'gap-1',\n default: 'gap-1.5',\n loose: 'gap-2',\n} as const\n\nexport interface BadgeGroupProps {\n max?: number\n gap?: keyof typeof GAP_CLASSES\n size?: BadgeProps['size']\n onOverflowClick?: () => void\n className?: string\n children: React.ReactNode\n}\n\nexport function BadgeGroup({\n max,\n gap = 'default',\n size,\n onOverflowClick,\n className,\n children,\n}: BadgeGroupProps) {\n const childArray = React.Children.toArray(children)\n const total = childArray.length\n const hasOverflow = max !== undefined && total > max\n const visible = hasOverflow ? childArray.slice(0, max) : childArray\n const overflowCount = hasOverflow ? total - max! : 0\n\n return (\n <div className={cn('flex flex-wrap items-center', GAP_CLASSES[gap], className)}>\n {visible}\n {hasOverflow && (\n <Badge\n variant=\"outline\"\n color=\"neutral\"\n size={size ?? 'sm'}\n onClick={onOverflowClick}\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, useReducedMotion } from 'framer-motion'\nimport * as React from 'react'\n\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 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 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 prefersReducedMotion = useReducedMotion()\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 + continuous 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=\"relative inline-flex h-1.5 w-1.5 shrink-0\"\n aria-hidden=\"true\"\n >\n <motion.span\n className=\"absolute inset-0 rounded-pill bg-current\"\n animate={prefersReducedMotion ? undefined : { scale: [1, 2.5], opacity: [0.35, 0] }}\n transition={prefersReducedMotion ? { duration: 0 } : { repeat: Infinity, repeatDelay: 0.3, duration: 1.2, ease: [0, 0, 0.58, 1] }}\n />\n <span className=\"relative h-1.5 w-1.5 rounded-pill bg-current\" />\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-[16px] min-h-[16px]'\n : 'p-px',\n )}\n aria-label={\n `Remove ${typeof children === 'string' ? children : ''}`.trim() || 'Remove'\n }\n >\n <Icon icon={IconX} size=\"xs\" />\n </button>\n )}\n </Comp>\n )\n },\n)\nBadge.displayName = 'Badge'\n\nimport { BadgeGroup } from './badge-group'\nimport { BadgeIndicator } from './badge-indicator'\n\nconst BadgeCompound = Object.assign(Badge, {\n Indicator: BadgeIndicator,\n Group: BadgeGroup,\n})\n\nexport { BadgeCompound as Badge, type BadgeColor,type BadgeProps, badgeVariants }\n","'use client'\n\nimport * as React from 'react'\n\nimport { Badge, type BadgeProps } from './badge'\nimport { cn } from './lib/utils'\n\nconst GAP_CLASSES = {\n tight: 'gap-1',\n default: 'gap-1.5',\n loose: 'gap-2',\n} as const\n\nexport interface BadgeGroupProps {\n max?: number\n gap?: keyof typeof GAP_CLASSES\n size?: BadgeProps['size']\n onOverflowClick?: () => void\n className?: string\n children: React.ReactNode\n}\n\nexport function BadgeGroup({\n max,\n gap = 'default',\n size,\n onOverflowClick,\n className,\n children,\n}: BadgeGroupProps) {\n const childArray = React.Children.toArray(children)\n const total = childArray.length\n const hasOverflow = max !== undefined && total > max\n const visible = hasOverflow ? childArray.slice(0, max) : childArray\n const overflowCount = hasOverflow ? total - max! : 0\n\n return (\n <div className={cn('flex flex-wrap items-center', GAP_CLASSES[gap], className)}>\n {visible}\n {hasOverflow && (\n // With onClick, Badge renders a real, keyboard-reachable <button>; add a\n // label since \"+N\" alone isn't descriptive to a screen reader.\n <Badge\n variant=\"outline\"\n color=\"neutral\"\n size={size ?? 'sm'}\n onClick={onOverflowClick}\n aria-label={onOverflowClick ? `Show ${overflowCount} more` : undefined}\n >\n +{overflowCount}\n </Badge>\n )}\n </div>\n )\n}\n\nBadgeGroup.displayName = 'BadgeGroup'\n"],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn as e } from "../ui/lib/utils.js";
|
|
3
|
+
import { Icon as t } from "../ui/icon.js";
|
|
4
|
+
import * as n from "react";
|
|
5
|
+
import { jsx as r, jsxs as i } from "react/jsx-runtime";
|
|
6
|
+
import { IconAlertTriangle as a } from "@tabler/icons-react";
|
|
7
|
+
//#region src/ai/blocks/block-shell.tsx
|
|
8
|
+
var o = n.memo(function({ confidence: n, className: o, children: s }) {
|
|
9
|
+
let c = n === "low";
|
|
10
|
+
return /* @__PURE__ */ i("div", {
|
|
11
|
+
"data-confidence": n,
|
|
12
|
+
className: e(c && "relative rounded-surface bg-warning-2 p-ds-04 pt-ds-07", o),
|
|
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-ds-xs font-semibold text-warning-11",
|
|
15
|
+
children: [/* @__PURE__ */ r(t, {
|
|
16
|
+
icon: a,
|
|
17
|
+
size: "xs",
|
|
18
|
+
"aria-hidden": !0
|
|
19
|
+
}), "Low confidence"]
|
|
20
|
+
}), s]
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
o.displayName = "BlockShell";
|
|
24
|
+
//#endregion
|
|
25
|
+
export { o as t };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"block-shell.js","names":[],"sources":["../../src/ai/blocks/block-shell.tsx"],"sourcesContent":["'use client'\n\nimport { IconAlertTriangle } from '@tabler/icons-react'\nimport * as React from 'react'\n\nimport { Icon } from '../../ui/icon'\nimport { cn } from '../../ui/lib/utils'\n\nexport interface BlockShellProps {\n confidence?: 'high' | 'medium' | 'low'\n className?: string\n children: React.ReactNode\n}\n\n/**\n * Shared wrapper for AI block renderers. Owns the low-confidence treatment so it\n * lives in ONE place instead of a copy-pasted rail across every block.\n *\n * Low confidence = a faint warning wash (`bg-warning-2`, the DS \"Subtle\n * background\" step) + a \"Low confidence\" chip pinned top-right. NOT a colored\n * left rail (the AI tell removed from Card in v0.44.0). `pt-ds-07` reserves\n * clearance so the chip never overlaps content in prose/table blocks.\n */\nconst BlockShell = React.memo(function BlockShell({\n confidence,\n className,\n children,\n}: BlockShellProps) {\n const low = confidence === 'low'\n return (\n <div\n data-confidence={confidence}\n className={cn(\n low && 'relative rounded-surface bg-warning-2 p-ds-04 pt-ds-07',\n className,\n )}\n >\n {low && (\n <span className=\"absolute right-ds-03 top-ds-03 inline-flex items-center gap-1 rounded-pill bg-warning-3 px-ds-02 py-px text-ds-xs font-semibold text-warning-11\">\n <Icon icon={IconAlertTriangle} size=\"xs\" aria-hidden />\n Low confidence\n </span>\n )}\n {children}\n </div>\n )\n})\n\nBlockShell.displayName = 'BlockShell'\n\nexport { BlockShell }\n"],"mappings":";;;;;;AAuBA,IAAM,IAAa,EAAM,KAAK,SAAoB,EAChD,eACA,cACA,eACkB;CAClB,IAAM,IAAM,MAAe;AAC3B,QACE,kBAAC,OAAD;EACE,mBAAiB;EACjB,WAAW,EACT,KAAO,0DACP,EACD;YALH,CAOG,KACC,kBAAC,QAAD;GAAM,WAAU;aAAhB,CACE,kBAAC,GAAD;IAAM,MAAM;IAAmB,MAAK;IAAK,eAAA;IAAc,CAAA,EAAA,iBAElD;MAER,EACG;;EAER;AAEF,EAAW,cAAc"}
|
package/dist/_chunks/chat.js
CHANGED
|
@@ -79,6 +79,7 @@ var k = g.forwardRef(({ children: e, variant: r = "flat", placement: a = "start"
|
|
|
79
79
|
value: m,
|
|
80
80
|
children: /* @__PURE__ */ _(w.div, {
|
|
81
81
|
ref: p,
|
|
82
|
+
"data-highlight": s,
|
|
82
83
|
initial: {
|
|
83
84
|
opacity: 0,
|
|
84
85
|
y: 8
|
|
@@ -88,7 +89,7 @@ var k = g.forwardRef(({ children: e, variant: r = "flat", placement: a = "start"
|
|
|
88
89
|
y: 0
|
|
89
90
|
},
|
|
90
91
|
transition: n.snappy,
|
|
91
|
-
className: i("group/message relative flex", a === "end" ? "justify-end" : "justify-start", s === "
|
|
92
|
+
className: i("group/message relative flex", a === "end" ? "justify-end" : "justify-start", s === "internal" && "bg-warning-2/50 rounded-control-inner", d),
|
|
92
93
|
...t(f),
|
|
93
94
|
children: /* @__PURE__ */ _("div", {
|
|
94
95
|
className: i("max-w-[85%] rounded-bubble px-ds-04 py-ds-03", a === "end" ? "bg-accent-3 text-surface-fg" : "bg-surface-raised text-surface-fg"),
|
|
@@ -99,6 +100,7 @@ var k = g.forwardRef(({ children: e, variant: r = "flat", placement: a = "start"
|
|
|
99
100
|
value: m,
|
|
100
101
|
children: /* @__PURE__ */ _(w.div, {
|
|
101
102
|
ref: p,
|
|
103
|
+
"data-highlight": s,
|
|
102
104
|
initial: {
|
|
103
105
|
opacity: 0,
|
|
104
106
|
y: 8
|
|
@@ -108,7 +110,7 @@ var k = g.forwardRef(({ children: e, variant: r = "flat", placement: a = "start"
|
|
|
108
110
|
y: 0
|
|
109
111
|
},
|
|
110
112
|
transition: n.snappy,
|
|
111
|
-
className: i("group/message relative flex gap-ds-04", c && "-mt-ds-01", s === "
|
|
113
|
+
className: i("group/message relative flex gap-ds-04", c && "-mt-ds-01", s === "internal" && "bg-warning-2/50 rounded-control-inner", d),
|
|
112
114
|
...t(f),
|
|
113
115
|
children: e
|
|
114
116
|
})
|