@xemahq/ui-kernel 0.11.1 → 0.12.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/dist/errors/http-error-status.d.ts +17 -0
- package/dist/errors/http-error-status.d.ts.map +1 -0
- package/dist/errors/http-error-status.js +59 -0
- package/dist/errors/http-error-status.js.map +1 -0
- package/dist/errors/index.d.ts +2 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +2 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/biome-host/errors.d.ts.map +1 -1
- package/dist/lib/biome-host/errors.js +1 -19
- package/dist/lib/biome-host/errors.js.map +1 -1
- package/dist/offline/index.d.ts.map +1 -1
- package/dist/offline/index.js.map +1 -1
- package/dist/offline/online-controller.d.ts.map +1 -1
- package/dist/offline/online-controller.js +6 -1
- package/dist/offline/online-controller.js.map +1 -1
- package/dist/offline/outbox.d.ts.map +1 -1
- package/dist/offline/outbox.js +2 -24
- package/dist/offline/outbox.js.map +1 -1
- package/package.json +1 -2
- package/src/index.ts +0 -17
- package/src/lib/biome-host/agent-validation.ts +0 -239
- package/src/lib/biome-host/biome-builders.ts +0 -112
- package/src/lib/biome-host/biome-mode.ts +0 -6
- package/src/lib/biome-host/biome-navigation.ts +0 -37
- package/src/lib/biome-host/biome-registry.ts +0 -299
- package/src/lib/biome-host/biome-scope-hooks.ts +0 -41
- package/src/lib/biome-host/biome-scope.tsx +0 -52
- package/src/lib/biome-host/biome-scoped-query.ts +0 -134
- package/src/lib/biome-host/create-biome-orval-config.ts +0 -82
- package/src/lib/biome-host/define-web-biome.spec.ts +0 -221
- package/src/lib/biome-host/define-web-biome.ts +0 -222
- package/src/lib/biome-host/errors.ts +0 -220
- package/src/lib/biome-host/frontend-biome.ts +0 -256
- package/src/lib/biome-host/host-bridge.ts +0 -281
- package/src/lib/biome-host/host-sources.ts +0 -54
- package/src/lib/biome-host/i18n-hooks.ts +0 -51
- package/src/lib/biome-host/i18n-port.test.ts +0 -50
- package/src/lib/biome-host/i18n-port.ts +0 -96
- package/src/lib/biome-host/index.ts +0 -35
- package/src/lib/biome-host/realtime-hooks.ts +0 -75
- package/src/lib/biome-host/realtime-port.ts +0 -115
- package/src/lib/biome-host/session-contributions.ts +0 -296
- package/src/lib/biome-host/use-mutation-with-error-toast.ts +0 -90
- package/src/lib/biome-host/use-page-state.ts +0 -248
- package/src/lib/capabilities/capability-context.ts +0 -25
- package/src/lib/capabilities/capability-provider.tsx +0 -73
- package/src/lib/capabilities/index.ts +0 -17
- package/src/lib/capabilities/types.ts +0 -69
- package/src/lib/capabilities/use-capability.ts +0 -79
- package/src/lib/contribution-registry/contribution-registry.spec.ts +0 -141
- package/src/lib/contribution-registry/contribution-registry.ts +0 -204
- package/src/lib/contribution-registry/index.ts +0 -9
- package/src/lib/contribution-registry/renderable-registry.ts +0 -142
- package/src/lib/system-bus/capability-invoke.ts +0 -92
- package/src/lib/system-bus/deeplink.ts +0 -210
- package/src/lib/system-bus/enums.ts +0 -86
- package/src/lib/system-bus/host-ports.ts +0 -93
- package/src/lib/system-bus/index.ts +0 -16
- package/src/lib/system-bus/intent-registry.ts +0 -109
- package/src/lib/system-bus/intents.ts +0 -113
- package/src/lib/system-bus/palette.ts +0 -78
- package/src/lib/system-bus/system-bus-builder.ts +0 -159
- package/src/lib/system-bus/system-bus.ts +0 -37
- package/src/lib/system-bus/windows.ts +0 -51
- package/src/offline/id.ts +0 -16
- package/src/offline/index.ts +0 -54
- package/src/offline/mutation.ts +0 -75
- package/src/offline/offline-status-badge.tsx +0 -51
- package/src/offline/online-controller.ts +0 -105
- package/src/offline/outbox.test.ts +0 -172
- package/src/offline/outbox.ts +0 -348
- package/src/offline/react-hooks.ts +0 -40
- package/src/offline/react.tsx +0 -32
- package/src/offline/storage.ts +0 -112
- package/src/offline/types.ts +0 -77
- package/src/org-db/components/DbResultTable.tsx +0 -176
- package/src/org-db/index.ts +0 -1
- package/src/pdf/index.ts +0 -11
- package/src/registry/index.ts +0 -9
- package/src/registry/lib/agent-validation-host.ts +0 -36
- package/src/registry/lib/biome-slot.tsx +0 -50
- package/src/registry/lib/biomes-enabled-context.ts +0 -20
- package/src/registry/lib/extension-points.ts +0 -134
- package/src/registry/lib/primitives/SessionEventCard.tsx +0 -164
- package/src/registry/lib/primitives/SessionEventTimeline.tsx +0 -95
- package/src/registry/lib/primitives/SessionMutationBar.tsx +0 -76
- package/src/registry/lib/primitives/SessionTabbedDrawer.tsx +0 -165
- package/src/registry/lib/primitives/index.ts +0 -18
- package/src/registry/lib/session-context-builder.ts +0 -84
- package/src/registry/lib/session-context-provider.tsx +0 -33
- package/src/registry/lib/session-context.ts +0 -21
- package/src/registry/lib/session-selectors.ts +0 -272
- package/src/session/comments/CommentRail.tsx +0 -164
- package/src/session/index.ts +0 -3
- package/src/session/lib/cn.ts +0 -11
- package/src/session/shell/SessionWorkspaceShell.tsx +0 -147
- package/src/session-kit/approvals/ApprovalButton.tsx +0 -89
- package/src/session-kit/approvals/ApprovalCard.tsx +0 -341
- package/src/session-kit/approvals/ApprovalsCenter.tsx +0 -336
- package/src/session-kit/approvals/CapabilityApprovalStickyBar.tsx +0 -118
- package/src/session-kit/approvals/Obligation.tsx +0 -111
- package/src/session-kit/approvals/ScopedBody.tsx +0 -392
- package/src/session-kit/approvals/approval-icons.ts +0 -31
- package/src/session-kit/approvals/approval-model.ts +0 -204
- package/src/session-kit/approvals/index.ts +0 -22
- package/src/session-kit/approvals/obligation-display.ts +0 -100
- package/src/session-kit/approvals/risk-accent.ts +0 -47
- package/src/session-kit/approvals/scope-icons.ts +0 -19
- package/src/session-kit/combobox/Combobox.tsx +0 -358
- package/src/session-kit/combobox/use-click-outside.ts +0 -21
- package/src/session-kit/display/ContextHeader.tsx +0 -148
- package/src/session-kit/display/FileDiffCard.tsx +0 -140
- package/src/session-kit/display/MD.tsx +0 -162
- package/src/session-kit/display/MessageTurn.tsx +0 -157
- package/src/session-kit/display/ThinkingPanel.tsx +0 -81
- package/src/session-kit/display/TodoChecklist.tsx +0 -120
- package/src/session-kit/display/TokenMeter.tsx +0 -89
- package/src/session-kit/display/ToolStrip.tsx +0 -278
- package/src/session-kit/display/TypingDots.tsx +0 -24
- package/src/session-kit/index.ts +0 -44
- package/src/session-kit/lib/enums.ts +0 -66
- package/src/session-kit/lib/portal-accent.ts +0 -30
- package/src/session-kit/lib/status-dot.ts +0 -68
- package/src/session-kit/primitives/Avatar.tsx +0 -44
- package/src/session-kit/primitives/PortalGlyph.tsx +0 -51
- package/src/session-kit/primitives/RiskPill.tsx +0 -95
- package/src/session-kit/primitives/ScopeDot.tsx +0 -47
- package/src/session-kit/primitives/Segmented.tsx +0 -71
- package/src/ui/branding/app-branding-context.ts +0 -20
- package/src/ui/branding/app-branding-provider.tsx +0 -123
- package/src/ui/branding/sanitize.ts +0 -89
- package/src/ui/breakpoints.ts +0 -14
- package/src/ui/capture/document-preview.tsx +0 -166
- package/src/ui/capture/field-spec-to-zod.test.ts +0 -81
- package/src/ui/capture/field-spec-to-zod.ts +0 -174
- package/src/ui/capture/field-spec-validate.ts +0 -236
- package/src/ui/capture/field-spec.test.ts +0 -49
- package/src/ui/capture/field-spec.ts +0 -274
- package/src/ui/capture/index.ts +0 -51
- package/src/ui/capture/schema-field-input.tsx +0 -620
- package/src/ui/capture/schema-form.tsx +0 -149
- package/src/ui/capture/submit-values.test.ts +0 -70
- package/src/ui/capture/submit-values.ts +0 -63
- package/src/ui/capture/use-prefill.ts +0 -186
- package/src/ui/capture/use-schema-validation.ts +0 -145
- package/src/ui/capture/use-wizard.ts +0 -180
- package/src/ui/capture/value-format.ts +0 -32
- package/src/ui/capture/wizard.tsx +0 -105
- package/src/ui/charts/bar-chart.tsx +0 -139
- package/src/ui/charts/chart-frame.tsx +0 -125
- package/src/ui/charts/chart-types.ts +0 -52
- package/src/ui/charts/chart-utils.ts +0 -190
- package/src/ui/charts/charts.test.tsx +0 -204
- package/src/ui/charts/donut-chart.tsx +0 -129
- package/src/ui/charts/index.ts +0 -27
- package/src/ui/charts/line-chart.tsx +0 -202
- package/src/ui/charts/sparkline.tsx +0 -109
- package/src/ui/chrome/AsyncBoundary.tsx +0 -74
- package/src/ui/chrome/EmptyState.tsx +0 -257
- package/src/ui/chrome/ErrorCard.tsx +0 -63
- package/src/ui/chrome/LoadingState.tsx +0 -61
- package/src/ui/chrome/PageHeader.tsx +0 -137
- package/src/ui/chrome/RecordCardList.tsx +0 -98
- package/src/ui/chrome/StateCard.tsx +0 -150
- package/src/ui/chrome/confirm-delete-dialog.tsx +0 -59
- package/src/ui/chrome/page-shell.spec.tsx +0 -117
- package/src/ui/chrome/page-shell.tsx +0 -221
- package/src/ui/chrome/scope-badge.tsx +0 -40
- package/src/ui/chrome/status-badge.tsx +0 -79
- package/src/ui/cn.ts +0 -32
- package/src/ui/design-tokens.ts +0 -372
- package/src/ui/hooks/use-debounced-value.ts +0 -16
- package/src/ui/hooks/use-is-mobile.ts +0 -28
- package/src/ui/index.ts +0 -110
- package/src/ui/pdf/pdf-preview.tsx +0 -122
- package/src/ui/primitives/alert-dialog.tsx +0 -104
- package/src/ui/primitives/async-combobox.tsx +0 -182
- package/src/ui/primitives/badge-variants.ts +0 -21
- package/src/ui/primitives/badge.tsx +0 -25
- package/src/ui/primitives/button-variants.ts +0 -31
- package/src/ui/primitives/button.tsx +0 -29
- package/src/ui/primitives/card.tsx +0 -43
- package/src/ui/primitives/checkbox.tsx +0 -26
- package/src/ui/primitives/collapsible.tsx +0 -9
- package/src/ui/primitives/dialog.tsx +0 -103
- package/src/ui/primitives/dropdown-menu.tsx +0 -179
- package/src/ui/primitives/form-stepper.tsx +0 -94
- package/src/ui/primitives/form-stepper.types.ts +0 -15
- package/src/ui/primitives/input.tsx +0 -22
- package/src/ui/primitives/label.tsx +0 -17
- package/src/ui/primitives/overflow-tabs.tsx +0 -331
- package/src/ui/primitives/popover.tsx +0 -33
- package/src/ui/primitives/preview-device-frame.tsx +0 -213
- package/src/ui/primitives/radio-group.tsx +0 -36
- package/src/ui/primitives/resizable.tsx +0 -67
- package/src/ui/primitives/scroll-area.tsx +0 -38
- package/src/ui/primitives/select.tsx +0 -143
- package/src/ui/primitives/separator.tsx +0 -20
- package/src/ui/primitives/sheet.tsx +0 -107
- package/src/ui/primitives/skeleton.tsx +0 -99
- package/src/ui/primitives/switch.tsx +0 -27
- package/src/ui/primitives/table.tsx +0 -72
- package/src/ui/primitives/tabs.tsx +0 -53
- package/src/ui/primitives/tag-multi-select.tsx +0 -261
- package/src/ui/primitives/textarea.tsx +0 -21
- package/src/ui/primitives/tooltip.tsx +0 -30
- package/src/ui/primitives/url-preview-chrome.tsx +0 -103
- package/src/vista/GenericCatalogueSurface.tsx +0 -179
- package/src/vista/SurfaceFallbackCard.tsx +0 -109
- package/src/vista/VistaPanel.tsx +0 -163
- package/src/vista/form-payload.spec.ts +0 -139
- package/src/vista/html/CustomUiFrame.spec.tsx +0 -127
- package/src/vista/html/CustomUiFrame.tsx +0 -206
- package/src/vista/html/custom-ui-frame-bridge.spec.ts +0 -191
- package/src/vista/html/custom-ui-frame-bridge.ts +0 -98
- package/src/vista/html/custom-ui-frame-contract.ts +0 -88
- package/src/vista/html/custom-ui-intents.spec.ts +0 -135
- package/src/vista/html/custom-ui-intents.ts +0 -155
- package/src/vista/html/custom-ui-srcdoc.spec.ts +0 -151
- package/src/vista/html/custom-ui-srcdoc.ts +0 -193
- package/src/vista/html/index.ts +0 -13
- package/src/vista/index.ts +0 -52
- package/src/vista/surface-catalogue.spec.ts +0 -140
- package/src/vista/surface-catalogue.ts +0 -90
- package/src/vista/surface-icons.ts +0 -57
- package/src/vista/surface-registry.ts +0 -56
- package/src/vista/surfaces/ChartSurface.tsx +0 -34
- package/src/vista/surfaces/FilesSurface.tsx +0 -202
- package/src/vista/surfaces/FormSurface.tsx +0 -380
- package/src/vista/surfaces/HtmlSurface.tsx +0 -43
- package/src/vista/surfaces/TableSurface.tsx +0 -100
- package/src/vista/surfaces/UrlSurface.tsx +0 -40
- package/src/vista/surfaces/blob-surfaces.tsx +0 -139
- package/src/vista/surfaces/elicitation-transport.spec.ts +0 -369
- package/src/vista/surfaces/elicitation-transport.ts +0 -367
- package/src/vista/surfaces/file-surface-utils.ts +0 -69
- package/src/vista/surfaces/index.ts +0 -24
- package/src/vista/surfaces/register-surfaces.tsx +0 -139
- package/src/vista/surfaces/text-surfaces.tsx +0 -132
- package/src/vista/use-vista-tabs.ts +0 -196
- package/src/vista/vista-code-renderer-context.ts +0 -16
- package/src/vista/vista-code-renderer.tsx +0 -35
- package/src/vista/vista-file-context.ts +0 -14
- package/src/vista/vista-file-source.tsx +0 -141
- package/src/vista/vista-form-context.ts +0 -20
- package/src/vista/vista-form-host.tsx +0 -48
- package/src/vista/vista-model.ts +0 -137
- package/src/vista/vista-open-context.tsx +0 -27
- package/src/vista/vista-open-state.ts +0 -11
- package/src/vista/vista-payloads.ts +0 -635
- package/src/vista/vista-tabs-manifest.ts +0 -138
- package/src/vista/vista-tools.ts +0 -232
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
|
2
|
-
import { Check, ChevronRight, Circle } from "lucide-react";
|
|
3
|
-
import * as React from "react";
|
|
4
|
-
|
|
5
|
-
import { cn } from '../cn';
|
|
6
|
-
|
|
7
|
-
const DropdownMenu = DropdownMenuPrimitive.Root;
|
|
8
|
-
|
|
9
|
-
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
|
|
10
|
-
|
|
11
|
-
const DropdownMenuGroup = DropdownMenuPrimitive.Group;
|
|
12
|
-
|
|
13
|
-
const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
|
|
14
|
-
|
|
15
|
-
const DropdownMenuSub = DropdownMenuPrimitive.Sub;
|
|
16
|
-
|
|
17
|
-
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
|
|
18
|
-
|
|
19
|
-
const DropdownMenuSubTrigger = React.forwardRef<
|
|
20
|
-
React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
|
|
21
|
-
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
|
|
22
|
-
inset?: boolean;
|
|
23
|
-
}
|
|
24
|
-
>(({ className, inset, children, ...props }, ref) => (
|
|
25
|
-
<DropdownMenuPrimitive.SubTrigger
|
|
26
|
-
ref={ref}
|
|
27
|
-
className={cn(
|
|
28
|
-
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-body-1 outline-none data-[state=open]:bg-accent focus:bg-accent",
|
|
29
|
-
inset && "pl-8",
|
|
30
|
-
className,
|
|
31
|
-
)}
|
|
32
|
-
{...props}
|
|
33
|
-
>
|
|
34
|
-
{children}
|
|
35
|
-
<ChevronRight className="ml-auto h-4 w-4" />
|
|
36
|
-
</DropdownMenuPrimitive.SubTrigger>
|
|
37
|
-
));
|
|
38
|
-
DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;
|
|
39
|
-
|
|
40
|
-
const DropdownMenuSubContent = React.forwardRef<
|
|
41
|
-
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
|
|
42
|
-
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
|
|
43
|
-
>(({ className, ...props }, ref) => (
|
|
44
|
-
<DropdownMenuPrimitive.SubContent
|
|
45
|
-
ref={ref}
|
|
46
|
-
className={cn(
|
|
47
|
-
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 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",
|
|
48
|
-
className,
|
|
49
|
-
)}
|
|
50
|
-
{...props}
|
|
51
|
-
/>
|
|
52
|
-
));
|
|
53
|
-
DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;
|
|
54
|
-
|
|
55
|
-
const DropdownMenuContent = React.forwardRef<
|
|
56
|
-
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
|
|
57
|
-
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
|
|
58
|
-
>(({ className, sideOffset = 4, ...props }, ref) => (
|
|
59
|
-
<DropdownMenuPrimitive.Portal>
|
|
60
|
-
<DropdownMenuPrimitive.Content
|
|
61
|
-
ref={ref}
|
|
62
|
-
sideOffset={sideOffset}
|
|
63
|
-
className={cn(
|
|
64
|
-
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 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",
|
|
65
|
-
className,
|
|
66
|
-
)}
|
|
67
|
-
{...props}
|
|
68
|
-
/>
|
|
69
|
-
</DropdownMenuPrimitive.Portal>
|
|
70
|
-
));
|
|
71
|
-
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
|
|
72
|
-
|
|
73
|
-
const DropdownMenuItem = React.forwardRef<
|
|
74
|
-
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
|
|
75
|
-
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
|
|
76
|
-
inset?: boolean;
|
|
77
|
-
}
|
|
78
|
-
>(({ className, inset, ...props }, ref) => (
|
|
79
|
-
<DropdownMenuPrimitive.Item
|
|
80
|
-
ref={ref}
|
|
81
|
-
className={cn(
|
|
82
|
-
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-body-1 outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-accent focus:text-accent-foreground",
|
|
83
|
-
inset && "pl-8",
|
|
84
|
-
className,
|
|
85
|
-
)}
|
|
86
|
-
{...props}
|
|
87
|
-
/>
|
|
88
|
-
));
|
|
89
|
-
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
|
|
90
|
-
|
|
91
|
-
const DropdownMenuCheckboxItem = React.forwardRef<
|
|
92
|
-
React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
|
|
93
|
-
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>
|
|
94
|
-
>(({ className, children, checked, ...props }, ref) => (
|
|
95
|
-
<DropdownMenuPrimitive.CheckboxItem
|
|
96
|
-
ref={ref}
|
|
97
|
-
className={cn(
|
|
98
|
-
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-body-1 outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-accent focus:text-accent-foreground",
|
|
99
|
-
className,
|
|
100
|
-
)}
|
|
101
|
-
checked={checked}
|
|
102
|
-
{...props}
|
|
103
|
-
>
|
|
104
|
-
<span className="absolute left-2 flex h-4 w-4 items-center justify-center">
|
|
105
|
-
<DropdownMenuPrimitive.ItemIndicator>
|
|
106
|
-
<Check className="h-4 w-4" />
|
|
107
|
-
</DropdownMenuPrimitive.ItemIndicator>
|
|
108
|
-
</span>
|
|
109
|
-
{children}
|
|
110
|
-
</DropdownMenuPrimitive.CheckboxItem>
|
|
111
|
-
));
|
|
112
|
-
DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;
|
|
113
|
-
|
|
114
|
-
const DropdownMenuRadioItem = React.forwardRef<
|
|
115
|
-
React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
|
|
116
|
-
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
|
|
117
|
-
>(({ className, children, ...props }, ref) => (
|
|
118
|
-
<DropdownMenuPrimitive.RadioItem
|
|
119
|
-
ref={ref}
|
|
120
|
-
className={cn(
|
|
121
|
-
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-body-1 outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-accent focus:text-accent-foreground",
|
|
122
|
-
className,
|
|
123
|
-
)}
|
|
124
|
-
{...props}
|
|
125
|
-
>
|
|
126
|
-
<span className="absolute left-2 flex h-4 w-4 items-center justify-center">
|
|
127
|
-
<DropdownMenuPrimitive.ItemIndicator>
|
|
128
|
-
<Circle className="h-2 w-2 fill-current" />
|
|
129
|
-
</DropdownMenuPrimitive.ItemIndicator>
|
|
130
|
-
</span>
|
|
131
|
-
{children}
|
|
132
|
-
</DropdownMenuPrimitive.RadioItem>
|
|
133
|
-
));
|
|
134
|
-
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
|
|
135
|
-
|
|
136
|
-
const DropdownMenuLabel = React.forwardRef<
|
|
137
|
-
React.ElementRef<typeof DropdownMenuPrimitive.Label>,
|
|
138
|
-
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
|
|
139
|
-
inset?: boolean;
|
|
140
|
-
}
|
|
141
|
-
>(({ className, inset, ...props }, ref) => (
|
|
142
|
-
<DropdownMenuPrimitive.Label
|
|
143
|
-
ref={ref}
|
|
144
|
-
className={cn("px-2 py-1.5 text-body-1 font-semibold", inset && "pl-8", className)}
|
|
145
|
-
{...props}
|
|
146
|
-
/>
|
|
147
|
-
));
|
|
148
|
-
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
|
|
149
|
-
|
|
150
|
-
const DropdownMenuSeparator = React.forwardRef<
|
|
151
|
-
React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
|
|
152
|
-
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
|
|
153
|
-
>(({ className, ...props }, ref) => (
|
|
154
|
-
<DropdownMenuPrimitive.Separator ref={ref} className={cn("-mx-1 my-1 h-px bg-muted", className)} {...props} />
|
|
155
|
-
));
|
|
156
|
-
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
|
|
157
|
-
|
|
158
|
-
const DropdownMenuShortcut = ({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) => {
|
|
159
|
-
return <span className={cn("ml-auto text-body-1 tracking-widest opacity-60", className)} {...props} />;
|
|
160
|
-
};
|
|
161
|
-
DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
|
|
162
|
-
|
|
163
|
-
export {
|
|
164
|
-
DropdownMenu,
|
|
165
|
-
DropdownMenuTrigger,
|
|
166
|
-
DropdownMenuContent,
|
|
167
|
-
DropdownMenuItem,
|
|
168
|
-
DropdownMenuCheckboxItem,
|
|
169
|
-
DropdownMenuRadioItem,
|
|
170
|
-
DropdownMenuLabel,
|
|
171
|
-
DropdownMenuSeparator,
|
|
172
|
-
DropdownMenuShortcut,
|
|
173
|
-
DropdownMenuGroup,
|
|
174
|
-
DropdownMenuPortal,
|
|
175
|
-
DropdownMenuSub,
|
|
176
|
-
DropdownMenuSubContent,
|
|
177
|
-
DropdownMenuSubTrigger,
|
|
178
|
-
DropdownMenuRadioGroup,
|
|
179
|
-
};
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import { Check } from 'lucide-react';
|
|
2
|
-
|
|
3
|
-
import { cn } from '../cn';
|
|
4
|
-
import { FormStepStatus, type FormStep } from './form-stepper.types';
|
|
5
|
-
|
|
6
|
-
interface FormStepperProps {
|
|
7
|
-
readonly steps: readonly FormStep[];
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Vertical stepper for in-dialog multi-step forms — numbered badges with a
|
|
12
|
-
* connector rail. Every step's body is rendered inline (pending steps are
|
|
13
|
-
* dimmed and pointer-disabled). The dialog owns the submit button; this
|
|
14
|
-
* primitive renders structure only.
|
|
15
|
-
*/
|
|
16
|
-
export function FormStepper({ steps }: FormStepperProps) {
|
|
17
|
-
return (
|
|
18
|
-
<ol className="space-y-4">
|
|
19
|
-
{steps.map((step, index) => (
|
|
20
|
-
<FormStepperItem
|
|
21
|
-
key={step.key}
|
|
22
|
-
step={step}
|
|
23
|
-
stepNumber={index + 1}
|
|
24
|
-
isLast={index === steps.length - 1}
|
|
25
|
-
/>
|
|
26
|
-
))}
|
|
27
|
-
</ol>
|
|
28
|
-
);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
interface FormStepperItemProps {
|
|
32
|
-
readonly step: FormStep;
|
|
33
|
-
readonly stepNumber: number;
|
|
34
|
-
readonly isLast: boolean;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function FormStepperItem({ step, stepNumber, isLast }: FormStepperItemProps) {
|
|
38
|
-
const isPending = step.status === FormStepStatus.PENDING;
|
|
39
|
-
const isDone = step.status === FormStepStatus.DONE;
|
|
40
|
-
const isActive = step.status === FormStepStatus.ACTIVE;
|
|
41
|
-
|
|
42
|
-
return (
|
|
43
|
-
<li className="relative flex gap-3">
|
|
44
|
-
{/* Connector rail — hugs the numbered badge column. Hidden on the last
|
|
45
|
-
item so the chain doesn't dangle past the final step. */}
|
|
46
|
-
{!isLast && (
|
|
47
|
-
<span
|
|
48
|
-
aria-hidden
|
|
49
|
-
className={cn(
|
|
50
|
-
'absolute left-3.5 top-8 bottom-0 w-px -translate-x-1/2',
|
|
51
|
-
isDone ? 'bg-primary/30' : 'bg-rule',
|
|
52
|
-
)}
|
|
53
|
-
/>
|
|
54
|
-
)}
|
|
55
|
-
|
|
56
|
-
<span
|
|
57
|
-
className={cn(
|
|
58
|
-
'relative z-[1] mt-0.5 inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-full border text-caption font-semibold',
|
|
59
|
-
isDone && 'border-primary/40 bg-primary/15 text-primary',
|
|
60
|
-
isActive && 'border-primary bg-primary text-primary-foreground',
|
|
61
|
-
isPending && 'border-rule bg-paper-elev text-ink-3',
|
|
62
|
-
)}
|
|
63
|
-
>
|
|
64
|
-
{isDone ? <Check className="h-3.5 w-3.5" strokeWidth={2.5} /> : stepNumber}
|
|
65
|
-
</span>
|
|
66
|
-
|
|
67
|
-
<div
|
|
68
|
-
className={cn(
|
|
69
|
-
'flex-1 min-w-0 rounded-lg border bg-card p-4 transition-opacity',
|
|
70
|
-
isActive && 'border-primary/40 shadow-sm',
|
|
71
|
-
isDone && 'border-rule',
|
|
72
|
-
isPending && 'border-rule opacity-60',
|
|
73
|
-
)}
|
|
74
|
-
>
|
|
75
|
-
<div className="mb-3 space-y-0.5">
|
|
76
|
-
<p
|
|
77
|
-
className={cn(
|
|
78
|
-
'text-body-1 font-medium',
|
|
79
|
-
isPending ? 'text-ink-3' : 'text-foreground',
|
|
80
|
-
)}
|
|
81
|
-
>
|
|
82
|
-
{step.label}
|
|
83
|
-
</p>
|
|
84
|
-
{step.hint && <p className="text-caption text-ink-3">{step.hint}</p>}
|
|
85
|
-
</div>
|
|
86
|
-
{/* Keep pointer/keyboard focus out of pending steps without disabling
|
|
87
|
-
them globally — every input retains its native disabled semantics. */}
|
|
88
|
-
<div className={cn(isPending && 'pointer-events-none select-none')}>
|
|
89
|
-
{step.children}
|
|
90
|
-
</div>
|
|
91
|
-
</div>
|
|
92
|
-
</li>
|
|
93
|
-
);
|
|
94
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { ReactNode } from 'react';
|
|
2
|
-
|
|
3
|
-
export enum FormStepStatus {
|
|
4
|
-
PENDING = 'pending',
|
|
5
|
-
ACTIVE = 'active',
|
|
6
|
-
DONE = 'done',
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export interface FormStep {
|
|
10
|
-
readonly key: string;
|
|
11
|
-
readonly label: string;
|
|
12
|
-
readonly hint?: string;
|
|
13
|
-
readonly status: FormStepStatus;
|
|
14
|
-
readonly children: ReactNode;
|
|
15
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
|
|
3
|
-
import { cn } from '../cn';
|
|
4
|
-
|
|
5
|
-
const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>(
|
|
6
|
-
({ className, type, ...props }, ref) => {
|
|
7
|
-
return (
|
|
8
|
-
<input
|
|
9
|
-
type={type}
|
|
10
|
-
className={cn(
|
|
11
|
-
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background file:border-0 file:bg-transparent file:text-body-1 file:font-medium file:text-foreground placeholder:text-ink-3 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-body-1",
|
|
12
|
-
className,
|
|
13
|
-
)}
|
|
14
|
-
ref={ref}
|
|
15
|
-
{...props}
|
|
16
|
-
/>
|
|
17
|
-
);
|
|
18
|
-
},
|
|
19
|
-
);
|
|
20
|
-
Input.displayName = "Input";
|
|
21
|
-
|
|
22
|
-
export { Input };
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import * as LabelPrimitive from "@radix-ui/react-label";
|
|
2
|
-
import { cva, type VariantProps } from "class-variance-authority";
|
|
3
|
-
import * as React from "react";
|
|
4
|
-
|
|
5
|
-
import { cn } from '../cn';
|
|
6
|
-
|
|
7
|
-
const labelVariants = cva("text-body-1 font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70");
|
|
8
|
-
|
|
9
|
-
const Label = React.forwardRef<
|
|
10
|
-
React.ElementRef<typeof LabelPrimitive.Root>,
|
|
11
|
-
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> & VariantProps<typeof labelVariants>
|
|
12
|
-
>(({ className, ...props }, ref) => (
|
|
13
|
-
<LabelPrimitive.Root ref={ref} className={cn(labelVariants(), className)} {...props} />
|
|
14
|
-
));
|
|
15
|
-
Label.displayName = LabelPrimitive.Root.displayName;
|
|
16
|
-
|
|
17
|
-
export { Label };
|
|
@@ -1,331 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* OverflowTabs — editorial tab strip that auto-collapses overflowing items
|
|
3
|
-
* into a "More…" dropdown instead of scrolling horizontally.
|
|
4
|
-
*
|
|
5
|
-
* Behavior:
|
|
6
|
-
* 1. All tabs render off-screen for measurement (visibility: hidden, but
|
|
7
|
-
* still laid out so widths are real).
|
|
8
|
-
* 2. A ResizeObserver tracks the container width; once known we walk the
|
|
9
|
-
* tab widths left-to-right and pick the cutoff where they still fit
|
|
10
|
-
* alongside a fixed "More…" trigger.
|
|
11
|
-
* 3. Visible tabs render inline; overflow tabs go into a dropdown.
|
|
12
|
-
*
|
|
13
|
-
* The active tab is always pulled into the visible set, even if its index
|
|
14
|
-
* would be in the overflow bucket — users should never lose sight of "where
|
|
15
|
-
* am I." Same for tabs marked `pinned: true` (indicator dot is sticky).
|
|
16
|
-
*/
|
|
17
|
-
import { ChevronDown, X } from 'lucide-react';
|
|
18
|
-
import {
|
|
19
|
-
useEffect,
|
|
20
|
-
useLayoutEffect,
|
|
21
|
-
useMemo,
|
|
22
|
-
useRef,
|
|
23
|
-
useState,
|
|
24
|
-
type ComponentType,
|
|
25
|
-
} from 'react';
|
|
26
|
-
|
|
27
|
-
import {
|
|
28
|
-
DropdownMenu,
|
|
29
|
-
DropdownMenuContent,
|
|
30
|
-
DropdownMenuItem,
|
|
31
|
-
DropdownMenuTrigger,
|
|
32
|
-
} from './dropdown-menu';
|
|
33
|
-
import { cn } from '../cn';
|
|
34
|
-
|
|
35
|
-
export interface OverflowTab {
|
|
36
|
-
readonly value: string;
|
|
37
|
-
readonly label: string;
|
|
38
|
-
/** Optional warning/indicator dot rendered next to the label. */
|
|
39
|
-
readonly indicator?: boolean;
|
|
40
|
-
/** Optional numeric badge. */
|
|
41
|
-
readonly count?: number;
|
|
42
|
-
/**
|
|
43
|
-
* A pinned tab is ALWAYS in the visible set (never collapsed into "More…")
|
|
44
|
-
* and never renders a close affordance, even when `onClose` is supplied.
|
|
45
|
-
* Used for a panel's permanent first tab (e.g. the Vista file browser).
|
|
46
|
-
*/
|
|
47
|
-
readonly pinned?: boolean;
|
|
48
|
-
/** Optional leading glyph (a `lucide-react` icon component). */
|
|
49
|
-
readonly icon?: ComponentType<{ className?: string }>;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
interface OverflowTabsProps {
|
|
53
|
-
readonly tabs: readonly OverflowTab[];
|
|
54
|
-
readonly value: string;
|
|
55
|
-
readonly onChange: (value: string) => void;
|
|
56
|
-
/** Reserved px for the "More…" trigger when measuring. Default 88. */
|
|
57
|
-
readonly moreTriggerWidth?: number;
|
|
58
|
-
readonly className?: string;
|
|
59
|
-
/** Each tab's px gap from the next. Matches the visual rendering. Default 4. */
|
|
60
|
-
readonly gap?: number;
|
|
61
|
-
/**
|
|
62
|
-
* When provided, every tab renders a hover `×` that calls this with the
|
|
63
|
-
* tab value. Closable tabs (multi-thread surfaces, etc.) opt in by
|
|
64
|
-
* passing it; surfaces that just navigate omit it.
|
|
65
|
-
*/
|
|
66
|
-
readonly onClose?: (value: string) => void;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export function OverflowTabs({
|
|
70
|
-
tabs,
|
|
71
|
-
value,
|
|
72
|
-
onChange,
|
|
73
|
-
moreTriggerWidth = 88,
|
|
74
|
-
className,
|
|
75
|
-
gap = 4,
|
|
76
|
-
onClose,
|
|
77
|
-
}: OverflowTabsProps) {
|
|
78
|
-
const containerRef = useRef<HTMLDivElement>(null);
|
|
79
|
-
const measureRef = useRef<HTMLDivElement>(null);
|
|
80
|
-
const [containerWidth, setContainerWidth] = useState(0);
|
|
81
|
-
const [tabWidths, setTabWidths] = useState<readonly number[]>([]);
|
|
82
|
-
|
|
83
|
-
// Measure container width and react to resizes.
|
|
84
|
-
useEffect(() => {
|
|
85
|
-
const el = containerRef.current;
|
|
86
|
-
if (!el) {
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
const ro = new ResizeObserver((entries) => {
|
|
90
|
-
const w = entries[0]?.contentRect.width ?? el.clientWidth;
|
|
91
|
-
setContainerWidth(w);
|
|
92
|
-
});
|
|
93
|
-
ro.observe(el);
|
|
94
|
-
setContainerWidth(el.clientWidth);
|
|
95
|
-
return () => ro.disconnect();
|
|
96
|
-
}, []);
|
|
97
|
-
|
|
98
|
-
// Measure each tab's natural width once after first render. We re-measure
|
|
99
|
-
// when the tab list itself changes (new tabs, label edits).
|
|
100
|
-
useLayoutEffect(() => {
|
|
101
|
-
const el = measureRef.current;
|
|
102
|
-
if (!el) {
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
const children = Array.from(el.children) as HTMLElement[];
|
|
106
|
-
setTabWidths(children.map((c) => c.getBoundingClientRect().width));
|
|
107
|
-
}, [tabs]);
|
|
108
|
-
|
|
109
|
-
// Decide split point: walk left-to-right, summing widths + gaps, stopping
|
|
110
|
-
// when the next tab would exceed (container - moreTrigger). The active
|
|
111
|
-
// tab and any pinned tabs are always pulled into the visible set.
|
|
112
|
-
const { visible, overflow } = useMemo(() => {
|
|
113
|
-
if (tabWidths.length !== tabs.length || containerWidth === 0) {
|
|
114
|
-
return { visible: tabs, overflow: [] as readonly OverflowTab[] };
|
|
115
|
-
}
|
|
116
|
-
const totalNatural =
|
|
117
|
-
tabWidths.reduce((s, w) => s + w, 0) + gap * Math.max(0, tabs.length - 1);
|
|
118
|
-
if (totalNatural <= containerWidth) {
|
|
119
|
-
return { visible: tabs, overflow: [] as readonly OverflowTab[] };
|
|
120
|
-
}
|
|
121
|
-
const budget = containerWidth - moreTriggerWidth;
|
|
122
|
-
const vis: OverflowTab[] = [];
|
|
123
|
-
const over: OverflowTab[] = [];
|
|
124
|
-
let used = 0;
|
|
125
|
-
for (const [i, tab] of tabs.entries()) {
|
|
126
|
-
const natural = tabWidths[i];
|
|
127
|
-
if (natural === undefined) {
|
|
128
|
-
// Unreachable: the length-parity guard above already returned. Kept as a
|
|
129
|
-
// real check because the alternative — treating a missing measurement as
|
|
130
|
-
// 0px — would lay tabs out against a budget they don't actually fit.
|
|
131
|
-
// Fall back to the same all-visible layout the parity guard renders.
|
|
132
|
-
return { visible: tabs, overflow: [] as readonly OverflowTab[] };
|
|
133
|
-
}
|
|
134
|
-
const w = natural + (vis.length > 0 ? gap : 0);
|
|
135
|
-
// A pinned tab is never collapsed — it stays visible whatever the budget
|
|
136
|
-
// says, so a panel's permanent first tab can't hide behind "More…".
|
|
137
|
-
if (tab.pinned === true || used + w <= budget) {
|
|
138
|
-
vis.push(tab);
|
|
139
|
-
used += w;
|
|
140
|
-
} else {
|
|
141
|
-
over.push(tab);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
// Force the active tab into the visible set if it ended up in overflow.
|
|
145
|
-
// `find` (not `findIndex` + lookup) so the hit is typed as present.
|
|
146
|
-
const activeTab = tabs.find((t) => t.value === value);
|
|
147
|
-
if (activeTab !== undefined) {
|
|
148
|
-
const inVisible = vis.some((t) => t.value === activeTab.value);
|
|
149
|
-
if (!inVisible) {
|
|
150
|
-
// Swap the last visible for the active one to keep the budget OK.
|
|
151
|
-
const dropped = vis.pop();
|
|
152
|
-
if (dropped) {
|
|
153
|
-
over.unshift(dropped);
|
|
154
|
-
}
|
|
155
|
-
vis.push(activeTab);
|
|
156
|
-
const removeIdx = over.findIndex((t) => t.value === activeTab.value);
|
|
157
|
-
if (removeIdx !== -1) {
|
|
158
|
-
over.splice(removeIdx, 1);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
return { visible: vis, overflow: over };
|
|
163
|
-
}, [tabs, tabWidths, containerWidth, gap, moreTriggerWidth, value]);
|
|
164
|
-
|
|
165
|
-
return (
|
|
166
|
-
<div
|
|
167
|
-
className={cn(
|
|
168
|
-
'relative -mb-px flex items-end border-b border-rule',
|
|
169
|
-
className,
|
|
170
|
-
)}
|
|
171
|
-
>
|
|
172
|
-
{/* Off-screen measurement layer — renders ALL tabs so widths are real. */}
|
|
173
|
-
<div
|
|
174
|
-
ref={measureRef}
|
|
175
|
-
aria-hidden
|
|
176
|
-
className="pointer-events-none absolute left-0 top-0 flex items-center gap-1 opacity-0"
|
|
177
|
-
style={{ visibility: 'hidden' }}
|
|
178
|
-
>
|
|
179
|
-
{tabs.map((t) => (
|
|
180
|
-
<TabPill
|
|
181
|
-
key={`measure-${t.value}`}
|
|
182
|
-
tab={t}
|
|
183
|
-
active={false}
|
|
184
|
-
onClick={() => undefined}
|
|
185
|
-
/>
|
|
186
|
-
))}
|
|
187
|
-
</div>
|
|
188
|
-
|
|
189
|
-
{/* Live visible row. */}
|
|
190
|
-
<div
|
|
191
|
-
ref={containerRef}
|
|
192
|
-
role="tablist"
|
|
193
|
-
className="flex flex-1 items-end gap-1 overflow-hidden"
|
|
194
|
-
>
|
|
195
|
-
{visible.map((t) => (
|
|
196
|
-
<TabPill
|
|
197
|
-
key={t.value}
|
|
198
|
-
tab={t}
|
|
199
|
-
active={t.value === value}
|
|
200
|
-
onClick={() => onChange(t.value)}
|
|
201
|
-
onClose={
|
|
202
|
-
onClose && t.pinned !== true ? () => onClose(t.value) : undefined
|
|
203
|
-
}
|
|
204
|
-
/>
|
|
205
|
-
))}
|
|
206
|
-
</div>
|
|
207
|
-
|
|
208
|
-
{overflow.length > 0 && (
|
|
209
|
-
<DropdownMenu>
|
|
210
|
-
<DropdownMenuTrigger asChild>
|
|
211
|
-
<button
|
|
212
|
-
type="button"
|
|
213
|
-
className="ml-1 -mb-px inline-flex shrink-0 items-center gap-1 whitespace-nowrap px-2 py-2 text-body-1 text-ink-3 transition-colors hover:text-ink"
|
|
214
|
-
aria-label="More tabs"
|
|
215
|
-
>
|
|
216
|
-
More
|
|
217
|
-
<span className="rounded bg-paper-elev px-1 font-mono text-[10px] leading-4 text-ink-4">
|
|
218
|
-
{overflow.length}
|
|
219
|
-
</span>
|
|
220
|
-
<ChevronDown className="h-3 w-3" strokeWidth={1.6} />
|
|
221
|
-
</button>
|
|
222
|
-
</DropdownMenuTrigger>
|
|
223
|
-
<DropdownMenuContent align="end" className="min-w-[180px]">
|
|
224
|
-
{overflow.map((t) => (
|
|
225
|
-
<DropdownMenuItem
|
|
226
|
-
key={t.value}
|
|
227
|
-
onClick={() => onChange(t.value)}
|
|
228
|
-
className={cn(
|
|
229
|
-
t.value === value && 'bg-accent/60 text-foreground',
|
|
230
|
-
)}
|
|
231
|
-
>
|
|
232
|
-
<span className="flex-1 truncate">{t.label}</span>
|
|
233
|
-
{t.count !== undefined && (
|
|
234
|
-
<span className="ml-2 text-caption tabular-nums text-ink-4">
|
|
235
|
-
{t.count}
|
|
236
|
-
</span>
|
|
237
|
-
)}
|
|
238
|
-
{t.indicator && (
|
|
239
|
-
<span
|
|
240
|
-
aria-hidden
|
|
241
|
-
className="ml-2 inline-block h-1.5 w-1.5 rounded-full bg-warning"
|
|
242
|
-
/>
|
|
243
|
-
)}
|
|
244
|
-
{onClose && t.pinned !== true && (
|
|
245
|
-
<button
|
|
246
|
-
type="button"
|
|
247
|
-
aria-label={`Close ${t.label}`}
|
|
248
|
-
className="ml-2 rounded p-0.5 text-ink-4 hover:bg-paper-elev hover:text-ink"
|
|
249
|
-
onClick={(e) => {
|
|
250
|
-
e.stopPropagation();
|
|
251
|
-
onClose(t.value);
|
|
252
|
-
}}
|
|
253
|
-
>
|
|
254
|
-
<X className="h-3 w-3" strokeWidth={1.8} />
|
|
255
|
-
</button>
|
|
256
|
-
)}
|
|
257
|
-
</DropdownMenuItem>
|
|
258
|
-
))}
|
|
259
|
-
</DropdownMenuContent>
|
|
260
|
-
</DropdownMenu>
|
|
261
|
-
)}
|
|
262
|
-
</div>
|
|
263
|
-
);
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
function TabPill({
|
|
267
|
-
tab,
|
|
268
|
-
active,
|
|
269
|
-
onClick,
|
|
270
|
-
onClose,
|
|
271
|
-
}: Readonly<{
|
|
272
|
-
tab: OverflowTab;
|
|
273
|
-
active: boolean;
|
|
274
|
-
onClick: () => void;
|
|
275
|
-
onClose?: () => void;
|
|
276
|
-
}>) {
|
|
277
|
-
return (
|
|
278
|
-
<div
|
|
279
|
-
className={cn(
|
|
280
|
-
'group relative -mb-px inline-flex items-center gap-1.5 whitespace-nowrap rounded-t-md border px-3 py-2 text-body-1 transition-colors',
|
|
281
|
-
active
|
|
282
|
-
? 'border-rule border-b-transparent bg-paper-elev text-ink font-medium'
|
|
283
|
-
: 'border-transparent text-ink-3 hover:border-rule/40 hover:bg-paper-elev/60 hover:text-ink-2',
|
|
284
|
-
)}
|
|
285
|
-
>
|
|
286
|
-
<button
|
|
287
|
-
type="button"
|
|
288
|
-
role="tab"
|
|
289
|
-
aria-selected={active}
|
|
290
|
-
onClick={onClick}
|
|
291
|
-
className="inline-flex items-center gap-2 outline-none"
|
|
292
|
-
>
|
|
293
|
-
{tab.icon && <tab.icon className="h-3.5 w-3.5 shrink-0" />}
|
|
294
|
-
{tab.label}
|
|
295
|
-
{tab.count !== undefined && (
|
|
296
|
-
<span className="rounded bg-paper-elev px-1 font-mono text-[10px] tabular-nums leading-4 text-ink-4">
|
|
297
|
-
{tab.count}
|
|
298
|
-
</span>
|
|
299
|
-
)}
|
|
300
|
-
{tab.indicator && (
|
|
301
|
-
<span
|
|
302
|
-
aria-hidden
|
|
303
|
-
className="inline-block h-1.5 w-1.5 rounded-full bg-warning"
|
|
304
|
-
/>
|
|
305
|
-
)}
|
|
306
|
-
</button>
|
|
307
|
-
{onClose && (
|
|
308
|
-
<button
|
|
309
|
-
type="button"
|
|
310
|
-
aria-label={`Close ${tab.label}`}
|
|
311
|
-
onClick={(e) => {
|
|
312
|
-
e.stopPropagation();
|
|
313
|
-
onClose();
|
|
314
|
-
}}
|
|
315
|
-
className={cn(
|
|
316
|
-
'rounded p-0.5 text-ink-4 transition-opacity hover:bg-paper hover:text-ink',
|
|
317
|
-
active ? 'opacity-70' : 'opacity-0 group-hover:opacity-70',
|
|
318
|
-
)}
|
|
319
|
-
>
|
|
320
|
-
<X className="h-3 w-3" strokeWidth={1.8} />
|
|
321
|
-
</button>
|
|
322
|
-
)}
|
|
323
|
-
{active && (
|
|
324
|
-
<span
|
|
325
|
-
aria-hidden
|
|
326
|
-
className="absolute inset-x-2 bottom-[-1px] h-[2px] rounded-full bg-primary"
|
|
327
|
-
/>
|
|
328
|
-
)}
|
|
329
|
-
</div>
|
|
330
|
-
);
|
|
331
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
2
|
-
import * as React from "react";
|
|
3
|
-
|
|
4
|
-
import { cn } from '../cn';
|
|
5
|
-
|
|
6
|
-
const Popover = PopoverPrimitive.Root;
|
|
7
|
-
|
|
8
|
-
const PopoverTrigger = PopoverPrimitive.Trigger;
|
|
9
|
-
|
|
10
|
-
type PopoverContentProps = React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content> & {
|
|
11
|
-
container?: HTMLElement | null;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
const PopoverContent = React.forwardRef<
|
|
15
|
-
React.ElementRef<typeof PopoverPrimitive.Content>,
|
|
16
|
-
PopoverContentProps
|
|
17
|
-
>(({ className, align = "center", sideOffset = 4, container, ...props }, ref) => (
|
|
18
|
-
<PopoverPrimitive.Portal container={container ?? undefined}>
|
|
19
|
-
<PopoverPrimitive.Content
|
|
20
|
-
ref={ref}
|
|
21
|
-
align={align}
|
|
22
|
-
sideOffset={sideOffset}
|
|
23
|
-
className={cn(
|
|
24
|
-
"z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 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",
|
|
25
|
-
className,
|
|
26
|
-
)}
|
|
27
|
-
{...props}
|
|
28
|
-
/>
|
|
29
|
-
</PopoverPrimitive.Portal>
|
|
30
|
-
));
|
|
31
|
-
PopoverContent.displayName = PopoverPrimitive.Content.displayName;
|
|
32
|
-
|
|
33
|
-
export { Popover, PopoverTrigger, PopoverContent };
|