@object-ui/components 3.3.0 → 3.3.1
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/CHANGELOG.md +20 -0
- package/README.md +21 -1
- package/dist/index.css +6339 -2
- package/dist/index.js +17600 -17481
- package/dist/index.umd.cjs +36 -36
- package/dist/packages/components/src/custom/empty.d.ts +12 -1
- package/dist/packages/components/src/renderers/action/action-bar.d.ts +12 -1
- package/dist/packages/components/src/ui/chart.d.ts +10 -29
- package/package.json +65 -44
- package/.turbo/turbo-build.log +0 -84
- package/README_SHADCN_SYNC.md +0 -281
- package/TESTING.md +0 -335
- package/docs/FilterBuilder.md +0 -268
- package/metadata/Chart.component.yml +0 -30
- package/metadata/FilterBuilder.component.yml +0 -39
- package/metadata/GridLayout.component.yml +0 -27
- package/metadata/Menu.component.yml +0 -31
- package/metadata/ObjectForm.component.yml +0 -34
- package/metadata/ObjectGrid.component.yml +0 -72
- package/metadata/Page.component.yml +0 -24
- package/postcss.config.js +0 -14
- package/shadcn-components.json +0 -440
- package/src/SchemaRenderer.tsx +0 -28
- package/src/__tests__/PageRendererRegions.test.tsx +0 -668
- package/src/__tests__/README.md +0 -124
- package/src/__tests__/__snapshots__/snapshot-critical.test.tsx.snap +0 -811
- package/src/__tests__/__snapshots__/snapshot.test.tsx.snap +0 -327
- package/src/__tests__/accessibility.test.tsx +0 -137
- package/src/__tests__/action-bar.test.tsx +0 -206
- package/src/__tests__/api-consistency.test.tsx +0 -596
- package/src/__tests__/basic-renderers.test.tsx +0 -255
- package/src/__tests__/color-contrast.test.tsx +0 -212
- package/src/__tests__/complex-disclosure-renderers.test.tsx +0 -302
- package/src/__tests__/compliance.test.tsx +0 -72
- package/src/__tests__/config-field-renderer.test.tsx +0 -307
- package/src/__tests__/config-panel-renderer.test.tsx +0 -580
- package/src/__tests__/config-primitives.test.tsx +0 -106
- package/src/__tests__/edge-cases.test.tsx +0 -285
- package/src/__tests__/feedback-overlay-renderers.test.tsx +0 -349
- package/src/__tests__/filter-builder.test.tsx +0 -409
- package/src/__tests__/form-renderers.test.tsx +0 -364
- package/src/__tests__/layout-data-renderers.test.tsx +0 -340
- package/src/__tests__/mobile-accessibility.test.tsx +0 -120
- package/src/__tests__/navigation-overlay.test.tsx +0 -370
- package/src/__tests__/snapshot-critical.test.tsx +0 -317
- package/src/__tests__/snapshot.test.tsx +0 -205
- package/src/__tests__/test-utils.tsx +0 -190
- package/src/__tests__/use-config-draft.test.tsx +0 -295
- package/src/__tests__/view-compliance.test.tsx +0 -153
- package/src/__tests__/wcag-audit.test.tsx +0 -493
- package/src/custom/action-param-dialog.tsx +0 -264
- package/src/custom/button-group.tsx +0 -91
- package/src/custom/combobox.tsx +0 -104
- package/src/custom/config-field-renderer.tsx +0 -276
- package/src/custom/config-panel-renderer.tsx +0 -306
- package/src/custom/config-row.tsx +0 -50
- package/src/custom/date-picker.tsx +0 -61
- package/src/custom/empty.tsx +0 -112
- package/src/custom/field.tsx +0 -81
- package/src/custom/filter-builder.tsx +0 -418
- package/src/custom/index.ts +0 -21
- package/src/custom/input-group.tsx +0 -53
- package/src/custom/item.tsx +0 -201
- package/src/custom/kbd.tsx +0 -36
- package/src/custom/mobile-dialog-content.tsx +0 -67
- package/src/custom/native-select.tsx +0 -33
- package/src/custom/navigation-overlay.tsx +0 -334
- package/src/custom/section-header.tsx +0 -68
- package/src/custom/sort-builder.tsx +0 -129
- package/src/custom/spinner.tsx +0 -26
- package/src/custom/view-skeleton.tsx +0 -243
- package/src/custom/view-states.tsx +0 -153
- package/src/debug/DebugPanel.tsx +0 -313
- package/src/debug/__tests__/DebugPanel.test.tsx +0 -134
- package/src/debug/index.ts +0 -10
- package/src/hooks/use-config-draft.ts +0 -127
- package/src/hooks/use-mobile.tsx +0 -27
- package/src/index.css +0 -245
- package/src/index.ts +0 -47
- package/src/lib/use-sync-external-store-shim.ts +0 -10
- package/src/lib/use-sync-external-store-with-selector-shim.ts +0 -90
- package/src/lib/utils.tsx +0 -35
- package/src/new-components.test.ts +0 -73
- package/src/renderers/action/action-bar.tsx +0 -221
- package/src/renderers/action/action-button.tsx +0 -158
- package/src/renderers/action/action-group.tsx +0 -270
- package/src/renderers/action/action-icon.tsx +0 -150
- package/src/renderers/action/action-menu.tsx +0 -203
- package/src/renderers/action/index.ts +0 -19
- package/src/renderers/action/resolve-icon.ts +0 -35
- package/src/renderers/basic/button-group.tsx +0 -79
- package/src/renderers/basic/div.tsx +0 -60
- package/src/renderers/basic/html.tsx +0 -43
- package/src/renderers/basic/icon.tsx +0 -89
- package/src/renderers/basic/image.tsx +0 -49
- package/src/renderers/basic/index.ts +0 -18
- package/src/renderers/basic/navigation-menu.tsx +0 -81
- package/src/renderers/basic/pagination.tsx +0 -109
- package/src/renderers/basic/separator.tsx +0 -57
- package/src/renderers/basic/span.tsx +0 -63
- package/src/renderers/basic/text.tsx +0 -52
- package/src/renderers/complex/README-KANBAN.md +0 -208
- package/src/renderers/complex/TIMELINE.md +0 -353
- package/src/renderers/complex/__tests__/data-table-airtable-ux.test.tsx +0 -239
- package/src/renderers/complex/__tests__/data-table-batch-editing.test.tsx +0 -275
- package/src/renderers/complex/__tests__/data-table-cell-renderer.test.tsx +0 -120
- package/src/renderers/complex/__tests__/data-table-editing.test.tsx +0 -221
- package/src/renderers/complex/__tests__/data-table.test.ts +0 -76
- package/src/renderers/complex/carousel.tsx +0 -69
- package/src/renderers/complex/data-table.tsx +0 -1243
- package/src/renderers/complex/filter-builder.tsx +0 -77
- package/src/renderers/complex/index.ts +0 -16
- package/src/renderers/complex/resizable.tsx +0 -66
- package/src/renderers/complex/scroll-area.tsx +0 -58
- package/src/renderers/complex/table.tsx +0 -95
- package/src/renderers/data-display/alert.tsx +0 -46
- package/src/renderers/data-display/avatar.tsx +0 -38
- package/src/renderers/data-display/badge.tsx +0 -55
- package/src/renderers/data-display/breadcrumb.tsx +0 -61
- package/src/renderers/data-display/index.ts +0 -18
- package/src/renderers/data-display/kbd.tsx +0 -50
- package/src/renderers/data-display/list.tsx +0 -75
- package/src/renderers/data-display/statistic.tsx +0 -95
- package/src/renderers/data-display/table.tsx +0 -78
- package/src/renderers/data-display/tree-view.tsx +0 -176
- package/src/renderers/disclosure/accordion.tsx +0 -69
- package/src/renderers/disclosure/collapsible.tsx +0 -53
- package/src/renderers/disclosure/index.ts +0 -11
- package/src/renderers/disclosure/toggle-group.tsx +0 -79
- package/src/renderers/feedback/empty.tsx +0 -49
- package/src/renderers/feedback/index.ts +0 -16
- package/src/renderers/feedback/loading.tsx +0 -78
- package/src/renderers/feedback/progress.tsx +0 -29
- package/src/renderers/feedback/skeleton.tsx +0 -31
- package/src/renderers/feedback/sonner.tsx +0 -56
- package/src/renderers/feedback/spinner.tsx +0 -55
- package/src/renderers/feedback/toast.tsx +0 -59
- package/src/renderers/feedback/toaster.tsx +0 -23
- package/src/renderers/form/button.tsx +0 -103
- package/src/renderers/form/calendar.tsx +0 -34
- package/src/renderers/form/checkbox.tsx +0 -71
- package/src/renderers/form/combobox.tsx +0 -48
- package/src/renderers/form/command.tsx +0 -58
- package/src/renderers/form/date-picker.tsx +0 -84
- package/src/renderers/form/file-upload.tsx +0 -184
- package/src/renderers/form/form.tsx +0 -540
- package/src/renderers/form/index.ts +0 -26
- package/src/renderers/form/input-otp.tsx +0 -51
- package/src/renderers/form/input.tsx +0 -121
- package/src/renderers/form/label.tsx +0 -45
- package/src/renderers/form/radio-group.tsx +0 -63
- package/src/renderers/form/select.tsx +0 -94
- package/src/renderers/form/slider.tsx +0 -61
- package/src/renderers/form/switch.tsx +0 -48
- package/src/renderers/form/textarea.tsx +0 -76
- package/src/renderers/form/toggle.tsx +0 -42
- package/src/renderers/index.ts +0 -18
- package/src/renderers/layout/aspect-ratio.tsx +0 -51
- package/src/renderers/layout/card.tsx +0 -85
- package/src/renderers/layout/container.tsx +0 -122
- package/src/renderers/layout/flex.tsx +0 -132
- package/src/renderers/layout/grid.tsx +0 -178
- package/src/renderers/layout/index.ts +0 -19
- package/src/renderers/layout/page.tsx +0 -466
- package/src/renderers/layout/semantic.tsx +0 -48
- package/src/renderers/layout/stack.tsx +0 -132
- package/src/renderers/layout/tabs.tsx +0 -97
- package/src/renderers/navigation/header-bar.tsx +0 -118
- package/src/renderers/navigation/index.ts +0 -10
- package/src/renderers/navigation/sidebar.tsx +0 -208
- package/src/renderers/overlay/alert-dialog.tsx +0 -72
- package/src/renderers/overlay/context-menu.tsx +0 -100
- package/src/renderers/overlay/dialog.tsx +0 -77
- package/src/renderers/overlay/drawer.tsx +0 -77
- package/src/renderers/overlay/dropdown-menu.tsx +0 -99
- package/src/renderers/overlay/hover-card.tsx +0 -55
- package/src/renderers/overlay/index.ts +0 -18
- package/src/renderers/overlay/menubar.tsx +0 -76
- package/src/renderers/overlay/popover.tsx +0 -56
- package/src/renderers/overlay/sheet.tsx +0 -77
- package/src/renderers/overlay/tooltip.tsx +0 -67
- package/src/renderers/placeholders.tsx +0 -107
- package/src/stories/CRMApp.stories.tsx +0 -706
- package/src/stories/ConfigPanel.stories.tsx +0 -232
- package/src/stories/Guide.mdx +0 -55
- package/src/stories/MockedData.stories.tsx +0 -121
- package/src/stories/assets/accessibility.png +0 -0
- package/src/stories/assets/accessibility.svg +0 -1
- package/src/stories/assets/addon-library.png +0 -0
- package/src/stories/assets/assets.png +0 -0
- package/src/stories/assets/avif-test-image.avif +0 -0
- package/src/stories/assets/context.png +0 -0
- package/src/stories/assets/discord.svg +0 -1
- package/src/stories/assets/docs.png +0 -0
- package/src/stories/assets/figma-plugin.png +0 -0
- package/src/stories/assets/github.svg +0 -1
- package/src/stories/assets/share.png +0 -0
- package/src/stories/assets/styling.png +0 -0
- package/src/stories/assets/testing.png +0 -0
- package/src/stories/assets/theming.png +0 -0
- package/src/stories/assets/tutorials.svg +0 -1
- package/src/stories/assets/youtube.svg +0 -1
- package/src/stories/button.css +0 -30
- package/src/stories/header.css +0 -32
- package/src/stories/page.css +0 -68
- package/src/stories-json/Accessibility.mdx +0 -297
- package/src/stories-json/EdgeCases.stories.tsx +0 -160
- package/src/stories-json/GettingStarted.mdx +0 -89
- package/src/stories-json/Introduction.mdx +0 -127
- package/src/stories-json/accordion.stories.tsx +0 -43
- package/src/stories-json/aggrid.stories.tsx +0 -103
- package/src/stories-json/alert.stories.tsx +0 -39
- package/src/stories-json/aspect-ratio.stories.tsx +0 -34
- package/src/stories-json/avatar.stories.tsx +0 -38
- package/src/stories-json/badge.stories.tsx +0 -53
- package/src/stories-json/breadcrumb.stories.tsx +0 -30
- package/src/stories-json/button-group.stories.tsx +0 -43
- package/src/stories-json/button.stories.tsx +0 -73
- package/src/stories-json/calendar.stories.tsx +0 -85
- package/src/stories-json/card.stories.tsx +0 -48
- package/src/stories-json/carousel.stories.tsx +0 -33
- package/src/stories-json/charts.stories.tsx +0 -195
- package/src/stories-json/chatbot.stories.tsx +0 -349
- package/src/stories-json/code-editor.stories.tsx +0 -92
- package/src/stories-json/collapsible.stories.tsx +0 -40
- package/src/stories-json/controls.stories.tsx +0 -36
- package/src/stories-json/crm-live-data.stories.tsx +0 -154
- package/src/stories-json/dashboard.stories.tsx +0 -318
- package/src/stories-json/data-table.stories.tsx +0 -136
- package/src/stories-json/data_display_extras.stories.tsx +0 -102
- package/src/stories-json/date-picker.stories.tsx +0 -28
- package/src/stories-json/detail-view.stories.tsx +0 -258
- package/src/stories-json/dialog.stories.tsx +0 -43
- package/src/stories-json/feedback_extras.stories.tsx +0 -40
- package/src/stories-json/feedback_others.stories.tsx +0 -46
- package/src/stories-json/form-variants.stories.tsx +0 -210
- package/src/stories-json/form_advanced.stories.tsx +0 -117
- package/src/stories-json/form_extras.stories.tsx +0 -123
- package/src/stories-json/grid.stories.tsx +0 -56
- package/src/stories-json/icon.stories.tsx +0 -36
- package/src/stories-json/input.stories.tsx +0 -52
- package/src/stories-json/kanban.stories.tsx +0 -295
- package/src/stories-json/layout_extended.stories.tsx +0 -76
- package/src/stories-json/layout_flex.stories.tsx +0 -107
- package/src/stories-json/list-view.stories.tsx +0 -97
- package/src/stories-json/markdown.stories.tsx +0 -129
- package/src/stories-json/menus.stories.tsx +0 -63
- package/src/stories-json/metric-card.stories.tsx +0 -143
- package/src/stories-json/navigation-menu.stories.tsx +0 -37
- package/src/stories-json/object-aggrid-advanced.stories.tsx +0 -389
- package/src/stories-json/object-aggrid.stories.tsx +0 -252
- package/src/stories-json/object-form.stories.tsx +0 -130
- package/src/stories-json/object-gantt.stories.tsx +0 -114
- package/src/stories-json/object-grid.stories.tsx +0 -315
- package/src/stories-json/object-map.stories.tsx +0 -116
- package/src/stories-json/object-view.stories.tsx +0 -118
- package/src/stories-json/overlay_extras.stories.tsx +0 -113
- package/src/stories-json/overlay_others.stories.tsx +0 -76
- package/src/stories-json/page.stories.tsx +0 -55
- package/src/stories-json/reports.stories.tsx +0 -163
- package/src/stories-json/resizable.stories.tsx +0 -44
- package/src/stories-json/select.stories.tsx +0 -34
- package/src/stories-json/separator.stories.tsx +0 -41
- package/src/stories-json/sidebar.stories.tsx +0 -147
- package/src/stories-json/statistic.stories.tsx +0 -44
- package/src/stories-json/tabs.stories.tsx +0 -51
- package/src/stories-json/timeline.stories.tsx +0 -188
- package/src/stories-json/typography.stories.tsx +0 -45
- package/src/types/config-panel.ts +0 -101
- package/src/ui/accordion.tsx +0 -66
- package/src/ui/alert-dialog.tsx +0 -149
- package/src/ui/alert.tsx +0 -67
- package/src/ui/aspect-ratio.tsx +0 -15
- package/src/ui/avatar.tsx +0 -58
- package/src/ui/badge.tsx +0 -44
- package/src/ui/breadcrumb.tsx +0 -123
- package/src/ui/button.tsx +0 -64
- package/src/ui/calendar.tsx +0 -221
- package/src/ui/card.tsx +0 -87
- package/src/ui/carousel.tsx +0 -270
- package/src/ui/chart.tsx +0 -377
- package/src/ui/checkbox.tsx +0 -38
- package/src/ui/collapsible.tsx +0 -19
- package/src/ui/command.tsx +0 -161
- package/src/ui/context-menu.tsx +0 -208
- package/src/ui/dialog.tsx +0 -130
- package/src/ui/drawer.tsx +0 -126
- package/src/ui/dropdown-menu.tsx +0 -208
- package/src/ui/form.tsx +0 -186
- package/src/ui/hover-card.tsx +0 -37
- package/src/ui/index.ts +0 -56
- package/src/ui/input-otp.tsx +0 -79
- package/src/ui/input.tsx +0 -30
- package/src/ui/label.tsx +0 -34
- package/src/ui/menubar.tsx +0 -264
- package/src/ui/navigation-menu.tsx +0 -136
- package/src/ui/pagination.tsx +0 -125
- package/src/ui/popover.tsx +0 -39
- package/src/ui/progress.tsx +0 -36
- package/src/ui/radio-group.tsx +0 -52
- package/src/ui/resizable.tsx +0 -53
- package/src/ui/scroll-area.tsx +0 -56
- package/src/ui/select.tsx +0 -168
- package/src/ui/separator.tsx +0 -39
- package/src/ui/sheet.tsx +0 -150
- package/src/ui/sidebar.tsx +0 -781
- package/src/ui/skeleton.tsx +0 -23
- package/src/ui/slider.tsx +0 -39
- package/src/ui/sonner.tsx +0 -53
- package/src/ui/switch.tsx +0 -37
- package/src/ui/table.tsx +0 -125
- package/src/ui/tabs.tsx +0 -63
- package/src/ui/textarea.tsx +0 -30
- package/src/ui/toast.tsx +0 -137
- package/src/ui/toggle-group.tsx +0 -69
- package/src/ui/toggle.tsx +0 -53
- package/src/ui/tooltip.tsx +0 -38
- package/src/ui/typography.tsx +0 -85
- package/tsconfig.json +0 -19
- package/vite.config.ts +0 -71
- package/vitest.config.ts +0 -5
package/src/custom/item.tsx
DELETED
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ObjectUI
|
|
3
|
-
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
-
*
|
|
5
|
-
* This source code is licensed under the MIT license found in the
|
|
6
|
-
* LICENSE file in the root directory of this source tree.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import * as React from "react"
|
|
10
|
-
import { Slot as SlotPrimitive } from "@radix-ui/react-slot"
|
|
11
|
-
import { cva, type VariantProps } from "class-variance-authority"
|
|
12
|
-
|
|
13
|
-
import { cn } from "../lib/utils"
|
|
14
|
-
import { Separator } from "../ui/separator"
|
|
15
|
-
|
|
16
|
-
function ItemGroup({ className, ...props }: React.ComponentProps<"div">) {
|
|
17
|
-
return (
|
|
18
|
-
<div
|
|
19
|
-
role="list"
|
|
20
|
-
data-slot="item-group"
|
|
21
|
-
className={cn("group/item-group flex flex-col", className)}
|
|
22
|
-
{...props}
|
|
23
|
-
/>
|
|
24
|
-
)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function ItemSeparator({
|
|
28
|
-
className,
|
|
29
|
-
...props
|
|
30
|
-
}: React.ComponentProps<typeof Separator>) {
|
|
31
|
-
return (
|
|
32
|
-
<Separator
|
|
33
|
-
data-slot="item-separator"
|
|
34
|
-
orientation="horizontal"
|
|
35
|
-
className={cn("my-0", className)}
|
|
36
|
-
{...props}
|
|
37
|
-
/>
|
|
38
|
-
)
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const itemVariants = cva(
|
|
42
|
-
"group/item flex items-center border border-transparent text-sm rounded-md transition-colors [a]:hover:bg-accent/50 [a]:transition-colors duration-100 flex-wrap outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
|
|
43
|
-
{
|
|
44
|
-
variants: {
|
|
45
|
-
variant: {
|
|
46
|
-
default: "bg-transparent",
|
|
47
|
-
outline: "border-border",
|
|
48
|
-
muted: "bg-muted/50",
|
|
49
|
-
},
|
|
50
|
-
size: {
|
|
51
|
-
default: "p-4 gap-4 ",
|
|
52
|
-
sm: "py-3 px-4 gap-2.5",
|
|
53
|
-
},
|
|
54
|
-
},
|
|
55
|
-
defaultVariants: {
|
|
56
|
-
variant: "default",
|
|
57
|
-
size: "default",
|
|
58
|
-
},
|
|
59
|
-
}
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
function Item({
|
|
63
|
-
className,
|
|
64
|
-
variant = "default",
|
|
65
|
-
size = "default",
|
|
66
|
-
asChild = false,
|
|
67
|
-
...props
|
|
68
|
-
}: React.ComponentProps<"div"> &
|
|
69
|
-
VariantProps<typeof itemVariants> & { asChild?: boolean }) {
|
|
70
|
-
const Comp = asChild ? SlotPrimitive : "div"
|
|
71
|
-
return (
|
|
72
|
-
<Comp
|
|
73
|
-
data-slot="item"
|
|
74
|
-
data-variant={variant}
|
|
75
|
-
data-size={size}
|
|
76
|
-
className={cn(itemVariants({ variant, size, className }))}
|
|
77
|
-
{...props}
|
|
78
|
-
/>
|
|
79
|
-
)
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const itemMediaVariants = cva(
|
|
83
|
-
"flex shrink-0 items-center justify-center gap-2 group-has-[[data-slot=item-description]]/item:self-start [&_svg]:pointer-events-none group-has-[[data-slot=item-description]]/item:translate-y-0.5",
|
|
84
|
-
{
|
|
85
|
-
variants: {
|
|
86
|
-
variant: {
|
|
87
|
-
default: "bg-transparent",
|
|
88
|
-
icon: "size-8 border rounded-sm bg-muted [&_svg:not([class*='size-'])]:size-4",
|
|
89
|
-
image:
|
|
90
|
-
"size-10 rounded-sm overflow-hidden [&_img]:size-full [&_img]:object-cover",
|
|
91
|
-
},
|
|
92
|
-
},
|
|
93
|
-
defaultVariants: {
|
|
94
|
-
variant: "default",
|
|
95
|
-
},
|
|
96
|
-
}
|
|
97
|
-
)
|
|
98
|
-
|
|
99
|
-
function ItemMedia({
|
|
100
|
-
className,
|
|
101
|
-
variant = "default",
|
|
102
|
-
...props
|
|
103
|
-
}: React.ComponentProps<"div"> & VariantProps<typeof itemMediaVariants>) {
|
|
104
|
-
return (
|
|
105
|
-
<div
|
|
106
|
-
data-slot="item-media"
|
|
107
|
-
data-variant={variant}
|
|
108
|
-
className={cn(itemMediaVariants({ variant, className }))}
|
|
109
|
-
{...props}
|
|
110
|
-
/>
|
|
111
|
-
)
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function ItemContent({ className, ...props }: React.ComponentProps<"div">) {
|
|
115
|
-
return (
|
|
116
|
-
<div
|
|
117
|
-
data-slot="item-content"
|
|
118
|
-
className={cn(
|
|
119
|
-
"flex flex-1 flex-col gap-1 [&+[data-slot=item-content]]:flex-none",
|
|
120
|
-
className
|
|
121
|
-
)}
|
|
122
|
-
{...props}
|
|
123
|
-
/>
|
|
124
|
-
)
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
function ItemTitle({ className, ...props }: React.ComponentProps<"div">) {
|
|
128
|
-
return (
|
|
129
|
-
<div
|
|
130
|
-
data-slot="item-title"
|
|
131
|
-
className={cn(
|
|
132
|
-
"flex w-fit items-center gap-2 text-sm leading-snug font-medium",
|
|
133
|
-
className
|
|
134
|
-
)}
|
|
135
|
-
{...props}
|
|
136
|
-
/>
|
|
137
|
-
)
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
function ItemDescription({ className, ...props }: React.ComponentProps<"p">) {
|
|
141
|
-
return (
|
|
142
|
-
<p
|
|
143
|
-
data-slot="item-description"
|
|
144
|
-
className={cn(
|
|
145
|
-
"text-muted-foreground line-clamp-2 text-sm leading-normal font-normal text-balance",
|
|
146
|
-
"[&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4",
|
|
147
|
-
className
|
|
148
|
-
)}
|
|
149
|
-
{...props}
|
|
150
|
-
/>
|
|
151
|
-
)
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
function ItemActions({ className, ...props }: React.ComponentProps<"div">) {
|
|
155
|
-
return (
|
|
156
|
-
<div
|
|
157
|
-
data-slot="item-actions"
|
|
158
|
-
className={cn("flex items-center gap-2", className)}
|
|
159
|
-
{...props}
|
|
160
|
-
/>
|
|
161
|
-
)
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
function ItemHeader({ className, ...props }: React.ComponentProps<"div">) {
|
|
165
|
-
return (
|
|
166
|
-
<div
|
|
167
|
-
data-slot="item-header"
|
|
168
|
-
className={cn(
|
|
169
|
-
"flex basis-full items-center justify-between gap-2",
|
|
170
|
-
className
|
|
171
|
-
)}
|
|
172
|
-
{...props}
|
|
173
|
-
/>
|
|
174
|
-
)
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
function ItemFooter({ className, ...props }: React.ComponentProps<"div">) {
|
|
178
|
-
return (
|
|
179
|
-
<div
|
|
180
|
-
data-slot="item-footer"
|
|
181
|
-
className={cn(
|
|
182
|
-
"flex basis-full items-center justify-between gap-2",
|
|
183
|
-
className
|
|
184
|
-
)}
|
|
185
|
-
{...props}
|
|
186
|
-
/>
|
|
187
|
-
)
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
export {
|
|
191
|
-
Item,
|
|
192
|
-
ItemMedia,
|
|
193
|
-
ItemContent,
|
|
194
|
-
ItemActions,
|
|
195
|
-
ItemGroup,
|
|
196
|
-
ItemSeparator,
|
|
197
|
-
ItemTitle,
|
|
198
|
-
ItemDescription,
|
|
199
|
-
ItemHeader,
|
|
200
|
-
ItemFooter,
|
|
201
|
-
}
|
package/src/custom/kbd.tsx
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ObjectUI
|
|
3
|
-
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
-
*
|
|
5
|
-
* This source code is licensed under the MIT license found in the
|
|
6
|
-
* LICENSE file in the root directory of this source tree.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { cn } from "../lib/utils"
|
|
10
|
-
|
|
11
|
-
function Kbd({ className, ...props }: React.ComponentProps<"kbd">) {
|
|
12
|
-
return (
|
|
13
|
-
<kbd
|
|
14
|
-
data-slot="kbd"
|
|
15
|
-
className={cn(
|
|
16
|
-
"bg-muted text-muted-foreground pointer-events-none inline-flex h-5 w-fit min-w-5 items-center justify-center gap-1 rounded-sm px-1 font-sans text-xs font-medium select-none",
|
|
17
|
-
"[&_svg:not([class*='size-'])]:size-3",
|
|
18
|
-
"[[data-slot=tooltip-content]_&]:bg-background/20 [[data-slot=tooltip-content]_&]:text-background dark:[[data-slot=tooltip-content]_&]:bg-background/10",
|
|
19
|
-
className
|
|
20
|
-
)}
|
|
21
|
-
{...props}
|
|
22
|
-
/>
|
|
23
|
-
)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function KbdGroup({ className, ...props }: React.ComponentProps<"div">) {
|
|
27
|
-
return (
|
|
28
|
-
<kbd
|
|
29
|
-
data-slot="kbd-group"
|
|
30
|
-
className={cn("inline-flex items-center gap-1", className)}
|
|
31
|
-
{...props}
|
|
32
|
-
/>
|
|
33
|
-
)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export { Kbd, KbdGroup }
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ObjectUI
|
|
3
|
-
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
-
*
|
|
5
|
-
* This source code is licensed under the MIT license found in the
|
|
6
|
-
* LICENSE file in the root directory of this source tree.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* MobileDialogContent
|
|
11
|
-
*
|
|
12
|
-
* A mobile-optimized wrapper around the upstream Shadcn DialogContent.
|
|
13
|
-
* On mobile (< sm breakpoint), the dialog is full-screen with a larger
|
|
14
|
-
* close-button touch target (≥ 44×44px per WCAG 2.5.5).
|
|
15
|
-
* On tablet+ (≥ sm), it falls back to the standard centered dialog.
|
|
16
|
-
*
|
|
17
|
-
* This lives in `custom/` to avoid modifying the Shadcn-synced `ui/dialog.tsx`.
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
import * as React from 'react';
|
|
21
|
-
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
22
|
-
import { X } from 'lucide-react';
|
|
23
|
-
import { cn } from '../lib/utils';
|
|
24
|
-
import { DialogOverlay, DialogPortal } from '../ui/dialog';
|
|
25
|
-
|
|
26
|
-
export const MobileDialogContent = React.forwardRef<
|
|
27
|
-
React.ElementRef<typeof DialogPrimitive.Content>,
|
|
28
|
-
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
|
|
29
|
-
>(({ className, children, ...props }, ref) => (
|
|
30
|
-
<DialogPortal>
|
|
31
|
-
<DialogOverlay />
|
|
32
|
-
<DialogPrimitive.Content
|
|
33
|
-
ref={ref}
|
|
34
|
-
className={cn(
|
|
35
|
-
// Mobile-first: full-screen
|
|
36
|
-
'fixed inset-0 z-50 w-full bg-background p-4 shadow-lg duration-200',
|
|
37
|
-
'h-[100dvh]',
|
|
38
|
-
// Desktop (sm+): centered dialog with border + rounded corners
|
|
39
|
-
'sm:inset-auto sm:left-[50%] sm:top-[50%] sm:translate-x-[-50%] sm:translate-y-[-50%]',
|
|
40
|
-
'sm:max-w-lg sm:h-auto sm:max-h-[90vh] sm:rounded-lg sm:border sm:p-6',
|
|
41
|
-
// Animations
|
|
42
|
-
'data-[state=open]:animate-in data-[state=closed]:animate-out',
|
|
43
|
-
'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
|
|
44
|
-
'data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95',
|
|
45
|
-
'data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%]',
|
|
46
|
-
'data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]',
|
|
47
|
-
className,
|
|
48
|
-
)}
|
|
49
|
-
{...props}
|
|
50
|
-
>
|
|
51
|
-
{children}
|
|
52
|
-
<DialogPrimitive.Close
|
|
53
|
-
className={cn(
|
|
54
|
-
'absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity',
|
|
55
|
-
'hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
|
|
56
|
-
'disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground',
|
|
57
|
-
// Mobile touch target ≥ 44×44px (WCAG 2.5.5)
|
|
58
|
-
'min-h-[44px] min-w-[44px] sm:min-h-0 sm:min-w-0 flex items-center justify-center',
|
|
59
|
-
)}
|
|
60
|
-
>
|
|
61
|
-
<X className="h-5 w-5 sm:h-4 sm:w-4" />
|
|
62
|
-
<span className="sr-only">Close</span>
|
|
63
|
-
</DialogPrimitive.Close>
|
|
64
|
-
</DialogPrimitive.Content>
|
|
65
|
-
</DialogPortal>
|
|
66
|
-
));
|
|
67
|
-
MobileDialogContent.displayName = 'MobileDialogContent';
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ObjectUI
|
|
3
|
-
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
-
*
|
|
5
|
-
* This source code is licensed under the MIT license found in the
|
|
6
|
-
* LICENSE file in the root directory of this source tree.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import * as React from "react"
|
|
10
|
-
import { cn } from "../lib/utils"
|
|
11
|
-
|
|
12
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
13
|
-
export interface NativeSelectProps extends React.SelectHTMLAttributes<HTMLSelectElement> {}
|
|
14
|
-
|
|
15
|
-
const NativeSelect = React.forwardRef<HTMLSelectElement, NativeSelectProps>(
|
|
16
|
-
({ className, children, ...props }, ref) => {
|
|
17
|
-
return (
|
|
18
|
-
<select
|
|
19
|
-
className={cn(
|
|
20
|
-
"flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
|
21
|
-
className
|
|
22
|
-
)}
|
|
23
|
-
ref={ref}
|
|
24
|
-
{...props}
|
|
25
|
-
>
|
|
26
|
-
{children}
|
|
27
|
-
</select>
|
|
28
|
-
)
|
|
29
|
-
}
|
|
30
|
-
)
|
|
31
|
-
NativeSelect.displayName = "NativeSelect"
|
|
32
|
-
|
|
33
|
-
export { NativeSelect }
|
|
@@ -1,334 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ObjectUI
|
|
3
|
-
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
-
*
|
|
5
|
-
* This source code is licensed under the MIT license found in the
|
|
6
|
-
* LICENSE file in the root directory of this source tree.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* NavigationOverlay
|
|
11
|
-
*
|
|
12
|
-
* A reusable component that renders record detail overlays based on
|
|
13
|
-
* ViewNavigationConfig mode. Supports drawer (Sheet), modal (Dialog),
|
|
14
|
-
* split (ResizablePanelGroup), and popover modes.
|
|
15
|
-
*
|
|
16
|
-
* Works in conjunction with useNavigationOverlay hook from @object-ui/react —
|
|
17
|
-
* the hook manages state while this component handles the visual presentation.
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* ```tsx
|
|
21
|
-
* import { useNavigationOverlay } from '@object-ui/react';
|
|
22
|
-
* import { NavigationOverlay } from '@object-ui/components';
|
|
23
|
-
*
|
|
24
|
-
* const nav = useNavigationOverlay({
|
|
25
|
-
* navigation: schema.navigation,
|
|
26
|
-
* objectName: schema.objectName,
|
|
27
|
-
* });
|
|
28
|
-
*
|
|
29
|
-
* return (
|
|
30
|
-
* <>
|
|
31
|
-
* <DataTable onRowClick={nav.handleClick} />
|
|
32
|
-
* <NavigationOverlay {...nav} title="Record Detail">
|
|
33
|
-
* {(record) => <RecordDetail record={record} />}
|
|
34
|
-
* </NavigationOverlay>
|
|
35
|
-
* </>
|
|
36
|
-
* );
|
|
37
|
-
* ```
|
|
38
|
-
*/
|
|
39
|
-
|
|
40
|
-
import React from 'react';
|
|
41
|
-
import { cn } from '../lib/utils';
|
|
42
|
-
import {
|
|
43
|
-
Sheet,
|
|
44
|
-
SheetContent,
|
|
45
|
-
SheetHeader,
|
|
46
|
-
SheetTitle,
|
|
47
|
-
SheetDescription,
|
|
48
|
-
} from '../ui/sheet';
|
|
49
|
-
import {
|
|
50
|
-
Dialog,
|
|
51
|
-
DialogContent,
|
|
52
|
-
DialogHeader,
|
|
53
|
-
DialogTitle,
|
|
54
|
-
DialogDescription,
|
|
55
|
-
} from '../ui/dialog';
|
|
56
|
-
import {
|
|
57
|
-
Popover,
|
|
58
|
-
PopoverContent,
|
|
59
|
-
PopoverTrigger,
|
|
60
|
-
} from '../ui/popover';
|
|
61
|
-
import {
|
|
62
|
-
ResizablePanelGroup,
|
|
63
|
-
ResizablePanel,
|
|
64
|
-
ResizableHandle,
|
|
65
|
-
} from '../ui/resizable';
|
|
66
|
-
|
|
67
|
-
/** Navigation mode type — matches ViewNavigationConfig.mode */
|
|
68
|
-
export type NavigationOverlayMode =
|
|
69
|
-
| 'page'
|
|
70
|
-
| 'drawer'
|
|
71
|
-
| 'modal'
|
|
72
|
-
| 'split'
|
|
73
|
-
| 'popover'
|
|
74
|
-
| 'new_window'
|
|
75
|
-
| 'none';
|
|
76
|
-
|
|
77
|
-
export interface NavigationOverlayProps {
|
|
78
|
-
/** Whether the overlay is open */
|
|
79
|
-
isOpen: boolean;
|
|
80
|
-
/** The selected record */
|
|
81
|
-
selectedRecord: Record<string, unknown> | null;
|
|
82
|
-
/** The navigation mode */
|
|
83
|
-
mode: NavigationOverlayMode;
|
|
84
|
-
/** Close the overlay */
|
|
85
|
-
close: () => void;
|
|
86
|
-
/** Set open state (for controlled Sheet/Dialog onOpenChange) */
|
|
87
|
-
setIsOpen: (open: boolean) => void;
|
|
88
|
-
/** Width for the overlay (drawer/modal/split) */
|
|
89
|
-
width?: string | number;
|
|
90
|
-
/** Whether navigation is an overlay mode */
|
|
91
|
-
isOverlay: boolean;
|
|
92
|
-
/** Target view/form name from NavigationConfig */
|
|
93
|
-
view?: string;
|
|
94
|
-
/** Title for the overlay header */
|
|
95
|
-
title?: string;
|
|
96
|
-
/** Description for the overlay header */
|
|
97
|
-
description?: string;
|
|
98
|
-
/** CSS class for the overlay container */
|
|
99
|
-
className?: string;
|
|
100
|
-
/**
|
|
101
|
-
* Render function for the overlay content.
|
|
102
|
-
* Receives the selected record.
|
|
103
|
-
*/
|
|
104
|
-
children: (record: Record<string, unknown>) => React.ReactNode;
|
|
105
|
-
/**
|
|
106
|
-
* Optional render function for a specific view/form based on `view` prop.
|
|
107
|
-
* When provided, this takes priority over `children` for rendering overlay content.
|
|
108
|
-
* Receives the selected record and the view name.
|
|
109
|
-
*/
|
|
110
|
-
renderView?: (record: Record<string, unknown>, viewName: string) => React.ReactNode;
|
|
111
|
-
/**
|
|
112
|
-
* The main content to wrap (for split mode only).
|
|
113
|
-
* In split mode, the main content is rendered in the left panel.
|
|
114
|
-
*/
|
|
115
|
-
mainContent?: React.ReactNode;
|
|
116
|
-
/**
|
|
117
|
-
* Popover trigger element (for popover mode).
|
|
118
|
-
*/
|
|
119
|
-
popoverTrigger?: React.ReactNode;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Resolve width to CSS-compatible value
|
|
124
|
-
*/
|
|
125
|
-
function resolveWidth(width: string | number | undefined): string | undefined {
|
|
126
|
-
if (width == null) return undefined;
|
|
127
|
-
if (typeof width === 'number') return `${width}px`;
|
|
128
|
-
return width;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Compute CSS style from NavigationConfig width
|
|
133
|
-
*/
|
|
134
|
-
function getWidthStyle(width: string | number | undefined): React.CSSProperties {
|
|
135
|
-
const resolved = resolveWidth(width);
|
|
136
|
-
if (!resolved) return {};
|
|
137
|
-
return { maxWidth: resolved, width: '100%' };
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* NavigationOverlay — renders record detail in the configured overlay mode.
|
|
142
|
-
*
|
|
143
|
-
* Supports:
|
|
144
|
-
* - **drawer**: Right-side Sheet panel
|
|
145
|
-
* - **modal**: Center Dialog overlay
|
|
146
|
-
* - **split**: Side-by-side ResizablePanelGroup
|
|
147
|
-
* - **popover**: Hoverable/clickable popover card
|
|
148
|
-
* - **page / new_window / none**: No overlay rendered (handled by hook)
|
|
149
|
-
*/
|
|
150
|
-
export const NavigationOverlay: React.FC<NavigationOverlayProps> = ({
|
|
151
|
-
isOpen,
|
|
152
|
-
selectedRecord,
|
|
153
|
-
mode,
|
|
154
|
-
close,
|
|
155
|
-
setIsOpen,
|
|
156
|
-
width,
|
|
157
|
-
view,
|
|
158
|
-
title,
|
|
159
|
-
description,
|
|
160
|
-
className,
|
|
161
|
-
children,
|
|
162
|
-
renderView,
|
|
163
|
-
mainContent,
|
|
164
|
-
popoverTrigger,
|
|
165
|
-
}) => {
|
|
166
|
-
// Non-overlay modes don't render anything
|
|
167
|
-
if (mode === 'page' || mode === 'new_window' || mode === 'none') {
|
|
168
|
-
return null;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
if (!selectedRecord) {
|
|
172
|
-
return null;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
const widthStyle = getWidthStyle(width);
|
|
176
|
-
const resolvedTitle = title || 'Record Detail';
|
|
177
|
-
|
|
178
|
-
// Use renderView when both renderView and view are provided; otherwise fallback to children
|
|
179
|
-
const renderContent = (record: Record<string, unknown>) => {
|
|
180
|
-
if (renderView && view) {
|
|
181
|
-
return renderView(record, view);
|
|
182
|
-
}
|
|
183
|
-
return children(record);
|
|
184
|
-
};
|
|
185
|
-
|
|
186
|
-
// --- Drawer Mode (Sheet) ---
|
|
187
|
-
if (mode === 'drawer') {
|
|
188
|
-
return (
|
|
189
|
-
<Sheet open={isOpen} onOpenChange={setIsOpen}>
|
|
190
|
-
<SheetContent
|
|
191
|
-
side="right"
|
|
192
|
-
className={cn('w-full sm:max-w-2xl overflow-y-auto', className)}
|
|
193
|
-
style={widthStyle}
|
|
194
|
-
>
|
|
195
|
-
<SheetHeader>
|
|
196
|
-
<SheetTitle>{resolvedTitle}</SheetTitle>
|
|
197
|
-
{description && <SheetDescription>{description}</SheetDescription>}
|
|
198
|
-
</SheetHeader>
|
|
199
|
-
<div className="mt-4">
|
|
200
|
-
{renderContent(selectedRecord)}
|
|
201
|
-
</div>
|
|
202
|
-
</SheetContent>
|
|
203
|
-
</Sheet>
|
|
204
|
-
);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
// --- Modal Mode (Dialog) ---
|
|
208
|
-
if (mode === 'modal') {
|
|
209
|
-
return (
|
|
210
|
-
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
|
211
|
-
<DialogContent
|
|
212
|
-
className={cn('max-w-2xl max-h-[90vh] overflow-y-auto', className)}
|
|
213
|
-
style={widthStyle}
|
|
214
|
-
>
|
|
215
|
-
<DialogHeader>
|
|
216
|
-
<DialogTitle>{resolvedTitle}</DialogTitle>
|
|
217
|
-
{description && <DialogDescription>{description}</DialogDescription>}
|
|
218
|
-
</DialogHeader>
|
|
219
|
-
<div className="mt-4">
|
|
220
|
-
{renderContent(selectedRecord)}
|
|
221
|
-
</div>
|
|
222
|
-
</DialogContent>
|
|
223
|
-
</Dialog>
|
|
224
|
-
);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// --- Split Mode (Resizable Panels) ---
|
|
228
|
-
if (mode === 'split') {
|
|
229
|
-
if (!isOpen || !mainContent) {
|
|
230
|
-
return null;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
// Calculate panel sizes based on width config
|
|
234
|
-
const detailPercent = width
|
|
235
|
-
? typeof width === 'number'
|
|
236
|
-
? Math.min(70, Math.max(20, (width / 1200) * 100))
|
|
237
|
-
: 40
|
|
238
|
-
: 40;
|
|
239
|
-
const mainPercent = 100 - detailPercent;
|
|
240
|
-
|
|
241
|
-
// Cast needed: ResizablePanelGroup has correct runtime behavior but
|
|
242
|
-
// vite-plugin-dts may not resolve the direction prop type correctly
|
|
243
|
-
const PanelGroup = ResizablePanelGroup as React.FC<any>;
|
|
244
|
-
|
|
245
|
-
return (
|
|
246
|
-
<PanelGroup direction="horizontal" className={cn('h-full', className)}>
|
|
247
|
-
<ResizablePanel defaultSize={mainPercent} minSize={30}>
|
|
248
|
-
{mainContent}
|
|
249
|
-
</ResizablePanel>
|
|
250
|
-
<ResizableHandle withHandle />
|
|
251
|
-
<ResizablePanel defaultSize={detailPercent} minSize={20}>
|
|
252
|
-
<div className="h-full overflow-y-auto p-4">
|
|
253
|
-
<div className="flex items-center justify-between mb-4">
|
|
254
|
-
<h3 className="text-lg font-semibold">{resolvedTitle}</h3>
|
|
255
|
-
<button
|
|
256
|
-
onClick={close}
|
|
257
|
-
className="rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2"
|
|
258
|
-
aria-label="Close panel"
|
|
259
|
-
>
|
|
260
|
-
<svg
|
|
261
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
262
|
-
width="16"
|
|
263
|
-
height="16"
|
|
264
|
-
viewBox="0 0 24 24"
|
|
265
|
-
fill="none"
|
|
266
|
-
stroke="currentColor"
|
|
267
|
-
strokeWidth="2"
|
|
268
|
-
strokeLinecap="round"
|
|
269
|
-
strokeLinejoin="round"
|
|
270
|
-
>
|
|
271
|
-
<line x1="18" y1="6" x2="6" y2="18" />
|
|
272
|
-
<line x1="6" y1="6" x2="18" y2="18" />
|
|
273
|
-
</svg>
|
|
274
|
-
</button>
|
|
275
|
-
</div>
|
|
276
|
-
{description && (
|
|
277
|
-
<p className="text-sm text-muted-foreground mb-4">{description}</p>
|
|
278
|
-
)}
|
|
279
|
-
{renderContent(selectedRecord)}
|
|
280
|
-
</div>
|
|
281
|
-
</ResizablePanel>
|
|
282
|
-
</PanelGroup>
|
|
283
|
-
);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// --- Popover Mode ---
|
|
287
|
-
if (mode === 'popover') {
|
|
288
|
-
if (!popoverTrigger) {
|
|
289
|
-
// Fallback: render as a compact floating card when no trigger element is provided
|
|
290
|
-
if (!isOpen) return null;
|
|
291
|
-
return (
|
|
292
|
-
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
|
293
|
-
<DialogContent
|
|
294
|
-
className={cn('w-96 max-h-[80vh] overflow-y-auto p-4', className)}
|
|
295
|
-
style={widthStyle}
|
|
296
|
-
>
|
|
297
|
-
<DialogHeader>
|
|
298
|
-
<DialogTitle className="text-sm">{resolvedTitle}</DialogTitle>
|
|
299
|
-
{description && <DialogDescription className="text-xs">{description}</DialogDescription>}
|
|
300
|
-
</DialogHeader>
|
|
301
|
-
<div className="mt-2">
|
|
302
|
-
{renderContent(selectedRecord)}
|
|
303
|
-
</div>
|
|
304
|
-
</DialogContent>
|
|
305
|
-
</Dialog>
|
|
306
|
-
);
|
|
307
|
-
}
|
|
308
|
-
return (
|
|
309
|
-
<Popover open={isOpen} onOpenChange={setIsOpen}>
|
|
310
|
-
{popoverTrigger && (
|
|
311
|
-
<PopoverTrigger asChild>
|
|
312
|
-
{popoverTrigger}
|
|
313
|
-
</PopoverTrigger>
|
|
314
|
-
)}
|
|
315
|
-
<PopoverContent
|
|
316
|
-
className={cn('w-96 max-h-[400px] overflow-y-auto p-4', className)}
|
|
317
|
-
style={widthStyle}
|
|
318
|
-
>
|
|
319
|
-
<div className="space-y-2">
|
|
320
|
-
<h4 className="text-sm font-semibold">{resolvedTitle}</h4>
|
|
321
|
-
{description && (
|
|
322
|
-
<p className="text-xs text-muted-foreground">{description}</p>
|
|
323
|
-
)}
|
|
324
|
-
{renderContent(selectedRecord)}
|
|
325
|
-
</div>
|
|
326
|
-
</PopoverContent>
|
|
327
|
-
</Popover>
|
|
328
|
-
);
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
return null;
|
|
332
|
-
};
|
|
333
|
-
|
|
334
|
-
NavigationOverlay.displayName = 'NavigationOverlay';
|