@devalok/shilp-sutra 0.43.0 → 0.44.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/MIGRATION.md +46 -0
- package/dist/_chunks/chat.js +163 -162
- package/dist/_chunks/chat.js.map +1 -1
- package/dist/_chunks/mention-suggestion.js +34 -32
- package/dist/_chunks/mention-suggestion.js.map +1 -1
- package/dist/_chunks/oauth-button.js +102 -97
- package/dist/_chunks/oauth-button.js.map +1 -1
- package/dist/_chunks/tree-view.js +1 -1
- package/dist/_chunks/tree-view.js.map +1 -1
- package/dist/ai/command-bar.js.map +1 -1
- package/dist/composed/command-palette.js +3 -3
- package/dist/composed/command-palette.js.map +1 -1
- package/dist/composed/content-card.d.ts +6 -0
- package/dist/composed/content-card.d.ts.map +1 -1
- package/dist/composed/content-card.js.map +1 -1
- package/dist/composed/extensions/file-attachment.d.ts.map +1 -1
- package/dist/composed/file-preview/audio-preview.d.ts.map +1 -1
- package/dist/composed/file-preview.d.ts.map +1 -1
- package/dist/composed/file-preview.js +146 -142
- package/dist/composed/file-preview.js.map +1 -1
- package/dist/composed/filter-bar.js +5 -2
- package/dist/composed/filter-bar.js.map +1 -1
- package/dist/composed/master-detail.js +1 -1
- package/dist/composed/master-detail.js.map +1 -1
- package/dist/composed/page-header.js +1 -1
- package/dist/composed/page-header.js.map +1 -1
- package/dist/composed/rich-chat-input/attachment-strip.d.ts.map +1 -1
- package/dist/composed/rich-chat-input/audio-player.d.ts.map +1 -1
- package/dist/composed/rich-chat-input/schedule-send.d.ts.map +1 -1
- package/dist/composed/rich-chat-input.js +595 -586
- package/dist/composed/rich-chat-input.js.map +1 -1
- package/dist/composed/rich-text-editor.d.ts.map +1 -1
- package/dist/composed/rich-text-editor.js +164 -162
- package/dist/composed/rich-text-editor.js.map +1 -1
- package/dist/hooks/index.d.ts +2 -2
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/shell/notification-center.d.ts.map +1 -1
- package/dist/shell/notification-center.js +101 -97
- package/dist/shell/notification-center.js.map +1 -1
- package/dist/shell/sidebar.d.ts.map +1 -1
- package/dist/shell/sidebar.js +137 -122
- package/dist/shell/sidebar.js.map +1 -1
- package/dist/shell/top-bar.d.ts.map +1 -1
- package/dist/shell/top-bar.js +86 -83
- package/dist/shell/top-bar.js.map +1 -1
- package/dist/tokens/semantic.css +1 -0
- package/dist/ui/avatar.js +1 -1
- package/dist/ui/avatar.js.map +1 -1
- package/dist/ui/breadcrumb.js +2 -2
- package/dist/ui/breadcrumb.js.map +1 -1
- package/dist/ui/button.js.map +1 -1
- package/dist/ui/card.d.ts +82 -7
- package/dist/ui/card.d.ts.map +1 -1
- package/dist/ui/card.js +74 -108
- package/dist/ui/card.js.map +1 -1
- package/dist/ui/chat/message.d.ts.map +1 -1
- package/dist/ui/combobox.js +2 -2
- package/dist/ui/combobox.js.map +1 -1
- package/dist/ui/dropdown-menu.js +9 -3
- package/dist/ui/dropdown-menu.js.map +1 -1
- package/dist/ui/index.d.ts +2 -1
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +58 -57
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/menubar.js +9 -3
- package/dist/ui/menubar.js.map +1 -1
- package/dist/ui/oauth-button/oauth-button.d.ts.map +1 -1
- package/dist/ui/select.js +5 -2
- package/dist/ui/select.js.map +1 -1
- package/dist/ui/sidebar.js +73 -73
- package/dist/ui/sidebar.js.map +1 -1
- package/dist/ui/stat-card.d.ts +8 -5
- package/dist/ui/stat-card.d.ts.map +1 -1
- package/dist/ui/stat-card.js +168 -150
- package/dist/ui/stat-card.js.map +1 -1
- package/dist/ui/tabs.d.ts.map +1 -1
- package/dist/ui/tabs.js +5 -2
- package/dist/ui/tabs.js.map +1 -1
- package/dist/ui/truncated-text.d.ts +37 -0
- package/dist/ui/truncated-text.d.ts.map +1 -0
- package/dist/ui/truncated-text.js +53 -0
- package/dist/ui/truncated-text.js.map +1 -0
- package/docs/components/ui/card.md +13 -4
- package/docs/components/ui/stat-card.md +7 -2
- package/docs/components/ui/truncated-text.md +49 -0
- package/llms-full.txt +70 -7
- package/make-kit/components/card.md +14 -4
- package/package.json +1 -1
- package/skill/SKILL.md +1 -1
- package/skill/references/components-full.md +70 -7
package/dist/ui/card.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { motionProps as e, springs as t
|
|
3
|
-
import { t as
|
|
4
|
-
import { cn as
|
|
5
|
-
import * as
|
|
6
|
-
import { jsx as
|
|
7
|
-
import { motion as
|
|
2
|
+
import { motionProps as e, springs as t } from "./lib/motion.js";
|
|
3
|
+
import { t as n } from "../_chunks/vendor-utils.js";
|
|
4
|
+
import { cn as r } from "./lib/utils.js";
|
|
5
|
+
import * as i from "react";
|
|
6
|
+
import { jsx as a } from "react/jsx-runtime";
|
|
7
|
+
import { motion as o } from "framer-motion";
|
|
8
8
|
//#region src/ui/card.tsx
|
|
9
|
-
var
|
|
9
|
+
var s = i.createContext("md"), c = n("relative flex flex-col rounded-surface text-surface-fg transition-shadow duration-fast-02 ease-productive-standard", {
|
|
10
10
|
variants: {
|
|
11
11
|
variant: {
|
|
12
12
|
default: "bg-surface-raised border border-transparent shadow-raised",
|
|
@@ -24,9 +24,9 @@ var l = a.createContext("md"), u = r("rounded-surface text-surface-fg transition
|
|
|
24
24
|
neutral: ""
|
|
25
25
|
},
|
|
26
26
|
size: {
|
|
27
|
-
sm: "",
|
|
28
|
-
md: "",
|
|
29
|
-
lg: ""
|
|
27
|
+
sm: "py-ds-05 gap-ds-03",
|
|
28
|
+
md: "py-ds-05b gap-ds-04",
|
|
29
|
+
lg: "py-ds-06 gap-ds-05"
|
|
30
30
|
}
|
|
31
31
|
},
|
|
32
32
|
defaultVariants: {
|
|
@@ -34,123 +34,89 @@ var l = a.createContext("md"), u = r("rounded-surface text-surface-fg transition
|
|
|
34
34
|
color: "default",
|
|
35
35
|
size: "md"
|
|
36
36
|
}
|
|
37
|
-
}),
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
6: "w-[6px]"
|
|
50
|
-
},
|
|
51
|
-
top: {
|
|
52
|
-
2: "h-[2px]",
|
|
53
|
-
3: "h-[3px]",
|
|
54
|
-
4: "h-[4px]",
|
|
55
|
-
6: "h-[6px]"
|
|
56
|
-
},
|
|
57
|
-
right: {
|
|
58
|
-
2: "w-[2px]",
|
|
59
|
-
3: "w-[3px]",
|
|
60
|
-
4: "w-[4px]",
|
|
61
|
-
6: "w-[6px]"
|
|
62
|
-
},
|
|
63
|
-
bottom: {
|
|
64
|
-
2: "h-[2px]",
|
|
65
|
-
3: "h-[3px]",
|
|
66
|
-
4: "h-[4px]",
|
|
67
|
-
6: "h-[6px]"
|
|
68
|
-
}
|
|
69
|
-
}, p = {
|
|
70
|
-
left: "left-0 top-0 bottom-0 rounded-l-surface",
|
|
71
|
-
top: "top-0 left-0 right-0 rounded-t-surface",
|
|
72
|
-
right: "right-0 top-0 bottom-0 rounded-r-surface",
|
|
73
|
-
bottom: "bottom-0 left-0 right-0 rounded-b-surface"
|
|
74
|
-
};
|
|
75
|
-
function m(e, t) {
|
|
76
|
-
return `${p[e] ?? ""} ${f[e]?.[t] ?? ""}`;
|
|
77
|
-
}
|
|
78
|
-
function h(e) {
|
|
79
|
-
return d[e] ?? e;
|
|
80
|
-
}
|
|
81
|
-
var g = a.forwardRef(({ className: r, variant: a, color: d, size: f, interactive: p, accent: g, accentColor: _ = "default", accentWidth: v = 3, children: y, ...b }, x) => {
|
|
82
|
-
let S = f ?? "md", C = i(u({
|
|
83
|
-
variant: a,
|
|
84
|
-
color: d,
|
|
85
|
-
size: f
|
|
86
|
-
}), g && "relative overflow-hidden", p && "hover:shadow-raised-hover cursor-pointer transition-shadow duration-fast-02 ease-productive-standard", r), w = g ? /* @__PURE__ */ o(c.span, {
|
|
87
|
-
"aria-hidden": "true",
|
|
88
|
-
initial: { opacity: 0 },
|
|
89
|
-
animate: { opacity: 1 },
|
|
90
|
-
transition: n.fade,
|
|
91
|
-
className: i("absolute pointer-events-none bg-[var(--card-accent-bg)]", m(g, v)),
|
|
92
|
-
style: { "--card-accent-bg": h(_) }
|
|
93
|
-
}) : null, T = /* @__PURE__ */ s(l.Provider, {
|
|
94
|
-
value: S,
|
|
95
|
-
children: [w, y]
|
|
37
|
+
}), l = {
|
|
38
|
+
sm: "px-ds-05",
|
|
39
|
+
md: "px-ds-05b",
|
|
40
|
+
lg: "px-ds-06"
|
|
41
|
+
}, u = i.forwardRef(({ className: n, variant: i, color: l, size: u, interactive: d, children: f, ...p }, m) => {
|
|
42
|
+
let h = u ?? "md", g = r(c({
|
|
43
|
+
variant: i,
|
|
44
|
+
color: l,
|
|
45
|
+
size: u
|
|
46
|
+
}), d && "hover:shadow-raised-hover cursor-pointer transition-shadow duration-fast-02 ease-productive-standard", n), _ = /* @__PURE__ */ a(s.Provider, {
|
|
47
|
+
value: h,
|
|
48
|
+
children: f
|
|
96
49
|
});
|
|
97
|
-
return
|
|
98
|
-
ref:
|
|
50
|
+
return d ? /* @__PURE__ */ a(o.div, {
|
|
51
|
+
ref: m,
|
|
99
52
|
whileHover: { y: -3 },
|
|
100
53
|
whileTap: { scale: .98 },
|
|
101
54
|
transition: t.snappy,
|
|
102
|
-
className:
|
|
103
|
-
...e(
|
|
104
|
-
children:
|
|
105
|
-
}) : /* @__PURE__ */
|
|
106
|
-
ref:
|
|
107
|
-
className:
|
|
108
|
-
...
|
|
109
|
-
children:
|
|
55
|
+
className: g,
|
|
56
|
+
...e(p),
|
|
57
|
+
children: _
|
|
58
|
+
}) : /* @__PURE__ */ a("div", {
|
|
59
|
+
ref: m,
|
|
60
|
+
className: g,
|
|
61
|
+
...p,
|
|
62
|
+
children: _
|
|
110
63
|
});
|
|
111
64
|
});
|
|
112
|
-
|
|
113
|
-
var
|
|
114
|
-
sm: "p-ds-05",
|
|
115
|
-
md: "p-ds-06",
|
|
116
|
-
lg: "p-ds-07"
|
|
117
|
-
}, v = a.forwardRef(({ className: e, ...t }, n) => /* @__PURE__ */ o("div", {
|
|
65
|
+
u.displayName = "Card";
|
|
66
|
+
var d = i.forwardRef(({ className: e, ...t }, n) => /* @__PURE__ */ a("div", {
|
|
118
67
|
ref: n,
|
|
119
|
-
className:
|
|
68
|
+
className: r("flex flex-col gap-ds-02b [&>:first-child]:mt-0 [&>:last-child]:mb-0", l[i.useContext(s)], e),
|
|
120
69
|
...t
|
|
121
70
|
}));
|
|
122
|
-
|
|
123
|
-
var
|
|
71
|
+
d.displayName = "CardHeader";
|
|
72
|
+
var f = i.forwardRef(({ className: e, ...t }, n) => /* @__PURE__ */ a("div", {
|
|
124
73
|
ref: n,
|
|
125
|
-
className:
|
|
74
|
+
className: r("font-sans font-semibold leading-ds-none tracking-normal text-surface-fg", e),
|
|
126
75
|
...t
|
|
127
76
|
}));
|
|
128
|
-
|
|
129
|
-
var
|
|
77
|
+
f.displayName = "CardTitle";
|
|
78
|
+
var p = i.forwardRef(({ className: e, ...t }, n) => /* @__PURE__ */ a("div", {
|
|
130
79
|
ref: n,
|
|
131
|
-
className:
|
|
80
|
+
className: r("text-ds-md text-surface-fg-muted", e),
|
|
132
81
|
...t
|
|
133
82
|
}));
|
|
134
|
-
|
|
135
|
-
var
|
|
136
|
-
sm: "p-ds-05 pt-0",
|
|
137
|
-
md: "p-ds-06 pt-0",
|
|
138
|
-
lg: "p-ds-07 pt-0"
|
|
139
|
-
}, S = a.forwardRef(({ className: e, ...t }, n) => /* @__PURE__ */ o("div", {
|
|
83
|
+
p.displayName = "CardDescription";
|
|
84
|
+
var m = i.forwardRef(({ className: e, ...t }, n) => /* @__PURE__ */ a("div", {
|
|
140
85
|
ref: n,
|
|
141
|
-
className:
|
|
86
|
+
className: r("[&>:first-child]:mt-0 [&>:last-child]:mb-0", l[i.useContext(s)], e),
|
|
142
87
|
...t
|
|
143
88
|
}));
|
|
144
|
-
|
|
145
|
-
var
|
|
146
|
-
sm: "p-ds-05 pt-0",
|
|
147
|
-
md: "p-ds-06 pt-0",
|
|
148
|
-
lg: "p-ds-07 pt-0"
|
|
149
|
-
}, w = a.forwardRef(({ className: e, ...t }, n) => /* @__PURE__ */ o("div", {
|
|
89
|
+
m.displayName = "CardContent";
|
|
90
|
+
var h = i.forwardRef(({ className: e, ...t }, n) => /* @__PURE__ */ a("div", {
|
|
150
91
|
ref: n,
|
|
151
|
-
className:
|
|
92
|
+
className: r("flex items-center gap-ds-03", l[i.useContext(s)], e),
|
|
152
93
|
...t
|
|
153
94
|
}));
|
|
154
|
-
|
|
95
|
+
h.displayName = "CardFooter";
|
|
96
|
+
var g = {
|
|
97
|
+
sm: {
|
|
98
|
+
"top-right": "top-ds-05 right-ds-05",
|
|
99
|
+
"top-left": "top-ds-05 left-ds-05",
|
|
100
|
+
"bottom-right": "bottom-ds-05 right-ds-05",
|
|
101
|
+
"bottom-left": "bottom-ds-05 left-ds-05"
|
|
102
|
+
},
|
|
103
|
+
md: {
|
|
104
|
+
"top-right": "top-ds-05b right-ds-05b",
|
|
105
|
+
"top-left": "top-ds-05b left-ds-05b",
|
|
106
|
+
"bottom-right": "bottom-ds-05b right-ds-05b",
|
|
107
|
+
"bottom-left": "bottom-ds-05b left-ds-05b"
|
|
108
|
+
},
|
|
109
|
+
lg: {
|
|
110
|
+
"top-right": "top-ds-06 right-ds-06",
|
|
111
|
+
"top-left": "top-ds-06 left-ds-06",
|
|
112
|
+
"bottom-right": "bottom-ds-06 right-ds-06",
|
|
113
|
+
"bottom-left": "bottom-ds-06 left-ds-06"
|
|
114
|
+
}
|
|
115
|
+
}, _ = i.forwardRef(({ className: e, placement: t = "top-right", tuck: n, ...o }, c) => /* @__PURE__ */ a("div", {
|
|
116
|
+
ref: c,
|
|
117
|
+
className: r("absolute z-[1] flex items-center gap-ds-02", g[i.useContext(s)][t], n && "-m-ds-02", e),
|
|
118
|
+
...o
|
|
119
|
+
}));
|
|
120
|
+
_.displayName = "CardAction";
|
|
155
121
|
//#endregion
|
|
156
|
-
export {
|
|
122
|
+
export { u as Card, _ as CardAction, m as CardContent, p as CardDescription, h as CardFooter, d as CardHeader, f as CardTitle, c as cardVariants };
|
package/dist/ui/card.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"card.js","names":[],"sources":["../../src/ui/card.tsx"],"sourcesContent":["'use client'\n\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { motionProps,springs, tweens } from './lib/motion'\nimport { cn } from './lib/utils'\n\ntype CardSize = 'sm' | 'md' | 'lg'\n\nconst CardSizeContext = React.createContext<CardSize>('md')\n\nconst cardVariants = cva(\n 'rounded-surface text-surface-fg transition-shadow duration-fast-02 ease-productive-standard',\n {\n variants: {\n variant: {\n // Elevation-led: the shadow's own ring is the edge (make-kit rule #6 — no\n // border+shadow double-edge). border-transparent keeps the `color` prop able to\n // paint a deliberate colored edge without a grey one by default.\n default: 'bg-surface-raised border border-transparent shadow-raised',\n elevated: 'bg-surface-raised border border-transparent shadow-raised-hover',\n // Border-led: a visible edge, no shadow.\n outline: 'bg-transparent border border-surface-border-strong shadow-none',\n flat: 'bg-surface-raised border-none shadow-none',\n },\n color: {\n default: '',\n accent: 'border-accent-7',\n error: 'border-error-7',\n success: 'border-success-7',\n warning: 'border-warning-7',\n info: 'border-info-7',\n neutral: '',\n },\n size: {\n sm: '',\n md: '',\n lg: '',\n },\n },\n defaultVariants: { variant: 'default', color: 'default', size: 'md' },\n },\n)\n\n/**\n * Props for Card — a general-purpose content container with 4 elevation/style variants and\n * an optional interactive hover state.\n *\n * **Variants (elevation-led vs border-led — never both):** `default` (ring-in-shadow, no border) |\n * `elevated` (stronger shadow-raised-hover, no border) | `outline` (visible border, no shadow) |\n * `flat` (filled background, no edge). The shadow tokens carry their own 1px ring, so elevated\n * variants need no explicit border (make-kit rule #6).\n *\n * **Composition:** Use sub-components `<CardHeader>`, `<CardTitle>`, `<CardDescription>`,\n * `<CardContent>`, and `<CardFooter>` for consistent internal spacing.\n *\n * **Interactive:** Pass `interactive` to enable hover shadow lift and pointer cursor —\n * useful for clickable cards in grids.\n *\n * @example\n * // Standard content card with header and body:\n * <Card>\n * <CardHeader>\n * <CardTitle>Project Alpha</CardTitle>\n * <CardDescription>Last updated 2 hours ago</CardDescription>\n * </CardHeader>\n * <CardContent>\n * <p>Sprint 4 is in progress with 12 open tasks.</p>\n * </CardContent>\n * </Card>\n *\n * @example\n * // Elevated card for a dashboard stat widget:\n * <Card variant=\"elevated\">\n * <CardContent>\n * <StatCard label=\"Revenue\" value=\"$12,400\" delta={{ value: \"+8%\", direction: \"up\" }} />\n * </CardContent>\n * </Card>\n *\n * @example\n * // Clickable card in a project grid (interactive hover effect):\n * <Card interactive onClick={() => router.push(`/projects/${id}`)}>\n * <CardHeader>\n * <CardTitle>{project.name}</CardTitle>\n * </CardHeader>\n * </Card>\n *\n * @example\n * // Flat card for a sidebar panel section (no shadow):\n * <Card variant=\"flat\" className=\"p-ds-05\">\n * <p className=\"text-surface-fg-muted text-ds-sm\">No recent activity</p>\n * </Card>\n * // These are just a few ways — feel free to combine props creatively!\n */\nconst accentColorMap: Record<string, string> = {\n default: 'var(--color-accent-9)',\n secondary: 'var(--color-secondary-9)',\n error: 'var(--color-error-9)',\n success: 'var(--color-success-9)',\n warning: 'var(--color-warning-9)',\n info: 'var(--color-info-9)',\n}\n\nexport interface CardProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'color'>,\n VariantProps<typeof cardVariants> {\n interactive?: boolean\n /** Position of the accent border strip */\n accent?: 'left' | 'top' | 'right' | 'bottom'\n /** Semantic color key or any CSS color string for the accent strip. Requires `accent` to be set. @default 'default' */\n accentColor?: 'default' | 'secondary' | 'error' | 'success' | 'warning' | 'info' | (string & {})\n /** Width of the accent strip in pixels @default 3 */\n accentWidth?: 2 | 3 | 4 | 6\n}\n\nexport type { CardSize }\n\nconst accentSizeClasses: Record<string, Record<number, string>> = {\n left: { 2: 'w-[2px]', 3: 'w-[3px]', 4: 'w-[4px]', 6: 'w-[6px]' },\n top: { 2: 'h-[2px]', 3: 'h-[3px]', 4: 'h-[4px]', 6: 'h-[6px]' },\n right: { 2: 'w-[2px]', 3: 'w-[3px]', 4: 'w-[4px]', 6: 'w-[6px]' },\n bottom: { 2: 'h-[2px]', 3: 'h-[3px]', 4: 'h-[4px]', 6: 'h-[6px]' },\n}\n\nconst accentPositionClasses: Record<string, string> = {\n left: 'left-0 top-0 bottom-0 rounded-l-surface',\n top: 'top-0 left-0 right-0 rounded-t-surface',\n right: 'right-0 top-0 bottom-0 rounded-r-surface',\n bottom: 'bottom-0 left-0 right-0 rounded-b-surface',\n}\n\nfunction getAccentPositionClasses(position: string, width: number): string {\n return `${accentPositionClasses[position] ?? ''} ${accentSizeClasses[position]?.[width] ?? ''}`\n}\n\nfunction resolveAccentColor(color: string): string {\n return accentColorMap[color] ?? color\n}\n\nconst Card = React.forwardRef<HTMLDivElement, CardProps>(\n ({ className, variant, color, size, interactive, accent, accentColor = 'default', accentWidth = 3, children, ...props }, ref) => {\n const resolvedSize: CardSize = size ?? 'md'\n const classes = cn(\n cardVariants({ variant, color, size }),\n accent && 'relative overflow-hidden',\n interactive && 'hover:shadow-raised-hover cursor-pointer transition-shadow duration-fast-02 ease-productive-standard',\n className,\n )\n\n const accentEl = accent ? (\n <motion.span\n aria-hidden=\"true\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={tweens.fade}\n className={cn('absolute pointer-events-none bg-[var(--card-accent-bg)]', getAccentPositionClasses(accent, accentWidth))}\n style={{ '--card-accent-bg': resolveAccentColor(accentColor) } as React.CSSProperties}\n />\n ) : null\n\n const content = (\n <CardSizeContext.Provider value={resolvedSize}>\n {accentEl}\n {children}\n </CardSizeContext.Provider>\n )\n\n if (interactive) {\n return (\n <motion.div\n ref={ref}\n whileHover={{ y: -3 }}\n whileTap={{ scale: 0.98 }}\n transition={springs.snappy}\n className={classes}\n {...motionProps(props)}\n >\n {content}\n </motion.div>\n )\n }\n\n return (\n <div ref={ref} className={classes} {...props}>\n {content}\n </div>\n )\n },\n)\nCard.displayName = 'Card'\n\nconst headerSizeClasses: Record<CardSize, string> = {\n sm: 'p-ds-05',\n md: 'p-ds-06',\n lg: 'p-ds-07',\n}\n\nconst CardHeader = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => {\n const size = React.useContext(CardSizeContext)\n return (\n <div\n ref={ref}\n className={cn('flex flex-col space-y-ds-02b', headerSizeClasses[size], className)}\n {...props}\n />\n )\n})\nCardHeader.displayName = 'CardHeader'\n\nconst CardTitle = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('font-sans font-semibold leading-ds-none tracking-normal text-surface-fg', className)}\n {...props}\n />\n))\nCardTitle.displayName = 'CardTitle'\n\nconst CardDescription = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('text-ds-md text-surface-fg-muted', className)}\n {...props}\n />\n))\nCardDescription.displayName = 'CardDescription'\n\nconst contentSizeClasses: Record<CardSize, string> = {\n sm: 'p-ds-05 pt-0',\n md: 'p-ds-06 pt-0',\n lg: 'p-ds-07 pt-0',\n}\n\nconst CardContent = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => {\n const size = React.useContext(CardSizeContext)\n return (\n <div ref={ref} className={cn(contentSizeClasses[size], className)} {...props} />\n )\n})\nCardContent.displayName = 'CardContent'\n\nconst footerSizeClasses: Record<CardSize, string> = {\n sm: 'p-ds-05 pt-0',\n md: 'p-ds-06 pt-0',\n lg: 'p-ds-07 pt-0',\n}\n\nconst CardFooter = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => {\n const size = React.useContext(CardSizeContext)\n return (\n <div\n ref={ref}\n className={cn('flex items-center', footerSizeClasses[size], className)}\n {...props}\n />\n )\n})\nCardFooter.displayName = 'CardFooter'\n\nexport { Card, CardContent,CardDescription, CardFooter, CardHeader, CardTitle, cardVariants }\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"card.js","names":[],"sources":["../../src/ui/card.tsx"],"sourcesContent":["'use client'\n\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { motionProps, springs } from './lib/motion'\nimport { cn } from './lib/utils'\n\ntype CardSize = 'sm' | 'md' | 'lg'\n\nconst CardSizeContext = React.createContext<CardSize>('md')\n\nconst cardVariants = cva(\n // Gap model: the container owns the vertical edge (py) and inter-slot rhythm (gap);\n // slots own only horizontal padding (px). No per-slot py, no pt-0, no per-element\n // margins — adding/removing a slot can't unbalance the bottom edge (make-kit rule:\n // shadow ring is the edge, gap is the rhythm).\n // `relative` establishes the positioning context for <CardAction> corner slots.\n 'relative flex flex-col rounded-surface text-surface-fg transition-shadow duration-fast-02 ease-productive-standard',\n {\n variants: {\n variant: {\n // Elevation-led: the shadow's own ring is the edge (make-kit rule #6 — no\n // border+shadow double-edge). border-transparent keeps the `color` prop able to\n // paint a deliberate colored edge without a grey one by default.\n default: 'bg-surface-raised border border-transparent shadow-raised',\n elevated: 'bg-surface-raised border border-transparent shadow-raised-hover',\n // Border-led: a visible edge, no shadow.\n outline: 'bg-transparent border border-surface-border-strong shadow-none',\n flat: 'bg-surface-raised border-none shadow-none',\n },\n color: {\n default: '',\n accent: 'border-accent-7',\n error: 'border-error-7',\n success: 'border-success-7',\n warning: 'border-warning-7',\n info: 'border-info-7',\n neutral: '',\n },\n // size drives the container's vertical padding + inter-slot gap; slots read\n // the same size from context for their horizontal padding.\n size: {\n sm: 'py-ds-05 gap-ds-03',\n md: 'py-ds-05b gap-ds-04',\n lg: 'py-ds-06 gap-ds-05',\n },\n },\n defaultVariants: { variant: 'default', color: 'default', size: 'md' },\n },\n)\n\n/** Horizontal padding per size — applied to every slot so full-bleed children\n * (dividers, media) can opt out, while the container owns the vertical edges. */\nconst slotPxClasses: Record<CardSize, string> = {\n sm: 'px-ds-05',\n md: 'px-ds-05b',\n lg: 'px-ds-06',\n}\n\n/**\n * Props for Card — a general-purpose content container with 4 elevation/style variants and\n * an optional interactive hover state.\n *\n * **Variants (elevation-led vs border-led — never both):** `default` (ring-in-shadow, no border) |\n * `elevated` (stronger shadow-raised-hover, no border) | `outline` (visible border, no shadow) |\n * `flat` (filled background, no edge). The shadow tokens carry their own 1px ring, so elevated\n * variants need no explicit border (make-kit rule #6).\n *\n * **Composition:** Use sub-components `<CardHeader>`, `<CardTitle>`, `<CardDescription>`,\n * `<CardContent>`, and `<CardFooter>` for consistent internal spacing.\n *\n * **Interactive:** Pass `interactive` to enable hover shadow lift and pointer cursor —\n * useful for clickable cards in grids.\n *\n * @example\n * // Standard content card with header and body:\n * <Card>\n * <CardHeader>\n * <CardTitle>Project Alpha</CardTitle>\n * <CardDescription>Last updated 2 hours ago</CardDescription>\n * </CardHeader>\n * <CardContent>\n * <p>Sprint 4 is in progress with 12 open tasks.</p>\n * </CardContent>\n * </Card>\n *\n * @example\n * // Elevated card for a dashboard stat widget:\n * <Card variant=\"elevated\">\n * <CardContent>\n * <StatCard label=\"Revenue\" value=\"$12,400\" delta={{ value: \"+8%\", direction: \"up\" }} />\n * </CardContent>\n * </Card>\n *\n * @example\n * // Clickable card in a project grid (interactive hover effect):\n * <Card interactive onClick={() => router.push(`/projects/${id}`)}>\n * <CardHeader>\n * <CardTitle>{project.name}</CardTitle>\n * </CardHeader>\n * </Card>\n *\n * @example\n * // Flat card for a sidebar panel section (no shadow):\n * <Card variant=\"flat\" className=\"p-ds-05\">\n * <p className=\"text-surface-fg-muted text-ds-sm\">No recent activity</p>\n * </Card>\n * // These are just a few ways — feel free to combine props creatively!\n */\nexport interface CardProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'color'>,\n VariantProps<typeof cardVariants> {\n interactive?: boolean\n}\n\nexport type { CardSize }\n\nconst Card = React.forwardRef<HTMLDivElement, CardProps>(\n ({ className, variant, color, size, interactive, children, ...props }, ref) => {\n const resolvedSize: CardSize = size ?? 'md'\n const classes = cn(\n cardVariants({ variant, color, size }),\n interactive && 'hover:shadow-raised-hover cursor-pointer transition-shadow duration-fast-02 ease-productive-standard',\n className,\n )\n\n const content = (\n <CardSizeContext.Provider value={resolvedSize}>\n {children}\n </CardSizeContext.Provider>\n )\n\n if (interactive) {\n return (\n <motion.div\n ref={ref}\n whileHover={{ y: -3 }}\n whileTap={{ scale: 0.98 }}\n transition={springs.snappy}\n className={classes}\n {...motionProps(props)}\n >\n {content}\n </motion.div>\n )\n }\n\n return (\n <div ref={ref} className={classes} {...props}>\n {content}\n </div>\n )\n },\n)\nCard.displayName = 'Card'\n\nconst CardHeader = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => {\n const size = React.useContext(CardSizeContext)\n return (\n <div\n ref={ref}\n className={cn(\n 'flex flex-col gap-ds-02b [&>:first-child]:mt-0 [&>:last-child]:mb-0',\n slotPxClasses[size],\n className,\n )}\n {...props}\n />\n )\n})\nCardHeader.displayName = 'CardHeader'\n\nconst CardTitle = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('font-sans font-semibold leading-ds-none tracking-normal text-surface-fg', className)}\n {...props}\n />\n))\nCardTitle.displayName = 'CardTitle'\n\nconst CardDescription = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('text-ds-md text-surface-fg-muted', className)}\n {...props}\n />\n))\nCardDescription.displayName = 'CardDescription'\n\nconst CardContent = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => {\n const size = React.useContext(CardSizeContext)\n return (\n <div\n ref={ref}\n className={cn(\n // Reset first/last child margins so a raw <p>/<h*>'s UA margin can't leak\n // past the slot onto the container's gap-model padding (the bottom-heavy bug).\n '[&>:first-child]:mt-0 [&>:last-child]:mb-0',\n slotPxClasses[size],\n className,\n )}\n {...props}\n />\n )\n})\nCardContent.displayName = 'CardContent'\n\nconst CardFooter = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => {\n const size = React.useContext(CardSizeContext)\n return (\n <div\n ref={ref}\n className={cn('flex items-center gap-ds-03', slotPxClasses[size], className)}\n {...props}\n />\n )\n})\nCardFooter.displayName = 'CardFooter'\n\ntype CardActionPlacement = 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left'\n\n// Corner inset matches the slot padding for the card's size, so an action's edge\n// lines up with the content edge. Class names are spelled out literally (not built\n// from the size) so Tailwind's JIT can see them.\nconst cornerPositions: Record<CardSize, Record<CardActionPlacement, string>> = {\n sm: {\n 'top-right': 'top-ds-05 right-ds-05',\n 'top-left': 'top-ds-05 left-ds-05',\n 'bottom-right': 'bottom-ds-05 right-ds-05',\n 'bottom-left': 'bottom-ds-05 left-ds-05',\n },\n md: {\n 'top-right': 'top-ds-05b right-ds-05b',\n 'top-left': 'top-ds-05b left-ds-05b',\n 'bottom-right': 'bottom-ds-05b right-ds-05b',\n 'bottom-left': 'bottom-ds-05b left-ds-05b',\n },\n lg: {\n 'top-right': 'top-ds-06 right-ds-06',\n 'top-left': 'top-ds-06 left-ds-06',\n 'bottom-right': 'bottom-ds-06 right-ds-06',\n 'bottom-left': 'bottom-ds-06 left-ds-06',\n },\n}\n\nexport interface CardActionProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Which corner the action sits in. @default 'top-right' */\n placement?: CardActionPlacement\n /**\n * Pull the action a step toward its corner (`-m-ds-02`) so an icon button's GLYPH —\n * not its padding box — aligns to the content-edge line. Use for ghost/icon buttons\n * placed in a corner; leave off for badges/text where the padding box is the edge.\n */\n tuck?: boolean\n}\n\n/**\n * An absolutely-positioned corner slot for a Card — a menu/icon button, a status badge,\n * an overflow action. The Card is `relative`, so this pins to one of its four corners\n * with an inset that matches the card's content padding.\n *\n * @example\n * <Card>\n * <CardAction><IconButton aria-label=\"More\" icon={<IconDots />} variant=\"ghost\" tuck /></CardAction>\n * <CardHeader><CardTitle>Project Alpha</CardTitle></CardHeader>\n * </Card>\n *\n * @example\n * // Accent status badge in the top-right:\n * <Card>\n * <CardAction><Badge color=\"accent\" size=\"xs\">LIVE</Badge></CardAction>\n * ...\n * </Card>\n */\nconst CardAction = React.forwardRef<HTMLDivElement, CardActionProps>(\n ({ className, placement = 'top-right', tuck, ...props }, ref) => {\n const size = React.useContext(CardSizeContext)\n return (\n <div\n ref={ref}\n className={cn(\n 'absolute z-[1] flex items-center gap-ds-02',\n cornerPositions[size][placement],\n tuck && '-m-ds-02',\n className,\n )}\n {...props}\n />\n )\n },\n)\nCardAction.displayName = 'CardAction'\n\nexport { Card, CardAction, CardContent,CardDescription, CardFooter, CardHeader, CardTitle, cardVariants }\nexport type { CardActionPlacement }\n"],"mappings":";;;;;;;;AAWA,IAAM,IAAkB,EAAM,cAAwB,KAAK,EAErD,IAAe,EAMnB,sHACA;CACE,UAAU;EACR,SAAS;GAIP,SAAS;GACT,UAAU;GAEV,SAAS;GACT,MAAM;GACP;EACD,OAAO;GACL,SAAS;GACT,QAAQ;GACR,OAAO;GACP,SAAS;GACT,SAAS;GACT,MAAM;GACN,SAAS;GACV;EAGD,MAAM;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACL;EACF;CACD,iBAAiB;EAAE,SAAS;EAAW,OAAO;EAAW,MAAM;EAAM;CACtE,CACF,EAIK,IAA0C;CAC9C,IAAI;CACJ,IAAI;CACJ,IAAI;CACL,EA4DK,IAAO,EAAM,YAChB,EAAE,cAAW,YAAS,UAAO,SAAM,gBAAa,aAAU,GAAG,KAAS,MAAQ;CAC7E,IAAM,IAAyB,KAAQ,MACjC,IAAU,EACd,EAAa;EAAE;EAAS;EAAO;EAAM,CAAC,EACtC,KAAe,wGACf,EACD,EAEK,IACJ,kBAAC,EAAgB,UAAjB;EAA0B,OAAO;EAC9B;EACwB,CAAA;AAkB7B,QAfI,IAEA,kBAAC,EAAO,KAAR;EACO;EACL,YAAY,EAAE,GAAG,IAAI;EACrB,UAAU,EAAE,OAAO,KAAM;EACzB,YAAY,EAAQ;EACpB,WAAW;EACX,GAAI,EAAY,EAAM;YAErB;EACU,CAAA,GAKf,kBAAC,OAAD;EAAU;EAAK,WAAW;EAAS,GAAI;YACpC;EACG,CAAA;EAGX;AACD,EAAK,cAAc;AAEnB,IAAM,IAAa,EAAM,YAGtB,EAAE,cAAW,GAAG,KAAS,MAGxB,kBAAC,OAAD;CACO;CACL,WAAW,EACT,uEACA,EANO,EAAM,WAAW,EAAgB,GAOxC,EACD;CACD,GAAI;CACJ,CAAA,CAEJ;AACF,EAAW,cAAc;AAEzB,IAAM,IAAY,EAAM,YAGrB,EAAE,cAAW,GAAG,KAAS,MAC1B,kBAAC,OAAD;CACO;CACL,WAAW,EAAG,2EAA2E,EAAU;CACnG,GAAI;CACJ,CAAA,CACF;AACF,EAAU,cAAc;AAExB,IAAM,IAAkB,EAAM,YAG3B,EAAE,cAAW,GAAG,KAAS,MAC1B,kBAAC,OAAD;CACO;CACL,WAAW,EAAG,oCAAoC,EAAU;CAC5D,GAAI;CACJ,CAAA,CACF;AACF,EAAgB,cAAc;AAE9B,IAAM,IAAc,EAAM,YAGvB,EAAE,cAAW,GAAG,KAAS,MAGxB,kBAAC,OAAD;CACO;CACL,WAAW,EAGT,8CACA,EARO,EAAM,WAAW,EAAgB,GASxC,EACD;CACD,GAAI;CACJ,CAAA,CAEJ;AACF,EAAY,cAAc;AAE1B,IAAM,IAAa,EAAM,YAGtB,EAAE,cAAW,GAAG,KAAS,MAGxB,kBAAC,OAAD;CACO;CACL,WAAW,EAAG,+BAA+B,EAJpC,EAAM,WAAW,EAAgB,GAIwB,EAAU;CAC5E,GAAI;CACJ,CAAA,CAEJ;AACF,EAAW,cAAc;AAOzB,IAAM,IAAyE;CAC7E,IAAI;EACF,aAAa;EACb,YAAY;EACZ,gBAAgB;EAChB,eAAe;EAChB;CACD,IAAI;EACF,aAAa;EACb,YAAY;EACZ,gBAAgB;EAChB,eAAe;EAChB;CACD,IAAI;EACF,aAAa;EACb,YAAY;EACZ,gBAAgB;EAChB,eAAe;EAChB;CACF,EA+BK,IAAa,EAAM,YACtB,EAAE,cAAW,eAAY,aAAa,SAAM,GAAG,KAAS,MAGrD,kBAAC,OAAD;CACO;CACL,WAAW,EACT,8CACA,EANO,EAAM,WAAW,EAAgB,EAMlB,IACtB,KAAQ,YACR,EACD;CACD,GAAI;CACJ,CAAA,CAGP;AACD,EAAW,cAAc"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../../src/ui/chat/message.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAK9B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../../src/ui/chat/message.tsx"],"names":[],"mappings":"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"}
|
package/dist/ui/combobox.js
CHANGED
|
@@ -144,12 +144,12 @@ var v = o([
|
|
|
144
144
|
if (!O && q.length === 1) {
|
|
145
145
|
let e = ue();
|
|
146
146
|
if (e) return /* @__PURE__ */ f("span", {
|
|
147
|
-
className: "flex-1 truncate text-left",
|
|
147
|
+
className: "min-w-0 flex-1 truncate text-left",
|
|
148
148
|
children: e
|
|
149
149
|
});
|
|
150
150
|
}
|
|
151
151
|
return /* @__PURE__ */ f("span", {
|
|
152
|
-
className: "flex-1 truncate text-left text-surface-fg-subtle",
|
|
152
|
+
className: "min-w-0 flex-1 truncate text-left text-surface-fg-subtle",
|
|
153
153
|
children: E
|
|
154
154
|
});
|
|
155
155
|
}, $ = l(), pe = $.state === "error", me = $.helperTextId, he = $.required;
|
package/dist/ui/combobox.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"combobox.js","names":[],"sources":["../../src/ui/combobox.tsx"],"sourcesContent":["'use client'\n\nimport * as PopoverPrimitive from '@primitives/react-popover'\nimport { IconCheck, IconChevronDown, IconSearch, IconX } from '@tabler/icons-react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { useFormField } from './form'\nimport { Icon } from './icon'\nimport { IconProvider, type IconSize } from './icon-context'\nimport type { IconInput } from './lib/icon-input'\nimport { normalizeIcon } from './lib/normalize-icon'\nimport { springs, tweens } from './lib/motion'\nimport { cn } from './lib/utils'\n\nexport const comboboxTriggerVariants = cva(\n [\n 'flex w-full items-center justify-between whitespace-nowrap rounded-control',\n 'border border-surface-border-strong bg-surface-raised-hover',\n 'transition-colors duration-fast-01 ease-productive-standard',\n 'focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2 focus-visible:border-accent-7',\n 'disabled:cursor-not-allowed disabled:opacity-action-disabled',\n ],\n {\n variants: {\n size: {\n xs: 'h-ds-xs-plus text-ds-sm px-ds-02',\n sm: 'h-ds-sm text-ds-sm px-ds-03',\n md: 'h-ds-md text-ds-md px-ds-04',\n lg: 'h-ds-lg text-ds-md px-ds-05',\n },\n },\n defaultVariants: { size: 'md' },\n },\n)\n\nexport type ComboboxSize = NonNullable<VariantProps<typeof comboboxTriggerVariants>['size']>\n\n/** Maps combobox size to Icon component size for chevron / check icons */\nconst iconSizeMap: Record<NonNullable<ComboboxSize>, IconSize> = {\n xs: 'xs',\n sm: 'sm',\n md: 'sm',\n lg: 'md',\n}\n\n/** Maps combobox size to pill text + padding classes */\nconst pillSizeMap: Record<NonNullable<ComboboxSize>, string> = {\n xs: 'px-ds-02 py-0 text-ds-xs',\n sm: 'px-ds-02 py-0 text-ds-xs',\n md: 'px-ds-03 py-[1px] text-ds-sm',\n lg: 'px-ds-03 py-[2px] text-ds-sm',\n}\n\n/** Maps combobox size to overflow text classes */\nconst overflowTextMap: Record<NonNullable<ComboboxSize>, string> = {\n xs: 'text-ds-xs',\n sm: 'text-ds-xs',\n md: 'text-ds-sm',\n lg: 'text-ds-sm',\n}\n\n/**\n * Option shape for a Combobox dropdown item.\n * `value` must be unique across all options — it is the key used in selection state.\n */\nexport interface ComboboxOption {\n value: string\n label: string\n description?: string\n icon?: IconInput\n disabled?: boolean\n}\n\n/**\n * Props for Combobox — a searchable single or multi-select dropdown with built-in keyboard\n * navigation, pill overflow (\"+ N more\"), and an optional custom option renderer.\n *\n * **Single vs multi:** `multiple={false}` (default) — `value` is a `string` and `onValueChange`\n * receives a `string`. When `multiple={true}`, `value` is `string[]`, `onValueChange` receives\n * `string[]`, and selected items appear as dismissible pills in the trigger.\n *\n * The props form a **discriminated union** on `multiple` — TypeScript will narrow `value` and\n * `onValueChange` automatically, so no manual casts are needed.\n *\n * **Custom rendering:** Use `renderOption` to return custom JSX per option (e.g. avatars, badges).\n *\n * @example\n * // Single-select country picker:\n * <Combobox\n * options={[{ value: 'in', label: 'India' }, { value: 'us', label: 'United States' }]}\n * value={country}\n * onValueChange={(v) => setCountry(v)}\n * placeholder=\"Select country\"\n * />\n *\n * @example\n * // Multi-select tag picker with pill display:\n * <Combobox\n * multiple\n * options={tagOptions}\n * value={selectedTags}\n * onValueChange={(v) => setSelectedTags(v)}\n * placeholder=\"Select tags...\"\n * />\n *\n * @example\n * // Custom option renderer (user avatars in assignee picker):\n * <Combobox\n * options={users.map(u => ({ value: u.id, label: u.name }))}\n * value={assigneeId}\n * onValueChange={(v) => setAssigneeId(v)}\n * renderOption={(option, selected) => (\n * <span className=\"flex items-center gap-ds-03\">\n * <Avatar size=\"xs\"><AvatarFallback>{option.label[0]}</AvatarFallback></Avatar>\n * {option.label}\n * </span>\n * )}\n * />\n * // These are just a few ways — feel free to combine props creatively!\n */\ninterface ComboboxBaseProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> {\n /** Available options shown in the dropdown. */\n options: ComboboxOption[]\n /** Placeholder shown in the trigger when no value is selected. */\n placeholder?: string\n /** Placeholder for the search input inside the dropdown. */\n searchPlaceholder?: string\n /** Message shown when the search yields no results. */\n emptyMessage?: string\n disabled?: boolean\n triggerClassName?: string\n /** Max visible items in the dropdown before scroll (default 6). */\n maxVisible?: number\n /** Custom renderer for each option row. Receives the option and whether it's currently selected. */\n renderOption?: (option: ComboboxOption, selected: boolean) => React.ReactNode\n /** Accessible label for the trigger button. Falls back to `placeholder` if not provided. */\n accessibleLabel?: string\n /** Size of the trigger. Controls height, text size, padding, and pill sizing. */\n size?: ComboboxSize\n}\n\ninterface ComboboxSingleProps extends ComboboxBaseProps {\n multiple?: false\n value?: string\n onValueChange: (value: string) => void\n}\n\ninterface ComboboxMultipleProps extends ComboboxBaseProps {\n multiple: true\n value?: string[]\n onValueChange: (value: string[]) => void\n}\n\nexport type ComboboxProps = ComboboxSingleProps | ComboboxMultipleProps\n\n/** Max pills shown in the trigger before \"+N more\" overflow */\nconst MAX_VISIBLE_PILLS = 2\n\n/** Approximate height of a single option item in px */\nconst ITEM_HEIGHT_PX = 36\n\nconst Combobox = React.forwardRef<HTMLButtonElement, ComboboxProps>(\n (\n {\n options,\n value,\n onValueChange,\n placeholder = 'Select...',\n searchPlaceholder = 'Search...',\n emptyMessage = 'No results found',\n multiple = false,\n disabled = false,\n className,\n triggerClassName,\n maxVisible = 6,\n renderOption,\n accessibleLabel,\n size: sizeProp = 'md',\n ...rest\n },\n ref,\n ) => {\n const size = sizeProp ?? 'md'\n const [open, setOpen] = React.useState(false)\n const [search, setSearch] = React.useState('')\n const [highlightedIndex, setHighlightedIndex] = React.useState(-1)\n const searchInputRef = React.useRef<HTMLInputElement>(null)\n const listRef = React.useRef<HTMLUListElement>(null)\n const optionIdPrefix = React.useId()\n const listboxId = React.useId()\n\n const selectedValues = React.useMemo<string[]>(() => {\n if (value === undefined || value === null) return []\n if (Array.isArray(value)) return value\n return [value]\n }, [value])\n\n const filteredOptions = React.useMemo(\n () =>\n search\n ? options.filter((o) =>\n o.label.toLowerCase().includes(search.toLowerCase()),\n )\n : options,\n [options, search],\n )\n\n const isSelected = React.useCallback(\n (optionValue: string) => selectedValues.includes(optionValue),\n [selectedValues],\n )\n\n const handleSelect = React.useCallback(\n (optionValue: string) => {\n if (multiple) {\n const newValue = selectedValues.includes(optionValue)\n ? selectedValues.filter((v) => v !== optionValue)\n : [...selectedValues, optionValue]\n ;(onValueChange as (value: string[]) => void)(newValue)\n } else {\n ;(onValueChange as (value: string) => void)(optionValue)\n setOpen(false)\n }\n },\n [multiple, selectedValues, onValueChange],\n )\n\n const handleRemovePill = React.useCallback(\n (e: React.SyntheticEvent, optionValue: string) => {\n e.stopPropagation()\n e.preventDefault()\n const newValue = selectedValues.filter((v) => v !== optionValue)\n ;(onValueChange as (value: string[]) => void)(newValue)\n },\n [selectedValues, onValueChange],\n )\n\n const handleOpenChange = React.useCallback(\n (nextOpen: boolean) => {\n if (disabled) return\n setOpen(nextOpen)\n if (!nextOpen) {\n setSearch('')\n setHighlightedIndex(-1)\n }\n },\n [disabled],\n )\n\n // Auto-focus search input when popover opens\n React.useEffect(() => {\n if (open) {\n // Use a small timeout to allow the popover to render\n const timer = setTimeout(() => {\n searchInputRef.current?.focus()\n }, 0)\n return () => clearTimeout(timer)\n }\n }, [open])\n\n const findNextEnabledIndex = React.useCallback(\n (currentIndex: number, direction: 1 | -1): number => {\n const len = filteredOptions.length\n if (len === 0) return -1\n\n let nextIndex = currentIndex + direction\n while (nextIndex >= 0 && nextIndex < len) {\n if (!filteredOptions[nextIndex].disabled) return nextIndex\n nextIndex += direction\n }\n return currentIndex\n },\n [filteredOptions],\n )\n\n const handleKeyDown = React.useCallback(\n (e: React.KeyboardEvent) => {\n switch (e.key) {\n case 'ArrowDown': {\n e.preventDefault()\n const nextIdx = findNextEnabledIndex(highlightedIndex, 1)\n setHighlightedIndex(nextIdx)\n break\n }\n case 'ArrowUp': {\n e.preventDefault()\n const prevIdx = findNextEnabledIndex(highlightedIndex, -1)\n setHighlightedIndex(prevIdx)\n break\n }\n case 'Home': {\n e.preventDefault()\n const firstEnabled = filteredOptions.findIndex((o) => !o.disabled)\n setHighlightedIndex(firstEnabled)\n break\n }\n case 'End': {\n e.preventDefault()\n let lastEnabled = -1\n for (let i = filteredOptions.length - 1; i >= 0; i--) {\n if (!filteredOptions[i].disabled) {\n lastEnabled = i\n break\n }\n }\n setHighlightedIndex(lastEnabled)\n break\n }\n case 'Enter': {\n e.preventDefault()\n if (\n highlightedIndex >= 0 &&\n highlightedIndex < filteredOptions.length &&\n !filteredOptions[highlightedIndex].disabled\n ) {\n handleSelect(filteredOptions[highlightedIndex].value)\n }\n break\n }\n case 'Escape': {\n e.preventDefault()\n setOpen(false)\n setSearch('')\n setHighlightedIndex(-1)\n break\n }\n }\n },\n [highlightedIndex, filteredOptions, findNextEnabledIndex, handleSelect],\n )\n\n // Scroll highlighted option into view\n React.useEffect(() => {\n if (highlightedIndex >= 0 && listRef.current) {\n const optionEl = listRef.current.children[highlightedIndex] as HTMLElement\n if (optionEl) {\n optionEl.scrollIntoView?.({ block: 'nearest' })\n }\n }\n }, [highlightedIndex])\n\n const getSelectedLabel = React.useCallback(() => {\n if (selectedValues.length === 0) return null\n const option = options.find((o) => o.value === selectedValues[0])\n return option?.label ?? null\n }, [selectedValues, options])\n\n const resolvedIconSize = iconSizeMap[size]\n const resolvedPillClasses = pillSizeMap[size]\n const resolvedOverflowText = overflowTextMap[size]\n\n const renderTriggerContent = () => {\n if (multiple && selectedValues.length > 0) {\n const visiblePills = selectedValues.slice(0, MAX_VISIBLE_PILLS)\n const remaining = selectedValues.length - MAX_VISIBLE_PILLS\n\n return (\n <span className=\"flex flex-1 flex-wrap items-center gap-ds-02 overflow-hidden\">\n {visiblePills.map((val) => {\n const option = options.find((o) => o.value === val)\n if (!option) return null\n return (\n <span\n key={val}\n className={cn('inline-flex items-center gap-ds-01 rounded-control-inner bg-accent-2', resolvedPillClasses)}\n >\n {option.label}\n <button\n type=\"button\"\n className=\"inline-flex items-center justify-center rounded-pill outline-hidden hover:scale-110 hover:bg-surface-raised-hover transition-transform duration-fast-01 ease-productive-standard\"\n onClick={(e) => handleRemovePill(e, val)}\n aria-label={`Remove ${option.label}`}\n tabIndex={-1}\n >\n <Icon icon={IconX} size={resolvedIconSize} />\n </button>\n </span>\n )\n })}\n {remaining > 0 && (\n <span className={cn('text-surface-fg-muted', resolvedOverflowText)}>\n +{remaining} more\n </span>\n )}\n </span>\n )\n }\n\n if (!multiple && selectedValues.length === 1) {\n const label = getSelectedLabel()\n if (label) {\n return <span className=\"flex-1 truncate text-left\">{label}</span>\n }\n }\n\n return (\n <span className=\"flex-1 truncate text-left text-surface-fg-subtle\">\n {placeholder}\n </span>\n )\n }\n\n const fieldCtx = useFormField()\n const isError = fieldCtx.state === 'error'\n const ariaDescribedBy = fieldCtx.helperTextId\n const ariaRequired = fieldCtx.required\n\n return (\n <PopoverPrimitive.Root open={open} onOpenChange={handleOpenChange}>\n <div className={cn('relative', className)} {...rest}>\n <PopoverPrimitive.Trigger asChild disabled={disabled}>\n <button\n ref={ref}\n type=\"button\"\n role=\"combobox\"\n aria-expanded={open}\n aria-controls={listboxId}\n aria-haspopup=\"listbox\"\n aria-label={accessibleLabel ?? placeholder}\n aria-invalid={isError || undefined}\n aria-describedby={ariaDescribedBy}\n aria-required={ariaRequired || undefined}\n disabled={disabled}\n className={cn(\n comboboxTriggerVariants({ size }),\n open && 'border-accent-7',\n triggerClassName,\n )}\n >\n {renderTriggerContent()}\n <Icon icon={IconChevronDown} size={resolvedIconSize} className={cn(\"ml-ds-02 shrink-0 opacity-50 transition-transform duration-fast-01 ease-productive-standard\", open && 'rotate-180')} />\n </button>\n </PopoverPrimitive.Trigger>\n\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n asChild\n sideOffset={4}\n align=\"start\"\n onOpenAutoFocus={(e) => {\n e.preventDefault()\n searchInputRef.current?.focus()\n }}\n >\n <motion.div\n initial={{ opacity: 0, scale: 0.95 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={{ ...springs.snappy, opacity: tweens.fade }}\n className={cn(\n 'z-popover w-[var(--radix-popover-trigger-width)] overflow-hidden rounded-overlay bg-surface-overlay shadow-floating',\n )}\n >\n {/* Search input */}\n <div className=\"flex items-center gap-ds-02 border-b border-surface-border px-ds-04\">\n <Icon icon={IconSearch} size=\"sm\" className=\"shrink-0 text-surface-fg-subtle\" />\n <input\n ref={searchInputRef}\n type=\"text\"\n className=\"flex-1 bg-transparent py-ds-03 text-ds-md outline-hidden placeholder:text-surface-fg-subtle\"\n placeholder={searchPlaceholder}\n value={search}\n onChange={(e) => {\n setSearch(e.target.value)\n setHighlightedIndex(-1)\n }}\n onKeyDown={handleKeyDown}\n aria-autocomplete=\"list\"\n aria-controls={listboxId}\n aria-activedescendant={\n highlightedIndex >= 0\n ? `${optionIdPrefix}-option-${highlightedIndex}`\n : undefined\n }\n aria-label=\"Search options\"\n />\n </div>\n\n {/* Options list */}\n {filteredOptions.length === 0 ? (\n <div className=\"px-ds-04 py-ds-05 text-center text-ds-md text-surface-fg-subtle\">\n {emptyMessage}\n </div>\n ) : (\n <ul\n ref={listRef}\n id={listboxId}\n role=\"listbox\"\n aria-multiselectable={multiple || undefined}\n className=\"overflow-auto p-ds-02\"\n style={{ maxHeight: `${maxVisible * ITEM_HEIGHT_PX}px` }}\n >\n {filteredOptions.map((option, index) => {\n const selected = isSelected(option.value)\n return (\n <li\n key={option.value}\n id={`${optionIdPrefix}-option-${index}`}\n role=\"option\"\n aria-selected={selected}\n aria-disabled={option.disabled || undefined}\n className={cn(\n 'relative flex cursor-pointer select-none items-center gap-ds-03 rounded-control px-ds-04 py-ds-03 text-ds-md outline-hidden',\n 'transition-colors duration-fast-01 ease-productive-standard',\n highlightedIndex === index &&\n 'bg-accent-2',\n selected && 'text-accent-11',\n option.disabled &&\n 'pointer-events-none opacity-action-disabled',\n )}\n onClick={() => {\n if (!option.disabled) {\n handleSelect(option.value)\n }\n }}\n onKeyDown={(e) => {\n if (!option.disabled && (e.key === 'Enter' || e.key === ' ')) {\n e.preventDefault()\n handleSelect(option.value)\n }\n }}\n onMouseEnter={() => {\n if (!option.disabled) {\n setHighlightedIndex(index)\n }\n }}\n >\n {option.icon && (\n <span className=\"flex h-ico-sm w-ico-sm items-center justify-center shrink-0\">\n <IconProvider size={resolvedIconSize}>\n {normalizeIcon(option.icon)}\n </IconProvider>\n </span>\n )}\n <span className=\"flex flex-1 flex-col\">\n {renderOption ? (\n renderOption(option, selected)\n ) : (\n <>\n <span>{option.label}</span>\n {option.description && (\n <span className=\"text-ds-sm text-surface-fg-muted\">\n {option.description}\n </span>\n )}\n </>\n )}\n </span>\n {selected && (\n <Icon icon={IconCheck} size=\"sm\" className=\"shrink-0\" />\n )}\n </li>\n )\n })}\n </ul>\n )}\n </motion.div>\n </PopoverPrimitive.Content>\n </PopoverPrimitive.Portal>\n </div>\n </PopoverPrimitive.Root>\n )\n },\n)\nCombobox.displayName = 'Combobox'\n\nexport { Combobox }\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"combobox.js","names":[],"sources":["../../src/ui/combobox.tsx"],"sourcesContent":["'use client'\n\nimport * as PopoverPrimitive from '@primitives/react-popover'\nimport { IconCheck, IconChevronDown, IconSearch, IconX } from '@tabler/icons-react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { useFormField } from './form'\nimport { Icon } from './icon'\nimport { IconProvider, type IconSize } from './icon-context'\nimport type { IconInput } from './lib/icon-input'\nimport { springs, tweens } from './lib/motion'\nimport { normalizeIcon } from './lib/normalize-icon'\nimport { cn } from './lib/utils'\n\nexport const comboboxTriggerVariants = cva(\n [\n 'flex w-full items-center justify-between whitespace-nowrap rounded-control',\n 'border border-surface-border-strong bg-surface-raised-hover',\n 'transition-colors duration-fast-01 ease-productive-standard',\n 'focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2 focus-visible:border-accent-7',\n 'disabled:cursor-not-allowed disabled:opacity-action-disabled',\n ],\n {\n variants: {\n size: {\n xs: 'h-ds-xs-plus text-ds-sm px-ds-02',\n sm: 'h-ds-sm text-ds-sm px-ds-03',\n md: 'h-ds-md text-ds-md px-ds-04',\n lg: 'h-ds-lg text-ds-md px-ds-05',\n },\n },\n defaultVariants: { size: 'md' },\n },\n)\n\nexport type ComboboxSize = NonNullable<VariantProps<typeof comboboxTriggerVariants>['size']>\n\n/** Maps combobox size to Icon component size for chevron / check icons */\nconst iconSizeMap: Record<NonNullable<ComboboxSize>, IconSize> = {\n xs: 'xs',\n sm: 'sm',\n md: 'sm',\n lg: 'md',\n}\n\n/** Maps combobox size to pill text + padding classes */\nconst pillSizeMap: Record<NonNullable<ComboboxSize>, string> = {\n xs: 'px-ds-02 py-0 text-ds-xs',\n sm: 'px-ds-02 py-0 text-ds-xs',\n md: 'px-ds-03 py-[1px] text-ds-sm',\n lg: 'px-ds-03 py-[2px] text-ds-sm',\n}\n\n/** Maps combobox size to overflow text classes */\nconst overflowTextMap: Record<NonNullable<ComboboxSize>, string> = {\n xs: 'text-ds-xs',\n sm: 'text-ds-xs',\n md: 'text-ds-sm',\n lg: 'text-ds-sm',\n}\n\n/**\n * Option shape for a Combobox dropdown item.\n * `value` must be unique across all options — it is the key used in selection state.\n */\nexport interface ComboboxOption {\n value: string\n label: string\n description?: string\n icon?: IconInput\n disabled?: boolean\n}\n\n/**\n * Props for Combobox — a searchable single or multi-select dropdown with built-in keyboard\n * navigation, pill overflow (\"+ N more\"), and an optional custom option renderer.\n *\n * **Single vs multi:** `multiple={false}` (default) — `value` is a `string` and `onValueChange`\n * receives a `string`. When `multiple={true}`, `value` is `string[]`, `onValueChange` receives\n * `string[]`, and selected items appear as dismissible pills in the trigger.\n *\n * The props form a **discriminated union** on `multiple` — TypeScript will narrow `value` and\n * `onValueChange` automatically, so no manual casts are needed.\n *\n * **Custom rendering:** Use `renderOption` to return custom JSX per option (e.g. avatars, badges).\n *\n * @example\n * // Single-select country picker:\n * <Combobox\n * options={[{ value: 'in', label: 'India' }, { value: 'us', label: 'United States' }]}\n * value={country}\n * onValueChange={(v) => setCountry(v)}\n * placeholder=\"Select country\"\n * />\n *\n * @example\n * // Multi-select tag picker with pill display:\n * <Combobox\n * multiple\n * options={tagOptions}\n * value={selectedTags}\n * onValueChange={(v) => setSelectedTags(v)}\n * placeholder=\"Select tags...\"\n * />\n *\n * @example\n * // Custom option renderer (user avatars in assignee picker):\n * <Combobox\n * options={users.map(u => ({ value: u.id, label: u.name }))}\n * value={assigneeId}\n * onValueChange={(v) => setAssigneeId(v)}\n * renderOption={(option, selected) => (\n * <span className=\"flex items-center gap-ds-03\">\n * <Avatar size=\"xs\"><AvatarFallback>{option.label[0]}</AvatarFallback></Avatar>\n * {option.label}\n * </span>\n * )}\n * />\n * // These are just a few ways — feel free to combine props creatively!\n */\ninterface ComboboxBaseProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> {\n /** Available options shown in the dropdown. */\n options: ComboboxOption[]\n /** Placeholder shown in the trigger when no value is selected. */\n placeholder?: string\n /** Placeholder for the search input inside the dropdown. */\n searchPlaceholder?: string\n /** Message shown when the search yields no results. */\n emptyMessage?: string\n disabled?: boolean\n triggerClassName?: string\n /** Max visible items in the dropdown before scroll (default 6). */\n maxVisible?: number\n /** Custom renderer for each option row. Receives the option and whether it's currently selected. */\n renderOption?: (option: ComboboxOption, selected: boolean) => React.ReactNode\n /** Accessible label for the trigger button. Falls back to `placeholder` if not provided. */\n accessibleLabel?: string\n /** Size of the trigger. Controls height, text size, padding, and pill sizing. */\n size?: ComboboxSize\n}\n\ninterface ComboboxSingleProps extends ComboboxBaseProps {\n multiple?: false\n value?: string\n onValueChange: (value: string) => void\n}\n\ninterface ComboboxMultipleProps extends ComboboxBaseProps {\n multiple: true\n value?: string[]\n onValueChange: (value: string[]) => void\n}\n\nexport type ComboboxProps = ComboboxSingleProps | ComboboxMultipleProps\n\n/** Max pills shown in the trigger before \"+N more\" overflow */\nconst MAX_VISIBLE_PILLS = 2\n\n/** Approximate height of a single option item in px */\nconst ITEM_HEIGHT_PX = 36\n\nconst Combobox = React.forwardRef<HTMLButtonElement, ComboboxProps>(\n (\n {\n options,\n value,\n onValueChange,\n placeholder = 'Select...',\n searchPlaceholder = 'Search...',\n emptyMessage = 'No results found',\n multiple = false,\n disabled = false,\n className,\n triggerClassName,\n maxVisible = 6,\n renderOption,\n accessibleLabel,\n size: sizeProp = 'md',\n ...rest\n },\n ref,\n ) => {\n const size = sizeProp ?? 'md'\n const [open, setOpen] = React.useState(false)\n const [search, setSearch] = React.useState('')\n const [highlightedIndex, setHighlightedIndex] = React.useState(-1)\n const searchInputRef = React.useRef<HTMLInputElement>(null)\n const listRef = React.useRef<HTMLUListElement>(null)\n const optionIdPrefix = React.useId()\n const listboxId = React.useId()\n\n const selectedValues = React.useMemo<string[]>(() => {\n if (value === undefined || value === null) return []\n if (Array.isArray(value)) return value\n return [value]\n }, [value])\n\n const filteredOptions = React.useMemo(\n () =>\n search\n ? options.filter((o) =>\n o.label.toLowerCase().includes(search.toLowerCase()),\n )\n : options,\n [options, search],\n )\n\n const isSelected = React.useCallback(\n (optionValue: string) => selectedValues.includes(optionValue),\n [selectedValues],\n )\n\n const handleSelect = React.useCallback(\n (optionValue: string) => {\n if (multiple) {\n const newValue = selectedValues.includes(optionValue)\n ? selectedValues.filter((v) => v !== optionValue)\n : [...selectedValues, optionValue]\n ;(onValueChange as (value: string[]) => void)(newValue)\n } else {\n ;(onValueChange as (value: string) => void)(optionValue)\n setOpen(false)\n }\n },\n [multiple, selectedValues, onValueChange],\n )\n\n const handleRemovePill = React.useCallback(\n (e: React.SyntheticEvent, optionValue: string) => {\n e.stopPropagation()\n e.preventDefault()\n const newValue = selectedValues.filter((v) => v !== optionValue)\n ;(onValueChange as (value: string[]) => void)(newValue)\n },\n [selectedValues, onValueChange],\n )\n\n const handleOpenChange = React.useCallback(\n (nextOpen: boolean) => {\n if (disabled) return\n setOpen(nextOpen)\n if (!nextOpen) {\n setSearch('')\n setHighlightedIndex(-1)\n }\n },\n [disabled],\n )\n\n // Auto-focus search input when popover opens\n React.useEffect(() => {\n if (open) {\n // Use a small timeout to allow the popover to render\n const timer = setTimeout(() => {\n searchInputRef.current?.focus()\n }, 0)\n return () => clearTimeout(timer)\n }\n }, [open])\n\n const findNextEnabledIndex = React.useCallback(\n (currentIndex: number, direction: 1 | -1): number => {\n const len = filteredOptions.length\n if (len === 0) return -1\n\n let nextIndex = currentIndex + direction\n while (nextIndex >= 0 && nextIndex < len) {\n if (!filteredOptions[nextIndex].disabled) return nextIndex\n nextIndex += direction\n }\n return currentIndex\n },\n [filteredOptions],\n )\n\n const handleKeyDown = React.useCallback(\n (e: React.KeyboardEvent) => {\n switch (e.key) {\n case 'ArrowDown': {\n e.preventDefault()\n const nextIdx = findNextEnabledIndex(highlightedIndex, 1)\n setHighlightedIndex(nextIdx)\n break\n }\n case 'ArrowUp': {\n e.preventDefault()\n const prevIdx = findNextEnabledIndex(highlightedIndex, -1)\n setHighlightedIndex(prevIdx)\n break\n }\n case 'Home': {\n e.preventDefault()\n const firstEnabled = filteredOptions.findIndex((o) => !o.disabled)\n setHighlightedIndex(firstEnabled)\n break\n }\n case 'End': {\n e.preventDefault()\n let lastEnabled = -1\n for (let i = filteredOptions.length - 1; i >= 0; i--) {\n if (!filteredOptions[i].disabled) {\n lastEnabled = i\n break\n }\n }\n setHighlightedIndex(lastEnabled)\n break\n }\n case 'Enter': {\n e.preventDefault()\n if (\n highlightedIndex >= 0 &&\n highlightedIndex < filteredOptions.length &&\n !filteredOptions[highlightedIndex].disabled\n ) {\n handleSelect(filteredOptions[highlightedIndex].value)\n }\n break\n }\n case 'Escape': {\n e.preventDefault()\n setOpen(false)\n setSearch('')\n setHighlightedIndex(-1)\n break\n }\n }\n },\n [highlightedIndex, filteredOptions, findNextEnabledIndex, handleSelect],\n )\n\n // Scroll highlighted option into view\n React.useEffect(() => {\n if (highlightedIndex >= 0 && listRef.current) {\n const optionEl = listRef.current.children[highlightedIndex] as HTMLElement\n if (optionEl) {\n optionEl.scrollIntoView?.({ block: 'nearest' })\n }\n }\n }, [highlightedIndex])\n\n const getSelectedLabel = React.useCallback(() => {\n if (selectedValues.length === 0) return null\n const option = options.find((o) => o.value === selectedValues[0])\n return option?.label ?? null\n }, [selectedValues, options])\n\n const resolvedIconSize = iconSizeMap[size]\n const resolvedPillClasses = pillSizeMap[size]\n const resolvedOverflowText = overflowTextMap[size]\n\n const renderTriggerContent = () => {\n if (multiple && selectedValues.length > 0) {\n const visiblePills = selectedValues.slice(0, MAX_VISIBLE_PILLS)\n const remaining = selectedValues.length - MAX_VISIBLE_PILLS\n\n return (\n <span className=\"flex flex-1 flex-wrap items-center gap-ds-02 overflow-hidden\">\n {visiblePills.map((val) => {\n const option = options.find((o) => o.value === val)\n if (!option) return null\n return (\n <span\n key={val}\n className={cn('inline-flex items-center gap-ds-01 rounded-control-inner bg-accent-2', resolvedPillClasses)}\n >\n {option.label}\n <button\n type=\"button\"\n className=\"inline-flex items-center justify-center rounded-pill outline-hidden hover:scale-110 hover:bg-surface-raised-hover transition-transform duration-fast-01 ease-productive-standard\"\n onClick={(e) => handleRemovePill(e, val)}\n aria-label={`Remove ${option.label}`}\n tabIndex={-1}\n >\n <Icon icon={IconX} size={resolvedIconSize} />\n </button>\n </span>\n )\n })}\n {remaining > 0 && (\n <span className={cn('text-surface-fg-muted', resolvedOverflowText)}>\n +{remaining} more\n </span>\n )}\n </span>\n )\n }\n\n if (!multiple && selectedValues.length === 1) {\n const label = getSelectedLabel()\n if (label) {\n return <span className=\"min-w-0 flex-1 truncate text-left\">{label}</span>\n }\n }\n\n return (\n <span className=\"min-w-0 flex-1 truncate text-left text-surface-fg-subtle\">\n {placeholder}\n </span>\n )\n }\n\n const fieldCtx = useFormField()\n const isError = fieldCtx.state === 'error'\n const ariaDescribedBy = fieldCtx.helperTextId\n const ariaRequired = fieldCtx.required\n\n return (\n <PopoverPrimitive.Root open={open} onOpenChange={handleOpenChange}>\n <div className={cn('relative', className)} {...rest}>\n <PopoverPrimitive.Trigger asChild disabled={disabled}>\n <button\n ref={ref}\n type=\"button\"\n role=\"combobox\"\n aria-expanded={open}\n aria-controls={listboxId}\n aria-haspopup=\"listbox\"\n aria-label={accessibleLabel ?? placeholder}\n aria-invalid={isError || undefined}\n aria-describedby={ariaDescribedBy}\n aria-required={ariaRequired || undefined}\n disabled={disabled}\n className={cn(\n comboboxTriggerVariants({ size }),\n open && 'border-accent-7',\n triggerClassName,\n )}\n >\n {renderTriggerContent()}\n <Icon icon={IconChevronDown} size={resolvedIconSize} className={cn(\"ml-ds-02 shrink-0 opacity-50 transition-transform duration-fast-01 ease-productive-standard\", open && 'rotate-180')} />\n </button>\n </PopoverPrimitive.Trigger>\n\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n asChild\n sideOffset={4}\n align=\"start\"\n onOpenAutoFocus={(e) => {\n e.preventDefault()\n searchInputRef.current?.focus()\n }}\n >\n <motion.div\n initial={{ opacity: 0, scale: 0.95 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={{ ...springs.snappy, opacity: tweens.fade }}\n className={cn(\n 'z-popover w-[var(--radix-popover-trigger-width)] overflow-hidden rounded-overlay bg-surface-overlay shadow-floating',\n )}\n >\n {/* Search input */}\n <div className=\"flex items-center gap-ds-02 border-b border-surface-border px-ds-04\">\n <Icon icon={IconSearch} size=\"sm\" className=\"shrink-0 text-surface-fg-subtle\" />\n <input\n ref={searchInputRef}\n type=\"text\"\n className=\"flex-1 bg-transparent py-ds-03 text-ds-md outline-hidden placeholder:text-surface-fg-subtle\"\n placeholder={searchPlaceholder}\n value={search}\n onChange={(e) => {\n setSearch(e.target.value)\n setHighlightedIndex(-1)\n }}\n onKeyDown={handleKeyDown}\n aria-autocomplete=\"list\"\n aria-controls={listboxId}\n aria-activedescendant={\n highlightedIndex >= 0\n ? `${optionIdPrefix}-option-${highlightedIndex}`\n : undefined\n }\n aria-label=\"Search options\"\n />\n </div>\n\n {/* Options list */}\n {filteredOptions.length === 0 ? (\n <div className=\"px-ds-04 py-ds-05 text-center text-ds-md text-surface-fg-subtle\">\n {emptyMessage}\n </div>\n ) : (\n <ul\n ref={listRef}\n id={listboxId}\n role=\"listbox\"\n aria-multiselectable={multiple || undefined}\n className=\"overflow-auto p-ds-02\"\n style={{ maxHeight: `${maxVisible * ITEM_HEIGHT_PX}px` }}\n >\n {filteredOptions.map((option, index) => {\n const selected = isSelected(option.value)\n return (\n <li\n key={option.value}\n id={`${optionIdPrefix}-option-${index}`}\n role=\"option\"\n aria-selected={selected}\n aria-disabled={option.disabled || undefined}\n className={cn(\n 'relative flex cursor-pointer select-none items-center gap-ds-03 rounded-control px-ds-04 py-ds-03 text-ds-md outline-hidden',\n 'transition-colors duration-fast-01 ease-productive-standard',\n highlightedIndex === index &&\n 'bg-accent-2',\n selected && 'text-accent-11',\n option.disabled &&\n 'pointer-events-none opacity-action-disabled',\n )}\n onClick={() => {\n if (!option.disabled) {\n handleSelect(option.value)\n }\n }}\n onKeyDown={(e) => {\n if (!option.disabled && (e.key === 'Enter' || e.key === ' ')) {\n e.preventDefault()\n handleSelect(option.value)\n }\n }}\n onMouseEnter={() => {\n if (!option.disabled) {\n setHighlightedIndex(index)\n }\n }}\n >\n {option.icon && (\n <span className=\"flex h-ico-sm w-ico-sm items-center justify-center shrink-0\">\n <IconProvider size={resolvedIconSize}>\n {normalizeIcon(option.icon)}\n </IconProvider>\n </span>\n )}\n <span className=\"flex flex-1 flex-col\">\n {renderOption ? (\n renderOption(option, selected)\n ) : (\n <>\n <span>{option.label}</span>\n {option.description && (\n <span className=\"text-ds-sm text-surface-fg-muted\">\n {option.description}\n </span>\n )}\n </>\n )}\n </span>\n {selected && (\n <Icon icon={IconCheck} size=\"sm\" className=\"shrink-0\" />\n )}\n </li>\n )\n })}\n </ul>\n )}\n </motion.div>\n </PopoverPrimitive.Content>\n </PopoverPrimitive.Portal>\n </div>\n </PopoverPrimitive.Root>\n )\n },\n)\nCombobox.displayName = 'Combobox'\n\nexport { Combobox }\n"],"mappings":"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"}
|
package/dist/ui/dropdown-menu.js
CHANGED
|
@@ -40,10 +40,13 @@ var P = i, F = y.forwardRef(({ className: e, inset: t, children: n, ...i }, a) =
|
|
|
40
40
|
ref: a,
|
|
41
41
|
className: _("flex cursor-default select-none items-center gap-ds-03 rounded-control px-ds-03 py-ds-02b text-ds-md outline-hidden focus:bg-surface-raised data-[state=open]:bg-surface-raised [&_svg]:pointer-events-none [&_svg]:h-ico-sm [&_svg]:w-ico-sm [&_svg]:shrink-0", t && "pl-ds-07", e),
|
|
42
42
|
...i,
|
|
43
|
-
children: [
|
|
43
|
+
children: [/* @__PURE__ */ b("span", {
|
|
44
|
+
className: "min-w-0 truncate",
|
|
45
|
+
children: n
|
|
46
|
+
}), /* @__PURE__ */ b(v, {
|
|
44
47
|
icon: C,
|
|
45
48
|
size: "sm",
|
|
46
|
-
className: "ml-auto"
|
|
49
|
+
className: "ml-auto shrink-0"
|
|
47
50
|
})]
|
|
48
51
|
}));
|
|
49
52
|
F.displayName = r.displayName;
|
|
@@ -132,7 +135,10 @@ var B = y.forwardRef(({ className: t, children: n, ...r }, i) => /* @__PURE__ */
|
|
|
132
135
|
children: [/* @__PURE__ */ b("span", {
|
|
133
136
|
className: "absolute left-ds-03 flex h-ico-sm w-ico-sm items-center justify-center",
|
|
134
137
|
children: /* @__PURE__ */ b(m, { children: /* @__PURE__ */ b(w, { className: "h-2 w-2 fill-current" }) })
|
|
135
|
-
}),
|
|
138
|
+
}), /* @__PURE__ */ b("span", {
|
|
139
|
+
className: "min-w-0 truncate",
|
|
140
|
+
children: n
|
|
141
|
+
})]
|
|
136
142
|
}));
|
|
137
143
|
B.displayName = e.displayName;
|
|
138
144
|
var V = y.forwardRef(({ className: e, inset: t, ...n }, r) => /* @__PURE__ */ b(s, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dropdown-menu.js","names":[],"sources":["../../src/ui/dropdown-menu.tsx"],"sourcesContent":["'use client'\n\nimport * as DropdownMenuPrimitive from '@primitives/react-dropdown-menu'\nimport { IconCheck, IconChevronRight, IconCircle } from '@tabler/icons-react'\nimport { AnimatePresence,motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { Icon } from './icon'\nimport { springs, tweens } from './lib/motion'\nimport { cn } from './lib/utils'\n\n// ── Internal contexts to thread open state ──\n\nconst DropdownMenuOpenContext = React.createContext(false)\nconst DropdownMenuSubOpenContext = React.createContext(false)\n\n/**\n * DropdownMenu compound component — accessible floating menu triggered by a button, with full\n * keyboard navigation and focus management.\n *\n * **Parts (in composition order):**\n * - `DropdownMenu` — manages open/closed state (this root)\n * - `DropdownMenuTrigger` — element that opens the menu (use `asChild` to render your own button)\n * - `DropdownMenuContent` — the floating menu panel (renders in a portal automatically)\n * - `DropdownMenuItem` — clickable menu item (use `onSelect` for actions)\n * - `DropdownMenuCheckboxItem` — item with a checkbox indicator\n * - `DropdownMenuRadioGroup` — wraps radio items for exclusive selection\n * - `DropdownMenuRadioItem` — item with a radio indicator (must be inside `DropdownMenuRadioGroup`)\n * - `DropdownMenuSub` — root for a nested submenu\n * - `DropdownMenuSubTrigger` — item that reveals a submenu on hover/focus\n * - `DropdownMenuSubContent` — the nested submenu panel\n * - `DropdownMenuLabel` — non-interactive group label (not selectable)\n * - `DropdownMenuSeparator` — horizontal divider between sections\n * - `DropdownMenuShortcut` — right-aligned keyboard shortcut hint text (display only)\n * - `DropdownMenuGroup` — semantic grouping wrapper (no visual output)\n * - `DropdownMenuPortal` — low-level portal wrapper (exported for custom positioning; used internally by DropdownMenuContent)\n *\n * @compound\n * @example\n * // Standard action menu:\n * <DropdownMenu>\n * <DropdownMenuTrigger asChild>\n * <Button variant=\"ghost\" size=\"icon\"><IconDotsVertical /></Button>\n * </DropdownMenuTrigger>\n * <DropdownMenuContent align=\"end\">\n * <DropdownMenuLabel>My account</DropdownMenuLabel>\n * <DropdownMenuSeparator />\n * <DropdownMenuItem>\n * <IconUser className=\"mr-ds-03\" />Profile\n * <DropdownMenuShortcut>⌘P</DropdownMenuShortcut>\n * </DropdownMenuItem>\n * <DropdownMenuItem>Settings</DropdownMenuItem>\n * <DropdownMenuSeparator />\n * <DropdownMenuItem className=\"text-error-11\">Sign out</DropdownMenuItem>\n * </DropdownMenuContent>\n * </DropdownMenu>\n *\n * @example\n * // Menu with checkbox items and a nested submenu:\n * <DropdownMenu>\n * <DropdownMenuTrigger asChild><Button>View options</Button></DropdownMenuTrigger>\n * <DropdownMenuContent>\n * <DropdownMenuCheckboxItem checked={showPanel} onCheckedChange={setShowPanel}>\n * Show side panel\n * </DropdownMenuCheckboxItem>\n * <DropdownMenuSeparator />\n * <DropdownMenuSub>\n * <DropdownMenuSubTrigger>More tools</DropdownMenuSubTrigger>\n * <DropdownMenuSubContent>\n * <DropdownMenuItem>Export CSV</DropdownMenuItem>\n * <DropdownMenuItem>Export PDF</DropdownMenuItem>\n * </DropdownMenuSubContent>\n * </DropdownMenuSub>\n * </DropdownMenuContent>\n * </DropdownMenu>\n */\nconst DropdownMenu: React.FC<React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Root>> = ({\n open: controlledOpen,\n defaultOpen = false,\n onOpenChange,\n ...props\n}) => {\n const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen)\n const isControlled = controlledOpen !== undefined\n const open = isControlled ? controlledOpen : uncontrolledOpen\n\n const handleOpenChange = React.useCallback(\n (value: boolean) => {\n if (!isControlled) setUncontrolledOpen(value)\n onOpenChange?.(value)\n },\n [isControlled, onOpenChange],\n )\n\n return (\n <DropdownMenuOpenContext.Provider value={open}>\n <DropdownMenuPrimitive.Root open={open} onOpenChange={handleOpenChange} {...props} />\n </DropdownMenuOpenContext.Provider>\n )\n}\nDropdownMenu.displayName = 'DropdownMenu'\n\nconst DropdownMenuTrigger = DropdownMenuPrimitive.Trigger\n\nconst DropdownMenuGroup = DropdownMenuPrimitive.Group\n\nconst DropdownMenuPortal = DropdownMenuPrimitive.Portal\n\nconst DropdownMenuSub: React.FC<React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Sub>> = ({\n open: controlledOpen,\n defaultOpen = false,\n onOpenChange,\n ...props\n}) => {\n const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen)\n const isControlled = controlledOpen !== undefined\n const open = isControlled ? controlledOpen : uncontrolledOpen\n\n const handleOpenChange = React.useCallback(\n (value: boolean) => {\n if (!isControlled) setUncontrolledOpen(value)\n onOpenChange?.(value)\n },\n [isControlled, onOpenChange],\n )\n\n return (\n <DropdownMenuSubOpenContext.Provider value={open}>\n <DropdownMenuPrimitive.Sub open={open} onOpenChange={handleOpenChange} {...props} />\n </DropdownMenuSubOpenContext.Provider>\n )\n}\nDropdownMenuSub.displayName = 'DropdownMenuSub'\n\nconst DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup\n\nconst DropdownMenuSubTrigger = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {\n inset?: boolean\n }\n>(({ className, inset, children, ...props }, ref) => (\n <DropdownMenuPrimitive.SubTrigger\n ref={ref}\n className={cn(\n 'flex cursor-default select-none items-center gap-ds-03 rounded-control px-ds-03 py-ds-02b text-ds-md outline-hidden focus:bg-surface-raised data-[state=open]:bg-surface-raised [&_svg]:pointer-events-none [&_svg]:h-ico-sm [&_svg]:w-ico-sm [&_svg]:shrink-0',\n inset && 'pl-ds-07',\n className,\n )}\n {...props}\n >\n {children}\n <Icon icon={IconChevronRight} size=\"sm\" className=\"ml-auto\" />\n </DropdownMenuPrimitive.SubTrigger>\n))\nDropdownMenuSubTrigger.displayName =\n DropdownMenuPrimitive.SubTrigger.displayName\n\nconst DropdownMenuSubContent = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>\n>(({ className, children, ...props }, ref) => {\n const open = React.useContext(DropdownMenuSubOpenContext)\n\n return (\n <AnimatePresence>\n {open && (\n <DropdownMenuPrimitive.SubContent\n ref={ref}\n forceMount\n asChild\n {...props}\n >\n <motion.div\n initial={{ opacity: 0, scale: 0.95 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.95 }}\n transition={{ ...springs.snappy, opacity: tweens.fade }}\n className={cn(\n 'z-popover min-w-[8rem] overflow-hidden rounded-overlay bg-surface-overlay p-ds-02 text-surface-fg shadow-floating',\n className,\n )}\n >\n {children}\n </motion.div>\n </DropdownMenuPrimitive.SubContent>\n )}\n </AnimatePresence>\n )\n})\nDropdownMenuSubContent.displayName =\n DropdownMenuPrimitive.SubContent.displayName\n\nconst DropdownMenuContent = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>\n>(({ className, sideOffset = 4, children, ...props }, ref) => {\n const open = React.useContext(DropdownMenuOpenContext)\n\n return (\n <AnimatePresence>\n {open && (\n <DropdownMenuPrimitive.Portal forceMount>\n <DropdownMenuPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n forceMount\n asChild\n {...props}\n >\n <motion.div\n initial={{ opacity: 0, scale: 0.95 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.95 }}\n transition={{ ...springs.snappy, opacity: tweens.fade }}\n className={cn(\n 'z-popover min-w-[8rem] rounded-overlay bg-surface-overlay p-ds-02 text-surface-fg shadow-floating',\n className,\n )}\n >\n {children}\n </motion.div>\n </DropdownMenuPrimitive.Content>\n </DropdownMenuPrimitive.Portal>\n )}\n </AnimatePresence>\n )\n})\nDropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName\n\nconst DropdownMenuItem = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {\n inset?: boolean\n }\n>(({ className, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.Item\n ref={ref}\n className={cn(\n 'relative flex cursor-default select-none items-center gap-ds-03 rounded-control px-ds-03 py-ds-02b text-ds-md outline-hidden transition-colors duration-fast-01 ease-productive-standard hover:bg-surface-raised focus:bg-surface-raised focus:text-surface-fg active:bg-surface-raised-hover data-[disabled]:pointer-events-none data-[disabled]:opacity-action-disabled [&>svg]:h-ico-sm [&>svg]:w-ico-sm [&>svg]:shrink-0',\n inset && 'pl-ds-07',\n className,\n )}\n {...props}\n />\n))\nDropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName\n\nconst DropdownMenuCheckboxItem = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>\n>(({ className, children, checked, ...props }, ref) => (\n <DropdownMenuPrimitive.CheckboxItem\n ref={ref}\n className={cn(\n 'relative flex cursor-default select-none items-center rounded-control py-ds-02b pl-ds-07 pr-ds-03 text-ds-md outline-hidden transition-colors duration-fast-01 ease-productive-standard hover:bg-surface-raised focus:bg-surface-raised focus:text-surface-fg active:bg-surface-raised-hover data-[disabled]:pointer-events-none data-[disabled]:opacity-action-disabled',\n className,\n )}\n checked={checked}\n {...props}\n >\n <span className=\"absolute left-ds-03 flex h-ico-sm w-ico-sm items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <Icon icon={IconCheck} size=\"sm\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.CheckboxItem>\n))\nDropdownMenuCheckboxItem.displayName =\n DropdownMenuPrimitive.CheckboxItem.displayName\n\nconst DropdownMenuRadioItem = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>\n>(({ className, children, ...props }, ref) => (\n <DropdownMenuPrimitive.RadioItem\n ref={ref}\n className={cn(\n 'relative flex cursor-default select-none items-center rounded-control py-ds-02b pl-ds-07 pr-ds-03 text-ds-md outline-hidden transition-colors duration-fast-01 ease-productive-standard hover:bg-surface-raised focus:bg-surface-raised focus:text-surface-fg active:bg-surface-raised-hover data-[disabled]:pointer-events-none data-[disabled]:opacity-action-disabled',\n className,\n )}\n {...props}\n >\n <span className=\"absolute left-ds-03 flex h-ico-sm w-ico-sm items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <IconCircle className=\"h-2 w-2 fill-current\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.RadioItem>\n))\nDropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName\n\nconst DropdownMenuLabel = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Label>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {\n inset?: boolean\n }\n>(({ className, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.Label\n ref={ref}\n className={cn(\n 'px-ds-03 py-ds-02b text-ds-md font-semibold',\n inset && 'pl-ds-07',\n className,\n )}\n {...props}\n />\n))\nDropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName\n\nconst DropdownMenuSeparator = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Separator>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.Separator\n ref={ref}\n className={cn('-mx-ds-01 my-ds-02 h-px bg-surface-border', className)}\n {...props}\n />\n))\nDropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName\n\nconst DropdownMenuShortcut = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLSpanElement>) => {\n return (\n <span\n className={cn('ml-auto text-ds-sm text-surface-fg-subtle', className)}\n {...props}\n />\n )\n}\nDropdownMenuShortcut.displayName = 'DropdownMenuShortcut'\n\nexport type DropdownMenuContentProps = React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>\nexport type DropdownMenuItemProps = React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item>\n\nexport {\n DropdownMenu,\n DropdownMenuCheckboxItem,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuPortal,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuSeparator,\n DropdownMenuShortcut,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n DropdownMenuTrigger,\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dropdown-menu.js","names":[],"sources":["../../src/ui/dropdown-menu.tsx"],"sourcesContent":["'use client'\n\nimport * as DropdownMenuPrimitive from '@primitives/react-dropdown-menu'\nimport { IconCheck, IconChevronRight, IconCircle } from '@tabler/icons-react'\nimport { AnimatePresence,motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { Icon } from './icon'\nimport { springs, tweens } from './lib/motion'\nimport { cn } from './lib/utils'\n\n// ── Internal contexts to thread open state ──\n\nconst DropdownMenuOpenContext = React.createContext(false)\nconst DropdownMenuSubOpenContext = React.createContext(false)\n\n/**\n * DropdownMenu compound component — accessible floating menu triggered by a button, with full\n * keyboard navigation and focus management.\n *\n * **Parts (in composition order):**\n * - `DropdownMenu` — manages open/closed state (this root)\n * - `DropdownMenuTrigger` — element that opens the menu (use `asChild` to render your own button)\n * - `DropdownMenuContent` — the floating menu panel (renders in a portal automatically)\n * - `DropdownMenuItem` — clickable menu item (use `onSelect` for actions)\n * - `DropdownMenuCheckboxItem` — item with a checkbox indicator\n * - `DropdownMenuRadioGroup` — wraps radio items for exclusive selection\n * - `DropdownMenuRadioItem` — item with a radio indicator (must be inside `DropdownMenuRadioGroup`)\n * - `DropdownMenuSub` — root for a nested submenu\n * - `DropdownMenuSubTrigger` — item that reveals a submenu on hover/focus\n * - `DropdownMenuSubContent` — the nested submenu panel\n * - `DropdownMenuLabel` — non-interactive group label (not selectable)\n * - `DropdownMenuSeparator` — horizontal divider between sections\n * - `DropdownMenuShortcut` — right-aligned keyboard shortcut hint text (display only)\n * - `DropdownMenuGroup` — semantic grouping wrapper (no visual output)\n * - `DropdownMenuPortal` — low-level portal wrapper (exported for custom positioning; used internally by DropdownMenuContent)\n *\n * @compound\n * @example\n * // Standard action menu:\n * <DropdownMenu>\n * <DropdownMenuTrigger asChild>\n * <Button variant=\"ghost\" size=\"icon\"><IconDotsVertical /></Button>\n * </DropdownMenuTrigger>\n * <DropdownMenuContent align=\"end\">\n * <DropdownMenuLabel>My account</DropdownMenuLabel>\n * <DropdownMenuSeparator />\n * <DropdownMenuItem>\n * <IconUser className=\"mr-ds-03\" />Profile\n * <DropdownMenuShortcut>⌘P</DropdownMenuShortcut>\n * </DropdownMenuItem>\n * <DropdownMenuItem>Settings</DropdownMenuItem>\n * <DropdownMenuSeparator />\n * <DropdownMenuItem className=\"text-error-11\">Sign out</DropdownMenuItem>\n * </DropdownMenuContent>\n * </DropdownMenu>\n *\n * @example\n * // Menu with checkbox items and a nested submenu:\n * <DropdownMenu>\n * <DropdownMenuTrigger asChild><Button>View options</Button></DropdownMenuTrigger>\n * <DropdownMenuContent>\n * <DropdownMenuCheckboxItem checked={showPanel} onCheckedChange={setShowPanel}>\n * Show side panel\n * </DropdownMenuCheckboxItem>\n * <DropdownMenuSeparator />\n * <DropdownMenuSub>\n * <DropdownMenuSubTrigger>More tools</DropdownMenuSubTrigger>\n * <DropdownMenuSubContent>\n * <DropdownMenuItem>Export CSV</DropdownMenuItem>\n * <DropdownMenuItem>Export PDF</DropdownMenuItem>\n * </DropdownMenuSubContent>\n * </DropdownMenuSub>\n * </DropdownMenuContent>\n * </DropdownMenu>\n */\nconst DropdownMenu: React.FC<React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Root>> = ({\n open: controlledOpen,\n defaultOpen = false,\n onOpenChange,\n ...props\n}) => {\n const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen)\n const isControlled = controlledOpen !== undefined\n const open = isControlled ? controlledOpen : uncontrolledOpen\n\n const handleOpenChange = React.useCallback(\n (value: boolean) => {\n if (!isControlled) setUncontrolledOpen(value)\n onOpenChange?.(value)\n },\n [isControlled, onOpenChange],\n )\n\n return (\n <DropdownMenuOpenContext.Provider value={open}>\n <DropdownMenuPrimitive.Root open={open} onOpenChange={handleOpenChange} {...props} />\n </DropdownMenuOpenContext.Provider>\n )\n}\nDropdownMenu.displayName = 'DropdownMenu'\n\nconst DropdownMenuTrigger = DropdownMenuPrimitive.Trigger\n\nconst DropdownMenuGroup = DropdownMenuPrimitive.Group\n\nconst DropdownMenuPortal = DropdownMenuPrimitive.Portal\n\nconst DropdownMenuSub: React.FC<React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Sub>> = ({\n open: controlledOpen,\n defaultOpen = false,\n onOpenChange,\n ...props\n}) => {\n const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen)\n const isControlled = controlledOpen !== undefined\n const open = isControlled ? controlledOpen : uncontrolledOpen\n\n const handleOpenChange = React.useCallback(\n (value: boolean) => {\n if (!isControlled) setUncontrolledOpen(value)\n onOpenChange?.(value)\n },\n [isControlled, onOpenChange],\n )\n\n return (\n <DropdownMenuSubOpenContext.Provider value={open}>\n <DropdownMenuPrimitive.Sub open={open} onOpenChange={handleOpenChange} {...props} />\n </DropdownMenuSubOpenContext.Provider>\n )\n}\nDropdownMenuSub.displayName = 'DropdownMenuSub'\n\nconst DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup\n\nconst DropdownMenuSubTrigger = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {\n inset?: boolean\n }\n>(({ className, inset, children, ...props }, ref) => (\n <DropdownMenuPrimitive.SubTrigger\n ref={ref}\n className={cn(\n 'flex cursor-default select-none items-center gap-ds-03 rounded-control px-ds-03 py-ds-02b text-ds-md outline-hidden focus:bg-surface-raised data-[state=open]:bg-surface-raised [&_svg]:pointer-events-none [&_svg]:h-ico-sm [&_svg]:w-ico-sm [&_svg]:shrink-0',\n inset && 'pl-ds-07',\n className,\n )}\n {...props}\n >\n <span className=\"min-w-0 truncate\">{children}</span>\n <Icon icon={IconChevronRight} size=\"sm\" className=\"ml-auto shrink-0\" />\n </DropdownMenuPrimitive.SubTrigger>\n))\nDropdownMenuSubTrigger.displayName =\n DropdownMenuPrimitive.SubTrigger.displayName\n\nconst DropdownMenuSubContent = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>\n>(({ className, children, ...props }, ref) => {\n const open = React.useContext(DropdownMenuSubOpenContext)\n\n return (\n <AnimatePresence>\n {open && (\n <DropdownMenuPrimitive.SubContent\n ref={ref}\n forceMount\n asChild\n {...props}\n >\n <motion.div\n initial={{ opacity: 0, scale: 0.95 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.95 }}\n transition={{ ...springs.snappy, opacity: tweens.fade }}\n className={cn(\n 'z-popover min-w-[8rem] overflow-hidden rounded-overlay bg-surface-overlay p-ds-02 text-surface-fg shadow-floating',\n className,\n )}\n >\n {children}\n </motion.div>\n </DropdownMenuPrimitive.SubContent>\n )}\n </AnimatePresence>\n )\n})\nDropdownMenuSubContent.displayName =\n DropdownMenuPrimitive.SubContent.displayName\n\nconst DropdownMenuContent = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>\n>(({ className, sideOffset = 4, children, ...props }, ref) => {\n const open = React.useContext(DropdownMenuOpenContext)\n\n return (\n <AnimatePresence>\n {open && (\n <DropdownMenuPrimitive.Portal forceMount>\n <DropdownMenuPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n forceMount\n asChild\n {...props}\n >\n <motion.div\n initial={{ opacity: 0, scale: 0.95 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.95 }}\n transition={{ ...springs.snappy, opacity: tweens.fade }}\n className={cn(\n 'z-popover min-w-[8rem] rounded-overlay bg-surface-overlay p-ds-02 text-surface-fg shadow-floating',\n className,\n )}\n >\n {children}\n </motion.div>\n </DropdownMenuPrimitive.Content>\n </DropdownMenuPrimitive.Portal>\n )}\n </AnimatePresence>\n )\n})\nDropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName\n\nconst DropdownMenuItem = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {\n inset?: boolean\n }\n>(({ className, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.Item\n ref={ref}\n className={cn(\n 'relative flex cursor-default select-none items-center gap-ds-03 rounded-control px-ds-03 py-ds-02b text-ds-md outline-hidden transition-colors duration-fast-01 ease-productive-standard hover:bg-surface-raised focus:bg-surface-raised focus:text-surface-fg active:bg-surface-raised-hover data-[disabled]:pointer-events-none data-[disabled]:opacity-action-disabled [&>svg]:h-ico-sm [&>svg]:w-ico-sm [&>svg]:shrink-0',\n inset && 'pl-ds-07',\n className,\n )}\n {...props}\n />\n))\nDropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName\n\nconst DropdownMenuCheckboxItem = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>\n>(({ className, children, checked, ...props }, ref) => (\n <DropdownMenuPrimitive.CheckboxItem\n ref={ref}\n className={cn(\n 'relative flex cursor-default select-none items-center rounded-control py-ds-02b pl-ds-07 pr-ds-03 text-ds-md outline-hidden transition-colors duration-fast-01 ease-productive-standard hover:bg-surface-raised focus:bg-surface-raised focus:text-surface-fg active:bg-surface-raised-hover data-[disabled]:pointer-events-none data-[disabled]:opacity-action-disabled',\n className,\n )}\n checked={checked}\n {...props}\n >\n <span className=\"absolute left-ds-03 flex h-ico-sm w-ico-sm items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <Icon icon={IconCheck} size=\"sm\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.CheckboxItem>\n))\nDropdownMenuCheckboxItem.displayName =\n DropdownMenuPrimitive.CheckboxItem.displayName\n\nconst DropdownMenuRadioItem = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>\n>(({ className, children, ...props }, ref) => (\n <DropdownMenuPrimitive.RadioItem\n ref={ref}\n className={cn(\n 'relative flex cursor-default select-none items-center rounded-control py-ds-02b pl-ds-07 pr-ds-03 text-ds-md outline-hidden transition-colors duration-fast-01 ease-productive-standard hover:bg-surface-raised focus:bg-surface-raised focus:text-surface-fg active:bg-surface-raised-hover data-[disabled]:pointer-events-none data-[disabled]:opacity-action-disabled',\n className,\n )}\n {...props}\n >\n <span className=\"absolute left-ds-03 flex h-ico-sm w-ico-sm items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <IconCircle className=\"h-2 w-2 fill-current\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n <span className=\"min-w-0 truncate\">{children}</span>\n </DropdownMenuPrimitive.RadioItem>\n))\nDropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName\n\nconst DropdownMenuLabel = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Label>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {\n inset?: boolean\n }\n>(({ className, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.Label\n ref={ref}\n className={cn(\n 'px-ds-03 py-ds-02b text-ds-md font-semibold',\n inset && 'pl-ds-07',\n className,\n )}\n {...props}\n />\n))\nDropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName\n\nconst DropdownMenuSeparator = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Separator>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.Separator\n ref={ref}\n className={cn('-mx-ds-01 my-ds-02 h-px bg-surface-border', className)}\n {...props}\n />\n))\nDropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName\n\nconst DropdownMenuShortcut = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLSpanElement>) => {\n return (\n <span\n className={cn('ml-auto text-ds-sm text-surface-fg-subtle', className)}\n {...props}\n />\n )\n}\nDropdownMenuShortcut.displayName = 'DropdownMenuShortcut'\n\nexport type DropdownMenuContentProps = React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>\nexport type DropdownMenuItemProps = React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item>\n\nexport {\n DropdownMenu,\n DropdownMenuCheckboxItem,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuPortal,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuSeparator,\n DropdownMenuShortcut,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n DropdownMenuTrigger,\n}\n"],"mappings":"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"}
|
package/dist/ui/index.d.ts
CHANGED
|
@@ -42,6 +42,7 @@ export { Switch, type SwitchProps } from './switch';
|
|
|
42
42
|
export { Textarea, type TextareaProps, textareaVariants } from './textarea';
|
|
43
43
|
export { Toggle, type ToggleProps, toggleVariants } from './toggle';
|
|
44
44
|
export { ToggleGroup, ToggleGroupItem, type ToggleGroupItemProps, type ToggleGroupProps } from './toggle-group';
|
|
45
|
+
export { TruncatedText, type TruncatedTextProps } from './truncated-text';
|
|
45
46
|
export { AlertDialog, AlertDialogAction, type AlertDialogActionProps, AlertDialogCancel, type AlertDialogCancelProps, AlertDialogContent, type AlertDialogContentProps, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, } from './alert-dialog';
|
|
46
47
|
export { Collapsible, CollapsibleContent, type CollapsibleProps, CollapsibleTrigger } from './collapsible';
|
|
47
48
|
export { Dialog, DialogClose, DialogContent, type DialogContentProps, DialogContentRaw, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, type DialogTitleProps, DialogTrigger, } from './dialog';
|
|
@@ -57,7 +58,7 @@ export { Avatar, AvatarFallback, type AvatarFallbackProps, AvatarImage, type Ava
|
|
|
57
58
|
export { Badge, type BadgeProps, badgeVariants } from './badge';
|
|
58
59
|
export { BadgeGroup, type BadgeGroupProps } from './badge-group';
|
|
59
60
|
export { BadgeIndicator, type BadgeIndicatorProps } from './badge-indicator';
|
|
60
|
-
export { Card, CardContent, CardDescription, CardFooter, CardHeader, type CardProps, CardTitle, cardVariants } from './card';
|
|
61
|
+
export { Card, CardAction, type CardActionPlacement, type CardActionProps, CardContent, CardDescription, CardFooter, CardHeader, type CardProps, CardTitle, cardVariants } from './card';
|
|
61
62
|
export { Code, type CodeProps } from './code';
|
|
62
63
|
export { ColorSwatch, type ColorSwatchProps } from './color-swatch';
|
|
63
64
|
export { Progress, progressIndicatorVariants, type ProgressProps, progressTrackVariants } from './progress';
|