@monkey-mini-app/ui 0.1.1 → 0.1.5

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 (203) hide show
  1. package/README.md +12 -6
  2. package/dist/globals.css +1 -1
  3. package/dist/index.js +12 -2
  4. package/dist/manifest.json +6 -6
  5. package/dist/runtime.js +9 -0
  6. package/dist/sdk.js +158 -0
  7. package/dist/src/blocks/activity-feed.tsx +7 -0
  8. package/dist/src/blocks/app-shell.tsx +1 -0
  9. package/dist/src/blocks/attachment-gallery.tsx +7 -0
  10. package/dist/src/blocks/bar-chart.tsx +11 -0
  11. package/dist/src/blocks/comment-thread.tsx +7 -0
  12. package/dist/src/blocks/dashboard-shell.tsx +109 -0
  13. package/dist/src/blocks/description-list.tsx +7 -0
  14. package/dist/src/blocks/detail-panel.tsx +1 -0
  15. package/dist/src/blocks/donut-chart.tsx +7 -0
  16. package/dist/src/blocks/env-badge.tsx +7 -0
  17. package/dist/src/blocks/env-table.tsx +316 -0
  18. package/dist/src/blocks/file-tree.tsx +7 -0
  19. package/dist/src/blocks/filter-bar.tsx +1 -0
  20. package/dist/src/blocks/form-sheet.tsx +160 -0
  21. package/dist/src/blocks/gauge.tsx +7 -0
  22. package/dist/src/blocks/list-detail.tsx +121 -0
  23. package/dist/src/blocks/notification-center.tsx +7 -0
  24. package/dist/src/blocks/page-header.tsx +1 -0
  25. package/dist/src/blocks/progress-ring.tsx +7 -0
  26. package/dist/src/blocks/radar-chart.tsx +7 -0
  27. package/dist/src/blocks/request-inspector.tsx +7 -0
  28. package/dist/src/blocks/reveal.tsx +56 -0
  29. package/dist/src/blocks/run-timeline.tsx +7 -0
  30. package/dist/src/blocks/scrollspy.tsx +7 -0
  31. package/dist/src/blocks/settings-split.tsx +154 -0
  32. package/dist/src/blocks/severity-chip.tsx +7 -0
  33. package/dist/src/blocks/sparkline.tsx +7 -0
  34. package/dist/src/blocks/stat-card.tsx +1 -0
  35. package/dist/src/blocks/status-badge.tsx +1 -0
  36. package/dist/src/blocks/table-page.tsx +83 -0
  37. package/dist/src/blocks/terminal.tsx +21 -3
  38. package/dist/src/blocks/test-step-list.tsx +7 -0
  39. package/dist/src/blocks/trend-card.tsx +7 -0
  40. package/dist/src/blocks/wizard-shell.tsx +132 -0
  41. package/dist/src/cdn-modules.d.ts +5 -0
  42. package/dist/src/components/accordion.tsx +7 -0
  43. package/dist/src/components/alert-dialog.tsx +7 -0
  44. package/dist/src/components/alert.tsx +7 -0
  45. package/dist/src/components/aspect-ratio.tsx +4 -0
  46. package/dist/src/components/attachment.tsx +4 -0
  47. package/dist/src/components/avatar.tsx +4 -0
  48. package/dist/src/components/badge.tsx +7 -0
  49. package/dist/src/components/breadcrumb.tsx +4 -0
  50. package/dist/src/components/bubble.tsx +4 -0
  51. package/dist/src/components/button-group.tsx +6 -0
  52. package/dist/src/components/button.tsx +7 -0
  53. package/dist/src/components/calendar.tsx +4 -0
  54. package/dist/src/components/card.tsx +8 -1
  55. package/dist/src/components/chart.tsx +7 -0
  56. package/dist/src/components/checkbox.tsx +5 -0
  57. package/dist/src/components/collapsible.tsx +4 -0
  58. package/dist/src/components/combobox.tsx +4 -0
  59. package/dist/src/components/command.tsx +6 -0
  60. package/dist/src/components/context-menu.tsx +4 -0
  61. package/dist/src/components/dialog.tsx +21 -0
  62. package/dist/src/components/drawer.tsx +4 -0
  63. package/dist/src/components/dropdown-menu.tsx +7 -0
  64. package/dist/src/components/empty.tsx +7 -0
  65. package/dist/src/components/field.tsx +6 -0
  66. package/dist/src/components/hover-card.tsx +4 -0
  67. package/dist/src/components/input-group.tsx +4 -0
  68. package/dist/src/components/input.tsx +7 -0
  69. package/dist/src/components/item.tsx +4 -0
  70. package/dist/src/components/kbd.tsx +4 -0
  71. package/dist/src/components/label.tsx +7 -0
  72. package/dist/src/components/marker.tsx +4 -0
  73. package/dist/src/components/menubar.tsx +4 -0
  74. package/dist/src/components/message-scroller.tsx +4 -0
  75. package/dist/src/components/message.tsx +4 -0
  76. package/dist/src/components/native-select.tsx +4 -0
  77. package/dist/src/components/navigation-menu.tsx +4 -0
  78. package/dist/src/components/pagination.tsx +4 -0
  79. package/dist/src/components/popover.tsx +7 -0
  80. package/dist/src/components/progress.tsx +7 -0
  81. package/dist/src/components/questionnaire.tsx +4 -0
  82. package/dist/src/components/radio-group.tsx +4 -0
  83. package/dist/src/components/resizable.tsx +7 -0
  84. package/dist/src/components/scroll-area.tsx +4 -0
  85. package/dist/src/components/select.tsx +7 -0
  86. package/dist/src/components/separator.tsx +5 -0
  87. package/dist/src/components/sheet.tsx +22 -0
  88. package/dist/src/components/sidebar.tsx +4 -0
  89. package/dist/src/components/skeleton.tsx +7 -0
  90. package/dist/src/components/slider.tsx +4 -0
  91. package/dist/src/components/spinner.tsx +6 -0
  92. package/dist/src/components/switch.tsx +7 -0
  93. package/dist/src/components/table.tsx +7 -0
  94. package/dist/src/components/tabs.tsx +7 -0
  95. package/dist/src/components/textarea.tsx +7 -0
  96. package/dist/src/components/toast.tsx +7 -0
  97. package/dist/src/components/toggle-group.tsx +4 -0
  98. package/dist/src/components/toggle.tsx +4 -0
  99. package/dist/src/components/tooltip.tsx +7 -0
  100. package/dist/src/composites/autocomplete.tsx +7 -0
  101. package/dist/src/composites/cascader.tsx +7 -0
  102. package/dist/src/composites/color-picker.tsx +7 -0
  103. package/dist/src/composites/confirm-dialog.tsx +7 -0
  104. package/dist/src/composites/copyable.tsx +9 -1
  105. package/dist/src/composites/currency-input.tsx +7 -0
  106. package/dist/src/composites/date-picker.tsx +7 -0
  107. package/dist/src/composites/date-range-picker.tsx +4 -0
  108. package/dist/src/composites/date-time-picker.tsx +7 -0
  109. package/dist/src/composites/date-time-range-picker.tsx +7 -0
  110. package/dist/src/composites/duration-input.tsx +7 -0
  111. package/dist/src/composites/mini-calendar.tsx +7 -0
  112. package/dist/src/composites/number-field.tsx +7 -0
  113. package/dist/src/composites/password-field.tsx +7 -0
  114. package/dist/src/composites/phone-input.tsx +7 -0
  115. package/dist/src/composites/rating.tsx +7 -0
  116. package/dist/src/composites/relative-date-picker.tsx +7 -0
  117. package/dist/src/composites/search-input.tsx +7 -0
  118. package/dist/src/composites/slider-range.tsx +7 -0
  119. package/dist/src/composites/tag-input.tsx +7 -0
  120. package/dist/src/composites/time-picker.tsx +11 -1
  121. package/dist/src/composites/time-range-picker.tsx +7 -0
  122. package/dist/src/composites/timezone-select.tsx +7 -0
  123. package/dist/src/composites/transfer.tsx +7 -0
  124. package/dist/src/composites/user-picker.tsx +7 -0
  125. package/dist/src/hooks/use-html-dark.ts +37 -0
  126. package/dist/src/hooks/use-mobile.ts +3 -0
  127. package/dist/src/i18n/en.ts +109 -2
  128. package/dist/src/i18n/zh.ts +99 -2
  129. package/dist/src/index.ts +147 -134
  130. package/dist/src/lib/clipboard.ts +10 -0
  131. package/dist/src/lib/illustrations.tsx +2 -2
  132. package/dist/src/products/code-block.tsx +35 -18
  133. package/dist/src/products/code-editor.tsx +156 -24
  134. package/dist/src/products/commit-graph.tsx +644 -0
  135. package/dist/src/products/data-grid.tsx +2 -1
  136. package/dist/src/products/diff-viewer.tsx +104 -8
  137. package/dist/src/products/event-calendar.tsx +28 -823
  138. package/dist/src/products/file-dropzone.tsx +7 -0
  139. package/dist/src/products/full-calendar/animations.ts +38 -0
  140. package/dist/src/products/full-calendar/calendar-body.tsx +77 -0
  141. package/dist/src/products/full-calendar/constants.ts +10 -0
  142. package/dist/src/products/full-calendar/contexts/calendar-context.tsx +255 -0
  143. package/dist/src/products/full-calendar/contexts/dnd-context.tsx +157 -0
  144. package/dist/src/products/full-calendar/dialogs/add-edit-event-dialog.tsx +187 -0
  145. package/dist/src/products/full-calendar/dialogs/delete-event-dialog.tsx +39 -0
  146. package/dist/src/products/full-calendar/dialogs/event-details-dialog.tsx +100 -0
  147. package/dist/src/products/full-calendar/dialogs/events-list-dialog.tsx +87 -0
  148. package/dist/src/products/full-calendar/dnd/draggable-event.tsx +45 -0
  149. package/dist/src/products/full-calendar/dnd/droppable-area.tsx +45 -0
  150. package/dist/src/products/full-calendar/dnd/resizable-event.tsx +179 -0
  151. package/dist/src/products/full-calendar/header/calendar-header.tsx +65 -0
  152. package/dist/src/products/full-calendar/header/date-navigator.tsx +110 -0
  153. package/dist/src/products/full-calendar/header/filter.tsx +58 -0
  154. package/dist/src/products/full-calendar/header/today-button.tsx +45 -0
  155. package/dist/src/products/full-calendar/header/user-select.tsx +64 -0
  156. package/dist/src/products/full-calendar/header/view-tabs.tsx +36 -0
  157. package/dist/src/products/full-calendar/helpers.ts +453 -0
  158. package/dist/src/products/full-calendar/hooks/use-time-range-create.ts +152 -0
  159. package/dist/src/products/full-calendar/hooks.ts +70 -0
  160. package/dist/src/products/full-calendar/interfaces.ts +23 -0
  161. package/dist/src/products/full-calendar/settings/settings.tsx +80 -0
  162. package/dist/src/products/full-calendar/shims/avatar-group.tsx +16 -0
  163. package/dist/src/products/full-calendar/shims/day-picker.tsx +1 -0
  164. package/dist/src/products/full-calendar/shims/motion.tsx +97 -0
  165. package/dist/src/products/full-calendar/shims/next-themes.ts +6 -0
  166. package/dist/src/products/full-calendar/shims/re-resizable.tsx +25 -0
  167. package/dist/src/products/full-calendar/shims/sonner.ts +4 -0
  168. package/dist/src/products/full-calendar/types.ts +8 -0
  169. package/dist/src/products/full-calendar/views/agenda-view/agenda-events.tsx +140 -0
  170. package/dist/src/products/full-calendar/views/month-view/calendar-month-view.tsx +69 -0
  171. package/dist/src/products/full-calendar/views/month-view/day-cell.tsx +201 -0
  172. package/dist/src/products/full-calendar/views/month-view/event-bullet.tsx +40 -0
  173. package/dist/src/products/full-calendar/views/month-view/month-event-badge.tsx +143 -0
  174. package/dist/src/products/full-calendar/views/week-and-day-view/calendar-day-view.tsx +295 -0
  175. package/dist/src/products/full-calendar/views/week-and-day-view/calendar-time-line.tsx +35 -0
  176. package/dist/src/products/full-calendar/views/week-and-day-view/calendar-week-view.tsx +253 -0
  177. package/dist/src/products/full-calendar/views/week-and-day-view/day-view-multi-day-events-row.tsx +73 -0
  178. package/dist/src/products/full-calendar/views/week-and-day-view/event-block.tsx +114 -0
  179. package/dist/src/products/full-calendar/views/week-and-day-view/render-grouped-events.tsx +49 -0
  180. package/dist/src/products/full-calendar/views/week-and-day-view/week-view-multi-day-events-row.tsx +143 -0
  181. package/dist/src/products/full-calendar/views/year-view/calendar-year-view.tsx +161 -0
  182. package/dist/src/products/gantt.tsx +7 -0
  183. package/dist/src/products/jira-wiki.tsx +1 -0
  184. package/dist/src/products/jql-input.tsx +340 -37
  185. package/dist/src/products/json-viewer.tsx +7 -0
  186. package/dist/src/products/kanban-issue-panel.tsx +7 -0
  187. package/dist/src/products/kanban.tsx +1 -0
  188. package/dist/src/products/log-viewer.tsx +390 -18
  189. package/dist/src/products/markdown-editor.tsx +21 -6
  190. package/dist/src/products/markdown.tsx +7 -0
  191. package/dist/src/products/rich-text-editor.tsx +65 -59
  192. package/dist/src/products/sortable-list.tsx +7 -0
  193. package/dist/src/products/stepper.tsx +219 -70
  194. package/dist/src/products/timeline.tsx +7 -0
  195. package/dist/src/products/tree-view.tsx +7 -0
  196. package/dist/src/sdk/app-error-boundary.tsx +240 -0
  197. package/dist/src/sdk/app-id.ts +7 -0
  198. package/dist/src/sdk/use-app.ts +126 -0
  199. package/dist/src/styles/globals.css +1 -0
  200. package/dist/vendors/lodash.js +20 -0
  201. package/dist/vendors/motion.js +12 -0
  202. package/package.json +20 -19
  203. package/dist/src/products/jql-language.ts +0 -70
@@ -0,0 +1,83 @@
1
+ "use client";
2
+
3
+ import type { ReactNode } from "react";
4
+
5
+ import { cn } from "@monkey-mini-app/ui/lib/utils";
6
+
7
+ export type TablePageProps = {
8
+ /** Page-level actions above the table: search, filters, "New". Pinned; it never scrolls away. */
9
+ toolbar?: ReactNode;
10
+ /** The table itself (a `DataGrid`, usually). The only slot that scrolls. */
11
+ grid?: ReactNode;
12
+ /** First-run / no-match placeholder. Renders when `grid` is not given. */
13
+ empty?: ReactNode;
14
+ /** A pager you own. `DataGrid` already renders its own when `features.pagination` is on. */
15
+ pagination?: ReactNode;
16
+ /** Bulk actions. Floats over the bottom of the grid instead of pushing the rows around. */
17
+ bulk?: ReactNode;
18
+ className?: string;
19
+ };
20
+
21
+ /**
22
+ * Full-height table page: toolbar pinned, one scrolling band for the grid, bulk bar floating.
23
+ *
24
+ * Without it a `DataGrid` is dropped into a plain flex column, the tallest child wins, and the
25
+ * page scrolls instead of the table: the toolbar slides off, pagination ends up below the fold,
26
+ * and selecting 200 rows shoves the table down every time the bulk bar appears. The band owns
27
+ * `min-h-0` + `overflow-y-auto` here, and the bulk bar is out of flow with `pointer-events-none`
28
+ * on its track so the rows under it stay clickable.
29
+ *
30
+ * @when Page shape: one wide filterable table is the product — inventories, ledgers, saved views
31
+ * @example
32
+ * <TablePage
33
+ * toolbar={<FilterBar {...{ query, onQueryChange, filters }} />}
34
+ * grid={rows.length ? <DataGrid columns={columns} data={rows} /> : undefined}
35
+ * empty={<FirstRun onImport={import} />}
36
+ * bulk={selected.size ? <BulkBar count={selected.size} onClear={clear} /> : undefined}
37
+ * />
38
+ * @family Layout & structure
39
+ */
40
+ export function TablePage({
41
+ toolbar,
42
+ grid,
43
+ empty,
44
+ pagination,
45
+ bulk,
46
+ className,
47
+ }: TablePageProps) {
48
+ return (
49
+ <div
50
+ className={cn("relative flex h-full min-h-0 w-full flex-col", className)}
51
+ data-testid="table-page"
52
+ >
53
+ {toolbar ? (
54
+ <div className="shrink-0" data-testid="table-page-toolbar">
55
+ {toolbar}
56
+ </div>
57
+ ) : null}
58
+
59
+ {/* The one scroller. `grid ?? empty` keeps "no rows" the app's decision, not a prop. */}
60
+ <div
61
+ className="min-h-0 flex-1 overflow-y-auto"
62
+ data-testid="table-page-grid"
63
+ >
64
+ {grid ?? empty ?? null}
65
+ </div>
66
+
67
+ {pagination ? (
68
+ <div className="shrink-0" data-testid="table-page-pagination">
69
+ {pagination}
70
+ </div>
71
+ ) : null}
72
+
73
+ {bulk ? (
74
+ <div
75
+ className="pointer-events-none absolute inset-x-0 bottom-0 flex justify-center px-4 pb-4"
76
+ data-testid="table-page-bulk"
77
+ >
78
+ <div className="pointer-events-auto">{bulk}</div>
79
+ </div>
80
+ ) : null}
81
+ </div>
82
+ );
83
+ }
@@ -1,10 +1,28 @@
1
- export function Terminal({ lines }: { lines: string[] }) {
1
+ import { cn } from "@monkey-mini-app/ui/lib/utils";
2
+
3
+ /**
4
+ * Fixed-width console block.
5
+ * @when Showing a command + its output verbatim. Timestamped levels/scrolling → `LogViewer`.
6
+ * @example
7
+ * <Terminal lines={["$ df -h", "/dev/disk1 62%"]} />
8
+ * @family Realtime
9
+ */
10
+ export function Terminal({
11
+ lines,
12
+ className,
13
+ }: {
14
+ lines: string[];
15
+ className?: string;
16
+ }) {
2
17
  return (
3
18
  <pre
4
19
  data-testid="terminal"
5
- className="overflow-auto rounded-xl bg-zinc-950 p-3 font-mono text-xs leading-6 text-zinc-100"
20
+ className={cn(
21
+ "overflow-auto rounded-xl bg-zinc-950 p-3 font-mono text-xs leading-6 text-zinc-100",
22
+ className,
23
+ )}
6
24
  >
7
25
  {lines.join("\n")}
8
26
  </pre>
9
- )
27
+ );
10
28
  }
@@ -2,6 +2,13 @@ import { StatusBadge, type StatusKey } from "@monkey-mini-app/ui/blocks/status-b
2
2
 
3
3
  export type TestStep = { id: string; title: string; status: StatusKey | string }
4
4
 
5
+ /**
6
+ * Numbered test steps with expected/actual + status.
7
+ * @when QA cases, checklists that get executed and graded.
8
+ * @example
9
+ * <TestStepList steps={[{ id: "s1", name: "登录", status: "pass" }]} />
10
+ * @family Data & tables
11
+ */
5
12
  export function TestStepList({ steps }: { steps: TestStep[] }) {
6
13
  return (
7
14
  <ol className="flex flex-col gap-2" data-testid="test-step-list">
@@ -17,6 +17,13 @@ const chartConfig = {
17
17
  value: { label: "Value", color: "var(--chart-1)" },
18
18
  } satisfies ChartConfig
19
19
 
20
+ /**
21
+ * KPI card with a trend series.
22
+ * @when Metric + direction over time. Metric only → `StatCard`.
23
+ * @example
24
+ * <TrendCard title="请求数" value="1.2k" trend="up" data={[{ value: 9 }, { value: 12 }]} />
25
+ * @family Chart & data
26
+ */
20
27
  export function TrendCard({
21
28
  title,
22
29
  value,
@@ -0,0 +1,132 @@
1
+ "use client";
2
+
3
+ import type { ReactNode } from "react";
4
+
5
+ import { Button } from "@monkey-mini-app/ui/components/button";
6
+ import { Stepper, StepperItem } from "@monkey-mini-app/ui/products/stepper";
7
+ import { useLabels } from "@monkey-mini-app/ui/i18n/context";
8
+ import { cn } from "@monkey-mini-app/ui/lib/utils";
9
+
10
+ export type WizardStep = {
11
+ id: string;
12
+ label: string;
13
+ /** Pass `false` while the step's form is incomplete — Next disables itself. Omit to allow. */
14
+ valid?: boolean;
15
+ };
16
+
17
+ export type WizardShellProps = {
18
+ /** The steps, in order. The rail is generated from this, so it cannot disagree with the body. */
19
+ steps: WizardStep[];
20
+ /** Which step is showing. The app owns it — the preset never navigates on its own. */
21
+ index: number;
22
+ /** Current step's content. The only scrolling area. */
23
+ body: ReactNode;
24
+ /** Replaces the generated Back/Next/Finish row (a preview pane, a second action…). */
25
+ footer?: ReactNode;
26
+ onBack?: () => void;
27
+ onNext?: () => void;
28
+ /** Fires on the last step's primary action. Without it the last step still shows Next. */
29
+ onSubmit?: () => void;
30
+ /** Greys the primary action and swaps in the busy label. */
31
+ submitting?: boolean;
32
+ className?: string;
33
+ };
34
+
35
+ /**
36
+ * Multi-step flow: step rail on top, scrolling body, action row that never moves.
37
+ *
38
+ * Hand-rolled, a wizard's footer rides along inside the scrolling column, so every step change
39
+ * jumps the buttons to a different height and the user chases them with the cursor; and Next is
40
+ * enabled into an invalid step because the validity check lives in the form and the button lives
41
+ * outside it. Here the footer is a `shrink-0` sibling of the scroller, and Next/Finish are
42
+ * disabled straight from `steps[index].valid`, which is the only place that can know.
43
+ *
44
+ * @when Page shape: create / import / onboarding, one step at a time with validation per step
45
+ * @example
46
+ * <WizardShell
47
+ * steps={[{ id: "pick", label: "Choose file", valid: Boolean(file) }, { id: "map", label: "Map columns", valid: mapped }]}
48
+ * index={step}
49
+ * body={<StepBody />}
50
+ * onBack={() => setStep((s) => s - 1)}
51
+ * onNext={() => setStep((s) => s + 1)}
52
+ * onSubmit={() => void run()}
53
+ * />
54
+ * @family Layout & structure
55
+ */
56
+ export function WizardShell({
57
+ steps,
58
+ index,
59
+ body,
60
+ footer,
61
+ onBack,
62
+ onNext,
63
+ onSubmit,
64
+ submitting = false,
65
+ className,
66
+ }: WizardShellProps) {
67
+ const t = useLabels("wizardShell");
68
+ const current = steps[index];
69
+ const last = index >= steps.length - 1;
70
+ const canAdvance = current?.valid !== false;
71
+ const primary = last && onSubmit ? t.finish : t.next;
72
+
73
+ return (
74
+ <div
75
+ className={cn("flex h-full min-h-0 w-full flex-col", className)}
76
+ data-testid="wizard-shell"
77
+ >
78
+ <div
79
+ className="border-border shrink-0 border-b px-4 py-3"
80
+ data-testid="wizard-rail"
81
+ >
82
+ <Stepper orientation="horizontal">
83
+ {steps.map((s, i) => (
84
+ <StepperItem
85
+ key={s.id}
86
+ step={i + 1}
87
+ title={s.label}
88
+ status={
89
+ i < index ? "completed" : i === index ? "active" : "default"
90
+ }
91
+ />
92
+ ))}
93
+ </Stepper>
94
+ </div>
95
+
96
+ <div
97
+ className="min-h-0 flex-1 overflow-y-auto px-4 py-4"
98
+ data-testid="wizard-body"
99
+ >
100
+ {body}
101
+ </div>
102
+
103
+ <div
104
+ className="border-border bg-background flex shrink-0 items-center justify-between gap-3 border-t px-4 py-3"
105
+ data-testid="wizard-footer"
106
+ >
107
+ {footer ?? (
108
+ <>
109
+ <Button
110
+ variant="ghost"
111
+ onClick={onBack}
112
+ disabled={index === 0 || submitting}
113
+ data-testid="wizard-back"
114
+ >
115
+ {t.back}
116
+ </Button>
117
+ <span className="text-muted-foreground text-xs tabular-nums">
118
+ {t.stepOf(index + 1, steps.length)}
119
+ </span>
120
+ <Button
121
+ onClick={last && onSubmit ? onSubmit : onNext}
122
+ disabled={!canAdvance || submitting}
123
+ data-testid="wizard-next"
124
+ >
125
+ {submitting ? t.working : primary}
126
+ </Button>
127
+ </>
128
+ )}
129
+ </div>
130
+ </div>
131
+ );
132
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Heavy editors load CodeMirror / shiki from esm.sh on demand (not npm peers).
3
+ * Ambient so `import("https://esm.sh/...")` type-checks in the IDE.
4
+ */
5
+ declare module "https://esm.sh/*";
@@ -3,6 +3,13 @@ import { Accordion as AccordionPrimitive } from "@base-ui/react/accordion"
3
3
  import { cn } from "@monkey-mini-app/ui/lib/utils"
4
4
  import { ChevronDownIcon, ChevronUpIcon } from "lucide-react"
5
5
 
6
+ /**
7
+ * Vertically expanding sections.
8
+ * @when Collapsible groups in settings/details.
9
+ * @example
10
+ * <Accordion type="single"><AccordionItem value="s1"><AccordionTrigger>高级</AccordionTrigger><AccordionContent>…</AccordionContent></AccordionItem></Accordion>
11
+ * @family Surface
12
+ */
6
13
  function Accordion({ className, ...props }: AccordionPrimitive.Root.Props) {
7
14
  return (
8
15
  <AccordionPrimitive.Root
@@ -4,6 +4,13 @@ import { AlertDialog as AlertDialogPrimitive } from "@base-ui/react/alert-dialog
4
4
  import { cn } from "@monkey-mini-app/ui/lib/utils"
5
5
  import { Button } from "@monkey-mini-app/ui/components/button"
6
6
 
7
+ /**
8
+ * Blocking confirm modal (no click-outside dismiss).
9
+ * @when Deleting/irreversible actions that must be answered.
10
+ * @example
11
+ * <AlertDialog open={ask} onOpenChange={setAsk}><AlertDialogContent><AlertDialogTitle>确定删除?</AlertDialogTitle><AlertDialogAction onClick={del}>删除</AlertDialogAction></AlertDialogContent></AlertDialog>
12
+ * @family Surface
13
+ */
7
14
  function AlertDialog({ ...props }: AlertDialogPrimitive.Root.Props) {
8
15
  return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />
9
16
  }
@@ -19,6 +19,13 @@ const alertVariants = cva(
19
19
  }
20
20
  )
21
21
 
22
+ /**
23
+ * Inline message block (info/warning/error).
24
+ * @when Explaining a failed state in place. Transient → `toast()`.
25
+ * @example
26
+ * <Alert variant="destructive"><AlertTitle>拉取失败</AlertTitle><AlertDescription>上游 502,已用缓存</AlertDescription></Alert>
27
+ * @family Feedback & status
28
+ */
22
29
  function Alert({
23
30
  className,
24
31
  variant,
@@ -1,5 +1,9 @@
1
1
  import { cn } from "@monkey-mini-app/ui/lib/utils"
2
2
 
3
+ /**
4
+ * @family Layout & structure
5
+ * @when Keeping an image/video/embed from shifting the layout while loading.
6
+ */
3
7
  function AspectRatio({
4
8
  ratio,
5
9
  className,
@@ -24,6 +24,10 @@ const attachmentVariants = cva(
24
24
  }
25
25
  )
26
26
 
27
+ /**
28
+ * @family Discovery & inspect
29
+ * @when One selected file inside a form. A grid of many → `AttachmentGallery`.
30
+ */
27
31
  function Attachment({
28
32
  className,
29
33
  state = "done",
@@ -3,6 +3,10 @@ import { Avatar as AvatarPrimitive } from "@base-ui/react/avatar"
3
3
 
4
4
  import { cn } from "@monkey-mini-app/ui/lib/utils"
5
5
 
6
+ /**
7
+ * @family Layout & structure
8
+ * @when User initials/photo next to a name in rows, comments, pickers.
9
+ */
6
10
  function Avatar({
7
11
  className,
8
12
  size = "default",
@@ -27,6 +27,13 @@ const badgeVariants = cva(
27
27
  }
28
28
  )
29
29
 
30
+ /**
31
+ * Inline label chip.
32
+ * @when Static tags/counts. Status → `StatusBadge`, severity → `SeverityChip`.
33
+ * @example
34
+ * <Badge variant="secondary">草稿</Badge>
35
+ * @family Feedback & status
36
+ */
30
37
  function Badge({
31
38
  className,
32
39
  variant = "default",
@@ -5,6 +5,10 @@ import { useRender } from "@base-ui/react/use-render"
5
5
  import { cn } from "@monkey-mini-app/ui/lib/utils"
6
6
  import { ChevronRightIcon, MoreHorizontalIcon } from "lucide-react"
7
7
 
8
+ /**
9
+ * @family Navigation
10
+ * @when Deep mini-app views; usually one level is enough — prefer `Tabs`/`AppShell` nav.
11
+ */
8
12
  function Breadcrumb({ className, ...props }: React.ComponentProps<"nav">) {
9
13
  return (
10
14
  <nav
@@ -42,6 +42,10 @@ const bubbleVariants = cva(
42
42
  }
43
43
  )
44
44
 
45
+ /**
46
+ * @family Surface
47
+ * @when Conversational UI (assistant turns). Records/logs → `ActivityFeed` / `Message`.
48
+ */
45
49
  function Bubble({
46
50
  variant = "default",
47
51
  align = "start",
@@ -22,6 +22,12 @@ const buttonGroupVariants = cva(
22
22
  }
23
23
  )
24
24
 
25
+ /**
26
+ * @family Form
27
+ * @when 2–5 mutually related actions (view switch, alignment). Tabs of content → `Tabs`.
28
+ * @example
29
+ * <ButtonGroup><Button variant="outline">List</Button><Button variant="outline">Board</Button></ButtonGroup>
30
+ */
25
31
  function ButtonGroup({
26
32
  className,
27
33
  orientation,
@@ -40,6 +40,13 @@ const buttonVariants = cva(
40
40
  }
41
41
  )
42
42
 
43
+ /**
44
+ * Action button with variants and icon sizing.
45
+ * @when Every click target. `variant="destructive"` for delete, `size="icon*"` for icon-only (add aria-label).
46
+ * @example
47
+ * <Button variant="outline" size="sm" onClick={run}>刷新</Button>
48
+ * @family Form
49
+ */
43
50
  function Button({
44
51
  className,
45
52
  variant = "default",
@@ -12,6 +12,10 @@ import { cn } from "@monkey-mini-app/ui/lib/utils"
12
12
  import { Button, buttonVariants } from "@monkey-mini-app/ui/components/button"
13
13
  import { ChevronLeftIcon, ChevronRightIcon, ChevronDownIcon } from "lucide-react"
14
14
 
15
+ /**
16
+ * @family Calendar & date
17
+ * @when An inline calendar inside your own layout. As a field with input → `DatePicker`.
18
+ */
15
19
  function Calendar({
16
20
  className,
17
21
  classNames,
@@ -2,6 +2,13 @@ import * as React from "react"
2
2
 
3
3
  import { cn } from "@monkey-mini-app/ui/lib/utils"
4
4
 
5
+ /**
6
+ * Surface with header/content/footer.
7
+ * @when The default container for a block of related UI.
8
+ * @example
9
+ * <Card><CardHeader><CardTitle>今日摘要</CardTitle></CardHeader><CardContent>…</CardContent></Card>
10
+ * @family Surface
11
+ */
5
12
  function Card({
6
13
  className,
7
14
  size = "default",
@@ -12,7 +19,7 @@ function Card({
12
19
  data-slot="card"
13
20
  data-size={size}
14
21
  className={cn(
15
- "group/card flex flex-col gap-(--card-spacing) overflow-hidden rounded-xl bg-card py-(--card-spacing) text-sm text-card-foreground ring-1 ring-foreground/10 [--card-spacing:--spacing(4)] has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:[--card-spacing:--spacing(3)] data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
22
+ "group/card flex flex-col gap-(--card-spacing) overflow-hidden rounded-xl border border-border bg-card py-(--card-spacing) text-sm text-card-foreground [--card-spacing:--spacing(4)] has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:[--card-spacing:--spacing(3)] data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
16
23
  className
17
24
  )}
18
25
  {...props}
@@ -37,6 +37,13 @@ function useChart() {
37
37
  return context
38
38
  }
39
39
 
40
+ /**
41
+ * Recharts container + theme CSS vars + tooltip/legend parts.
42
+ * @when Only when no `*Chart` block fits — then you own the series. Prefer `DonutChart` / `StackedBarChart` / `Sparkline` / `Gauge` / `RadarChart`.
43
+ * @example
44
+ * <ChartContainer config={cfg} className="h-40 w-full"><Bar data={rows} dataKey="v" /></ChartContainer>
45
+ * @family Chart & data
46
+ */
40
47
  function ChartContainer({
41
48
  id,
42
49
  className,
@@ -5,6 +5,11 @@ import { Checkbox as CheckboxPrimitive } from "@base-ui/react/checkbox"
5
5
  import { cn } from "@monkey-mini-app/ui/lib/utils"
6
6
  import { CheckIcon } from "lucide-react"
7
7
 
8
+ /**
9
+ * Single boolean box.
10
+ * @when Multi-select rows / opt-in.
11
+ * @family Form
12
+ */
8
13
  function Checkbox({ className, ...props }: CheckboxPrimitive.Root.Props) {
9
14
  return (
10
15
  <CheckboxPrimitive.Root
@@ -1,5 +1,9 @@
1
1
  import { Collapsible as CollapsiblePrimitive } from "@base-ui/react/collapsible"
2
2
 
3
+ /**
4
+ * @family Layout & structure
5
+ * @when A single disclosure (advanced options). Several stacked → `Accordion`.
6
+ */
3
7
  function Collapsible({ ...props }: CollapsiblePrimitive.Root.Props) {
4
8
  return <CollapsiblePrimitive.Root data-slot="collapsible" {...props} />
5
9
  }
@@ -11,6 +11,10 @@ import {
11
11
  } from "@monkey-mini-app/ui/components/input-group"
12
12
  import { ChevronDownIcon, XIcon, CheckIcon } from "lucide-react"
13
13
 
14
+ /**
15
+ * @family Form
16
+ * @when When you need full control of the popover list. Simple suggestion box → `Autocomplete`.
17
+ */
14
18
  const Combobox = ComboboxPrimitive.Root
15
19
 
16
20
  function ComboboxValue({ ...props }: ComboboxPrimitive.Value.Props) {
@@ -17,6 +17,12 @@ import {
17
17
  } from "@monkey-mini-app/ui/components/input-group"
18
18
  import { SearchIcon, CheckIcon } from "lucide-react"
19
19
 
20
+ /**
21
+ * @family Navigation
22
+ * @when Jump between views/actions inside one app.
23
+ * @example
24
+ * <CommandDialog open={open} onOpenChange={setOpen}><CommandInput placeholder="跳转…" /><CommandList><CommandItem onSelect={go}>今日</CommandItem></CommandList></CommandDialog>
25
+ */
20
26
  function Command({
21
27
  className,
22
28
  ...props
@@ -6,6 +6,10 @@ import { ContextMenu as ContextMenuPrimitive } from "@base-ui/react/context-menu
6
6
  import { cn } from "@monkey-mini-app/ui/lib/utils"
7
7
  import { ChevronRightIcon, CheckIcon } from "lucide-react"
8
8
 
9
+ /**
10
+ * @family Navigation
11
+ * @when Row/canvas operations. Trigger-button actions → `DropdownMenu`.
12
+ */
9
13
  function ContextMenu({ ...props }: ContextMenuPrimitive.Root.Props) {
10
14
  return <ContextMenuPrimitive.Root data-slot="context-menu" {...props} />
11
15
  }
@@ -5,6 +5,13 @@ import { cn } from "@monkey-mini-app/ui/lib/utils"
5
5
  import { Button } from "@monkey-mini-app/ui/components/button"
6
6
  import { XIcon } from "lucide-react"
7
7
 
8
+ /**
9
+ * Modal overlay: Trigger + Content(+Header/Footer).
10
+ * @when Focused edit/confirm flow. Needs no focus takeover → `Sheet`. Destructive yes/no → `ConfirmDialog`. Size it with `width` on `DialogContent`: the base caps at `sm:max-w-sm`, so a `max-w-*` in `className` loses at ≥sm.
11
+ * @example
12
+ * <Dialog open={open} onOpenChange={setOpen}><DialogTrigger asChild><Button>编辑</Button></DialogTrigger><DialogContent><DialogHeader><DialogTitle>标题</DialogTitle></DialogHeader>…<DialogFooter><Button onClick={save}>保存</Button></DialogFooter></DialogContent></Dialog>
13
+ * @family Surface
14
+ */
8
15
  function Dialog({ ...props }: DialogPrimitive.Root.Props) {
9
16
  return <DialogPrimitive.Root data-slot="dialog" {...props} />
10
17
  }
@@ -41,15 +48,29 @@ function DialogContent({
41
48
  className,
42
49
  children,
43
50
  showCloseButton = true,
51
+ width,
52
+ style,
44
53
  ...props
45
54
  }: DialogPrimitive.Popup.Props & {
46
55
  showCloseButton?: boolean
56
+ /**
57
+ * Dialog width — a number is px. Inline `maxWidth`, because the base class caps the dialog at
58
+ * `sm:max-w-sm` and that utility outranks one the caller passes in `className`.
59
+ */
60
+ width?: string | number
47
61
  }) {
62
+ const maxWidth =
63
+ width == null
64
+ ? undefined
65
+ : typeof width === "number"
66
+ ? `${width}px`
67
+ : width
48
68
  return (
49
69
  <DialogPortal>
50
70
  <DialogOverlay />
51
71
  <DialogPrimitive.Popup
52
72
  data-slot="dialog-content"
73
+ style={maxWidth == null ? style : { ...style, maxWidth }}
53
74
  className={cn(
54
75
  "fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl bg-popover p-4 text-sm text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
55
76
  className
@@ -22,6 +22,10 @@ function useDrawer() {
22
22
  return context
23
23
  }
24
24
 
25
+ /**
26
+ * @family Surface
27
+ * @when Mobile-ish bottom sheet on narrow panels. Desktop detail → `Sheet`.
28
+ */
25
29
  function Drawer({
26
30
  modal = true,
27
31
  showSwipeHandle = false,
@@ -6,6 +6,13 @@ import { Menu as MenuPrimitive } from "@base-ui/react/menu"
6
6
  import { cn } from "@monkey-mini-app/ui/lib/utils"
7
7
  import { ChevronRightIcon, CheckIcon } from "lucide-react"
8
8
 
9
+ /**
10
+ * Command menu on a trigger.
11
+ * @when Row `MoreHorizontal` actions. Free-form panel content → `Popover`.
12
+ * @example
13
+ * <DropdownMenu><DropdownMenuTrigger asChild><Button><Icon.MoreHorizontal /></Button></DropdownMenuTrigger><DropdownMenuContent><DropdownMenuItem onClick={edit}>编辑</DropdownMenuItem></DropdownMenuContent></DropdownMenu>
14
+ * @family Navigation
15
+ */
9
16
  function DropdownMenu({ ...props }: MenuPrimitive.Root.Props) {
10
17
  return <MenuPrimitive.Root data-slot="dropdown-menu" {...props} />
11
18
  }
@@ -2,6 +2,13 @@ import { cva, type VariantProps } from "class-variance-authority"
2
2
 
3
3
  import { cn } from "@monkey-mini-app/ui/lib/utils"
4
4
 
5
+ /**
6
+ * Empty-state block: media + title + description + action.
7
+ * @when Any list/panel with no rows — pair media with an `Illu*`.
8
+ * @example
9
+ * <Empty><EmptyHeader><EmptyMedia variant="icon"><IlluEmpty /></EmptyMedia><EmptyTitle>还没有数据</EmptyTitle><EmptyDescription>点右上角添加</EmptyDescription></EmptyHeader></Empty>
10
+ * @family Feedback & status
11
+ */
5
12
  function Empty({
6
13
  className,
7
14
  title,
@@ -67,6 +67,12 @@ const fieldVariants = cva(
67
67
  }
68
68
  )
69
69
 
70
+ /**
71
+ * @family Form
72
+ * @when Any form row that must read well and stay accessible.
73
+ * @example
74
+ * <Field><FieldLabel htmlFor="n">名称</FieldLabel><Input id="n" /><FieldDescription>显示在列表里</FieldDescription></Field>
75
+ */
70
76
  function Field({
71
77
  className,
72
78
  orientation = "vertical",
@@ -2,6 +2,10 @@ import { PreviewCard as PreviewCardPrimitive } from "@base-ui/react/preview-card
2
2
 
3
3
  import { cn } from "@monkey-mini-app/ui/lib/utils"
4
4
 
5
+ /**
6
+ * @family Surface
7
+ * @when Peek a user/issue without navigating. Needs a decision → `Dialog`.
8
+ */
5
9
  function HoverCard({ ...props }: PreviewCardPrimitive.Root.Props) {
6
10
  return <PreviewCardPrimitive.Root data-slot="hover-card" {...props} />
7
11
  }