@twoux/ui 0.0.0-stage → 0.1.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/LICENSE.md +61 -0
- package/LICENSES/Apache-2.0.txt +202 -0
- package/NOTICE.md +64 -0
- package/SHADCN-DIFF.md +228 -0
- package/agent/AGENTS.md +358 -0
- package/agent/docs-md/accessibility.md +49 -0
- package/agent/docs-md/action-catalogue.md +81 -0
- package/agent/docs-md/actions.md +74 -0
- package/agent/docs-md/agent-activity-log.md +70 -0
- package/agent/docs-md/agent-permissions.md +82 -0
- package/agent/docs-md/agent-run.md +90 -0
- package/agent/docs-md/agents-on-behalf.md +74 -0
- package/agent/docs-md/ai-column.md +85 -0
- package/agent/docs-md/ai-origin-label.md +70 -0
- package/agent/docs-md/announcing-features.md +73 -0
- package/agent/docs-md/answer-actions.md +81 -0
- package/agent/docs-md/app-shell.md +114 -0
- package/agent/docs-md/artifact-card.md +89 -0
- package/agent/docs-md/ask-on-screen.md +72 -0
- package/agent/docs-md/assistant-page.md +100 -0
- package/agent/docs-md/assistant-panel.md +142 -0
- package/agent/docs-md/avatar.md +82 -0
- package/agent/docs-md/banner.md +106 -0
- package/agent/docs-md/board.md +163 -0
- package/agent/docs-md/breadcrumb.md +89 -0
- package/agent/docs-md/breakdown-table.md +97 -0
- package/agent/docs-md/bulk-action-bar.md +112 -0
- package/agent/docs-md/button.md +293 -0
- package/agent/docs-md/card.md +115 -0
- package/agent/docs-md/change-list.md +99 -0
- package/agent/docs-md/change-request.md +166 -0
- package/agent/docs-md/chart-area.md +87 -0
- package/agent/docs-md/chart-bar.md +100 -0
- package/agent/docs-md/chart-box-plot.md +88 -0
- package/agent/docs-md/chart-bullet.md +89 -0
- package/agent/docs-md/chart-candlestick.md +112 -0
- package/agent/docs-md/chart-card-line.md +120 -0
- package/agent/docs-md/chart-donut.md +90 -0
- package/agent/docs-md/chart-drill-down.md +72 -0
- package/agent/docs-md/chart-funnel.md +71 -0
- package/agent/docs-md/chart-heatmap.md +76 -0
- package/agent/docs-md/chart-histogram.md +81 -0
- package/agent/docs-md/chart-map.md +165 -0
- package/agent/docs-md/chart-mixed.md +88 -0
- package/agent/docs-md/chart-price.md +92 -0
- package/agent/docs-md/chart-radial-bars.md +109 -0
- package/agent/docs-md/chart-radial-lines.md +111 -0
- package/agent/docs-md/chart-sankey.md +104 -0
- package/agent/docs-md/chart-scatter.md +87 -0
- package/agent/docs-md/chart-share-bar.md +89 -0
- package/agent/docs-md/chart-treemap.md +98 -0
- package/agent/docs-md/chart-waterfall.md +93 -0
- package/agent/docs-md/checkbox.md +131 -0
- package/agent/docs-md/choosing-selection-control.md +71 -0
- package/agent/docs-md/citations-sources.md +79 -0
- package/agent/docs-md/citing-sources.md +63 -0
- package/agent/docs-md/clarify-before-acting.md +69 -0
- package/agent/docs-md/clarifying-question.md +92 -0
- package/agent/docs-md/code-block.md +174 -0
- package/agent/docs-md/colours.md +87 -0
- package/agent/docs-md/columns-menu.md +140 -0
- package/agent/docs-md/combobox.md +161 -0
- package/agent/docs-md/command-palette.md +126 -0
- package/agent/docs-md/confidence-note.md +87 -0
- package/agent/docs-md/configurable-dashboard.md +76 -0
- package/agent/docs-md/confirmation-dialog.md +93 -0
- package/agent/docs-md/connected-tools.md +80 -0
- package/agent/docs-md/connector-picker.md +127 -0
- package/agent/docs-md/consistency.md +53 -0
- package/agent/docs-md/content-density.md +61 -0
- package/agent/docs-md/conversation-history.md +78 -0
- package/agent/docs-md/create-record.md +80 -0
- package/agent/docs-md/csv-import.md +88 -0
- package/agent/docs-md/dashboard-items.md +78 -0
- package/agent/docs-md/data-export.md +61 -0
- package/agent/docs-md/data-grid.md +137 -0
- package/agent/docs-md/data-vis-colours.md +76 -0
- package/agent/docs-md/data-visualisation.md +76 -0
- package/agent/docs-md/date-picker.md +178 -0
- package/agent/docs-md/delete-record.md +75 -0
- package/agent/docs-md/dense-table.md +495 -0
- package/agent/docs-md/design-tokens.md +53 -0
- package/agent/docs-md/disabled-read-only.md +75 -0
- package/agent/docs-md/drag-and-drop.md +74 -0
- package/agent/docs-md/dropdown-menu.md +137 -0
- package/agent/docs-md/edit-record.md +73 -0
- package/agent/docs-md/empty-loading-error.md +78 -0
- package/agent/docs-md/empty-state.md +128 -0
- package/agent/docs-md/error-messages.md +75 -0
- package/agent/docs-md/error-state.md +123 -0
- package/agent/docs-md/export-menu.md +86 -0
- package/agent/docs-md/feedback-prompt.md +88 -0
- package/agent/docs-md/field-mapping.md +78 -0
- package/agent/docs-md/file-drop.md +110 -0
- package/agent/docs-md/filter-bar.md +138 -0
- package/agent/docs-md/filter-panel.md +103 -0
- package/agent/docs-md/filtering-search.md +79 -0
- package/agent/docs-md/follow-ups-starters.md +79 -0
- package/agent/docs-md/form-validation.md +95 -0
- package/agent/docs-md/generated-columns.md +65 -0
- package/agent/docs-md/generated-drafts-files.md +71 -0
- package/agent/docs-md/grouped-list.md +89 -0
- package/agent/docs-md/guide-cue.md +170 -0
- package/agent/docs-md/help-panel.md +103 -0
- package/agent/docs-md/help-system.md +74 -0
- package/agent/docs-md/iconography.md +49 -0
- package/agent/docs-md/inbox.md +108 -0
- package/agent/docs-md/inline-editing-validation.md +80 -0
- package/agent/docs-md/inline-input-in-answer.md +70 -0
- package/agent/docs-md/items-palette.md +116 -0
- package/agent/docs-md/keyboard-model.md +47 -0
- package/agent/docs-md/keyboard-navigation.md +68 -0
- package/agent/docs-md/keyboard-shortcut-hint.md +87 -0
- package/agent/docs-md/keyboard-shortcut-sheet.md +90 -0
- package/agent/docs-md/labelling-ai-output.md +66 -0
- package/agent/docs-md/layout.md +47 -0
- package/agent/docs-md/list-table.md +254 -0
- package/agent/docs-md/loading-skeleton.md +91 -0
- package/agent/docs-md/managing-agents.md +71 -0
- package/agent/docs-md/message-composer.md +105 -0
- package/agent/docs-md/migrating.md +49 -0
- package/agent/docs-md/motion.md +93 -0
- package/agent/docs-md/navigation.md +76 -0
- package/agent/docs-md/notification-channels.md +65 -0
- package/agent/docs-md/notifications-decision.md +100 -0
- package/agent/docs-md/onboarding-step.md +114 -0
- package/agent/docs-md/order-book.md +108 -0
- package/agent/docs-md/page-header.md +96 -0
- package/agent/docs-md/pagination.md +88 -0
- package/agent/docs-md/pane-layout.md +105 -0
- package/agent/docs-md/period-comparison.md +66 -0
- package/agent/docs-md/plan-card.md +120 -0
- package/agent/docs-md/popover-rules.md +88 -0
- package/agent/docs-md/prompt-editor.md +90 -0
- package/agent/docs-md/propose-apply.md +65 -0
- package/agent/docs-md/provider-logo.md +97 -0
- package/agent/docs-md/radio.md +83 -0
- package/agent/docs-md/ranked-list.md +102 -0
- package/agent/docs-md/reasoning-progress.md +72 -0
- package/agent/docs-md/record-detail.md +71 -0
- package/agent/docs-md/regenerating-answers.md +70 -0
- package/agent/docs-md/run-status-bar.md +94 -0
- package/agent/docs-md/saved-tasks-schedules.md +63 -0
- package/agent/docs-md/saved-views.md +149 -0
- package/agent/docs-md/saving-views.md +68 -0
- package/agent/docs-md/scheduler.md +258 -0
- package/agent/docs-md/secondary-panels.md +72 -0
- package/agent/docs-md/segmented-control.md +88 -0
- package/agent/docs-md/selection-bulk-actions.md +70 -0
- package/agent/docs-md/separator.md +75 -0
- package/agent/docs-md/setup-checklist.md +92 -0
- package/agent/docs-md/shape-elevation.md +55 -0
- package/agent/docs-md/sheet-grid.md +211 -0
- package/agent/docs-md/side-panel.md +134 -0
- package/agent/docs-md/sign-in.md +114 -0
- package/agent/docs-md/spacing.md +55 -0
- package/agent/docs-md/split-button.md +100 -0
- package/agent/docs-md/stat-compare.md +82 -0
- package/agent/docs-md/static-dashboard.md +75 -0
- package/agent/docs-md/status-badge.md +140 -0
- package/agent/docs-md/step-card.md +75 -0
- package/agent/docs-md/stepper.md +92 -0
- package/agent/docs-md/suggested-changes.md +91 -0
- package/agent/docs-md/switch.md +78 -0
- package/agent/docs-md/table-settings.md +81 -0
- package/agent/docs-md/tabs.md +85 -0
- package/agent/docs-md/tag-input.md +108 -0
- package/agent/docs-md/tag.md +79 -0
- package/agent/docs-md/task-builder.md +87 -0
- package/agent/docs-md/team-instructions.md +72 -0
- package/agent/docs-md/templates-gallery.md +85 -0
- package/agent/docs-md/text-input.md +160 -0
- package/agent/docs-md/thinking-steps.md +89 -0
- package/agent/docs-md/timeline.md +189 -0
- package/agent/docs-md/timestamp.md +84 -0
- package/agent/docs-md/timestamps.md +70 -0
- package/agent/docs-md/toast.md +117 -0
- package/agent/docs-md/tooltip.md +90 -0
- package/agent/docs-md/typography.md +62 -0
- package/agent/docs-md/undo-destructive.md +66 -0
- package/agent/docs-md/unsaved-changes.md +71 -0
- package/agent/docs-md/usage-meter.md +80 -0
- package/agent/docs-md/user-feedback.md +71 -0
- package/agent/docs-md/voice-and-tone.md +60 -0
- package/agent/docs-md/why-choice.md +93 -0
- package/agent/docs-md/workspace-onboarding.md +74 -0
- package/agent/docs-md/writing.md +48 -0
- package/agent/llms-full.txt +18369 -0
- package/agent/llms.txt +198 -0
- package/agent/skills/twoux-audit/SKILL.md +49 -0
- package/agent/skills/twoux-build/SKILL.md +39 -0
- package/agent/skills/twoux-design/SKILL.md +54 -0
- package/agent/skills/twoux-write/SKILL.md +32 -0
- package/bin/check.mjs +123 -0
- package/bin/docs.mjs +24 -0
- package/bin/guard.mjs +27 -0
- package/bin/init.mjs +113 -0
- package/bin/knowledge.mjs +87 -0
- package/bin/mcp.mjs +116 -0
- package/bin/theme.mjs +168 -0
- package/bin/twoux.mjs +25 -0
- package/package.json +80 -3
- package/registry/jobs.json +1028 -0
- package/registry/palette.json +770 -0
- package/registry/rules.json +913 -0
- package/src/components/agent-review.tsx +364 -0
- package/src/components/ai-basics.tsx +212 -0
- package/src/components/ai-work.tsx +304 -0
- package/src/components/ai.tsx +227 -0
- package/src/components/alert-dialog.tsx +203 -0
- package/src/components/alert.tsx +86 -0
- package/src/components/avatar.tsx +114 -0
- package/src/components/badge.tsx +59 -0
- package/src/components/board.tsx +397 -0
- package/src/components/breadcrumb.tsx +114 -0
- package/src/components/button-group.tsx +90 -0
- package/src/components/button.tsx +109 -0
- package/src/components/calendar.tsx +247 -0
- package/src/components/card.tsx +102 -0
- package/src/components/chart-map.tsx +336 -0
- package/src/components/charts-more.tsx +1331 -0
- package/src/components/charts-radial.tsx +328 -0
- package/src/components/charts.tsx +390 -0
- package/src/components/checkbox.tsx +40 -0
- package/src/components/code.tsx +139 -0
- package/src/components/collapsible.tsx +37 -0
- package/src/components/combobox.tsx +339 -0
- package/src/components/command-extras.tsx +11 -0
- package/src/components/command.tsx +196 -0
- package/src/components/data-grid.tsx +213 -0
- package/src/components/data-table.tsx +334 -0
- package/src/components/data-views.tsx +740 -0
- package/src/components/date-picker.tsx +686 -0
- package/src/components/dense-table.tsx +207 -0
- package/src/components/dialog.tsx +162 -0
- package/src/components/dropdown-menu.tsx +264 -0
- package/src/components/empty.tsx +114 -0
- package/src/components/feedback-prompt.tsx +80 -0
- package/src/components/field.tsx +254 -0
- package/src/components/fields.tsx +112 -0
- package/src/components/flow.tsx +840 -0
- package/src/components/guide-cue.tsx +273 -0
- package/src/components/inbox.tsx +113 -0
- package/src/components/input-group.tsx +176 -0
- package/src/components/input.tsx +26 -0
- package/src/components/kbd.tsx +34 -0
- package/src/components/label.tsx +27 -0
- package/src/components/labels.tsx +176 -0
- package/src/components/motion.tsx +136 -0
- package/src/components/onboarding.tsx +454 -0
- package/src/components/order-book.tsx +185 -0
- package/src/components/pane-layout.tsx +417 -0
- package/src/components/popover.tsx +96 -0
- package/src/components/provider-logos.data.ts +49 -0
- package/src/components/radio-group.tsx +52 -0
- package/src/components/scheduler.tsx +997 -0
- package/src/components/segmented-control.tsx +28 -0
- package/src/components/select.tsx +195 -0
- package/src/components/separator.tsx +31 -0
- package/src/components/sheet.tsx +148 -0
- package/src/components/shell.tsx +426 -0
- package/src/components/shortcut-sheet.tsx +83 -0
- package/src/components/skeleton.tsx +18 -0
- package/src/components/sonner.tsx +107 -0
- package/src/components/spinner.tsx +13 -0
- package/src/components/split-button.tsx +58 -0
- package/src/components/stepper.tsx +78 -0
- package/src/components/switch.tsx +43 -0
- package/src/components/table.tsx +126 -0
- package/src/components/tabs.tsx +118 -0
- package/src/components/tag-input.tsx +253 -0
- package/src/components/textarea.tsx +21 -0
- package/src/components/theme.tsx +80 -0
- package/src/components/timeline.tsx +408 -0
- package/src/components/toggle-group.tsx +87 -0
- package/src/components/toggle.tsx +54 -0
- package/src/components/tooltip.tsx +65 -0
- package/src/components/workspace-actions.tsx +294 -0
- package/src/components/workspace-import.tsx +465 -0
- package/src/components/workspace.tsx +1884 -0
- package/src/index.ts +80 -0
- package/src/lib/active-indicator.tsx +53 -0
- package/src/lib/chart-kit.tsx +72 -0
- package/src/lib/cn.ts +6 -0
- package/src/lib/shortcuts.tsx +61 -0
- package/src/lib/workspace.tsx +10 -0
- package/src/shadcn/alert-dialog.tsx +196 -0
- package/src/shadcn/alert.tsx +65 -0
- package/src/shadcn/avatar.tsx +108 -0
- package/src/shadcn/badge.tsx +47 -0
- package/src/shadcn/breadcrumb.tsx +108 -0
- package/src/shadcn/button-group.tsx +83 -0
- package/src/shadcn/button.tsx +63 -0
- package/src/shadcn/calendar.tsx +220 -0
- package/src/shadcn/card.tsx +91 -0
- package/src/shadcn/checkbox.tsx +31 -0
- package/src/shadcn/collapsible.tsx +33 -0
- package/src/shadcn/command.tsx +184 -0
- package/src/shadcn/dialog.tsx +158 -0
- package/src/shadcn/dropdown-menu.tsx +256 -0
- package/src/shadcn/empty.tsx +103 -0
- package/src/shadcn/field.tsx +248 -0
- package/src/shadcn/input-group.tsx +170 -0
- package/src/shadcn/input.tsx +20 -0
- package/src/shadcn/kbd.tsx +28 -0
- package/src/shadcn/label.tsx +23 -0
- package/src/shadcn/popover.tsx +88 -0
- package/src/shadcn/radio-group.tsx +44 -0
- package/src/shadcn/select.tsx +189 -0
- package/src/shadcn/separator.tsx +27 -0
- package/src/shadcn/sheet.tsx +142 -0
- package/src/shadcn/skeleton.tsx +13 -0
- package/src/shadcn/sonner.tsx +40 -0
- package/src/shadcn/switch.tsx +34 -0
- package/src/shadcn/table.tsx +115 -0
- package/src/shadcn/tabs.tsx +90 -0
- package/src/shadcn/textarea.tsx +17 -0
- package/src/shadcn/toggle-group.tsx +83 -0
- package/src/shadcn/toggle.tsx +46 -0
- package/src/shadcn/tooltip.tsx +56 -0
- package/src/styles/palette.css +127 -0
- package/src/styles/theme.css +35 -0
- package/src/styles/twoux.css +236 -0
- package/theme.json +14 -0
- package/README.md +0 -3
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TwoUX compositions for the dense Table (size="dense", 28px rows) used for spreadsheet-like data: inventories,
|
|
3
|
+
* ledgers, imports and mapping. Built on the generated shadcn Table, Button, Input, DropdownMenu and Tooltip.
|
|
4
|
+
* TableGroupRow: a full-width section row with its label, an optional info tooltip and count, optionally collapsible.
|
|
5
|
+
* TableRowNumber: the row number with a ⋮ menu of row actions, named "Actions for <row>".
|
|
6
|
+
* TableFilterRow: one compact search field under each filterable header, named "Filter <column>".
|
|
7
|
+
* TableCellAction: an in-cell button revealed on row hover and keyboard focus, always shown on touch. Its action is
|
|
8
|
+
* always in the row menu too, so it is never the only way.
|
|
9
|
+
* TableNotApplicable and TableLinkedItems: "n/a" read as "not applicable", and two items joined by an arrow.
|
|
10
|
+
*/
|
|
11
|
+
import { ArrowRight, ChevronRight, EllipsisVertical, Info, Search } from "lucide-react"
|
|
12
|
+
import * as React from "react"
|
|
13
|
+
import { cn } from "../lib/cn"
|
|
14
|
+
import { Button } from "./button"
|
|
15
|
+
import { DropdownMenu, DropdownMenuContent, DropdownMenuTrigger } from "./dropdown-menu"
|
|
16
|
+
import { TableCell, TableRow } from "./table"
|
|
17
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from "./tooltip"
|
|
18
|
+
|
|
19
|
+
/* ---------------------------------------------------------------- group row */
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Put each group in its own TableBody with this row first. With onExpandedChange the label becomes a button with
|
|
23
|
+
* aria-expanded; leave the group's rows out while it is collapsed.
|
|
24
|
+
*/
|
|
25
|
+
export function TableGroupRow({
|
|
26
|
+
label,
|
|
27
|
+
info,
|
|
28
|
+
count,
|
|
29
|
+
colSpan,
|
|
30
|
+
expanded,
|
|
31
|
+
onExpandedChange,
|
|
32
|
+
controls,
|
|
33
|
+
children,
|
|
34
|
+
className,
|
|
35
|
+
}: {
|
|
36
|
+
label: string
|
|
37
|
+
/** What belongs in the group, in a tooltip on the info button. */
|
|
38
|
+
info?: React.ReactNode
|
|
39
|
+
count?: number
|
|
40
|
+
/** The number of columns in the table. */
|
|
41
|
+
colSpan: number
|
|
42
|
+
expanded?: boolean
|
|
43
|
+
onExpandedChange?: (expanded: boolean) => void
|
|
44
|
+
/** id of the TableBody the row opens and closes. */
|
|
45
|
+
controls?: string
|
|
46
|
+
/** Extra content on the right of the row, such as a group total. */
|
|
47
|
+
children?: React.ReactNode
|
|
48
|
+
className?: string
|
|
49
|
+
}) {
|
|
50
|
+
const collapsible = !!onExpandedChange
|
|
51
|
+
const open = expanded ?? true
|
|
52
|
+
const name = (
|
|
53
|
+
<>
|
|
54
|
+
{collapsible && <ChevronRight aria-hidden="true" className={cn("size-3.5 shrink-0 text-ink-3 transition-transform duration-(--duration-fast) ease-(--ease-out)", open && "rotate-90")} />}
|
|
55
|
+
<span className="truncate font-medium text-ink">{label}</span>
|
|
56
|
+
{count !== undefined && <span className="tabular shrink-0 text-sm font-normal text-ink-3">{count.toLocaleString("en-GB")}<span className="sr-only"> rows</span></span>}
|
|
57
|
+
</>
|
|
58
|
+
)
|
|
59
|
+
return (
|
|
60
|
+
<TableRow data-slot="table-group-row" className={cn("bg-surface-2 hover:bg-surface-2", className)}>
|
|
61
|
+
<th scope="rowgroup" colSpan={colSpan} className="h-9 p-0 text-left align-middle text-base font-normal group-data-[size=dense]/table:h-7">
|
|
62
|
+
<div className="sticky left-0 flex w-fit max-w-full items-center gap-control px-3 group-data-[size=dense]/table:px-2">
|
|
63
|
+
{collapsible ? (
|
|
64
|
+
<button
|
|
65
|
+
type="button"
|
|
66
|
+
aria-expanded={open}
|
|
67
|
+
aria-controls={controls}
|
|
68
|
+
onClick={() => onExpandedChange?.(!open)}
|
|
69
|
+
className="-ml-1 flex min-w-0 items-center gap-control rounded-xs px-1 outline-none hover:bg-hover focus-visible:ring-2 focus-visible:ring-ring/50"
|
|
70
|
+
>
|
|
71
|
+
{name}
|
|
72
|
+
</button>
|
|
73
|
+
) : name}
|
|
74
|
+
{info && (
|
|
75
|
+
<Tooltip>
|
|
76
|
+
<TooltipTrigger asChild>
|
|
77
|
+
<button type="button" aria-label={`About ${label}`} className="relative grid size-5 shrink-0 place-items-center rounded-xs text-ink-3 outline-none after:absolute after:-inset-0.5 hover:bg-hover hover:text-ink focus-visible:ring-2 focus-visible:ring-ring/50">
|
|
78
|
+
<Info className="size-3.5" aria-hidden="true" />
|
|
79
|
+
</button>
|
|
80
|
+
</TooltipTrigger>
|
|
81
|
+
<TooltipContent className="max-w-64">{info}</TooltipContent>
|
|
82
|
+
</Tooltip>
|
|
83
|
+
)}
|
|
84
|
+
{children}
|
|
85
|
+
</div>
|
|
86
|
+
</th>
|
|
87
|
+
</TableRow>
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* ---------------------------------------------------------------- row number + row actions */
|
|
92
|
+
|
|
93
|
+
/** The first cell of a row: its number, then ⋮ with the row's actions (DropdownMenuItem children). */
|
|
94
|
+
export function TableRowNumber({
|
|
95
|
+
n,
|
|
96
|
+
label,
|
|
97
|
+
children,
|
|
98
|
+
className,
|
|
99
|
+
...props
|
|
100
|
+
}: Omit<React.ComponentProps<typeof TableCell>, "children"> & {
|
|
101
|
+
n: number
|
|
102
|
+
/** Names the row in the menu button: "Actions for <label>". */
|
|
103
|
+
label: string
|
|
104
|
+
/** The row's actions. Include every in-cell action here too. */
|
|
105
|
+
children: React.ReactNode
|
|
106
|
+
}) {
|
|
107
|
+
return (
|
|
108
|
+
<TableCell data-slot="table-row-number" className={cn("w-16 pr-1 text-sm text-ink-3 group-data-[size=dense]/table:pr-0.5", className)} {...props}>
|
|
109
|
+
<span className="flex items-center justify-between gap-1">
|
|
110
|
+
<span className="tabular">{n.toLocaleString("en-GB")}</span>
|
|
111
|
+
<DropdownMenu>
|
|
112
|
+
<DropdownMenuTrigger asChild>
|
|
113
|
+
<Button variant="ghost" size="icon-xs" aria-label={`Actions for ${label}`} className="size-5 text-ink-3 hover:text-ink data-[state=open]:bg-hover data-[state=open]:text-ink">
|
|
114
|
+
<EllipsisVertical />
|
|
115
|
+
</Button>
|
|
116
|
+
</DropdownMenuTrigger>
|
|
117
|
+
<DropdownMenuContent align="start" className="w-52">{children}</DropdownMenuContent>
|
|
118
|
+
</DropdownMenu>
|
|
119
|
+
</span>
|
|
120
|
+
</TableCell>
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/* ---------------------------------------------------------------- filter row */
|
|
125
|
+
|
|
126
|
+
export type TableFilterColumn = { id: string; label: string; align?: "left" | "right" } | null
|
|
127
|
+
|
|
128
|
+
/** Goes in TableHeader under the header row. Pass null for a column with no filter (selection, row number, actions). */
|
|
129
|
+
export function TableFilterRow({
|
|
130
|
+
columns,
|
|
131
|
+
values,
|
|
132
|
+
onChange,
|
|
133
|
+
className,
|
|
134
|
+
}: {
|
|
135
|
+
columns: TableFilterColumn[]
|
|
136
|
+
values: Record<string, string>
|
|
137
|
+
onChange: (columnId: string, value: string) => void
|
|
138
|
+
className?: string
|
|
139
|
+
}) {
|
|
140
|
+
return (
|
|
141
|
+
<TableRow data-slot="table-filter-row" className={cn("bg-surface hover:bg-surface", className)}>
|
|
142
|
+
{columns.map((c, i) => (
|
|
143
|
+
<TableCell key={c?.id ?? `none-${i}`} className="px-1 group-data-[size=dense]/table:px-1">
|
|
144
|
+
{c && (
|
|
145
|
+
<span className="relative block">
|
|
146
|
+
<Search aria-hidden="true" className="pointer-events-none absolute top-1/2 left-1.5 size-3 -translate-y-1/2 text-ink-3" />
|
|
147
|
+
<input
|
|
148
|
+
type="search"
|
|
149
|
+
value={values[c.id] ?? ""}
|
|
150
|
+
onChange={(e) => onChange(c.id, e.target.value)}
|
|
151
|
+
onKeyDown={(e) => { if (e.key === "Escape" && values[c.id]) { e.preventDefault(); e.stopPropagation(); onChange(c.id, "") } }}
|
|
152
|
+
placeholder="Search"
|
|
153
|
+
aria-label={`Filter ${c.label}`}
|
|
154
|
+
className={cn(
|
|
155
|
+
"h-7 w-full min-w-0 rounded-xs border border-input bg-background pr-2 pl-5.5 text-sm text-ink outline-none placeholder:text-ink-3 hover:border-input-hover focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/50 group-data-[size=dense]/table:h-5.5 [&::-webkit-search-cancel-button]:hidden",
|
|
156
|
+
c.align === "right" && "text-right",
|
|
157
|
+
values[c.id] && "border-primary"
|
|
158
|
+
)}
|
|
159
|
+
/>
|
|
160
|
+
</span>
|
|
161
|
+
)}
|
|
162
|
+
</TableCell>
|
|
163
|
+
))}
|
|
164
|
+
</TableRow>
|
|
165
|
+
)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/* ---------------------------------------------------------------- in-cell action */
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* A quiet button inside a cell, such as Open or Share, revealed while the row is hovered or has keyboard focus and
|
|
172
|
+
* always shown on touch screens. aria-label names the row ("Open Magnet preparation"). Put the same action in the
|
|
173
|
+
* row's ⋮ menu: an in-cell button is a shortcut, never the only way.
|
|
174
|
+
*/
|
|
175
|
+
export function TableCellAction({ className, ...props }: React.ComponentProps<typeof Button> & { "aria-label": string }) {
|
|
176
|
+
return (
|
|
177
|
+
<Button
|
|
178
|
+
data-slot="table-cell-action"
|
|
179
|
+
variant="outline"
|
|
180
|
+
size="xs"
|
|
181
|
+
className={cn(
|
|
182
|
+
"h-5 shrink-0 px-control opacity-0 transition-opacity duration-(--duration-fast) ease-(--ease-out) focus-visible:opacity-100 pointer-coarse:opacity-100 in-[tr:hover]:opacity-100 in-[tr:focus-within]:opacity-100 in-data-[focused=true]:opacity-100",
|
|
183
|
+
className
|
|
184
|
+
)}
|
|
185
|
+
{...props}
|
|
186
|
+
/>
|
|
187
|
+
)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/* ---------------------------------------------------------------- small cell contents */
|
|
191
|
+
|
|
192
|
+
/** "n/a" for a value that doesn't apply to this row, read as "not applicable". Not the same as empty (a dash). */
|
|
193
|
+
export function TableNotApplicable({ className }: { className?: string }) {
|
|
194
|
+
return <span aria-label="not applicable" className={cn("text-sm text-ink-3", className)}>n/a</span>
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/** Two linked items, such as a process and what it makes: "Magnet preparation → NdFeB magnet powder". */
|
|
198
|
+
export function TableLinkedItems({ from, to, className }: { from: React.ReactNode; to: React.ReactNode; className?: string }) {
|
|
199
|
+
return (
|
|
200
|
+
<span className={cn("flex min-w-0 items-center gap-control", className)}>
|
|
201
|
+
<span className="min-w-0 truncate">{from}</span>
|
|
202
|
+
<ArrowRight className="size-3 shrink-0 text-ink-3" aria-hidden="true" />
|
|
203
|
+
<span className="sr-only">to</span>
|
|
204
|
+
<span className="min-w-0 truncate text-ink-2">{to}</span>
|
|
205
|
+
</span>
|
|
206
|
+
)
|
|
207
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generated from shadcn/ui new-york-v4 "dialog" by scripts/tailor-shadcn.mjs. Do not edit by hand.
|
|
3
|
+
* TwoUX changes: shared changes only (imports, role tokens for light and dark, type scale).
|
|
4
|
+
*/
|
|
5
|
+
"use client"
|
|
6
|
+
|
|
7
|
+
import * as React from "react"
|
|
8
|
+
import { cn } from "../lib/cn"
|
|
9
|
+
import { XIcon } from "lucide-react"
|
|
10
|
+
import { Dialog as DialogPrimitive } from "radix-ui"
|
|
11
|
+
|
|
12
|
+
import { Button } from "./button"
|
|
13
|
+
|
|
14
|
+
function Dialog({
|
|
15
|
+
...props
|
|
16
|
+
}: React.ComponentProps<typeof DialogPrimitive.Root>) {
|
|
17
|
+
return <DialogPrimitive.Root data-slot="dialog" {...props} />
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function DialogTrigger({
|
|
21
|
+
...props
|
|
22
|
+
}: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
|
|
23
|
+
return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function DialogPortal({
|
|
27
|
+
...props
|
|
28
|
+
}: React.ComponentProps<typeof DialogPrimitive.Portal>) {
|
|
29
|
+
return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function DialogClose({
|
|
33
|
+
...props
|
|
34
|
+
}: React.ComponentProps<typeof DialogPrimitive.Close>) {
|
|
35
|
+
return <DialogPrimitive.Close data-slot="dialog-close" {...props} />
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function DialogOverlay({
|
|
39
|
+
className,
|
|
40
|
+
...props
|
|
41
|
+
}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
|
|
42
|
+
return (
|
|
43
|
+
<DialogPrimitive.Overlay
|
|
44
|
+
data-slot="dialog-overlay"
|
|
45
|
+
className={cn(
|
|
46
|
+
"fixed inset-0 z-50 bg-scrim data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0",
|
|
47
|
+
className
|
|
48
|
+
)}
|
|
49
|
+
{...props}
|
|
50
|
+
/>
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function DialogContent({
|
|
55
|
+
className,
|
|
56
|
+
children,
|
|
57
|
+
showCloseButton = true,
|
|
58
|
+
...props
|
|
59
|
+
}: React.ComponentProps<typeof DialogPrimitive.Content> & {
|
|
60
|
+
showCloseButton?: boolean
|
|
61
|
+
}) {
|
|
62
|
+
return (
|
|
63
|
+
<DialogPortal data-slot="dialog-portal">
|
|
64
|
+
<DialogOverlay />
|
|
65
|
+
<DialogPrimitive.Content
|
|
66
|
+
data-slot="dialog-content"
|
|
67
|
+
className={cn(
|
|
68
|
+
"fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-md border border-line bg-background p-5 shadow-pop duration-200 outline-none data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 sm:max-w-lg",
|
|
69
|
+
className
|
|
70
|
+
)}
|
|
71
|
+
{...props}
|
|
72
|
+
>
|
|
73
|
+
{children}
|
|
74
|
+
{showCloseButton && (
|
|
75
|
+
<DialogPrimitive.Close
|
|
76
|
+
data-slot="dialog-close"
|
|
77
|
+
className="absolute top-4 right-4 rounded-xs opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
|
|
78
|
+
>
|
|
79
|
+
<XIcon />
|
|
80
|
+
<span className="sr-only">Close</span>
|
|
81
|
+
</DialogPrimitive.Close>
|
|
82
|
+
)}
|
|
83
|
+
</DialogPrimitive.Content>
|
|
84
|
+
</DialogPortal>
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
|
|
89
|
+
return (
|
|
90
|
+
<div
|
|
91
|
+
data-slot="dialog-header"
|
|
92
|
+
className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
|
|
93
|
+
{...props}
|
|
94
|
+
/>
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function DialogFooter({
|
|
99
|
+
className,
|
|
100
|
+
showCloseButton = false,
|
|
101
|
+
children,
|
|
102
|
+
...props
|
|
103
|
+
}: React.ComponentProps<"div"> & {
|
|
104
|
+
showCloseButton?: boolean
|
|
105
|
+
}) {
|
|
106
|
+
return (
|
|
107
|
+
<div
|
|
108
|
+
data-slot="dialog-footer"
|
|
109
|
+
className={cn(
|
|
110
|
+
"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
|
|
111
|
+
className
|
|
112
|
+
)}
|
|
113
|
+
{...props}
|
|
114
|
+
>
|
|
115
|
+
{children}
|
|
116
|
+
{showCloseButton && (
|
|
117
|
+
<DialogPrimitive.Close asChild>
|
|
118
|
+
<Button variant="outline">Close</Button>
|
|
119
|
+
</DialogPrimitive.Close>
|
|
120
|
+
)}
|
|
121
|
+
</div>
|
|
122
|
+
)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function DialogTitle({
|
|
126
|
+
className,
|
|
127
|
+
...props
|
|
128
|
+
}: React.ComponentProps<typeof DialogPrimitive.Title>) {
|
|
129
|
+
return (
|
|
130
|
+
<DialogPrimitive.Title
|
|
131
|
+
data-slot="dialog-title"
|
|
132
|
+
className={cn("text-lg leading-none font-semibold", className)}
|
|
133
|
+
{...props}
|
|
134
|
+
/>
|
|
135
|
+
)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function DialogDescription({
|
|
139
|
+
className,
|
|
140
|
+
...props
|
|
141
|
+
}: React.ComponentProps<typeof DialogPrimitive.Description>) {
|
|
142
|
+
return (
|
|
143
|
+
<DialogPrimitive.Description
|
|
144
|
+
data-slot="dialog-description"
|
|
145
|
+
className={cn("text-base text-muted-foreground", className)}
|
|
146
|
+
{...props}
|
|
147
|
+
/>
|
|
148
|
+
)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export {
|
|
152
|
+
Dialog,
|
|
153
|
+
DialogClose,
|
|
154
|
+
DialogContent,
|
|
155
|
+
DialogDescription,
|
|
156
|
+
DialogFooter,
|
|
157
|
+
DialogHeader,
|
|
158
|
+
DialogOverlay,
|
|
159
|
+
DialogPortal,
|
|
160
|
+
DialogTitle,
|
|
161
|
+
DialogTrigger,
|
|
162
|
+
}
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generated from shadcn/ui new-york-v4 "dropdown-menu" by scripts/tailor-shadcn.mjs. Do not edit by hand.
|
|
3
|
+
* TwoUX changes:
|
|
4
|
+
* - Shortcut slot holds keys; no letter-spacing so Kbd groups read cleanly
|
|
5
|
+
* - Icons stay smaller than the 13px label and muted
|
|
6
|
+
* - Check and radio marks sit at the end of the item, so every label in a menu starts at the same edge
|
|
7
|
+
* - Group headings are smaller and muted, so they read as headings, not as items people can choose
|
|
8
|
+
*/
|
|
9
|
+
"use client"
|
|
10
|
+
|
|
11
|
+
import * as React from "react"
|
|
12
|
+
import { cn } from "../lib/cn"
|
|
13
|
+
import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"
|
|
14
|
+
import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui"
|
|
15
|
+
|
|
16
|
+
function DropdownMenu({
|
|
17
|
+
...props
|
|
18
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {
|
|
19
|
+
return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function DropdownMenuPortal({
|
|
23
|
+
...props
|
|
24
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {
|
|
25
|
+
return (
|
|
26
|
+
<DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function DropdownMenuTrigger({
|
|
31
|
+
...props
|
|
32
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {
|
|
33
|
+
return (
|
|
34
|
+
<DropdownMenuPrimitive.Trigger
|
|
35
|
+
data-slot="dropdown-menu-trigger"
|
|
36
|
+
{...props}
|
|
37
|
+
/>
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function DropdownMenuContent({
|
|
42
|
+
className,
|
|
43
|
+
sideOffset = 4,
|
|
44
|
+
...props
|
|
45
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {
|
|
46
|
+
return (
|
|
47
|
+
<DropdownMenuPrimitive.Portal>
|
|
48
|
+
<DropdownMenuPrimitive.Content
|
|
49
|
+
data-slot="dropdown-menu-content"
|
|
50
|
+
sideOffset={sideOffset}
|
|
51
|
+
className={cn(
|
|
52
|
+
"z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
|
|
53
|
+
className
|
|
54
|
+
)}
|
|
55
|
+
{...props}
|
|
56
|
+
/>
|
|
57
|
+
</DropdownMenuPrimitive.Portal>
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function DropdownMenuGroup({
|
|
62
|
+
...props
|
|
63
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {
|
|
64
|
+
return (
|
|
65
|
+
<DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function DropdownMenuItem({
|
|
70
|
+
className,
|
|
71
|
+
inset,
|
|
72
|
+
variant = "default",
|
|
73
|
+
...props
|
|
74
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
|
|
75
|
+
inset?: boolean
|
|
76
|
+
variant?: "default" | "destructive"
|
|
77
|
+
}) {
|
|
78
|
+
return (
|
|
79
|
+
<DropdownMenuPrimitive.Item
|
|
80
|
+
data-slot="dropdown-menu-item"
|
|
81
|
+
data-inset={inset}
|
|
82
|
+
data-variant={variant}
|
|
83
|
+
className={cn(
|
|
84
|
+
"relative flex cursor-default items-center gap-2 rounded-xs px-2 py-1.5 text-base outline-hidden select-none transition-colors duration-(--duration-fast) ease-(--ease-out) focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5 [&_svg:not([class*='text-'])]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground data-[variant=destructive]:*:[svg]:text-destructive!",
|
|
85
|
+
className
|
|
86
|
+
)}
|
|
87
|
+
{...props}
|
|
88
|
+
/>
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function DropdownMenuCheckboxItem({
|
|
93
|
+
className,
|
|
94
|
+
children,
|
|
95
|
+
checked,
|
|
96
|
+
...props
|
|
97
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) {
|
|
98
|
+
return (
|
|
99
|
+
<DropdownMenuPrimitive.CheckboxItem
|
|
100
|
+
data-slot="dropdown-menu-checkbox-item"
|
|
101
|
+
className={cn(
|
|
102
|
+
"relative flex cursor-default items-center gap-2 rounded-xs py-1.5 pr-8 pl-2 text-base outline-hidden select-none transition-colors duration-(--duration-fast) ease-(--ease-out) focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5 [&_svg:not([class*='text-'])]:text-muted-foreground",
|
|
103
|
+
className
|
|
104
|
+
)}
|
|
105
|
+
checked={checked}
|
|
106
|
+
{...props}
|
|
107
|
+
>
|
|
108
|
+
<span className="pointer-events-none absolute right-2 flex size-3.5 items-center justify-center">
|
|
109
|
+
<DropdownMenuPrimitive.ItemIndicator>
|
|
110
|
+
<CheckIcon className="size-4" />
|
|
111
|
+
</DropdownMenuPrimitive.ItemIndicator>
|
|
112
|
+
</span>
|
|
113
|
+
{children}
|
|
114
|
+
</DropdownMenuPrimitive.CheckboxItem>
|
|
115
|
+
)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function DropdownMenuRadioGroup({
|
|
119
|
+
...props
|
|
120
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {
|
|
121
|
+
return (
|
|
122
|
+
<DropdownMenuPrimitive.RadioGroup
|
|
123
|
+
data-slot="dropdown-menu-radio-group"
|
|
124
|
+
{...props}
|
|
125
|
+
/>
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function DropdownMenuRadioItem({
|
|
130
|
+
className,
|
|
131
|
+
children,
|
|
132
|
+
...props
|
|
133
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {
|
|
134
|
+
return (
|
|
135
|
+
<DropdownMenuPrimitive.RadioItem
|
|
136
|
+
data-slot="dropdown-menu-radio-item"
|
|
137
|
+
className={cn(
|
|
138
|
+
"relative flex cursor-default items-center gap-2 rounded-xs py-1.5 pr-8 pl-2 text-base outline-hidden select-none transition-colors duration-(--duration-fast) ease-(--ease-out) focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5 [&_svg:not([class*='text-'])]:text-muted-foreground",
|
|
139
|
+
className
|
|
140
|
+
)}
|
|
141
|
+
{...props}
|
|
142
|
+
>
|
|
143
|
+
<span className="pointer-events-none absolute right-2 flex size-3.5 items-center justify-center">
|
|
144
|
+
<DropdownMenuPrimitive.ItemIndicator>
|
|
145
|
+
<CircleIcon className="size-2 fill-current" />
|
|
146
|
+
</DropdownMenuPrimitive.ItemIndicator>
|
|
147
|
+
</span>
|
|
148
|
+
{children}
|
|
149
|
+
</DropdownMenuPrimitive.RadioItem>
|
|
150
|
+
)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function DropdownMenuLabel({
|
|
154
|
+
className,
|
|
155
|
+
inset,
|
|
156
|
+
...props
|
|
157
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {
|
|
158
|
+
inset?: boolean
|
|
159
|
+
}) {
|
|
160
|
+
return (
|
|
161
|
+
<DropdownMenuPrimitive.Label
|
|
162
|
+
data-slot="dropdown-menu-label"
|
|
163
|
+
data-inset={inset}
|
|
164
|
+
className={cn(
|
|
165
|
+
"px-2 pt-2 pb-1 text-sm font-medium text-ink-3 data-[inset]:pl-8",
|
|
166
|
+
className
|
|
167
|
+
)}
|
|
168
|
+
{...props}
|
|
169
|
+
/>
|
|
170
|
+
)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function DropdownMenuSeparator({
|
|
174
|
+
className,
|
|
175
|
+
...props
|
|
176
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {
|
|
177
|
+
return (
|
|
178
|
+
<DropdownMenuPrimitive.Separator
|
|
179
|
+
data-slot="dropdown-menu-separator"
|
|
180
|
+
className={cn("-mx-1 my-1 h-px bg-border", className)}
|
|
181
|
+
{...props}
|
|
182
|
+
/>
|
|
183
|
+
)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function DropdownMenuShortcut({
|
|
187
|
+
className,
|
|
188
|
+
...props
|
|
189
|
+
}: React.ComponentProps<"span">) {
|
|
190
|
+
return (
|
|
191
|
+
<span
|
|
192
|
+
data-slot="dropdown-menu-shortcut"
|
|
193
|
+
className={cn(
|
|
194
|
+
"ml-auto flex items-center gap-0.5 text-sm text-muted-foreground",
|
|
195
|
+
className
|
|
196
|
+
)}
|
|
197
|
+
{...props}
|
|
198
|
+
/>
|
|
199
|
+
)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function DropdownMenuSub({
|
|
203
|
+
...props
|
|
204
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {
|
|
205
|
+
return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function DropdownMenuSubTrigger({
|
|
209
|
+
className,
|
|
210
|
+
inset,
|
|
211
|
+
children,
|
|
212
|
+
...props
|
|
213
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {
|
|
214
|
+
inset?: boolean
|
|
215
|
+
}) {
|
|
216
|
+
return (
|
|
217
|
+
<DropdownMenuPrimitive.SubTrigger
|
|
218
|
+
data-slot="dropdown-menu-sub-trigger"
|
|
219
|
+
data-inset={inset}
|
|
220
|
+
className={cn(
|
|
221
|
+
"flex cursor-default items-center gap-2 rounded-xs px-2 py-1.5 text-base outline-hidden select-none transition-colors duration-(--duration-fast) ease-(--ease-out) focus:bg-accent focus:text-accent-foreground data-[inset]:pl-8 data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5 [&_svg:not([class*='text-'])]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground",
|
|
222
|
+
className
|
|
223
|
+
)}
|
|
224
|
+
{...props}
|
|
225
|
+
>
|
|
226
|
+
{children}
|
|
227
|
+
<ChevronRightIcon className="ml-auto size-4" />
|
|
228
|
+
</DropdownMenuPrimitive.SubTrigger>
|
|
229
|
+
)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function DropdownMenuSubContent({
|
|
233
|
+
className,
|
|
234
|
+
...props
|
|
235
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {
|
|
236
|
+
return (
|
|
237
|
+
<DropdownMenuPrimitive.SubContent
|
|
238
|
+
data-slot="dropdown-menu-sub-content"
|
|
239
|
+
className={cn(
|
|
240
|
+
"z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
|
|
241
|
+
className
|
|
242
|
+
)}
|
|
243
|
+
{...props}
|
|
244
|
+
/>
|
|
245
|
+
)
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export {
|
|
249
|
+
DropdownMenu,
|
|
250
|
+
DropdownMenuPortal,
|
|
251
|
+
DropdownMenuTrigger,
|
|
252
|
+
DropdownMenuContent,
|
|
253
|
+
DropdownMenuGroup,
|
|
254
|
+
DropdownMenuLabel,
|
|
255
|
+
DropdownMenuItem,
|
|
256
|
+
DropdownMenuCheckboxItem,
|
|
257
|
+
DropdownMenuRadioGroup,
|
|
258
|
+
DropdownMenuRadioItem,
|
|
259
|
+
DropdownMenuSeparator,
|
|
260
|
+
DropdownMenuShortcut,
|
|
261
|
+
DropdownMenuSub,
|
|
262
|
+
DropdownMenuSubTrigger,
|
|
263
|
+
DropdownMenuSubContent,
|
|
264
|
+
}
|