@devalok/shilp-sutra 0.47.0 → 0.49.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +36 -12
- package/BREAKING.json +78 -0
- package/MIGRATION.md +891 -846
- package/dist/_chunks/badge-group.js +50 -63
- package/dist/_chunks/badge-group.js.map +1 -1
- package/dist/_chunks/chat.js +1 -1
- package/dist/_chunks/chat.js.map +1 -1
- package/dist/_chunks/emoji-suggestion.js +124 -0
- package/dist/_chunks/emoji-suggestion.js.map +1 -0
- package/dist/_chunks/emoji.js +1115 -0
- package/dist/_chunks/emoji.js.map +1 -0
- package/dist/_chunks/field-state.js +8 -0
- package/dist/_chunks/field-state.js.map +1 -0
- package/dist/_chunks/popover.js +50 -47
- package/dist/_chunks/popover.js.map +1 -1
- package/dist/_chunks/primitives.js +155 -155
- package/dist/_chunks/primitives.js.map +1 -1
- package/dist/_chunks/shared.js +4 -4
- package/dist/_chunks/tiptap.js +10 -10
- package/dist/_chunks/tiptap.js.map +1 -1
- package/dist/_chunks/use-calendar.js +1 -1
- package/dist/_chunks/use-calendar.js.map +1 -1
- package/dist/_chunks/use-controllable-open.js +15 -0
- package/dist/_chunks/use-controllable-open.js.map +1 -0
- package/dist/composed/command-palette.js +3 -3
- package/dist/composed/command-palette.js.map +1 -1
- package/dist/composed/confirm-dialog.js +3 -3
- package/dist/composed/confirm-dialog.js.map +1 -1
- package/dist/composed/date-picker/index.js +3 -3
- package/dist/composed/date-picker/index.js.map +1 -1
- package/dist/composed/emoji-picker.d.ts +19 -9
- package/dist/composed/emoji-picker.d.ts.map +1 -1
- package/dist/composed/emoji-picker.js +87 -68
- package/dist/composed/emoji-picker.js.map +1 -1
- package/dist/composed/error-boundary.js +1 -1
- package/dist/composed/error-boundary.js.map +1 -1
- package/dist/composed/extensions/emoji-data.d.ts +1 -14
- package/dist/composed/extensions/emoji-data.d.ts.map +1 -1
- package/dist/composed/extensions/emoji-node.d.ts +0 -3
- package/dist/composed/extensions/emoji-node.d.ts.map +1 -1
- package/dist/composed/extensions/emoji-node.js +9 -34
- package/dist/composed/extensions/emoji-node.js.map +1 -1
- package/dist/composed/extensions/emoji-suggestion.d.ts +2 -2
- package/dist/composed/extensions/emoji-suggestion.d.ts.map +1 -1
- package/dist/composed/extensions/emoji-suggestion.js +2 -116
- package/dist/composed/index.d.ts +3 -1
- package/dist/composed/index.d.ts.map +1 -1
- package/dist/composed/index.js +4 -3
- package/dist/composed/loading-skeleton.js +15 -15
- package/dist/composed/loading-skeleton.js.map +1 -1
- package/dist/composed/page-header.d.ts.map +1 -1
- package/dist/composed/page-header.js +32 -45
- package/dist/composed/page-header.js.map +1 -1
- package/dist/composed/page-skeletons.js +19 -19
- package/dist/composed/page-skeletons.js.map +1 -1
- package/dist/composed/responsive-modal.d.ts +39 -0
- package/dist/composed/responsive-modal.d.ts.map +1 -0
- package/dist/composed/responsive-modal.js +212 -0
- package/dist/composed/responsive-modal.js.map +1 -0
- package/dist/composed/rich-chat-input.d.ts.map +1 -1
- package/dist/composed/rich-chat-input.js +558 -579
- 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 +167 -190
- package/dist/composed/rich-text-editor.js.map +1 -1
- package/dist/composed/schedule-view.d.ts +1 -1
- package/dist/composed/schedule-view.d.ts.map +1 -1
- package/dist/composed/schedule-view.js +48 -54
- package/dist/composed/schedule-view.js.map +1 -1
- package/dist/composed/status-badge.d.ts +13 -11
- package/dist/composed/status-badge.d.ts.map +1 -1
- package/dist/composed/status-badge.js +54 -130
- package/dist/composed/status-badge.js.map +1 -1
- package/dist/shell/bottom-navbar.js +1 -1
- package/dist/shell/bottom-navbar.js.map +1 -1
- package/dist/shell/top-bar.js +1 -1
- package/dist/shell/top-bar.js.map +1 -1
- package/dist/tokens/semantic.css +8 -1
- package/dist/ui/accordion.js +9 -9
- package/dist/ui/alert-dialog.js +26 -26
- package/dist/ui/aspect-ratio.js +1 -1
- package/dist/ui/autocomplete.js +7 -7
- package/dist/ui/avatar.d.ts.map +1 -1
- package/dist/ui/avatar.js +87 -82
- package/dist/ui/avatar.js.map +1 -1
- package/dist/ui/badge.d.ts.map +1 -1
- package/dist/ui/breadcrumb.d.ts +0 -1
- package/dist/ui/breadcrumb.d.ts.map +1 -1
- package/dist/ui/breadcrumb.js +58 -35
- package/dist/ui/breadcrumb.js.map +1 -1
- package/dist/ui/button.js +3 -3
- package/dist/ui/checkbox.d.ts +4 -2
- package/dist/ui/checkbox.d.ts.map +1 -1
- package/dist/ui/checkbox.js +33 -28
- package/dist/ui/checkbox.js.map +1 -1
- package/dist/ui/collapsible.js +4 -4
- package/dist/ui/combobox.d.ts +3 -0
- package/dist/ui/combobox.d.ts.map +1 -1
- package/dist/ui/combobox.js +137 -132
- package/dist/ui/combobox.js.map +1 -1
- package/dist/ui/context-menu.js +46 -46
- package/dist/ui/dialog.d.ts.map +1 -1
- package/dist/ui/dialog.js +53 -50
- package/dist/ui/dialog.js.map +1 -1
- package/dist/ui/dot.d.ts +38 -0
- package/dist/ui/dot.d.ts.map +1 -0
- package/dist/ui/dot.js +92 -0
- package/dist/ui/dot.js.map +1 -0
- package/dist/ui/dropdown-menu.d.ts.map +1 -1
- package/dist/ui/dropdown-menu.js +70 -65
- package/dist/ui/dropdown-menu.js.map +1 -1
- package/dist/ui/hover-card.js +11 -11
- package/dist/ui/index.d.ts +3 -2
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +67 -67
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/input-otp.js +1 -1
- package/dist/ui/input-otp.js.map +1 -1
- package/dist/ui/input.d.ts +4 -2
- package/dist/ui/input.d.ts.map +1 -1
- package/dist/ui/input.js +38 -37
- package/dist/ui/input.js.map +1 -1
- package/dist/ui/label.js +1 -1
- package/dist/ui/lib/field-state.d.ts +21 -0
- package/dist/ui/lib/field-state.d.ts.map +1 -0
- package/dist/ui/lib/use-controllable-open.d.ts +32 -0
- package/dist/ui/lib/use-controllable-open.d.ts.map +1 -0
- package/dist/ui/link.js +1 -1
- package/dist/ui/number-input.d.ts +4 -2
- package/dist/ui/number-input.d.ts.map +1 -1
- package/dist/ui/number-input.js +51 -50
- package/dist/ui/number-input.js.map +1 -1
- package/dist/ui/pagination.js +1 -1
- package/dist/ui/popover.d.ts.map +1 -1
- package/dist/ui/progress.d.ts +66 -42
- package/dist/ui/progress.d.ts.map +1 -1
- package/dist/ui/progress.js +144 -40
- package/dist/ui/progress.js.map +1 -1
- package/dist/ui/radio.d.ts +6 -2
- package/dist/ui/radio.d.ts.map +1 -1
- package/dist/ui/radio.js +44 -33
- package/dist/ui/radio.js.map +1 -1
- package/dist/ui/select.d.ts +1 -1
- package/dist/ui/select.d.ts.map +1 -1
- package/dist/ui/select.js +58 -57
- package/dist/ui/select.js.map +1 -1
- package/dist/ui/separator.js +2 -2
- package/dist/ui/separator.js.map +1 -1
- package/dist/ui/sheet.d.ts.map +1 -1
- package/dist/ui/sheet.js +59 -56
- package/dist/ui/sheet.js.map +1 -1
- package/dist/ui/sidebar.js +5 -5
- package/dist/ui/sidebar.js.map +1 -1
- package/dist/ui/slider.js +6 -6
- package/dist/ui/slider.js.map +1 -1
- package/dist/ui/stat-card.d.ts.map +1 -1
- package/dist/ui/stat-card.js +122 -125
- package/dist/ui/stat-card.js.map +1 -1
- package/dist/ui/surface.js +1 -1
- package/dist/ui/switch.d.ts +3 -1
- package/dist/ui/switch.d.ts.map +1 -1
- package/dist/ui/switch.js +32 -27
- package/dist/ui/switch.js.map +1 -1
- package/dist/ui/textarea.d.ts +3 -3
- package/dist/ui/textarea.d.ts.map +1 -1
- package/dist/ui/textarea.js +18 -17
- package/dist/ui/textarea.js.map +1 -1
- package/dist/ui/toast.js +2 -2
- package/dist/ui/toast.js.map +1 -1
- package/dist/ui/toggle-group.js +1 -1
- package/dist/ui/toggle.js +1 -1
- package/dist/ui/tooltip.d.ts.map +1 -1
- package/dist/ui/tooltip.js +36 -33
- package/dist/ui/tooltip.js.map +1 -1
- package/docs/components/ai/ai-command-provider.md +46 -0
- package/docs/components/ai/block-renderer.md +59 -0
- package/docs/components/ai/command-bar.md +78 -0
- package/docs/components/ai/conversation.md +59 -0
- package/docs/components/ai/devadoot-icon.md +41 -0
- package/docs/components/composed/emoji-picker.md +19 -17
- package/docs/components/composed/page-header.md +1 -1
- package/docs/components/composed/responsive-modal.md +66 -0
- package/docs/components/composed/rich-text-editor.md +1 -1
- package/docs/components/composed/schedule-view.md +6 -2
- package/docs/components/ui/breadcrumb.md +1 -1
- package/docs/components/ui/checkbox.md +4 -1
- package/docs/components/ui/combobox.md +4 -0
- package/docs/components/ui/dot.md +61 -0
- package/docs/components/ui/progress.md +54 -16
- package/docs/components/ui/radio.md +6 -2
- package/docs/components/ui/select.md +9 -5
- package/docs/components/ui/switch.md +4 -1
- package/docs/components/ui/table-row-link.md +1 -1
- package/docs/components/ui/table.md +2 -1
- package/docs/recipes/index.md +1 -1
- package/docs/recipes/install-astro.md +15 -12
- package/docs/recipes/install-next-app-router.md +20 -12
- package/docs/recipes/install-next-pages.md +3 -1
- package/docs/recipes/install-remix.md +16 -13
- package/docs/recipes/install-tanstack-start.md +19 -12
- package/docs/recipes/install-vite.md +18 -15
- package/docs/recipes/troubleshoot.md +7 -8
- package/llms.txt +12 -4
- package/make-kit/components/form.md +2 -2
- package/make-kit/components/icon.md +2 -2
- package/make-kit/components/overview.md +2 -2
- package/make-kit/components/select.md +1 -1
- package/make-kit/components/table.md +1 -1
- package/mcp-manifest.json +2696 -1145
- package/mcp-manifest.schema.json +18 -0
- package/package.json +16 -14
- package/skill/SKILL.md +1 -1
- package/skill/references/components.md +12 -4
- package/skill/references/setup-astro.md +15 -12
- package/skill/references/setup-next-app-router.md +20 -12
- package/skill/references/setup-next-pages.md +3 -1
- package/skill/references/setup-remix.md +16 -13
- package/skill/references/setup-tanstack-start.md +19 -12
- package/skill/references/setup-vite.md +18 -15
- package/skill/references/troubleshoot.md +7 -8
- package/dist/_chunks/emoji-data.js +0 -45
- package/dist/_chunks/emoji-data.js.map +0 -1
- package/dist/composed/extensions/emoji-suggestion.js.map +0 -1
- package/dist/ui/status-dot.d.ts +0 -27
- package/dist/ui/status-dot.d.ts.map +0 -1
- package/dist/ui/status-dot.js +0 -68
- package/dist/ui/status-dot.js.map +0 -1
- package/docs/components/ui/status-dot.md +0 -35
|
@@ -1,139 +1,63 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import
|
|
9
|
-
import { jsx as s, jsxs as c } from "react/jsx-runtime";
|
|
10
|
-
import { IconChevronDown as l } from "@tabler/icons-react";
|
|
11
|
-
import { AnimatePresence as u, motion as d } from "framer-motion";
|
|
2
|
+
import { motionProps as e } from "../ui/lib/motion.js";
|
|
3
|
+
import { Dot as t } from "../ui/dot.js";
|
|
4
|
+
import { n } from "../_chunks/badge-group.js";
|
|
5
|
+
import * as r from "react";
|
|
6
|
+
import { jsx as i } from "react/jsx-runtime";
|
|
7
|
+
import { IconChevronDown as a } from "@tabler/icons-react";
|
|
8
|
+
import { AnimatePresence as o, motion as s } from "framer-motion";
|
|
12
9
|
//#region src/composed/status-badge.tsx
|
|
13
|
-
var
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
draft: "bg-surface-raised text-surface-fg-subtle"
|
|
26
|
-
},
|
|
27
|
-
color: {
|
|
28
|
-
success: "bg-success-3 text-success-11",
|
|
29
|
-
warning: "bg-warning-3 text-warning-11",
|
|
30
|
-
error: "bg-error-3 text-error-11",
|
|
31
|
-
info: "bg-info-3 text-info-11",
|
|
32
|
-
neutral: "bg-surface-raised text-surface-fg-subtle"
|
|
33
|
-
},
|
|
34
|
-
size: {
|
|
35
|
-
sm: "px-ds-03 py-ds-01 text-ds-xs font-semibold",
|
|
36
|
-
md: "px-ds-04 py-ds-02 text-ds-sm font-medium"
|
|
37
|
-
}
|
|
38
|
-
},
|
|
39
|
-
defaultVariants: { size: "md" }
|
|
40
|
-
}), p = {
|
|
41
|
-
active: "bg-success-9",
|
|
42
|
-
pending: "bg-warning-9",
|
|
43
|
-
approved: "bg-success-9",
|
|
44
|
-
rejected: "bg-error-9",
|
|
45
|
-
completed: "bg-success-9",
|
|
46
|
-
blocked: "bg-error-9",
|
|
47
|
-
"in-progress": "bg-accent-9",
|
|
48
|
-
review: "bg-info-9",
|
|
49
|
-
cancelled: "bg-disabled",
|
|
50
|
-
draft: "bg-surface-fg-subtle"
|
|
51
|
-
}, m = {
|
|
52
|
-
success: "bg-success-9",
|
|
53
|
-
warning: "bg-warning-9",
|
|
54
|
-
error: "bg-error-9",
|
|
55
|
-
info: "bg-info-9",
|
|
56
|
-
neutral: "bg-surface-fg-subtle"
|
|
57
|
-
}, h = {
|
|
10
|
+
var c = {
|
|
11
|
+
active: "success",
|
|
12
|
+
approved: "success",
|
|
13
|
+
completed: "success",
|
|
14
|
+
pending: "warning",
|
|
15
|
+
rejected: "error",
|
|
16
|
+
blocked: "error",
|
|
17
|
+
"in-progress": "accent",
|
|
18
|
+
review: "info",
|
|
19
|
+
cancelled: "neutral",
|
|
20
|
+
draft: "neutral"
|
|
21
|
+
}, l = {
|
|
58
22
|
duration: .3,
|
|
59
23
|
ease: "easeOut"
|
|
60
|
-
},
|
|
61
|
-
let
|
|
62
|
-
|
|
63
|
-
size: "xs",
|
|
64
|
-
className: "text-current/50 -mr-0.5 shrink-0"
|
|
65
|
-
}) : null : /* @__PURE__ */ s(e, {
|
|
66
|
-
size: "xs",
|
|
67
|
-
children: a(b)
|
|
68
|
-
});
|
|
69
|
-
if (o != null) {
|
|
70
|
-
let e = _ ?? o.charAt(0).toUpperCase() + o.slice(1), n = m[o];
|
|
71
|
-
return /* @__PURE__ */ s(u, {
|
|
72
|
-
mode: "wait",
|
|
73
|
-
children: /* @__PURE__ */ c(T, {
|
|
74
|
-
ref: C,
|
|
75
|
-
...w ? {
|
|
76
|
-
type: "button",
|
|
77
|
-
onClick: y
|
|
78
|
-
} : {},
|
|
79
|
-
initial: {
|
|
80
|
-
opacity: .6,
|
|
81
|
-
scale: .95
|
|
82
|
-
},
|
|
83
|
-
animate: {
|
|
84
|
-
opacity: 1,
|
|
85
|
-
scale: 1
|
|
86
|
-
},
|
|
87
|
-
exit: {
|
|
88
|
-
opacity: .6,
|
|
89
|
-
scale: .95
|
|
90
|
-
},
|
|
91
|
-
transition: h,
|
|
92
|
-
className: r(f({
|
|
93
|
-
color: o,
|
|
94
|
-
size: g
|
|
95
|
-
}), E, x),
|
|
96
|
-
...t(S),
|
|
97
|
-
children: [
|
|
98
|
-
!v && /* @__PURE__ */ s("span", {
|
|
99
|
-
className: r("shrink-0 rounded-pill", g === "sm" ? "h-ds-02b w-ds-02b" : "h-[8px] w-[8px]", n),
|
|
100
|
-
"aria-hidden": "true"
|
|
101
|
-
}),
|
|
102
|
-
e,
|
|
103
|
-
D
|
|
104
|
-
]
|
|
105
|
-
}, o)
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
let O = n ?? "pending", k = _ ?? O.charAt(0).toUpperCase() + O.slice(1), A = p[O];
|
|
109
|
-
return /* @__PURE__ */ s(u, {
|
|
24
|
+
}, u = (e) => e.charAt(0).toUpperCase() + e.slice(1), d = r.forwardRef(({ status: r, color: d, size: f = "md", label: p, hideDot: m = !1, onClick: h, icon: g, className: _, ...v }, y) => {
|
|
25
|
+
let b = d ?? r ?? "pending", x = d ?? c[r ?? "pending"], S = p ?? u(d ?? r ?? "pending").replace("-", " "), C = g ?? (h == null ? void 0 : a);
|
|
26
|
+
return /* @__PURE__ */ i(o, {
|
|
110
27
|
mode: "wait",
|
|
111
|
-
children: /* @__PURE__ */
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
28
|
+
children: /* @__PURE__ */ i(s.span, {
|
|
29
|
+
initial: {
|
|
30
|
+
opacity: .6,
|
|
31
|
+
scale: .95
|
|
32
|
+
},
|
|
33
|
+
animate: {
|
|
34
|
+
opacity: 1,
|
|
35
|
+
scale: 1
|
|
36
|
+
},
|
|
37
|
+
exit: {
|
|
38
|
+
opacity: .6,
|
|
39
|
+
scale: .95
|
|
40
|
+
},
|
|
41
|
+
transition: l,
|
|
42
|
+
className: "inline-flex",
|
|
43
|
+
...e(v),
|
|
44
|
+
children: /* @__PURE__ */ i(n, {
|
|
45
|
+
ref: y,
|
|
46
|
+
variant: "soft",
|
|
47
|
+
color: x,
|
|
48
|
+
size: f,
|
|
49
|
+
onClick: h,
|
|
50
|
+
startIcon: m ? void 0 : /* @__PURE__ */ i(t, {
|
|
51
|
+
color: x,
|
|
52
|
+
size: "sm"
|
|
130
53
|
}),
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
54
|
+
endIcon: C,
|
|
55
|
+
className: _,
|
|
56
|
+
children: S
|
|
57
|
+
})
|
|
58
|
+
}, b)
|
|
135
59
|
});
|
|
136
60
|
});
|
|
137
|
-
|
|
61
|
+
d.displayName = "StatusBadge";
|
|
138
62
|
//#endregion
|
|
139
|
-
export {
|
|
63
|
+
export { d as StatusBadge };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status-badge.js","names":[],"sources":["../../src/composed/status-badge.tsx"],"sourcesContent":["'use client'\n\nimport { IconChevronDown } from '@tabler/icons-react'\nimport {
|
|
1
|
+
{"version":3,"file":"status-badge.js","names":[],"sources":["../../src/composed/status-badge.tsx"],"sourcesContent":["'use client'\n\nimport { IconChevronDown } from '@tabler/icons-react'\nimport { AnimatePresence, motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { Badge } from '../ui/badge'\nimport { Dot, type DotColor } from '../ui/dot'\nimport type { IconInput } from '../ui/lib/icon-input'\nimport { motionProps } from '../ui/lib/motion'\n\n/**\n * Domain work-statuses → the shared intent colour used by both the Badge pill\n * and the leading Dot. StatusBadge is a thin semantic wrapper: it owns the\n * status vocabulary and composes `<Badge>` + `<Dot>` rather than re-styling a pill.\n */\ntype StatusKey =\n | 'active' | 'pending' | 'approved' | 'rejected' | 'completed'\n | 'blocked' | 'in-progress' | 'review' | 'cancelled' | 'draft'\n\n// Intent colours shared by Badge + Dot (never 'current' — that's a Badge-internal mode).\ntype IntentColor = Exclude<DotColor, 'current'>\n\nconst STATUS_TO_COLOR: Record<StatusKey, IntentColor> = {\n active: 'success',\n approved: 'success',\n completed: 'success',\n pending: 'warning',\n rejected: 'error',\n blocked: 'error',\n 'in-progress': 'accent',\n review: 'info',\n cancelled: 'neutral',\n draft: 'neutral',\n}\n\ntype StatusColor = 'success' | 'warning' | 'error' | 'info' | 'neutral'\n\ninterface StatusBadgeBaseProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, 'children' | 'color'> {\n label?: string\n hideDot?: boolean\n size?: 'sm' | 'md'\n onClick?: () => void\n /** Trailing icon. When omitted on a clickable badge, a chevron is shown. */\n icon?: IconInput\n}\n\ninterface StatusBadgeWithStatus extends StatusBadgeBaseProps {\n status?: StatusKey\n color?: never\n}\n\ninterface StatusBadgeWithColor extends StatusBadgeBaseProps {\n status?: never\n color: StatusColor\n}\n\nexport type StatusBadgeProps = StatusBadgeWithStatus | StatusBadgeWithColor\n\n/* Between durations.moderate02 (0.24) and slow01 (0.4) — smooth status morph. */\nconst statusMorphTransition = { duration: 0.3, ease: 'easeOut' as const }\n\nconst titleCase = (s: string) => s.charAt(0).toUpperCase() + s.slice(1)\n\nconst StatusBadge = React.forwardRef<HTMLElement, StatusBadgeProps>(\n ({ status, color, size = 'md', label, hideDot = false, onClick, icon, className, ...props }, ref) => {\n // A `color` wins if given; otherwise derive from `status` (default 'pending').\n const key = color ?? status ?? 'pending'\n const dotColor: IntentColor = color ?? STATUS_TO_COLOR[(status ?? 'pending') as StatusKey]\n const displayLabel = label ?? titleCase(color ?? status ?? 'pending').replace('-', ' ')\n const isClickable = onClick != null\n\n // Trailing: an explicit icon, else a chevron for clickable badges.\n const endIcon: IconInput | undefined = icon ?? (isClickable ? IconChevronDown : undefined)\n\n return (\n <AnimatePresence mode=\"wait\">\n <motion.span\n key={key}\n initial={{ opacity: 0.6, scale: 0.95 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0.6, scale: 0.95 }}\n transition={statusMorphTransition}\n className=\"inline-flex\"\n {...motionProps(props)}\n >\n <Badge\n ref={ref}\n variant=\"soft\"\n color={dotColor}\n size={size}\n onClick={onClick}\n startIcon={!hideDot ? <Dot color={dotColor} size=\"sm\" /> : undefined}\n endIcon={endIcon}\n className={className}\n >\n {displayLabel}\n </Badge>\n </motion.span>\n </AnimatePresence>\n )\n },\n)\nStatusBadge.displayName = 'StatusBadge'\n\nexport { StatusBadge }\n"],"mappings":";;;;;;;;;AAuBA,IAAM,IAAkD;CACtD,QAAQ;CACR,UAAU;CACV,WAAW;CACX,SAAS;CACT,UAAU;CACV,SAAS;CACT,eAAe;CACf,QAAQ;CACR,WAAW;CACX,OAAO;CACR,EA0BK,IAAwB;CAAE,UAAU;CAAK,MAAM;CAAoB,EAEnE,KAAa,MAAc,EAAE,OAAO,EAAE,CAAC,aAAa,GAAG,EAAE,MAAM,EAAE,EAEjE,IAAc,EAAM,YACvB,EAAE,WAAQ,UAAO,UAAO,MAAM,UAAO,aAAU,IAAO,YAAS,SAAM,cAAW,GAAG,KAAS,MAAQ;CAEnG,IAAM,IAAM,KAAS,KAAU,WACzB,IAAwB,KAAS,EAAiB,KAAU,YAC5D,IAAe,KAAS,EAAU,KAAS,KAAU,UAAU,CAAC,QAAQ,KAAK,IAAI,EAIjF,IAAiC,MAHnB,KAAW,OAGiD,KAAA,IAAlB;AAE9D,QACE,kBAAC,GAAD;EAAiB,MAAK;YACpB,kBAAC,EAAO,MAAR;GAEE,SAAS;IAAE,SAAS;IAAK,OAAO;IAAM;GACtC,SAAS;IAAE,SAAS;IAAG,OAAO;IAAG;GACjC,MAAM;IAAE,SAAS;IAAK,OAAO;IAAM;GACnC,YAAY;GACZ,WAAU;GACV,GAAI,EAAY,EAAM;aAEtB,kBAAC,GAAD;IACO;IACL,SAAQ;IACR,OAAO;IACD;IACG;IACT,WAAY,IAA+C,KAAA,IAArC,kBAAC,GAAD;KAAK,OAAO;KAAU,MAAK;KAAO,CAAA;IAC/C;IACE;cAEV;IACK,CAAA;GACI,EApBP,EAoBO;EACE,CAAA;EAGvB;AACD,EAAY,cAAc"}
|
|
@@ -122,7 +122,7 @@ var x = o.forwardRef(({ currentPath: o = "/", user: y, primaryItems: x = [], mor
|
|
|
122
122
|
...w,
|
|
123
123
|
ref: T,
|
|
124
124
|
"aria-label": "Mobile navigation",
|
|
125
|
-
className: n("fixed bottom-0 left-0 right-0 z-sticky flex w-full flex-row items-start justify-between border-t border-surface-border-strong bg-surface-
|
|
125
|
+
className: n("fixed bottom-0 left-0 right-0 z-sticky flex w-full flex-row items-start justify-between border-t border-surface-border-strong bg-surface-chrome px-ds-05 pb-safe pt-0 md:hidden", C),
|
|
126
126
|
children: [x.map((e) => /* @__PURE__ */ f(b, {
|
|
127
127
|
item: e,
|
|
128
128
|
isActive: M(e.href, e.exact)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bottom-navbar.js","names":[],"sources":["../../src/shell/bottom-navbar.tsx"],"sourcesContent":["'use client'\n\n/**\n * BottomNavbar -- Mobile bottom navigation bar.\n *\n * Props-driven: accepts currentPath, user, navItems instead of\n * reading from Remix hooks or Zustand stores.\n */\nimport { IconDots, IconX } from '@tabler/icons-react'\nimport { AnimatePresence, motion, useReducedMotion } from 'framer-motion'\nimport * as React from 'react'\nimport { useCallback,useEffect, useRef, useState } from 'react'\n\nimport { Icon } from '../ui/icon'\nimport { IconProvider } from '../ui/icon-context'\nimport type { IconInput } from '../ui/lib/icon-input'\nimport { springs } from '../ui/lib/motion'\nimport { normalizeIcon } from '../ui/lib/normalize-icon'\nimport { cn } from '../ui/lib/utils'\nimport { useLink } from './link-context'\n\n// -----------------------------------------------------------------------\n// Types\n// -----------------------------------------------------------------------\n\nexport interface BottomNavItem {\n title: string\n href: string\n /** Icon for this nav item. Accepts any `IconInput`. */\n icon: IconInput\n /** When true, the route matches only when the path is exactly equal */\n exact?: boolean\n /** Notification badge count. 0 or undefined = hidden, 1–99 = shown, >99 = \"99+\" */\n badge?: number\n}\n\nexport interface BottomNavbarUser {\n name: string\n role?: string\n}\n\nexport interface BottomNavbarProps\n extends React.HTMLAttributes<HTMLElement> {\n /** Currently active pathname */\n currentPath?: string\n /** User information (used to determine admin status, presence) */\n user?: BottomNavbarUser | null\n /** Primary nav items shown directly in the bottom bar (max 4 recommended) */\n primaryItems?: BottomNavItem[]\n /** Additional items shown in the \"More\" overflow menu */\n moreItems?: BottomNavItem[]\n /** Additional className for the nav element */\n className?: string\n}\n\n// -----------------------------------------------------------------------\n// NavBadge (internal)\n// -----------------------------------------------------------------------\n\nfunction NavBadge({ count }: { count: number }) {\n if (!count || count <= 0) return null\n const display = count > 99 ? '99+' : String(count)\n const isMultiDigit = count >= 10\n return (\n <span\n aria-label={`${count} notifications`}\n className={cn(\n 'absolute -right-1 -top-0.5 flex h-4 min-w-4 items-center justify-center rounded-pill bg-error-9 text-[10px] font-semibold leading-none text-error-fg animate-in zoom-in-75',\n isMultiDigit ? 'px-0.5' : '',\n )}\n >\n {display}\n </span>\n )\n}\n\n// -----------------------------------------------------------------------\n// BottomNavLink (internal)\n// -----------------------------------------------------------------------\n\nfunction BottomNavLink({\n item,\n isActive,\n onClick,\n}: {\n item: BottomNavItem\n isActive: boolean\n onClick?: () => void\n}) {\n const Link = useLink()\n const prefersReducedMotion = useReducedMotion()\n return (\n <motion.div whileTap={prefersReducedMotion ? undefined : { y: -2 }} transition={prefersReducedMotion ? { duration: 0 } : springs.snappy} className=\"flex max-w-[70px] flex-1\">\n <Link\n href={item.href}\n onClick={onClick}\n aria-label={item.title}\n aria-current={isActive ? 'page' : undefined}\n className={cn(\n 'flex h-16 w-full cursor-pointer flex-col items-center gap-ds-02 p-ds-02 pt-0 text-ds-sm transition-colors duration-fast-02 ease-productive-standard',\n isActive\n ? 'font-semibold text-accent-11'\n : 'text-surface-fg-subtle',\n )}\n >\n <div className=\"relative flex w-full flex-col items-center gap-ds-02\">\n {isActive && (\n <motion.div\n layoutId=\"bottom-nav-indicator\"\n className=\"absolute top-0 h-[3px] w-full rounded-b-control-inner bg-accent-9 p-0\"\n aria-hidden=\"true\"\n transition={prefersReducedMotion ? { duration: 0 } : springs.snappy}\n />\n )}\n <div className=\"relative p-ds-03\">\n <span className=\"[&>svg]:h-ico-md [&>svg]:w-ico-md\" aria-hidden=\"true\"><IconProvider size=\"md\">{normalizeIcon(item.icon)}</IconProvider></span>\n {item.badge != null && <NavBadge count={item.badge} />}\n </div>\n <span className=\"text-center\">{item.title}</span>\n </div>\n </Link>\n </motion.div>\n )\n}\n\n// -----------------------------------------------------------------------\n// BottomNavbar\n// -----------------------------------------------------------------------\n\nconst BottomNavbar = React.forwardRef<HTMLElement, BottomNavbarProps>(\n (\n {\n currentPath = '/',\n user: _user,\n primaryItems = [],\n moreItems = [],\n className,\n ...props\n },\n ref,\n ) => {\n const Link = useLink()\n const prefersReducedMotion = useReducedMotion()\n const [showMore, setShowMore] = useState(false)\n const overlayRef = useRef<HTMLDivElement>(null)\n\n const closeMore = useCallback(() => setShowMore(false), [])\n\n // Focus first focusable item when overlay opens\n useEffect(() => {\n if (showMore && overlayRef.current) {\n const firstFocusable = overlayRef.current.querySelector<HTMLElement>('a, button')\n firstFocusable?.focus()\n }\n }, [showMore])\n\n const isActive = (path: string, exact = false) => {\n if (exact || path === '/') {\n return currentPath === path\n }\n return currentPath.startsWith(path)\n }\n\n // Check if any \"more\" item is active\n const isMoreActive = moreItems.some((item) =>\n isActive(item.href, item.exact),\n )\n\n return (\n <>\n {/* More Menu Overlay */}\n <AnimatePresence>\n {showMore && (\n // eslint-disable-next-line jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events -- backdrop overlay, dismiss via mouse only; keyboard users close via Escape\n <div\n className=\"fixed inset-0 z-overlay md:hidden\"\n onClick={() => setShowMore(false)}\n >\n <div className=\"absolute inset-0 bg-overlay\" />\n { }\n <motion.div\n ref={overlayRef}\n role=\"dialog\"\n aria-label=\"More navigation\"\n initial={{ y: '100%' }}\n animate={{ y: 0 }}\n exit={{ y: '100%' }}\n transition={prefersReducedMotion ? { duration: 0 } : springs.smooth}\n className=\"absolute bottom-[72px] left-0 right-0 rounded-t-bubble border-t border-surface-border-strong bg-surface-overlay p-ds-05 pb-ds-03\"\n onClick={(e) => e.stopPropagation()}\n onKeyDown={(e) => {\n e.stopPropagation()\n if (e.key === 'Escape') closeMore()\n }}\n >\n <div className=\"mb-ds-04 flex items-center justify-between\">\n <span className=\"text-ds-md font-semibold text-surface-fg\">\n More\n </span>\n <button\n onClick={() => setShowMore(false)}\n aria-label=\"Close more menu\"\n className=\"flex h-ds-sm w-ds-sm items-center justify-center rounded-pill hover:bg-surface-raised-hover\"\n >\n <Icon icon={IconX} size=\"sm\" className=\"text-surface-fg-muted\" />\n </button>\n </div>\n <div className=\"grid grid-cols-4 gap-ds-03\">\n {moreItems.map((item) => (\n <Link\n key={item.href}\n href={item.href}\n onClick={() => setShowMore(false)}\n className={cn(\n 'flex flex-col items-center gap-ds-02b rounded-overlay-lg p-ds-04 text-ds-sm transition-colors ease-productive-standard',\n isActive(item.href, item.exact)\n ? 'bg-surface-raised-hover text-accent-11'\n : 'text-surface-fg-subtle hover:bg-surface-raised-hover',\n )}\n >\n <span className=\"[&>svg]:h-ico-md [&>svg]:w-ico-md\"><IconProvider size=\"md\">{normalizeIcon(item.icon)}</IconProvider></span>\n <span className=\"text-center\">\n {item.title}\n </span>\n </Link>\n ))}\n </div>\n </motion.div>\n </div>\n )}\n </AnimatePresence>\n\n {/* Bottom Navigation Bar */}\n <nav\n {...props}\n ref={ref}\n aria-label=\"Mobile navigation\"\n className={cn(\n 'fixed bottom-0 left-0 right-0 z-sticky flex w-full flex-row items-start justify-between border-t border-surface-border-strong bg-surface-raised px-ds-05 pb-safe pt-0 md:hidden',\n className,\n )}\n >\n {primaryItems.map((item) => (\n <BottomNavLink\n key={item.href}\n item={item}\n isActive={isActive(item.href, item.exact)}\n />\n ))}\n\n {/* More Button */}\n {moreItems.length > 0 && (\n <motion.button\n type=\"button\"\n onClick={() => setShowMore(!showMore)}\n aria-label=\"More navigation options\"\n aria-expanded={showMore}\n whileTap={prefersReducedMotion ? undefined : { y: -2 }}\n transition={prefersReducedMotion ? { duration: 0 } : springs.snappy}\n className={cn(\n 'flex h-16 max-w-[70px] flex-1 cursor-pointer flex-col items-center gap-ds-02 p-ds-02 pt-0 text-ds-sm',\n showMore || isMoreActive\n ? 'font-semibold text-accent-11'\n : 'text-surface-fg-subtle',\n )}\n >\n <div className=\"relative flex w-full flex-col items-center gap-ds-02\">\n {(showMore || isMoreActive) && (\n <motion.div\n layoutId=\"bottom-nav-indicator\"\n className=\"absolute top-0 h-[3px] w-full rounded-b-control-inner bg-accent-9 p-0\"\n aria-hidden=\"true\"\n transition={prefersReducedMotion ? { duration: 0 } : springs.snappy}\n />\n )}\n <div className=\"p-ds-03\">\n <Icon icon={IconDots} />\n </div>\n <span className=\"text-center\">More</span>\n </div>\n </motion.button>\n )}\n </nav>\n </>\n )\n },\n)\nBottomNavbar.displayName = 'BottomNavbar'\n\nexport { BottomNavbar }\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"bottom-navbar.js","names":[],"sources":["../../src/shell/bottom-navbar.tsx"],"sourcesContent":["'use client'\n\n/**\n * BottomNavbar -- Mobile bottom navigation bar.\n *\n * Props-driven: accepts currentPath, user, navItems instead of\n * reading from Remix hooks or Zustand stores.\n */\nimport { IconDots, IconX } from '@tabler/icons-react'\nimport { AnimatePresence, motion, useReducedMotion } from 'framer-motion'\nimport * as React from 'react'\nimport { useCallback,useEffect, useRef, useState } from 'react'\n\nimport { Icon } from '../ui/icon'\nimport { IconProvider } from '../ui/icon-context'\nimport type { IconInput } from '../ui/lib/icon-input'\nimport { springs } from '../ui/lib/motion'\nimport { normalizeIcon } from '../ui/lib/normalize-icon'\nimport { cn } from '../ui/lib/utils'\nimport { useLink } from './link-context'\n\n// -----------------------------------------------------------------------\n// Types\n// -----------------------------------------------------------------------\n\nexport interface BottomNavItem {\n title: string\n href: string\n /** Icon for this nav item. Accepts any `IconInput`. */\n icon: IconInput\n /** When true, the route matches only when the path is exactly equal */\n exact?: boolean\n /** Notification badge count. 0 or undefined = hidden, 1–99 = shown, >99 = \"99+\" */\n badge?: number\n}\n\nexport interface BottomNavbarUser {\n name: string\n role?: string\n}\n\nexport interface BottomNavbarProps\n extends React.HTMLAttributes<HTMLElement> {\n /** Currently active pathname */\n currentPath?: string\n /** User information (used to determine admin status, presence) */\n user?: BottomNavbarUser | null\n /** Primary nav items shown directly in the bottom bar (max 4 recommended) */\n primaryItems?: BottomNavItem[]\n /** Additional items shown in the \"More\" overflow menu */\n moreItems?: BottomNavItem[]\n /** Additional className for the nav element */\n className?: string\n}\n\n// -----------------------------------------------------------------------\n// NavBadge (internal)\n// -----------------------------------------------------------------------\n\nfunction NavBadge({ count }: { count: number }) {\n if (!count || count <= 0) return null\n const display = count > 99 ? '99+' : String(count)\n const isMultiDigit = count >= 10\n return (\n <span\n aria-label={`${count} notifications`}\n className={cn(\n 'absolute -right-1 -top-0.5 flex h-4 min-w-4 items-center justify-center rounded-pill bg-error-9 text-[10px] font-semibold leading-none text-error-fg animate-in zoom-in-75',\n isMultiDigit ? 'px-0.5' : '',\n )}\n >\n {display}\n </span>\n )\n}\n\n// -----------------------------------------------------------------------\n// BottomNavLink (internal)\n// -----------------------------------------------------------------------\n\nfunction BottomNavLink({\n item,\n isActive,\n onClick,\n}: {\n item: BottomNavItem\n isActive: boolean\n onClick?: () => void\n}) {\n const Link = useLink()\n const prefersReducedMotion = useReducedMotion()\n return (\n <motion.div whileTap={prefersReducedMotion ? undefined : { y: -2 }} transition={prefersReducedMotion ? { duration: 0 } : springs.snappy} className=\"flex max-w-[70px] flex-1\">\n <Link\n href={item.href}\n onClick={onClick}\n aria-label={item.title}\n aria-current={isActive ? 'page' : undefined}\n className={cn(\n 'flex h-16 w-full cursor-pointer flex-col items-center gap-ds-02 p-ds-02 pt-0 text-ds-sm transition-colors duration-fast-02 ease-productive-standard',\n isActive\n ? 'font-semibold text-accent-11'\n : 'text-surface-fg-subtle',\n )}\n >\n <div className=\"relative flex w-full flex-col items-center gap-ds-02\">\n {isActive && (\n <motion.div\n layoutId=\"bottom-nav-indicator\"\n className=\"absolute top-0 h-[3px] w-full rounded-b-control-inner bg-accent-9 p-0\"\n aria-hidden=\"true\"\n transition={prefersReducedMotion ? { duration: 0 } : springs.snappy}\n />\n )}\n <div className=\"relative p-ds-03\">\n <span className=\"[&>svg]:h-ico-md [&>svg]:w-ico-md\" aria-hidden=\"true\"><IconProvider size=\"md\">{normalizeIcon(item.icon)}</IconProvider></span>\n {item.badge != null && <NavBadge count={item.badge} />}\n </div>\n <span className=\"text-center\">{item.title}</span>\n </div>\n </Link>\n </motion.div>\n )\n}\n\n// -----------------------------------------------------------------------\n// BottomNavbar\n// -----------------------------------------------------------------------\n\nconst BottomNavbar = React.forwardRef<HTMLElement, BottomNavbarProps>(\n (\n {\n currentPath = '/',\n user: _user,\n primaryItems = [],\n moreItems = [],\n className,\n ...props\n },\n ref,\n ) => {\n const Link = useLink()\n const prefersReducedMotion = useReducedMotion()\n const [showMore, setShowMore] = useState(false)\n const overlayRef = useRef<HTMLDivElement>(null)\n\n const closeMore = useCallback(() => setShowMore(false), [])\n\n // Focus first focusable item when overlay opens\n useEffect(() => {\n if (showMore && overlayRef.current) {\n const firstFocusable = overlayRef.current.querySelector<HTMLElement>('a, button')\n firstFocusable?.focus()\n }\n }, [showMore])\n\n const isActive = (path: string, exact = false) => {\n if (exact || path === '/') {\n return currentPath === path\n }\n return currentPath.startsWith(path)\n }\n\n // Check if any \"more\" item is active\n const isMoreActive = moreItems.some((item) =>\n isActive(item.href, item.exact),\n )\n\n return (\n <>\n {/* More Menu Overlay */}\n <AnimatePresence>\n {showMore && (\n // eslint-disable-next-line jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events -- backdrop overlay, dismiss via mouse only; keyboard users close via Escape\n <div\n className=\"fixed inset-0 z-overlay md:hidden\"\n onClick={() => setShowMore(false)}\n >\n <div className=\"absolute inset-0 bg-overlay\" />\n { }\n <motion.div\n ref={overlayRef}\n role=\"dialog\"\n aria-label=\"More navigation\"\n initial={{ y: '100%' }}\n animate={{ y: 0 }}\n exit={{ y: '100%' }}\n transition={prefersReducedMotion ? { duration: 0 } : springs.smooth}\n className=\"absolute bottom-[72px] left-0 right-0 rounded-t-bubble border-t border-surface-border-strong bg-surface-overlay p-ds-05 pb-ds-03\"\n onClick={(e) => e.stopPropagation()}\n onKeyDown={(e) => {\n e.stopPropagation()\n if (e.key === 'Escape') closeMore()\n }}\n >\n <div className=\"mb-ds-04 flex items-center justify-between\">\n <span className=\"text-ds-md font-semibold text-surface-fg\">\n More\n </span>\n <button\n onClick={() => setShowMore(false)}\n aria-label=\"Close more menu\"\n className=\"flex h-ds-sm w-ds-sm items-center justify-center rounded-pill hover:bg-surface-raised-hover\"\n >\n <Icon icon={IconX} size=\"sm\" className=\"text-surface-fg-muted\" />\n </button>\n </div>\n <div className=\"grid grid-cols-4 gap-ds-03\">\n {moreItems.map((item) => (\n <Link\n key={item.href}\n href={item.href}\n onClick={() => setShowMore(false)}\n className={cn(\n 'flex flex-col items-center gap-ds-02b rounded-overlay-lg p-ds-04 text-ds-sm transition-colors ease-productive-standard',\n isActive(item.href, item.exact)\n ? 'bg-surface-raised-hover text-accent-11'\n : 'text-surface-fg-subtle hover:bg-surface-raised-hover',\n )}\n >\n <span className=\"[&>svg]:h-ico-md [&>svg]:w-ico-md\"><IconProvider size=\"md\">{normalizeIcon(item.icon)}</IconProvider></span>\n <span className=\"text-center\">\n {item.title}\n </span>\n </Link>\n ))}\n </div>\n </motion.div>\n </div>\n )}\n </AnimatePresence>\n\n {/* Bottom Navigation Bar */}\n <nav\n {...props}\n ref={ref}\n aria-label=\"Mobile navigation\"\n className={cn(\n 'fixed bottom-0 left-0 right-0 z-sticky flex w-full flex-row items-start justify-between border-t border-surface-border-strong bg-surface-chrome px-ds-05 pb-safe pt-0 md:hidden',\n className,\n )}\n >\n {primaryItems.map((item) => (\n <BottomNavLink\n key={item.href}\n item={item}\n isActive={isActive(item.href, item.exact)}\n />\n ))}\n\n {/* More Button */}\n {moreItems.length > 0 && (\n <motion.button\n type=\"button\"\n onClick={() => setShowMore(!showMore)}\n aria-label=\"More navigation options\"\n aria-expanded={showMore}\n whileTap={prefersReducedMotion ? undefined : { y: -2 }}\n transition={prefersReducedMotion ? { duration: 0 } : springs.snappy}\n className={cn(\n 'flex h-16 max-w-[70px] flex-1 cursor-pointer flex-col items-center gap-ds-02 p-ds-02 pt-0 text-ds-sm',\n showMore || isMoreActive\n ? 'font-semibold text-accent-11'\n : 'text-surface-fg-subtle',\n )}\n >\n <div className=\"relative flex w-full flex-col items-center gap-ds-02\">\n {(showMore || isMoreActive) && (\n <motion.div\n layoutId=\"bottom-nav-indicator\"\n className=\"absolute top-0 h-[3px] w-full rounded-b-control-inner bg-accent-9 p-0\"\n aria-hidden=\"true\"\n transition={prefersReducedMotion ? { duration: 0 } : springs.snappy}\n />\n )}\n <div className=\"p-ds-03\">\n <Icon icon={IconDots} />\n </div>\n <span className=\"text-center\">More</span>\n </div>\n </motion.button>\n )}\n </nav>\n </>\n )\n },\n)\nBottomNavbar.displayName = 'BottomNavbar'\n\nexport { BottomNavbar }\n"],"mappings":"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"}
|
package/dist/shell/top-bar.js
CHANGED
|
@@ -17,7 +17,7 @@ var T = _.forwardRef(({ className: e, children: n, ...r }, i) => {
|
|
|
17
17
|
return /* @__PURE__ */ y("header", {
|
|
18
18
|
...r,
|
|
19
19
|
ref: i,
|
|
20
|
-
className: t("z-sticky w-full border-b border-surface-border-strong bg-surface-
|
|
20
|
+
className: t("z-sticky w-full border-b border-surface-border-strong bg-surface-chrome px-ds-05 py-ds-04 md:px-ds-06", a ? "grid grid-cols-[1fr_auto_1fr] items-center" : "flex items-center", e),
|
|
21
21
|
children: n
|
|
22
22
|
});
|
|
23
23
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"top-bar.js","names":[],"sources":["../../src/shell/top-bar.tsx"],"sourcesContent":["'use client'\n\n/**\n * TopBar v2 — Composition-based application top bar.\n *\n * Subcomponents: TopBar.Left, TopBar.Center, TopBar.Right,\n * TopBar.Section, TopBar.IconButton, TopBar.Title, TopBar.UserMenu.\n */\nimport { IconLogout, IconMoon, IconSun,IconUser } from '@tabler/icons-react'\nimport * as React from 'react'\n\nimport { useColorMode } from '../hooks/use-color-mode'\nimport { Avatar, AvatarFallback, AvatarImage } from '../ui/avatar'\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from '../ui/dropdown-menu'\nimport { Icon } from '../ui/icon'\nimport { IconProvider } from '../ui/icon-context'\nimport type { IconInput } from '../ui/lib/icon-input'\nimport { normalizeIcon } from '../ui/lib/normalize-icon'\nimport { cn } from '../ui/lib/utils'\nimport {\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from '../ui/tooltip'\nimport { TruncatedText } from '../ui/truncated-text'\n\n// -----------------------------------------------------------------------\n// Types\n// -----------------------------------------------------------------------\n\nexport interface TopBarUser {\n name: string\n email?: string\n image?: string | null\n}\n\nexport interface UserMenuItem {\n /** Display label */\n label: string\n /** Optional icon. Accepts any `IconInput`. */\n icon?: IconInput\n /** Navigate via onNavigate when clicked */\n href?: string\n /** Custom click handler */\n onClick?: () => void\n /** Render a separator before this item */\n separator?: boolean\n /** Text color semantic token (e.g. \"error\") — maps to text-{color} */\n color?: string\n /** Badge content — string for count, true for dot indicator */\n badge?: string | boolean\n /** Whether the item is disabled */\n disabled?: boolean\n}\n\n// -----------------------------------------------------------------------\n// TopBar (root)\n// -----------------------------------------------------------------------\n\ninterface TopBarRootProps extends React.HTMLAttributes<HTMLElement> {\n children: React.ReactNode\n className?: string\n}\n\nconst TopBarRoot = React.forwardRef<HTMLElement, TopBarRootProps>(\n ({ className, children, ...props }, ref) => {\n // Detect if a Center zone is present to switch to grid layout\n const hasCenter = React.Children.toArray(children).some(\n (child) => React.isValidElement(child) && child.type === TopBarCenter,\n )\n\n return (\n <header\n {...props}\n ref={ref}\n className={cn(\n 'z-sticky w-full border-b border-surface-border-strong bg-surface-raised px-ds-05 py-ds-04 md:px-ds-06',\n hasCenter\n ? 'grid grid-cols-[1fr_auto_1fr] items-center'\n : 'flex items-center',\n className,\n )}\n >\n {children}\n </header>\n )\n },\n)\nTopBarRoot.displayName = 'TopBar'\n\n// -----------------------------------------------------------------------\n// TopBar.Left\n// -----------------------------------------------------------------------\n\ninterface TopBarLeftProps extends React.HTMLAttributes<HTMLDivElement> {\n children: React.ReactNode\n}\n\nconst TopBarLeft = React.forwardRef<HTMLDivElement, TopBarLeftProps>(\n ({ className, children, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('flex items-center gap-ds-04', className)}\n {...props}\n >\n {children}\n </div>\n ),\n)\nTopBarLeft.displayName = 'TopBar.Left'\n\n// -----------------------------------------------------------------------\n// TopBar.Center\n// -----------------------------------------------------------------------\n\ninterface TopBarCenterProps extends React.HTMLAttributes<HTMLDivElement> {\n children: React.ReactNode\n}\n\nconst TopBarCenter = React.forwardRef<HTMLDivElement, TopBarCenterProps>(\n ({ className, children, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('flex items-center justify-center px-ds-04', className)}\n {...props}\n >\n {children}\n </div>\n ),\n)\nTopBarCenter.displayName = 'TopBar.Center'\n\n// -----------------------------------------------------------------------\n// TopBar.Right\n// -----------------------------------------------------------------------\n\ninterface TopBarRightProps extends React.HTMLAttributes<HTMLDivElement> {\n children: React.ReactNode\n}\n\nconst TopBarRight = React.forwardRef<HTMLDivElement, TopBarRightProps>(\n ({ className, children, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('ml-auto flex items-center gap-ds-04', className)}\n {...props}\n >\n {children}\n </div>\n ),\n)\nTopBarRight.displayName = 'TopBar.Right'\n\n// -----------------------------------------------------------------------\n// TopBar.Section\n// -----------------------------------------------------------------------\n\nconst gapMap = {\n tight: 'gap-ds-02',\n default: 'gap-ds-04',\n loose: 'gap-ds-06',\n} as const\n\ninterface TopBarSectionProps extends React.HTMLAttributes<HTMLDivElement> {\n gap?: keyof typeof gapMap\n children: React.ReactNode\n}\n\nconst TopBarSection = React.forwardRef<HTMLDivElement, TopBarSectionProps>(\n ({ gap = 'default', className, children, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('flex items-center', gapMap[gap], className)}\n {...props}\n >\n {children}\n </div>\n ),\n)\nTopBarSection.displayName = 'TopBar.Section'\n\n// -----------------------------------------------------------------------\n// TopBar.IconButton\n// -----------------------------------------------------------------------\n\ninterface TopBarIconButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n icon: IconInput\n tooltip: string\n}\n\nconst TopBarIconButton = React.forwardRef<\n HTMLButtonElement,\n TopBarIconButtonProps\n>(({ icon, tooltip, className, ...props }, ref) => (\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n ref={ref}\n type=\"button\"\n aria-label={tooltip}\n className={cn(\n 'flex h-ds-sm-plus w-ds-sm-plus items-center justify-center rounded-pill border border-surface-border-strong bg-surface-raised-hover text-surface-fg-muted transition-[color,background-color,border-color,transform] hover:bg-surface-raised-active active:scale-90 duration-fast-01 ease-productive-standard',\n className,\n )}\n {...props}\n >\n <span className=\"[&>svg]:h-ico-sm [&>svg]:w-ico-sm\" aria-hidden=\"true\">\n <IconProvider size=\"sm\">{normalizeIcon(icon)}</IconProvider>\n </span>\n </button>\n </TooltipTrigger>\n <TooltipContent side=\"bottom\" align=\"center\">\n {tooltip}\n </TooltipContent>\n </Tooltip>\n))\nTopBarIconButton.displayName = 'TopBar.IconButton'\n\n// -----------------------------------------------------------------------\n// TopBar.Title\n// -----------------------------------------------------------------------\n\ninterface TopBarTitleProps extends React.HTMLAttributes<HTMLHeadingElement> {\n children: React.ReactNode\n}\n\nconst TopBarTitle = React.forwardRef<HTMLHeadingElement, TopBarTitleProps>(\n ({ className, children, ...props }, ref) => (\n <h2\n ref={ref}\n className={cn(\n 'hidden text-ds-lg text-surface-fg md:block',\n className,\n )}\n {...props}\n >\n {children}\n </h2>\n ),\n)\nTopBarTitle.displayName = 'TopBar.Title'\n\n// -----------------------------------------------------------------------\n// TopBar.UserMenu\n// -----------------------------------------------------------------------\n\ninterface TopBarUserMenuProps {\n user: TopBarUser\n onNavigate?: (path: string) => void\n onLogout?: () => void\n userMenuItems?: UserMenuItem[]\n className?: string\n}\n\nconst TopBarUserMenu = React.forwardRef<HTMLButtonElement, TopBarUserMenuProps>(\n ({ user, onNavigate, onLogout, userMenuItems, className }, ref) => {\n const { colorMode, toggleColorMode } = useColorMode()\n\n return (\n <DropdownMenu>\n <Tooltip>\n <TooltipTrigger asChild>\n <DropdownMenuTrigger asChild>\n <button\n ref={ref}\n type=\"button\"\n className={cn('flex items-center gap-ds-03 outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2', className)}\n >\n <Avatar className=\"h-ds-sm-plus w-ds-sm-plus cursor-pointer\">\n {user.image ? (\n <AvatarImage src={user.image} alt={user.name} />\n ) : null}\n <AvatarFallback className=\"bg-surface-raised-hover text-surface-fg\">\n {user.name?.charAt(0).toUpperCase()}\n </AvatarFallback>\n </Avatar>\n </button>\n </DropdownMenuTrigger>\n </TooltipTrigger>\n <TooltipContent side=\"bottom\" align=\"center\">\n User Menu\n </TooltipContent>\n </Tooltip>\n\n <DropdownMenuContent\n className=\"w-[200px] rounded-overlay-lg bg-surface-overlay p-0 shadow-floating\"\n sideOffset={8}\n align=\"end\"\n >\n {/* User Info */}\n <div className=\"border-b border-surface-border-strong px-ds-05 py-ds-04\">\n <p className=\"text-ds-md text-surface-fg\">{user.name}</p>\n {user.email && (\n <TruncatedText as=\"p\" mode=\"middle\" className=\"text-ds-sm text-surface-fg-subtle\">\n {user.email}\n </TruncatedText>\n )}\n </div>\n\n <DropdownMenuItem\n className=\"flex w-full cursor-pointer items-center gap-ds-03 px-ds-05 py-ds-04 hover:bg-surface-raised\"\n onClick={() => onNavigate?.('/profile')}\n >\n <Icon icon={IconUser} size=\"sm\" className=\"text-surface-fg-muted\" />\n <span className=\"text-ds-md text-surface-fg-muted\">Profile</span>\n </DropdownMenuItem>\n\n {/* Custom user menu items */}\n {userMenuItems?.map((item, index) => {\n const colorMap: Record<string, string> = {\n error: 'text-error-11',\n success: 'text-success-11',\n warning: 'text-warning-11',\n info: 'text-info-11',\n }\n const textColor = item.color\n ? (colorMap[item.color] ?? 'text-surface-fg-muted')\n : 'text-surface-fg-muted'\n return (\n <React.Fragment key={item.label + index}>\n {item.separator && (\n <DropdownMenuSeparator className=\"bg-surface-border\" />\n )}\n <DropdownMenuItem\n className={cn(\n 'flex w-full cursor-pointer items-center gap-ds-03 px-ds-05 py-ds-04 hover:bg-surface-raised',\n item.disabled && 'pointer-events-none opacity-action-disabled',\n )}\n disabled={item.disabled}\n onClick={() => {\n if (item.disabled) return\n if (item.onClick) item.onClick()\n else if (item.href) onNavigate?.(item.href)\n }}\n >\n {item.icon && (\n <span\n className={cn(\n '[&>svg]:h-ico-sm [&>svg]:w-ico-sm',\n textColor,\n )}\n >\n <IconProvider size=\"sm\">{normalizeIcon(item.icon)}</IconProvider>\n </span>\n )}\n <span className={cn('text-ds-md', textColor)}>\n {item.label}\n </span>\n {item.badge != null &&\n item.badge !== false &&\n (typeof item.badge === 'string' ? (\n <span className=\"ml-auto inline-flex h-[18px] min-w-[18px] items-center justify-center rounded-pill bg-error-9 px-ds-02 text-[10px] font-semibold leading-none text-error-fg\">\n {item.badge}\n </span>\n ) : (\n <span className=\"ml-auto h-[8px] w-[8px] rounded-pill bg-error-9\" />\n ))}\n </DropdownMenuItem>\n </React.Fragment>\n )\n })}\n\n <DropdownMenuItem\n className=\"flex w-full cursor-pointer items-center gap-ds-03 px-ds-05 py-ds-04 hover:bg-surface-raised\"\n onClick={toggleColorMode}\n >\n {colorMode === 'dark' ? (\n <Icon icon={IconSun} size=\"sm\" className=\"text-surface-fg-muted\" />\n ) : (\n <Icon icon={IconMoon} size=\"sm\" className=\"text-surface-fg-muted\" />\n )}\n <span className=\"text-ds-md text-surface-fg-muted\">\n {colorMode === 'dark' ? 'Light Mode' : 'Dark Mode'}\n </span>\n </DropdownMenuItem>\n\n {onLogout && (\n <>\n <DropdownMenuSeparator className=\"bg-surface-border\" />\n <DropdownMenuItem\n className=\"flex w-full cursor-pointer items-center gap-ds-03 px-ds-05 py-ds-04 hover:bg-surface-raised\"\n onClick={onLogout}\n >\n <Icon icon={IconLogout} size=\"sm\" className=\"text-error-11\" />\n <span className=\"text-ds-md text-error-11\">Logout</span>\n </DropdownMenuItem>\n </>\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n )\n },\n)\nTopBarUserMenu.displayName = 'TopBar.UserMenu'\n\n// -----------------------------------------------------------------------\n// Compound export\n// -----------------------------------------------------------------------\n\nexport type TopBarProps = TopBarRootProps\n\nconst TopBar = Object.assign(TopBarRoot, {\n Left: TopBarLeft,\n Center: TopBarCenter,\n Right: TopBarRight,\n Section: TopBarSection,\n IconButton: TopBarIconButton,\n Title: TopBarTitle,\n UserMenu: TopBarUserMenu,\n})\n\nexport { TopBar }\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"top-bar.js","names":[],"sources":["../../src/shell/top-bar.tsx"],"sourcesContent":["'use client'\n\n/**\n * TopBar v2 — Composition-based application top bar.\n *\n * Subcomponents: TopBar.Left, TopBar.Center, TopBar.Right,\n * TopBar.Section, TopBar.IconButton, TopBar.Title, TopBar.UserMenu.\n */\nimport { IconLogout, IconMoon, IconSun,IconUser } from '@tabler/icons-react'\nimport * as React from 'react'\n\nimport { useColorMode } from '../hooks/use-color-mode'\nimport { Avatar, AvatarFallback, AvatarImage } from '../ui/avatar'\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from '../ui/dropdown-menu'\nimport { Icon } from '../ui/icon'\nimport { IconProvider } from '../ui/icon-context'\nimport type { IconInput } from '../ui/lib/icon-input'\nimport { normalizeIcon } from '../ui/lib/normalize-icon'\nimport { cn } from '../ui/lib/utils'\nimport {\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from '../ui/tooltip'\nimport { TruncatedText } from '../ui/truncated-text'\n\n// -----------------------------------------------------------------------\n// Types\n// -----------------------------------------------------------------------\n\nexport interface TopBarUser {\n name: string\n email?: string\n image?: string | null\n}\n\nexport interface UserMenuItem {\n /** Display label */\n label: string\n /** Optional icon. Accepts any `IconInput`. */\n icon?: IconInput\n /** Navigate via onNavigate when clicked */\n href?: string\n /** Custom click handler */\n onClick?: () => void\n /** Render a separator before this item */\n separator?: boolean\n /** Text color semantic token (e.g. \"error\") — maps to text-{color} */\n color?: string\n /** Badge content — string for count, true for dot indicator */\n badge?: string | boolean\n /** Whether the item is disabled */\n disabled?: boolean\n}\n\n// -----------------------------------------------------------------------\n// TopBar (root)\n// -----------------------------------------------------------------------\n\ninterface TopBarRootProps extends React.HTMLAttributes<HTMLElement> {\n children: React.ReactNode\n className?: string\n}\n\nconst TopBarRoot = React.forwardRef<HTMLElement, TopBarRootProps>(\n ({ className, children, ...props }, ref) => {\n // Detect if a Center zone is present to switch to grid layout\n const hasCenter = React.Children.toArray(children).some(\n (child) => React.isValidElement(child) && child.type === TopBarCenter,\n )\n\n return (\n <header\n {...props}\n ref={ref}\n className={cn(\n 'z-sticky w-full border-b border-surface-border-strong bg-surface-chrome px-ds-05 py-ds-04 md:px-ds-06',\n hasCenter\n ? 'grid grid-cols-[1fr_auto_1fr] items-center'\n : 'flex items-center',\n className,\n )}\n >\n {children}\n </header>\n )\n },\n)\nTopBarRoot.displayName = 'TopBar'\n\n// -----------------------------------------------------------------------\n// TopBar.Left\n// -----------------------------------------------------------------------\n\ninterface TopBarLeftProps extends React.HTMLAttributes<HTMLDivElement> {\n children: React.ReactNode\n}\n\nconst TopBarLeft = React.forwardRef<HTMLDivElement, TopBarLeftProps>(\n ({ className, children, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('flex items-center gap-ds-04', className)}\n {...props}\n >\n {children}\n </div>\n ),\n)\nTopBarLeft.displayName = 'TopBar.Left'\n\n// -----------------------------------------------------------------------\n// TopBar.Center\n// -----------------------------------------------------------------------\n\ninterface TopBarCenterProps extends React.HTMLAttributes<HTMLDivElement> {\n children: React.ReactNode\n}\n\nconst TopBarCenter = React.forwardRef<HTMLDivElement, TopBarCenterProps>(\n ({ className, children, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('flex items-center justify-center px-ds-04', className)}\n {...props}\n >\n {children}\n </div>\n ),\n)\nTopBarCenter.displayName = 'TopBar.Center'\n\n// -----------------------------------------------------------------------\n// TopBar.Right\n// -----------------------------------------------------------------------\n\ninterface TopBarRightProps extends React.HTMLAttributes<HTMLDivElement> {\n children: React.ReactNode\n}\n\nconst TopBarRight = React.forwardRef<HTMLDivElement, TopBarRightProps>(\n ({ className, children, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('ml-auto flex items-center gap-ds-04', className)}\n {...props}\n >\n {children}\n </div>\n ),\n)\nTopBarRight.displayName = 'TopBar.Right'\n\n// -----------------------------------------------------------------------\n// TopBar.Section\n// -----------------------------------------------------------------------\n\nconst gapMap = {\n tight: 'gap-ds-02',\n default: 'gap-ds-04',\n loose: 'gap-ds-06',\n} as const\n\ninterface TopBarSectionProps extends React.HTMLAttributes<HTMLDivElement> {\n gap?: keyof typeof gapMap\n children: React.ReactNode\n}\n\nconst TopBarSection = React.forwardRef<HTMLDivElement, TopBarSectionProps>(\n ({ gap = 'default', className, children, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('flex items-center', gapMap[gap], className)}\n {...props}\n >\n {children}\n </div>\n ),\n)\nTopBarSection.displayName = 'TopBar.Section'\n\n// -----------------------------------------------------------------------\n// TopBar.IconButton\n// -----------------------------------------------------------------------\n\ninterface TopBarIconButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n icon: IconInput\n tooltip: string\n}\n\nconst TopBarIconButton = React.forwardRef<\n HTMLButtonElement,\n TopBarIconButtonProps\n>(({ icon, tooltip, className, ...props }, ref) => (\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n ref={ref}\n type=\"button\"\n aria-label={tooltip}\n className={cn(\n 'flex h-ds-sm-plus w-ds-sm-plus items-center justify-center rounded-pill border border-surface-border-strong bg-surface-raised-hover text-surface-fg-muted transition-[color,background-color,border-color,transform] hover:bg-surface-raised-active active:scale-90 duration-fast-01 ease-productive-standard',\n className,\n )}\n {...props}\n >\n <span className=\"[&>svg]:h-ico-sm [&>svg]:w-ico-sm\" aria-hidden=\"true\">\n <IconProvider size=\"sm\">{normalizeIcon(icon)}</IconProvider>\n </span>\n </button>\n </TooltipTrigger>\n <TooltipContent side=\"bottom\" align=\"center\">\n {tooltip}\n </TooltipContent>\n </Tooltip>\n))\nTopBarIconButton.displayName = 'TopBar.IconButton'\n\n// -----------------------------------------------------------------------\n// TopBar.Title\n// -----------------------------------------------------------------------\n\ninterface TopBarTitleProps extends React.HTMLAttributes<HTMLHeadingElement> {\n children: React.ReactNode\n}\n\nconst TopBarTitle = React.forwardRef<HTMLHeadingElement, TopBarTitleProps>(\n ({ className, children, ...props }, ref) => (\n <h2\n ref={ref}\n className={cn(\n 'hidden text-ds-lg text-surface-fg md:block',\n className,\n )}\n {...props}\n >\n {children}\n </h2>\n ),\n)\nTopBarTitle.displayName = 'TopBar.Title'\n\n// -----------------------------------------------------------------------\n// TopBar.UserMenu\n// -----------------------------------------------------------------------\n\ninterface TopBarUserMenuProps {\n user: TopBarUser\n onNavigate?: (path: string) => void\n onLogout?: () => void\n userMenuItems?: UserMenuItem[]\n className?: string\n}\n\nconst TopBarUserMenu = React.forwardRef<HTMLButtonElement, TopBarUserMenuProps>(\n ({ user, onNavigate, onLogout, userMenuItems, className }, ref) => {\n const { colorMode, toggleColorMode } = useColorMode()\n\n return (\n <DropdownMenu>\n <Tooltip>\n <TooltipTrigger asChild>\n <DropdownMenuTrigger asChild>\n <button\n ref={ref}\n type=\"button\"\n className={cn('flex items-center gap-ds-03 outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2', className)}\n >\n <Avatar className=\"h-ds-sm-plus w-ds-sm-plus cursor-pointer\">\n {user.image ? (\n <AvatarImage src={user.image} alt={user.name} />\n ) : null}\n <AvatarFallback className=\"bg-surface-raised-hover text-surface-fg\">\n {user.name?.charAt(0).toUpperCase()}\n </AvatarFallback>\n </Avatar>\n </button>\n </DropdownMenuTrigger>\n </TooltipTrigger>\n <TooltipContent side=\"bottom\" align=\"center\">\n User Menu\n </TooltipContent>\n </Tooltip>\n\n <DropdownMenuContent\n className=\"w-[200px] rounded-overlay-lg bg-surface-overlay p-0 shadow-floating\"\n sideOffset={8}\n align=\"end\"\n >\n {/* User Info */}\n <div className=\"border-b border-surface-border-strong px-ds-05 py-ds-04\">\n <p className=\"text-ds-md text-surface-fg\">{user.name}</p>\n {user.email && (\n <TruncatedText as=\"p\" mode=\"middle\" className=\"text-ds-sm text-surface-fg-subtle\">\n {user.email}\n </TruncatedText>\n )}\n </div>\n\n <DropdownMenuItem\n className=\"flex w-full cursor-pointer items-center gap-ds-03 px-ds-05 py-ds-04 hover:bg-surface-raised\"\n onClick={() => onNavigate?.('/profile')}\n >\n <Icon icon={IconUser} size=\"sm\" className=\"text-surface-fg-muted\" />\n <span className=\"text-ds-md text-surface-fg-muted\">Profile</span>\n </DropdownMenuItem>\n\n {/* Custom user menu items */}\n {userMenuItems?.map((item, index) => {\n const colorMap: Record<string, string> = {\n error: 'text-error-11',\n success: 'text-success-11',\n warning: 'text-warning-11',\n info: 'text-info-11',\n }\n const textColor = item.color\n ? (colorMap[item.color] ?? 'text-surface-fg-muted')\n : 'text-surface-fg-muted'\n return (\n <React.Fragment key={item.label + index}>\n {item.separator && (\n <DropdownMenuSeparator className=\"bg-surface-border\" />\n )}\n <DropdownMenuItem\n className={cn(\n 'flex w-full cursor-pointer items-center gap-ds-03 px-ds-05 py-ds-04 hover:bg-surface-raised',\n item.disabled && 'pointer-events-none opacity-action-disabled',\n )}\n disabled={item.disabled}\n onClick={() => {\n if (item.disabled) return\n if (item.onClick) item.onClick()\n else if (item.href) onNavigate?.(item.href)\n }}\n >\n {item.icon && (\n <span\n className={cn(\n '[&>svg]:h-ico-sm [&>svg]:w-ico-sm',\n textColor,\n )}\n >\n <IconProvider size=\"sm\">{normalizeIcon(item.icon)}</IconProvider>\n </span>\n )}\n <span className={cn('text-ds-md', textColor)}>\n {item.label}\n </span>\n {item.badge != null &&\n item.badge !== false &&\n (typeof item.badge === 'string' ? (\n <span className=\"ml-auto inline-flex h-[18px] min-w-[18px] items-center justify-center rounded-pill bg-error-9 px-ds-02 text-[10px] font-semibold leading-none text-error-fg\">\n {item.badge}\n </span>\n ) : (\n <span className=\"ml-auto h-[8px] w-[8px] rounded-pill bg-error-9\" />\n ))}\n </DropdownMenuItem>\n </React.Fragment>\n )\n })}\n\n <DropdownMenuItem\n className=\"flex w-full cursor-pointer items-center gap-ds-03 px-ds-05 py-ds-04 hover:bg-surface-raised\"\n onClick={toggleColorMode}\n >\n {colorMode === 'dark' ? (\n <Icon icon={IconSun} size=\"sm\" className=\"text-surface-fg-muted\" />\n ) : (\n <Icon icon={IconMoon} size=\"sm\" className=\"text-surface-fg-muted\" />\n )}\n <span className=\"text-ds-md text-surface-fg-muted\">\n {colorMode === 'dark' ? 'Light Mode' : 'Dark Mode'}\n </span>\n </DropdownMenuItem>\n\n {onLogout && (\n <>\n <DropdownMenuSeparator className=\"bg-surface-border\" />\n <DropdownMenuItem\n className=\"flex w-full cursor-pointer items-center gap-ds-03 px-ds-05 py-ds-04 hover:bg-surface-raised\"\n onClick={onLogout}\n >\n <Icon icon={IconLogout} size=\"sm\" className=\"text-error-11\" />\n <span className=\"text-ds-md text-error-11\">Logout</span>\n </DropdownMenuItem>\n </>\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n )\n },\n)\nTopBarUserMenu.displayName = 'TopBar.UserMenu'\n\n// -----------------------------------------------------------------------\n// Compound export\n// -----------------------------------------------------------------------\n\nexport type TopBarProps = TopBarRootProps\n\nconst TopBar = Object.assign(TopBarRoot, {\n Left: TopBarLeft,\n Center: TopBarCenter,\n Right: TopBarRight,\n Section: TopBarSection,\n IconButton: TopBarIconButton,\n Title: TopBarTitle,\n UserMenu: TopBarUserMenu,\n})\n\nexport { TopBar }\n"],"mappings":"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"}
|
package/dist/tokens/semantic.css
CHANGED
|
@@ -169,6 +169,11 @@
|
|
|
169
169
|
--color-surface-overlay: var(--neutral-1);
|
|
170
170
|
--color-surface-raised-hover: var(--neutral-3);
|
|
171
171
|
--color-surface-raised-active: var(--neutral-4);
|
|
172
|
+
/* App chrome (TopBar, Sidebar, BottomNavbar). Its own tier so chrome's
|
|
173
|
+
surface is an explicit, independently-tunable decision (per the Carbon/
|
|
174
|
+
Atlassian/Ant model), not coupled to the card surface. Starts equal to
|
|
175
|
+
`raised` — zero visual change — but can now diverge without touching cards. */
|
|
176
|
+
--color-surface-chrome: var(--neutral-1);
|
|
172
177
|
--color-surface-inverted: var(--neutral-12);
|
|
173
178
|
--color-surface-inverted-fg: var(--neutral-1);
|
|
174
179
|
--color-surface-disabled: var(--neutral-2);
|
|
@@ -367,7 +372,7 @@
|
|
|
367
372
|
--radius-overlay-sm rounded-overlay-sm Tooltip, Toast
|
|
368
373
|
--radius-overlay rounded-overlay Popover, HoverCard, DropdownMenu / ContextMenu / Menubar content, listboxes, NavigationMenu viewport
|
|
369
374
|
--radius-overlay-lg rounded-overlay-lg Dialog, AlertDialog, Sheet, BottomSheet, ColorInput picker
|
|
370
|
-
--radius-pill rounded-pill Badge,
|
|
375
|
+
--radius-pill rounded-pill Badge, Dot, Radio, Switch, Slider, Progress, Avatar circle, SegmentedControl item
|
|
371
376
|
--radius-bubble rounded-bubble ChatMessage bubble
|
|
372
377
|
─────────────────────────────────────────────────────────── */
|
|
373
378
|
--radius-control: 6px;
|
|
@@ -585,6 +590,7 @@
|
|
|
585
590
|
/* Surface — dark page, lighter cards */
|
|
586
591
|
--color-surface-base: var(--neutral-1); /* 0.11L */
|
|
587
592
|
--color-surface-raised: var(--neutral-2); /* 0.17L */
|
|
593
|
+
--color-surface-chrome: var(--neutral-2); /* chrome tier — matches raised for now */
|
|
588
594
|
--color-surface-border: var(--neutral-4);
|
|
589
595
|
--color-surface-border-strong: var(--neutral-5);
|
|
590
596
|
--color-surface-overlay: oklch(0.13 0.0002 350);
|
|
@@ -706,6 +712,7 @@
|
|
|
706
712
|
--color-surface-raised: Canvas;
|
|
707
713
|
--color-surface-raised-hover: Canvas;
|
|
708
714
|
--color-surface-raised-active: Canvas;
|
|
715
|
+
--color-surface-chrome: Canvas;
|
|
709
716
|
--color-surface-overlay: Canvas;
|
|
710
717
|
--color-surface-disabled: Canvas;
|
|
711
718
|
--color-surface-inverted: CanvasText;
|
package/dist/ui/accordion.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { Fn as e, In as t, Ln as n,
|
|
2
|
+
import { Fn as e, In as t, Ln as n, Nn as r, Pn as i } from "../_chunks/primitives.js";
|
|
3
3
|
import { tweens as a } from "./lib/motion.js";
|
|
4
4
|
import { cn as o } from "./lib/utils.js";
|
|
5
5
|
import { Icon as s } from "./icon.js";
|
|
@@ -8,33 +8,33 @@ import { jsx as l, jsxs as u } from "react/jsx-runtime";
|
|
|
8
8
|
import { IconChevronDown as d } from "@tabler/icons-react";
|
|
9
9
|
import { motion as f } from "framer-motion";
|
|
10
10
|
//#region src/ui/accordion.tsx
|
|
11
|
-
var p =
|
|
11
|
+
var p = t, m = c.forwardRef(({ className: t, ...n }, r) => /* @__PURE__ */ l(e, {
|
|
12
12
|
ref: r,
|
|
13
|
-
className: o("border-b border-surface-border",
|
|
13
|
+
className: o("border-b border-surface-border", t),
|
|
14
14
|
...n
|
|
15
15
|
}));
|
|
16
16
|
m.displayName = "AccordionItem";
|
|
17
|
-
var h = c.forwardRef(({ className:
|
|
17
|
+
var h = c.forwardRef(({ className: e, children: t, chevronPosition: r = "right", ...a }, c) => {
|
|
18
18
|
let f = /* @__PURE__ */ l(s, {
|
|
19
19
|
icon: d,
|
|
20
20
|
size: "sm",
|
|
21
21
|
className: "shrink-0 text-surface-fg-muted transition-transform duration-moderate-02 ease-productive-standard group-data-[state=open]:rotate-180"
|
|
22
22
|
});
|
|
23
|
-
return /* @__PURE__ */ l(
|
|
23
|
+
return /* @__PURE__ */ l(i, {
|
|
24
24
|
className: "flex",
|
|
25
|
-
children: /* @__PURE__ */ u(
|
|
25
|
+
children: /* @__PURE__ */ u(n, {
|
|
26
26
|
ref: c,
|
|
27
|
-
className: o("group flex flex-1 items-center justify-between py-ds-05 text-left text-ds-md font-medium hover:bg-surface-raised rounded-control data-[state=open]:bg-surface-raised focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9",
|
|
27
|
+
className: o("group flex flex-1 items-center justify-between py-ds-05 text-left text-ds-md font-medium hover:bg-surface-raised rounded-control data-[state=open]:bg-surface-raised focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9", e),
|
|
28
28
|
...a,
|
|
29
29
|
children: [
|
|
30
30
|
r === "left" && f,
|
|
31
|
-
|
|
31
|
+
t,
|
|
32
32
|
r === "right" && f
|
|
33
33
|
]
|
|
34
34
|
})
|
|
35
35
|
});
|
|
36
36
|
});
|
|
37
|
-
h.displayName =
|
|
37
|
+
h.displayName = n.displayName;
|
|
38
38
|
var g = c.forwardRef(({ className: e, children: t, ...n }, i) => /* @__PURE__ */ l(r, {
|
|
39
39
|
ref: i,
|
|
40
40
|
className: "w-full overflow-hidden text-ds-md data-[state=open]:animate-accordion-down data-[state=closed]:animate-accordion-up",
|