sparkdesign 0.4.9 → 0.4.10

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.
Files changed (38) hide show
  1. package/AGENT_COMPONENT_LIBRARY_QUICKREF.md +117 -0
  2. package/AI_README.md +7 -2
  3. package/README.md +4 -1
  4. package/cli/registry/AGENTS.md +1 -1
  5. package/cli/registry/agent-manifest.json +137 -93
  6. package/cli/registry/basic/calendar.tsx +16 -16
  7. package/cli/registry/basic/combobox.tsx +11 -2
  8. package/cli/registry/basic/date-picker.tsx +3 -2
  9. package/cli/registry/basic/popover.tsx +19 -2
  10. package/cli/registry/basic/rating.tsx +161 -0
  11. package/cli/registry/basic/sidebar.tsx +1 -1
  12. package/cli/registry/basic/stepper.tsx +163 -0
  13. package/cli/registry/basic/timeline.tsx +129 -0
  14. package/cli/registry/chat/permission-card.tsx +1 -1
  15. package/cli/registry/meta.json +30 -25
  16. package/dist/registry/basic/calendar.d.ts +1 -1
  17. package/dist/registry/basic/combobox.d.ts +2 -1
  18. package/dist/registry/basic/date-picker.d.ts +2 -2
  19. package/dist/registry/basic/popover.d.ts +2 -0
  20. package/dist/registry/basic/rating.d.ts +31 -0
  21. package/dist/registry/basic/stepper.d.ts +36 -0
  22. package/dist/registry/basic/timeline.d.ts +34 -0
  23. package/dist/spark-design.cjs.js +23 -23
  24. package/dist/spark-design.es.js +3420 -3035
  25. package/dist/sparkdesign.css +1 -1
  26. package/dist/src/components/basic/Rating/index.d.ts +13 -0
  27. package/dist/src/components/basic/Stepper/index.d.ts +13 -0
  28. package/dist/src/components/basic/Timeline/index.d.ts +13 -0
  29. package/dist/src/components/index.d.ts +6 -2
  30. package/docs/agent/component-selection.md +1 -3
  31. package/docs/agent/prompt-recipes.md +167 -0
  32. package/docs/guides/agent-usage.md +213 -0
  33. package/docs/guides/system-operating-model.md +148 -0
  34. package/package.json +14 -2
  35. package/registry/agent-manifest.json +137 -93
  36. package/cli/registry/basic/sheet.tsx +0 -18
  37. package/dist/registry/basic/sheet.d.ts +0 -13
  38. package/dist/src/components/basic/Sheet/index.d.ts +0 -13
@@ -0,0 +1,117 @@
1
+ # Spark Design Agent Quick Reference
2
+
3
+ > 给进入本仓库的 agent 的 1 页速查卡。详细说明见 [docs/guides/agent-usage.md](./docs/guides/agent-usage.md);组件选择见 [docs/agent/component-selection.md](./docs/agent/component-selection.md);项目级质量标准见 [docs/guides/system-operating-model.md](./docs/guides/system-operating-model.md);可复制提示词见 [docs/agent/prompt-recipes.md](./docs/agent/prompt-recipes.md)。
4
+
5
+ ## 默认选择
6
+
7
+ - 默认优先:`npx sparkdesign@latest add <component>`
8
+ - 次选:`npm install sparkdesign`
9
+ - 只有用户明确要整包 import,或项目已经在用整包时,才优先走整包
10
+
11
+ ## 两条路径不要混用
12
+
13
+ ### CLI 本地源码模式
14
+
15
+ 使用:
16
+
17
+ ```bash
18
+ npx sparkdesign@latest init
19
+ npx sparkdesign@latest add button
20
+ ```
21
+
22
+ 默认导入:
23
+
24
+ ```tsx
25
+ import { Button } from '@/components/ui/basic/button'
26
+ import { Response } from '@/components/ui/chat/response'
27
+ ```
28
+
29
+ 不要再写:
30
+
31
+ ```tsx
32
+ import { Button } from 'sparkdesign'
33
+ ```
34
+
35
+ ### 整包模式
36
+
37
+ 使用:
38
+
39
+ ```bash
40
+ npm install sparkdesign
41
+ ```
42
+
43
+ 导入:
44
+
45
+ ```tsx
46
+ import 'sparkdesign/style'
47
+ import { Button, Response } from 'sparkdesign'
48
+ ```
49
+
50
+ ## 样式硬规则
51
+
52
+ - 一律优先 design tokens,不要硬编码颜色、圆角、间距
53
+ - 根节点优先设置 `data-theme` 和 `data-style`
54
+ - Portal / 浮层组件要考虑 theme/style 继承,不要靠 remount 刷主题
55
+
56
+ 允许:
57
+
58
+ ```tsx
59
+ className="bg-primary text-text rounded-md"
60
+ className="px-[var(--spacing-3)]"
61
+ ```
62
+
63
+ 不允许:
64
+
65
+ ```tsx
66
+ className="bg-[#1890FF] text-[#333] rounded-[10px]"
67
+ ```
68
+
69
+ ## 组件选择
70
+
71
+ - 先读 `registry/agent-manifest.json`,按 intent、states、a11y、composition、antiPatterns 选择
72
+ - `basic/*`: 通用 UI
73
+ - `chat/*`: 对话流 UI
74
+ - 常见组合优先看 manifest recipes,不要只按组件名猜
75
+
76
+ 优先复用已有组件:
77
+
78
+ - `button` / `icon-button`
79
+ - `tooltip` / `dropdown-menu` / `alert-dialog`
80
+ - `chat-input`
81
+ - `response`
82
+ - `reasoning-step`
83
+ - `code-block-part` / `terminal-code-block-part`
84
+ - `task-part` / `plan-part`
85
+
86
+ ## 影响 CLI 时必须检查
87
+
88
+ - `registry/`
89
+ - `registry/meta.json`
90
+ - `cli/registry/` 是否已同步
91
+ - `npm run check:registry-meta`
92
+
93
+ ## 组件完成定义
94
+
95
+ 组件不只是源码文件。公开变更完成前,必须让这些表面一致:
96
+
97
+ - registry 源码与 CLI 副本
98
+ - 主包导出与 props 类型
99
+ - showcase demo / config / props / 本地化标签
100
+ - `registry/agent-manifest.json` 的 intent、states、a11y、composition、antiPatterns
101
+ - P3 header 与相关 P2 map
102
+
103
+ ## 发布规则
104
+
105
+ - **唯一发布入口是仓库根目录**
106
+ - 不要从 `cli/` 目录执行 `npm publish`
107
+ - 根包 `sparkdesign` 同时承载:
108
+ - 运行时整包
109
+ - `bin.sparkdesign -> ./cli/dist/index.js`
110
+
111
+ ## 开工前先回答 5 个问题
112
+
113
+ 1. 当前项目是在用 CLI 本地源码,还是整包 import?
114
+ 2. 目标组件属于 `basic` 还是 `chat`?
115
+ 3. 是否已有可复用组件?
116
+ 4. 样式是否完全基于 token?
117
+ 5. 改动会不会影响 CLI registry 与发布链路?
package/AI_README.md CHANGED
@@ -7,8 +7,11 @@ Spark Design correctly.
7
7
 
8
8
  1. `registry/agent-manifest.json` — choose components by intent, slots, states, accessibility, composition, and anti-patterns.
9
9
  2. `registry/tokens/ontology.json` — choose token families by semantic purpose before writing styles.
10
- 3. `docs/guides/agent-usage.md` — consumption rules for CLI copy vs package import.
11
- 4. Component source only after the manifest tells you which component to use.
10
+ 3. `docs/guides/system-operating-model.md` — quality bar for structure, showcase, AI semantics, and maintenance gates.
11
+ 4. `docs/agent/component-selection.md` decision order, name boundaries, recipes, and manifest maintenance.
12
+ 5. `docs/agent/prompt-recipes.md` — copyable prompts for install, screen composition, AI workflows, component changes, and audits.
13
+ 6. `docs/guides/agent-usage.md` — consumption rules for CLI copy vs package import.
14
+ 7. Component source only after the manifest tells you which component to use.
12
15
 
13
16
  For npm package consumers:
14
17
 
@@ -22,7 +25,9 @@ import ontology from 'sparkdesign/token-ontology.json'
22
25
  - Prefer `npx sparkdesign@latest add <component>` when building a business app that should own component source.
23
26
  - Prefer `import { Component } from 'sparkdesign'` only for prototypes, showcase usage, or projects already using the package runtime.
24
27
  - Use `basic/*` for product primitives and `chat/*` for assistant, tool, file, reasoning, and response flows.
28
+ - Choose components by manifest intent and anti-patterns before matching by name.
25
29
  - Use `data-theme` for color and `data-style` for density, radius, and rhythm.
30
+ - Treat showcase, docs, registry metadata, and agent manifest updates as one public contract when a component changes.
26
31
 
27
32
  ## Hard Rules
28
33
 
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  现代化 React 设计系统,支持双维度主题(颜色 theme + 布局 scale),5 种内置布局风格,提供 Basic 基础组件与 Chat 对话流组件,可扩展颜色主题。
4
4
 
5
- **当前版本**:`0.4.6`([CLI 快速上手](docs/getting-started-cli.md) / [NPM 快速上手](docs/getting-started.md))
5
+ **当前版本**:`0.4.9`([CLI 快速上手](docs/getting-started-cli.md) / [NPM 快速上手](docs/getting-started.md))
6
6
 
7
7
  > 🌟 **纯新手?** 查看 [CLI 快速上手指南](docs/getting-started-cli.md),一步步带你跑起来!
8
8
 
@@ -17,6 +17,9 @@
17
17
  - **图标系统可替换**:通过 `IconsProvider` 接 Lucide、Remix 或自定义图标库
18
18
  - **Tailwind 友好**:类名与设计 token 映射,无硬编码色值
19
19
  - **组件分层**:Basic 原子组件 + Chat 对话组件,开箱即用
20
+ - **AI 友好契约**:`agent-manifest.json` + token ontology + component selection guide 让 agent 按 intent、states、a11y、composition 和 anti-patterns 选择组件
21
+ - **可复制 Agent Recipes**:安装、页面组合、AI 工作流、组件维护和审查都有提示词模板
22
+ - **同构维护流程**:registry、CLI、showcase、docs、P2/P3 与发布门禁保持一致
20
23
 
21
24
  ## 两种使用方式
22
25
 
@@ -4,7 +4,7 @@
4
4
 
5
5
  ## Member list
6
6
 
7
- - `basic/` — accordion, alert, alert-dialog, aspect-ratio, avatar, badge, breadcrumb, button, button-group, calendar, card, carousel, chart, checkbox, collapse, collapsible, collapsible-card, combobox, command, context-menu, data-table, date-picker, dialog, direction, drawer, dropdown-menu, ellipsis-text, empty, field, form, hover-card, icon-button, input, input-group, input-otp, item, kbd, label, menubar, native-select, navigation-menu, option-list, pagination, popover, progress, radio-group, resizable, scroll-area, scrollbar, select, separator, sheet, shimmering-text, sidebar, sidebar-menu, skeleton, slider, sonner, spinner, switch, table, tabs, tag, textarea, toggle, tooltip, typography.
7
+ - `basic/` — accordion, alert, alert-dialog, aspect-ratio, avatar, badge, breadcrumb, button, button-group, calendar, card, carousel, chart, checkbox, collapse, collapsible, collapsible-card, combobox, command, context-menu, data-table, date-picker, dialog, direction, drawer, dropdown-menu, ellipsis-text, empty, field, form, hover-card, icon-button, input, input-group, input-otp, item, kbd, label, menubar, native-select, navigation-menu, option-list, pagination, popover, progress, radio-group, rating, resizable, scroll-area, scrollbar, select, separator, shimmering-text, sidebar, sidebar-menu, skeleton, slider, spinner, stepper, switch, table, tabs, tag, textarea, timeline, toggle, tooltip, typography.
8
8
  - `chat/` — ask-user-part, browser-action-part, chat-input, code-block-part, conversation-anchor-nav, file-attachment, file-card, file-review-part, folder-button, generated-images-grid, generation-status-bar, hint-banner, image-attachment, image-generating, markdown, mermaid-part, permission-card, plan-part, queue-indicator, reasoning-step, related-prompts, response, send-button, streaming-markdown-block, task-part, terminal-code-block-part, thinking-indicator, tool-invocation-card, user-message, user-question, user-question-answer.
9
9
  - `lib/` — file-icon-maps, use-mermaid-render, utils; helper modules copied with registry components when needed.
10
10
  - `tokens/` — index.css, theme.css, theme-base.css, scale.css, ontology.json, scrollbar utility, theme presets, and scale token packs.
@@ -933,55 +933,7 @@
933
933
  ],
934
934
  "agentHints": [
935
935
  "Choose Popover for compact pickers and contextual controls.",
936
- "Use Dialog or Sheet when the content needs more space."
937
- ]
938
- },
939
- "sheet": {
940
- "id": "sheet",
941
- "name": "Sheet",
942
- "category": "basic",
943
- "status": "stable",
944
- "intent": "Side panel overlay for contextual details, filters, settings, or secondary editing flows.",
945
- "packageImport": "import { Sheet, SheetTrigger, SheetContent, SheetHeader, SheetTitle, SheetDescription } from 'sparkdesign'",
946
- "cliAdd": "npx sparkdesign@latest add sheet",
947
- "slots": [
948
- "Sheet",
949
- "SheetTrigger",
950
- "SheetContent",
951
- "SheetHeader",
952
- "SheetTitle",
953
- "SheetDescription",
954
- "SheetFooter"
955
- ],
956
- "states": [
957
- "open",
958
- "closed",
959
- "side-left",
960
- "side-right",
961
- "side-top",
962
- "side-bottom",
963
- "focus-trapped"
964
- ],
965
- "a11y": [
966
- "Always provide SheetTitle.",
967
- "Use SheetDescription when the panel purpose is not obvious.",
968
- "Return focus to the trigger after close."
969
- ],
970
- "composition": [
971
- "Button",
972
- "Field",
973
- "Tabs",
974
- "SidebarMenu",
975
- "Alert"
976
- ],
977
- "antiPatterns": [
978
- "Do not use Sheet for destructive confirmations; use AlertDialog.",
979
- "Do not create nested sheets unless the product specifically requires it.",
980
- "Do not put primary app navigation in a temporary sheet on desktop when persistent navigation is expected."
981
- ],
982
- "agentHints": [
983
- "Choose Sheet for secondary panels that preserve page context.",
984
- "Use Drawer when the product already follows drawer terminology or behavior."
936
+ "Use Dialog or Drawer when the content needs more space."
985
937
  ]
986
938
  },
987
939
  "sidebar-menu": {
@@ -2004,6 +1956,49 @@
2004
1956
  "Use Spinner for brief unknown-duration loading."
2005
1957
  ]
2006
1958
  },
1959
+ "rating": {
1960
+ "id": "rating",
1961
+ "name": "Rating",
1962
+ "category": "basic",
1963
+ "status": "stable",
1964
+ "intent": "Star-based score or preference input for reviews, quality signals, and lightweight sentiment feedback.",
1965
+ "packageImport": "import { Rating } from 'sparkdesign'",
1966
+ "cliAdd": "npx sparkdesign@latest add rating",
1967
+ "slots": [
1968
+ "Rating",
1969
+ "stars",
1970
+ "numeric value by option",
1971
+ "accessible label"
1972
+ ],
1973
+ "states": [
1974
+ "controlled",
1975
+ "uncontrolled",
1976
+ "whole precision",
1977
+ "half precision",
1978
+ "read-only",
1979
+ "disabled"
1980
+ ],
1981
+ "a11y": [
1982
+ "Provide a clear label when the rating is an input.",
1983
+ "Use readOnly for static review summaries.",
1984
+ "Do not rely on star color alone when numeric precision matters."
1985
+ ],
1986
+ "composition": [
1987
+ "Card",
1988
+ "Field",
1989
+ "Label",
1990
+ "Tooltip"
1991
+ ],
1992
+ "antiPatterns": [
1993
+ "Do not use Rating for exact numeric entry; use Input or Slider.",
1994
+ "Do not ask for ratings when the user needs categorical choices.",
1995
+ "Do not hide the current value in dense analytics summaries."
1996
+ ],
1997
+ "agentHints": [
1998
+ "Choose Rating for familiar 1-5 preference capture or review display.",
1999
+ "Use precision={0.5} only when half steps are meaningful to users."
2000
+ ]
2001
+ },
2007
2002
  "resizable": {
2008
2003
  "id": "resizable",
2009
2004
  "name": "Resizable",
@@ -2682,6 +2677,99 @@
2682
2677
  "Pair with Input when users need precise values."
2683
2678
  ]
2684
2679
  },
2680
+ "stepper": {
2681
+ "id": "stepper",
2682
+ "name": "Stepper",
2683
+ "category": "basic",
2684
+ "status": "stable",
2685
+ "intent": "Linear workflow progress for setup, checkout, approval, onboarding, and multi-step task status.",
2686
+ "packageImport": "import { Stepper, StepperItem, StepperIndicator, StepperContent, StepperTitle, StepperDescription, StepperSeparator } from 'sparkdesign'",
2687
+ "cliAdd": "npx sparkdesign@latest add stepper",
2688
+ "slots": [
2689
+ "Stepper",
2690
+ "StepperItem",
2691
+ "StepperIndicator",
2692
+ "StepperContent",
2693
+ "StepperTitle",
2694
+ "StepperDescription",
2695
+ "StepperSeparator"
2696
+ ],
2697
+ "states": [
2698
+ "horizontal",
2699
+ "vertical",
2700
+ "complete",
2701
+ "current",
2702
+ "upcoming",
2703
+ "error"
2704
+ ],
2705
+ "a11y": [
2706
+ "Use ordered steps when sequence matters.",
2707
+ "Make the current step visible in text, not only color.",
2708
+ "Do not hide validation errors behind completed-looking steps."
2709
+ ],
2710
+ "composition": [
2711
+ "Button",
2712
+ "Progress",
2713
+ "Alert",
2714
+ "Card"
2715
+ ],
2716
+ "antiPatterns": [
2717
+ "Do not use Stepper for non-linear tabs; use Tabs.",
2718
+ "Do not show too many steps when grouped milestones would scan better.",
2719
+ "Do not mark future steps as interactive unless navigation is supported."
2720
+ ],
2721
+ "agentHints": [
2722
+ "Choose Stepper when users need to understand where they are in a process.",
2723
+ "Use vertical orientation for verbose workflow history or mobile layouts."
2724
+ ]
2725
+ },
2726
+ "timeline": {
2727
+ "id": "timeline",
2728
+ "name": "Timeline",
2729
+ "category": "basic",
2730
+ "status": "stable",
2731
+ "intent": "Chronological event list for activity history, releases, audit logs, and milestone narratives.",
2732
+ "packageImport": "import { Timeline, TimelineItem, TimelineMarker, TimelineConnector, TimelineContent, TimelineTitle, TimelineDescription, TimelineTime } from 'sparkdesign'",
2733
+ "cliAdd": "npx sparkdesign@latest add timeline",
2734
+ "slots": [
2735
+ "Timeline",
2736
+ "TimelineItem",
2737
+ "TimelineMarker",
2738
+ "TimelineConnector",
2739
+ "TimelineContent",
2740
+ "TimelineTitle",
2741
+ "TimelineDescription",
2742
+ "TimelineTime"
2743
+ ],
2744
+ "states": [
2745
+ "default",
2746
+ "primary",
2747
+ "success",
2748
+ "warning",
2749
+ "error",
2750
+ "last item without connector"
2751
+ ],
2752
+ "a11y": [
2753
+ "Keep event order clear and consistent.",
2754
+ "Include timestamps or labels when chronology matters.",
2755
+ "Do not encode event meaning only through marker color."
2756
+ ],
2757
+ "composition": [
2758
+ "Badge",
2759
+ "Tag",
2760
+ "Card",
2761
+ "Separator"
2762
+ ],
2763
+ "antiPatterns": [
2764
+ "Do not use Timeline for dense tabular audit data; use Table or DataTable.",
2765
+ "Do not mix ascending and descending order in the same view.",
2766
+ "Do not overload markers with unrelated status meanings."
2767
+ ],
2768
+ "agentHints": [
2769
+ "Choose Timeline for readable event progression or product release histories.",
2770
+ "Use tone sparingly for the few events that need semantic emphasis."
2771
+ ]
2772
+ },
2685
2773
  "toggle": {
2686
2774
  "id": "toggle",
2687
2775
  "name": "Toggle",
@@ -2861,50 +2949,6 @@
2861
2949
  "Use Alert for feedback that must remain visible."
2862
2950
  ]
2863
2951
  },
2864
- "sonner": {
2865
- "id": "sonner",
2866
- "name": "Sonner",
2867
- "category": "basic",
2868
- "status": "stable",
2869
- "intent": "Sonner toaster entry using Spark token styling and theme/style portal inheritance.",
2870
- "packageImport": "import { Toaster, toast } from 'sparkdesign'",
2871
- "cliAdd": "npx sparkdesign@latest add sonner",
2872
- "slots": [
2873
- "Toaster",
2874
- "toast function",
2875
- "toast options",
2876
- "icons",
2877
- "portal wrapper"
2878
- ],
2879
- "states": [
2880
- "success",
2881
- "error",
2882
- "warning",
2883
- "info",
2884
- "loading",
2885
- "dismissed"
2886
- ],
2887
- "a11y": [
2888
- "Use concise notification text.",
2889
- "Do not put required decisions only in sonner toasts.",
2890
- "Ensure critical errors also appear inline when users need to recover."
2891
- ],
2892
- "composition": [
2893
- "Button",
2894
- "Alert",
2895
- "Form",
2896
- "ToolInvocationCard"
2897
- ],
2898
- "antiPatterns": [
2899
- "Do not use Sonner for persistent validation or destructive confirmation.",
2900
- "Do not stack noisy success toasts for every small state change.",
2901
- "Do not hide important recovery actions inside an auto-dismissing toast."
2902
- ],
2903
- "agentHints": [
2904
- "Choose Sonner when the target explicitly asks for the sonner toaster API.",
2905
- "Choose Toast when describing the semantic notification pattern."
2906
- ]
2907
- },
2908
2952
  "tooltip": {
2909
2953
  "id": "tooltip",
2910
2954
  "name": "Tooltip",
@@ -31,7 +31,7 @@ function Calendar({
31
31
  <DayPicker
32
32
  showOutsideDays={showOutsideDays}
33
33
  className={cn(
34
- "group/calendar bg-bg-base p-3 [--cell-size:--spacing(8)] [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent",
34
+ "group/calendar bg-bg-base p-3 [--cell-size:2rem] [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent",
35
35
  String.raw`rtl:**:[.rdp-button\_next>svg]:rotate-180`,
36
36
  String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
37
37
  className
@@ -55,24 +55,24 @@ function Calendar({
55
55
  ),
56
56
  button_previous: cn(
57
57
  buttonVariants({ variant: buttonVariant }),
58
- "size-(--cell-size) p-0 select-none aria-disabled:opacity-50",
58
+ "h-[var(--cell-size)] w-[var(--cell-size)] p-0 select-none aria-disabled:opacity-50",
59
59
  defaultClassNames.button_previous
60
60
  ),
61
61
  button_next: cn(
62
62
  buttonVariants({ variant: buttonVariant }),
63
- "size-(--cell-size) p-0 select-none aria-disabled:opacity-50",
63
+ "h-[var(--cell-size)] w-[var(--cell-size)] p-0 select-none aria-disabled:opacity-50",
64
64
  defaultClassNames.button_next
65
65
  ),
66
66
  month_caption: cn(
67
- "flex h-(--cell-size) w-full items-center justify-center px-(--cell-size)",
67
+ "flex h-[var(--cell-size)] w-full items-center justify-center px-[var(--cell-size)]",
68
68
  defaultClassNames.month_caption
69
69
  ),
70
70
  dropdowns: cn(
71
- "flex h-(--cell-size) w-full items-center justify-center gap-1.5 text-sm font-medium",
71
+ "flex h-[var(--cell-size)] w-full items-center justify-center gap-1.5 text-sm font-medium",
72
72
  defaultClassNames.dropdowns
73
73
  ),
74
74
  dropdown_root: cn(
75
- "relative rounded-md border border-border-tertiary shadow-sm has-focus:border-primary-border has-focus:ring-[3px] has-focus:ring-primary-border/50",
75
+ "has-focus:border-primary-border border-border-tertiary shadow-sm has-focus:ring-primary-border/50 has-focus:ring-[3px] relative rounded-md border",
76
76
  defaultClassNames.dropdown_root
77
77
  ),
78
78
  dropdown: cn(
@@ -80,7 +80,7 @@ function Calendar({
80
80
  defaultClassNames.dropdown
81
81
  ),
82
82
  caption_label: cn(
83
- "font-medium select-none",
83
+ "select-none font-medium",
84
84
  captionLayout === "label"
85
85
  ? "text-sm"
86
86
  : "flex h-8 items-center gap-1 rounded-md pr-1 pl-2 text-sm [&>svg]:size-3.5 [&>svg]:text-text-tertiary",
@@ -94,7 +94,7 @@ function Calendar({
94
94
  ),
95
95
  week: cn("mt-2 flex w-full", defaultClassNames.week),
96
96
  week_number_header: cn(
97
- "w-(--cell-size) select-none",
97
+ "w-[var(--cell-size)] select-none",
98
98
  defaultClassNames.week_number_header
99
99
  ),
100
100
  week_number: cn(
@@ -102,20 +102,20 @@ function Calendar({
102
102
  defaultClassNames.week_number
103
103
  ),
104
104
  day: cn(
105
- "group/day relative aspect-square h-full w-full p-0 text-center select-none [&:last-child[data-selected=true]_button]:rounded-r-md",
105
+ "group/day relative aspect-square h-full w-full p-0 text-center select-none [&:last-child[data-selected=true]_button]:rounded-r-sm",
106
106
  props.showWeekNumber
107
- ? "[&:nth-child(2)[data-selected=true]_button]:rounded-l-md"
108
- : "[&:first-child[data-selected=true]_button]:rounded-l-md",
107
+ ? "[&:nth-child(2)[data-selected=true]_button]:rounded-l-sm"
108
+ : "[&:first-child[data-selected=true]_button]:rounded-l-sm",
109
109
  defaultClassNames.day
110
110
  ),
111
111
  range_start: cn(
112
- "rounded-l-md bg-fill-secondary",
112
+ "rounded-l-sm bg-fill-secondary",
113
113
  defaultClassNames.range_start
114
114
  ),
115
115
  range_middle: cn("rounded-none", defaultClassNames.range_middle),
116
- range_end: cn("rounded-r-md bg-fill-secondary", defaultClassNames.range_end),
116
+ range_end: cn("rounded-r-sm bg-fill-secondary", defaultClassNames.range_end),
117
117
  today: cn(
118
- "rounded-md bg-fill-secondary text-text data-[selected=true]:rounded-none",
118
+ "rounded-sm bg-fill-secondary text-text data-[selected=true]:rounded-sm",
119
119
  defaultClassNames.today
120
120
  ),
121
121
  outside: cn(
@@ -164,7 +164,7 @@ function Calendar({
164
164
  WeekNumber: ({ children, ...props }) => {
165
165
  return (
166
166
  <td {...props}>
167
- <div className="flex size-(--cell-size) items-center justify-center text-center">
167
+ <div className="flex size-[var(--cell-size)] items-center justify-center text-center">
168
168
  {children}
169
169
  </div>
170
170
  </td>
@@ -209,7 +209,7 @@ function CalendarDayButton({
209
209
  data-range-middle={modifiers.range_middle}
210
210
  className={cn(
211
211
  "inline-flex items-center justify-center transition-colors hover:bg-fill-secondary hover:text-text",
212
- "flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 px-0 leading-none font-normal group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:border-primary-border group-data-[focused=true]/day:ring-[3px] group-data-[focused=true]/day:ring-primary-border/50 data-[range-end=true]:rounded-md data-[range-end=true]:rounded-r-md data-[range-end=true]:bg-primary data-[range-end=true]:text-text-on-primary data-[range-middle=true]:rounded-none data-[range-middle=true]:bg-fill-secondary data-[range-middle=true]:text-text data-[range-start=true]:rounded-md data-[range-start=true]:rounded-l-md data-[range-start=true]:bg-primary data-[range-start=true]:text-text-on-primary data-[selected-single=true]:bg-primary data-[selected-single=true]:text-text-on-primary dark:hover:text-text [&>span]:text-xs [&>span]:opacity-70",
212
+ "flex aspect-square size-auto w-full min-w-[var(--cell-size)] flex-col gap-1 px-0 leading-none font-normal hover:rounded-sm group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:border-primary-border group-data-[focused=true]/day:ring-[3px] group-data-[focused=true]/day:ring-primary-border/50 data-[range-end=true]:rounded-sm data-[range-end=true]:rounded-r-sm data-[range-end=true]:bg-primary data-[range-end=true]:text-text-on-primary data-[range-middle=true]:rounded-none data-[range-middle=true]:bg-fill-secondary data-[range-middle=true]:text-text data-[range-start=true]:rounded-sm data-[range-start=true]:rounded-l-sm data-[range-start=true]:bg-primary data-[range-start=true]:text-text-on-primary data-[selected=true]:rounded-sm data-[selected=true]:!outline-none data-[selected=true]:!shadow-none data-[selected=true]:!ring-0 data-[selected=true]:!ring-offset-0 data-[selected=true]:!border-transparent data-[selected=true]:focus-visible:!ring-0 data-[selected=true]:focus-visible:!outline-none data-[selected-single=true]:rounded-sm data-[selected-single=true]:bg-primary data-[selected-single=true]:text-text-on-primary dark:hover:text-text [&>span]:text-xs [&>span]:opacity-70",
213
213
  defaultClassNames.day,
214
214
  className
215
215
  )}
@@ -22,6 +22,7 @@ export interface ComboboxOption {
22
22
 
23
23
  export interface ComboboxProps {
24
24
  options: ComboboxOption[]
25
+ size?: 'default' | 'compact'
25
26
  value?: string
26
27
  defaultValue?: string
27
28
  onValueChange?: (value: string) => void
@@ -46,6 +47,7 @@ function Combobox({
46
47
  placeholder = 'Select an option…',
47
48
  searchPlaceholder = 'Search…',
48
49
  emptyText = 'No option found.',
50
+ size = 'compact',
49
51
  disabled,
50
52
  className,
51
53
  contentClassName,
@@ -96,9 +98,16 @@ function Combobox({
96
98
  </PopoverTrigger>
97
99
  <PopoverContent
98
100
  align={align}
99
- className={cn('w-[var(--radix-popover-trigger-width)] min-w-56 p-0', contentClassName)}
101
+ contentPadding="compact"
102
+ className={cn('w-[var(--radix-popover-trigger-width)] min-w-56', contentClassName)}
100
103
  >
101
- <Command>
104
+ <Command
105
+ className={cn(
106
+ 'w-full',
107
+ size === 'compact' &&
108
+ '[&_[data-slot=command-input-wrapper]]:h-8 [&_[data-slot=command-input]]:h-8 [&_[data-slot=command-input-wrapper]]:px-2 [&_[data-slot=command-input]]:py-1.5 [&_[cmdk-group]]:p-0 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-1.5 [&_[data-slot=command-empty]]:py-3'
109
+ )}
110
+ >
102
111
  <CommandInput placeholder={searchPlaceholder} />
103
112
  <CommandList>
104
113
  <CommandEmpty>{emptyText}</CommandEmpty>
@@ -61,15 +61,16 @@ function DatePicker({
61
61
  !selected && 'text-text-tertiary',
62
62
  className,
63
63
  )}
64
- suffixIcon={<CalendarIcon className="ml-auto size-4 opacity-60" />}
64
+ prefixIcon={<CalendarIcon className="size-4 text-text-tertiary" />}
65
65
  >
66
66
  {selected ? format(selected, formatString) : <span>{placeholder}</span>}
67
67
  </Button>
68
68
  </PopoverTrigger>
69
- <PopoverContent className="w-auto p-0" align={align}>
69
+ <PopoverContent className="w-auto" contentPadding="compact" align={align}>
70
70
  <Calendar
71
71
  mode="single"
72
72
  selected={selected}
73
+ defaultMonth={selected}
73
74
  onSelect={handleSelect}
74
75
  autoFocus
75
76
  />
@@ -14,6 +14,8 @@ export interface PopoverContentProps
14
14
  /** When provided (e.g. from ThemeStyleProvider), used for portal wrapper */
15
15
  dataStyle?: string
16
16
  dataTheme?: string
17
+ /** Popover internal padding; keep default to avoid breaking existing usages */
18
+ contentPadding?: 'default' | 'compact' | 'none'
17
19
  }
18
20
 
19
21
  const PopoverContent = React.forwardRef<
@@ -21,7 +23,16 @@ const PopoverContent = React.forwardRef<
21
23
  PopoverContentProps
22
24
  >(
23
25
  (
24
- { className, align = 'center', sideOffset = 4, children, dataStyle, dataTheme, ...props },
26
+ {
27
+ className,
28
+ align = 'center',
29
+ sideOffset = 4,
30
+ contentPadding = 'default',
31
+ children,
32
+ dataStyle,
33
+ dataTheme,
34
+ ...props
35
+ },
25
36
  ref,
26
37
  ) => {
27
38
  const fromDoc = getThemeFromDocument()
@@ -34,10 +45,16 @@ const PopoverContent = React.forwardRef<
34
45
  <div style={{ display: 'contents' }} {...dataProps}>
35
46
  <PopoverPrimitive.Content
36
47
  ref={ref}
48
+ data-slot="popover-content"
37
49
  align={align}
38
50
  sideOffset={sideOffset}
39
51
  className={cn(
40
- 'z-50 w-72 rounded-lg border border-border-tertiary bg-bg-container p-4 text-sm text-text shadow-md outline-none',
52
+ 'z-50 w-72 rounded-lg border border-border-tertiary bg-bg-container text-sm text-text shadow-md outline-none',
53
+ contentPadding === 'none'
54
+ ? 'p-0'
55
+ : contentPadding === 'compact'
56
+ ? 'p-1'
57
+ : 'p-4',
41
58
  className,
42
59
  )}
43
60
  {...props}