@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
|
@@ -1,68 +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 { ChevronDown, ChevronRight } from "lucide-react"
|
|
10
|
-
|
|
11
|
-
import { cn } from "../lib/utils"
|
|
12
|
-
|
|
13
|
-
export interface SectionHeaderProps {
|
|
14
|
-
/** Section heading text */
|
|
15
|
-
title: string
|
|
16
|
-
/** Icon rendered before the title */
|
|
17
|
-
icon?: React.ReactNode
|
|
18
|
-
/** Enable collapse/expand toggle */
|
|
19
|
-
collapsible?: boolean
|
|
20
|
-
/** Current collapsed state */
|
|
21
|
-
collapsed?: boolean
|
|
22
|
-
/** Callback when toggling collapse/expand */
|
|
23
|
-
onToggle?: () => void
|
|
24
|
-
/** Data-testid attribute */
|
|
25
|
-
testId?: string
|
|
26
|
-
/** Additional CSS class name */
|
|
27
|
-
className?: string
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Section heading with optional collapse/expand support.
|
|
32
|
-
*
|
|
33
|
-
* Renders as a `<button>` when collapsible, with a chevron icon
|
|
34
|
-
* indicating the expand/collapse state. Uses `aria-expanded` for accessibility.
|
|
35
|
-
*/
|
|
36
|
-
function SectionHeader({ title, icon, collapsible, collapsed, onToggle, testId, className }: SectionHeaderProps) {
|
|
37
|
-
const titleContent = (
|
|
38
|
-
<h3 className="text-xs font-semibold text-foreground uppercase tracking-wider flex items-center gap-1.5">
|
|
39
|
-
{icon && <span className="text-muted-foreground shrink-0" aria-hidden="true">{icon}</span>}
|
|
40
|
-
{title}
|
|
41
|
-
</h3>
|
|
42
|
-
)
|
|
43
|
-
if (collapsible) {
|
|
44
|
-
return (
|
|
45
|
-
<button
|
|
46
|
-
data-testid={testId}
|
|
47
|
-
className={cn("flex items-center justify-between pt-4 pb-1.5 first:pt-0 w-full text-left", className)}
|
|
48
|
-
onClick={onToggle}
|
|
49
|
-
type="button"
|
|
50
|
-
aria-expanded={!collapsed}
|
|
51
|
-
>
|
|
52
|
-
{titleContent}
|
|
53
|
-
{collapsed ? (
|
|
54
|
-
<ChevronRight className="h-3 w-3 text-muted-foreground" />
|
|
55
|
-
) : (
|
|
56
|
-
<ChevronDown className="h-3 w-3 text-muted-foreground" />
|
|
57
|
-
)}
|
|
58
|
-
</button>
|
|
59
|
-
)
|
|
60
|
-
}
|
|
61
|
-
return (
|
|
62
|
-
<div className={cn("pt-4 pb-1.5 first:pt-0", className)} data-testid={testId}>
|
|
63
|
-
{titleContent}
|
|
64
|
-
</div>
|
|
65
|
-
)
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export { SectionHeader }
|
|
@@ -1,129 +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 { X, Plus, Trash2 } from "lucide-react"
|
|
11
|
-
|
|
12
|
-
import { cn } from "../lib/utils"
|
|
13
|
-
import { Button } from "../ui/button"
|
|
14
|
-
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../ui/select"
|
|
15
|
-
|
|
16
|
-
export interface SortItem {
|
|
17
|
-
id: string;
|
|
18
|
-
field: string;
|
|
19
|
-
order: 'asc' | 'desc';
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface SortBuilderProps {
|
|
23
|
-
fields?: Array<{
|
|
24
|
-
value: string
|
|
25
|
-
label: string
|
|
26
|
-
}>;
|
|
27
|
-
value?: SortItem[];
|
|
28
|
-
onChange?: (value: SortItem[]) => void;
|
|
29
|
-
className?: string;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function SortBuilder({
|
|
33
|
-
fields = [],
|
|
34
|
-
value = [],
|
|
35
|
-
onChange,
|
|
36
|
-
className,
|
|
37
|
-
}: SortBuilderProps) {
|
|
38
|
-
// Use internal state initialization prop changes
|
|
39
|
-
const [items, setItems] = React.useState<SortItem[]>(value || []);
|
|
40
|
-
|
|
41
|
-
React.useEffect(() => {
|
|
42
|
-
if (value && JSON.stringify(value) !== JSON.stringify(items)) {
|
|
43
|
-
setItems(value);
|
|
44
|
-
}
|
|
45
|
-
}, [value]);
|
|
46
|
-
|
|
47
|
-
const handleChange = (newItems: SortItem[]) => {
|
|
48
|
-
setItems(newItems);
|
|
49
|
-
onChange?.(newItems);
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
const addItem = () => {
|
|
53
|
-
const newItem: SortItem = {
|
|
54
|
-
id: crypto.randomUUID(),
|
|
55
|
-
field: fields[0]?.value || "",
|
|
56
|
-
order: 'asc',
|
|
57
|
-
};
|
|
58
|
-
handleChange([...items, newItem]);
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
const updateItem = (id: string, updates: Partial<SortItem>) => {
|
|
62
|
-
handleChange(items.map(item => item.id === id ? { ...item, ...updates } : item));
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
const removeItem = (id: string) => {
|
|
66
|
-
handleChange(items.filter(item => item.id !== id));
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
return (
|
|
70
|
-
<div className={cn("space-y-3", className)}>
|
|
71
|
-
<div className="space-y-2">
|
|
72
|
-
{items.map((item, index) => (
|
|
73
|
-
<div key={item.id} className="flex items-center gap-2">
|
|
74
|
-
<span className="text-sm font-medium w-16 text-muted-foreground">
|
|
75
|
-
{index === 0 ? "Sort by" : "Then by"}
|
|
76
|
-
</span>
|
|
77
|
-
<div className="flex-1">
|
|
78
|
-
<Select
|
|
79
|
-
value={item.field}
|
|
80
|
-
onValueChange={(val) => updateItem(item.id, { field: val })}
|
|
81
|
-
>
|
|
82
|
-
<SelectTrigger className="h-9">
|
|
83
|
-
<SelectValue placeholder="Select field" />
|
|
84
|
-
</SelectTrigger>
|
|
85
|
-
<SelectContent>
|
|
86
|
-
{fields.map(f => (
|
|
87
|
-
<SelectItem key={f.value} value={f.value}>{f.label}</SelectItem>
|
|
88
|
-
))}
|
|
89
|
-
</SelectContent>
|
|
90
|
-
</Select>
|
|
91
|
-
</div>
|
|
92
|
-
<div className="w-28">
|
|
93
|
-
<Select
|
|
94
|
-
value={item.order}
|
|
95
|
-
onValueChange={(val) => updateItem(item.id, { order: val as 'asc' | 'desc' })}
|
|
96
|
-
>
|
|
97
|
-
<SelectTrigger className="h-9">
|
|
98
|
-
<SelectValue />
|
|
99
|
-
</SelectTrigger>
|
|
100
|
-
<SelectContent>
|
|
101
|
-
<SelectItem value="asc">A -> Z</SelectItem>
|
|
102
|
-
<SelectItem value="desc">Z -> A</SelectItem>
|
|
103
|
-
</SelectContent>
|
|
104
|
-
</Select>
|
|
105
|
-
</div>
|
|
106
|
-
<Button
|
|
107
|
-
variant="ghost"
|
|
108
|
-
size="icon"
|
|
109
|
-
className="h-9 w-9 shrink-0"
|
|
110
|
-
onClick={() => removeItem(item.id)}
|
|
111
|
-
>
|
|
112
|
-
<X className="h-4 w-4" />
|
|
113
|
-
</Button>
|
|
114
|
-
</div>
|
|
115
|
-
))}
|
|
116
|
-
</div>
|
|
117
|
-
<Button
|
|
118
|
-
variant="outline"
|
|
119
|
-
size="sm"
|
|
120
|
-
onClick={addItem}
|
|
121
|
-
className="h-8"
|
|
122
|
-
disabled={fields.length === 0}
|
|
123
|
-
>
|
|
124
|
-
<Plus className="h-3 w-3 mr-2" />
|
|
125
|
-
Add sort
|
|
126
|
-
</Button>
|
|
127
|
-
</div>
|
|
128
|
-
);
|
|
129
|
-
}
|
package/src/custom/spinner.tsx
DELETED
|
@@ -1,26 +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
|
-
import { Loader2 } from "lucide-react"
|
|
12
|
-
|
|
13
|
-
function Spinner({ className, ...props }: React.ComponentProps<"div">) {
|
|
14
|
-
return (
|
|
15
|
-
<div
|
|
16
|
-
role="status"
|
|
17
|
-
aria-label="Loading"
|
|
18
|
-
className={cn("flex items-center justify-center", className)}
|
|
19
|
-
{...props}
|
|
20
|
-
>
|
|
21
|
-
<Loader2 className="animate-spin text-muted-foreground w-full h-full min-w-4 min-h-4" />
|
|
22
|
-
</div>
|
|
23
|
-
)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export { Spinner }
|
|
@@ -1,243 +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
|
-
import { Skeleton } from "../ui/skeleton"
|
|
12
|
-
|
|
13
|
-
// ---------------------------------------------------------------------------
|
|
14
|
-
// Shared types
|
|
15
|
-
// ---------------------------------------------------------------------------
|
|
16
|
-
|
|
17
|
-
export interface ViewSkeletonProps extends React.ComponentProps<"div"> {
|
|
18
|
-
/** Number of rows/items to render */
|
|
19
|
-
rows?: number
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// ---------------------------------------------------------------------------
|
|
23
|
-
// GridSkeleton – table rows with header and column cells
|
|
24
|
-
// ---------------------------------------------------------------------------
|
|
25
|
-
|
|
26
|
-
export interface GridSkeletonProps extends ViewSkeletonProps {
|
|
27
|
-
/** Number of columns to render */
|
|
28
|
-
columns?: number
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function GridSkeleton({
|
|
32
|
-
rows = 5,
|
|
33
|
-
columns = 4,
|
|
34
|
-
className,
|
|
35
|
-
...props
|
|
36
|
-
}: GridSkeletonProps) {
|
|
37
|
-
return (
|
|
38
|
-
<div
|
|
39
|
-
data-slot="grid-skeleton"
|
|
40
|
-
className={cn("w-full space-y-2", className)}
|
|
41
|
-
{...props}
|
|
42
|
-
>
|
|
43
|
-
{/* Header row */}
|
|
44
|
-
<div className="flex gap-4 px-4 py-2">
|
|
45
|
-
{Array.from({ length: columns }).map((_, col) => (
|
|
46
|
-
<Skeleton key={col} className="h-4 flex-1 rounded" />
|
|
47
|
-
))}
|
|
48
|
-
</div>
|
|
49
|
-
|
|
50
|
-
{/* Data rows */}
|
|
51
|
-
{Array.from({ length: rows }).map((_, row) => (
|
|
52
|
-
<div key={row} className="flex gap-4 rounded-md border px-4 py-3">
|
|
53
|
-
{Array.from({ length: columns }).map((_, col) => (
|
|
54
|
-
<Skeleton
|
|
55
|
-
key={col}
|
|
56
|
-
className={cn("h-4 flex-1 rounded", col === 0 && "max-w-[40%]")}
|
|
57
|
-
/>
|
|
58
|
-
))}
|
|
59
|
-
</div>
|
|
60
|
-
))}
|
|
61
|
-
</div>
|
|
62
|
-
)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// ---------------------------------------------------------------------------
|
|
66
|
-
// KanbanSkeleton – columns with placeholder cards
|
|
67
|
-
// ---------------------------------------------------------------------------
|
|
68
|
-
|
|
69
|
-
export interface KanbanSkeletonProps extends ViewSkeletonProps {
|
|
70
|
-
/** Number of kanban columns to render */
|
|
71
|
-
columns?: number
|
|
72
|
-
/** Number of cards per column */
|
|
73
|
-
cardsPerColumn?: number
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function KanbanSkeleton({
|
|
77
|
-
columns = 3,
|
|
78
|
-
cardsPerColumn = 3,
|
|
79
|
-
className,
|
|
80
|
-
...props
|
|
81
|
-
}: KanbanSkeletonProps) {
|
|
82
|
-
return (
|
|
83
|
-
<div
|
|
84
|
-
data-slot="kanban-skeleton"
|
|
85
|
-
className={cn("flex gap-4 overflow-x-auto", className)}
|
|
86
|
-
{...props}
|
|
87
|
-
>
|
|
88
|
-
{Array.from({ length: columns }).map((_, col) => (
|
|
89
|
-
<div
|
|
90
|
-
key={col}
|
|
91
|
-
className="flex w-72 shrink-0 flex-col gap-3 rounded-lg border bg-muted/30 p-3"
|
|
92
|
-
>
|
|
93
|
-
{/* Column header */}
|
|
94
|
-
<Skeleton className="h-5 w-24 rounded" />
|
|
95
|
-
|
|
96
|
-
{/* Cards */}
|
|
97
|
-
{Array.from({ length: cardsPerColumn }).map((_, card) => (
|
|
98
|
-
<div key={card} className="space-y-2 rounded-md border bg-background p-3">
|
|
99
|
-
<Skeleton className="h-4 w-3/4 rounded" />
|
|
100
|
-
<Skeleton className="h-3 w-1/2 rounded" />
|
|
101
|
-
</div>
|
|
102
|
-
))}
|
|
103
|
-
</div>
|
|
104
|
-
))}
|
|
105
|
-
</div>
|
|
106
|
-
)
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// ---------------------------------------------------------------------------
|
|
110
|
-
// FormSkeleton – labeled form fields
|
|
111
|
-
// ---------------------------------------------------------------------------
|
|
112
|
-
|
|
113
|
-
function FormSkeleton({
|
|
114
|
-
rows = 4,
|
|
115
|
-
className,
|
|
116
|
-
...props
|
|
117
|
-
}: ViewSkeletonProps) {
|
|
118
|
-
return (
|
|
119
|
-
<div
|
|
120
|
-
data-slot="form-skeleton"
|
|
121
|
-
className={cn("w-full max-w-lg space-y-6", className)}
|
|
122
|
-
{...props}
|
|
123
|
-
>
|
|
124
|
-
{Array.from({ length: rows }).map((_, i) => (
|
|
125
|
-
<div key={i} className="space-y-2">
|
|
126
|
-
{/* Label */}
|
|
127
|
-
<Skeleton className="h-4 w-28 rounded" />
|
|
128
|
-
{/* Input */}
|
|
129
|
-
<Skeleton className="h-9 w-full rounded-md" />
|
|
130
|
-
</div>
|
|
131
|
-
))}
|
|
132
|
-
|
|
133
|
-
{/* Submit button */}
|
|
134
|
-
<Skeleton className="h-9 w-24 rounded-md" />
|
|
135
|
-
</div>
|
|
136
|
-
)
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// ---------------------------------------------------------------------------
|
|
140
|
-
// ListSkeleton – stacked list items
|
|
141
|
-
// ---------------------------------------------------------------------------
|
|
142
|
-
|
|
143
|
-
function ListSkeleton({
|
|
144
|
-
rows = 5,
|
|
145
|
-
className,
|
|
146
|
-
...props
|
|
147
|
-
}: ViewSkeletonProps) {
|
|
148
|
-
return (
|
|
149
|
-
<div
|
|
150
|
-
data-slot="list-skeleton"
|
|
151
|
-
className={cn("w-full space-y-3", className)}
|
|
152
|
-
{...props}
|
|
153
|
-
>
|
|
154
|
-
{Array.from({ length: rows }).map((_, i) => (
|
|
155
|
-
<div
|
|
156
|
-
key={i}
|
|
157
|
-
className="flex items-center gap-3 rounded-md border px-4 py-3"
|
|
158
|
-
>
|
|
159
|
-
<Skeleton className="size-8 shrink-0 rounded-full" />
|
|
160
|
-
<div className="flex-1 space-y-2">
|
|
161
|
-
<Skeleton className="h-4 w-3/5 rounded" />
|
|
162
|
-
<Skeleton className="h-3 w-2/5 rounded" />
|
|
163
|
-
</div>
|
|
164
|
-
</div>
|
|
165
|
-
))}
|
|
166
|
-
</div>
|
|
167
|
-
)
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// ---------------------------------------------------------------------------
|
|
171
|
-
// ChartSkeleton – chart area placeholder
|
|
172
|
-
// ---------------------------------------------------------------------------
|
|
173
|
-
|
|
174
|
-
function ChartSkeleton({
|
|
175
|
-
className,
|
|
176
|
-
...props
|
|
177
|
-
}: Omit<ViewSkeletonProps, "rows">) {
|
|
178
|
-
return (
|
|
179
|
-
<div
|
|
180
|
-
data-slot="chart-skeleton"
|
|
181
|
-
className={cn("w-full space-y-4", className)}
|
|
182
|
-
{...props}
|
|
183
|
-
>
|
|
184
|
-
{/* Chart title */}
|
|
185
|
-
<Skeleton className="h-5 w-40 rounded" />
|
|
186
|
-
|
|
187
|
-
{/* Chart area with bar placeholders */}
|
|
188
|
-
<div className="flex h-48 items-end gap-2 rounded-md border p-4">
|
|
189
|
-
{(["h-2/5", "h-3/5", "h-1/3", "h-4/5", "h-1/2", "h-3/4", "h-2/5"] as const).map((heightClass, i) => (
|
|
190
|
-
<Skeleton
|
|
191
|
-
key={i}
|
|
192
|
-
className={cn("flex-1 rounded-t", heightClass)}
|
|
193
|
-
/>
|
|
194
|
-
))}
|
|
195
|
-
</div>
|
|
196
|
-
|
|
197
|
-
{/* Legend */}
|
|
198
|
-
<div className="flex gap-4">
|
|
199
|
-
<Skeleton className="h-3 w-16 rounded" />
|
|
200
|
-
<Skeleton className="h-3 w-16 rounded" />
|
|
201
|
-
<Skeleton className="h-3 w-16 rounded" />
|
|
202
|
-
</div>
|
|
203
|
-
</div>
|
|
204
|
-
)
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
// ---------------------------------------------------------------------------
|
|
208
|
-
// ViewSkeleton – convenience wrapper that dispatches by variant
|
|
209
|
-
// ---------------------------------------------------------------------------
|
|
210
|
-
|
|
211
|
-
export type ViewSkeletonVariant = "grid" | "kanban" | "form" | "list" | "chart"
|
|
212
|
-
|
|
213
|
-
export interface ViewSkeletonDispatchProps extends ViewSkeletonProps {
|
|
214
|
-
variant: ViewSkeletonVariant
|
|
215
|
-
/** Number of columns (grid / kanban) */
|
|
216
|
-
columns?: number
|
|
217
|
-
/** Cards per column (kanban only) */
|
|
218
|
-
cardsPerColumn?: number
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
function ViewSkeleton({ variant, ...props }: ViewSkeletonDispatchProps) {
|
|
222
|
-
switch (variant) {
|
|
223
|
-
case "grid":
|
|
224
|
-
return <GridSkeleton {...props} />
|
|
225
|
-
case "kanban":
|
|
226
|
-
return <KanbanSkeleton {...props} />
|
|
227
|
-
case "form":
|
|
228
|
-
return <FormSkeleton {...props} />
|
|
229
|
-
case "list":
|
|
230
|
-
return <ListSkeleton {...props} />
|
|
231
|
-
case "chart":
|
|
232
|
-
return <ChartSkeleton {...props} />
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
export {
|
|
237
|
-
ViewSkeleton,
|
|
238
|
-
GridSkeleton,
|
|
239
|
-
KanbanSkeleton,
|
|
240
|
-
FormSkeleton,
|
|
241
|
-
ListSkeleton,
|
|
242
|
-
ChartSkeleton,
|
|
243
|
-
}
|
|
@@ -1,153 +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 { Loader2, InboxIcon, AlertCircle } from "lucide-react"
|
|
11
|
-
|
|
12
|
-
import { cn } from "../lib/utils"
|
|
13
|
-
import { Button } from "../ui/button"
|
|
14
|
-
|
|
15
|
-
// ---------------------------------------------------------------------------
|
|
16
|
-
// DataLoadingState
|
|
17
|
-
// ---------------------------------------------------------------------------
|
|
18
|
-
|
|
19
|
-
interface DataLoadingStateProps extends React.ComponentProps<"div"> {
|
|
20
|
-
/** Message displayed below the spinner */
|
|
21
|
-
message?: string
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function DataLoadingState({
|
|
25
|
-
className,
|
|
26
|
-
message = "Loading…",
|
|
27
|
-
...props
|
|
28
|
-
}: DataLoadingStateProps) {
|
|
29
|
-
return (
|
|
30
|
-
<div
|
|
31
|
-
role="status"
|
|
32
|
-
aria-label={message}
|
|
33
|
-
data-slot="data-loading-state"
|
|
34
|
-
className={cn(
|
|
35
|
-
"flex flex-col items-center justify-center gap-3 p-6 text-center",
|
|
36
|
-
className
|
|
37
|
-
)}
|
|
38
|
-
{...props}
|
|
39
|
-
>
|
|
40
|
-
<Loader2 className="size-6 animate-spin text-muted-foreground" />
|
|
41
|
-
{message && (
|
|
42
|
-
<p className="text-sm text-muted-foreground">{message}</p>
|
|
43
|
-
)}
|
|
44
|
-
</div>
|
|
45
|
-
)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// ---------------------------------------------------------------------------
|
|
49
|
-
// DataEmptyState
|
|
50
|
-
// ---------------------------------------------------------------------------
|
|
51
|
-
|
|
52
|
-
interface DataEmptyStateProps extends React.ComponentProps<"div"> {
|
|
53
|
-
/** Icon rendered above the title */
|
|
54
|
-
icon?: React.ReactNode
|
|
55
|
-
title?: string
|
|
56
|
-
description?: string
|
|
57
|
-
/** Optional action rendered below the description */
|
|
58
|
-
action?: React.ReactNode
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function DataEmptyState({
|
|
62
|
-
className,
|
|
63
|
-
icon,
|
|
64
|
-
title = "No data",
|
|
65
|
-
description,
|
|
66
|
-
action,
|
|
67
|
-
children,
|
|
68
|
-
...props
|
|
69
|
-
}: DataEmptyStateProps) {
|
|
70
|
-
return (
|
|
71
|
-
<div
|
|
72
|
-
data-slot="data-empty-state"
|
|
73
|
-
className={cn(
|
|
74
|
-
"flex flex-col items-center justify-center gap-3 p-6 text-center",
|
|
75
|
-
className
|
|
76
|
-
)}
|
|
77
|
-
{...props}
|
|
78
|
-
>
|
|
79
|
-
<div className="flex size-10 items-center justify-center rounded-lg bg-muted">
|
|
80
|
-
{icon ?? <InboxIcon className="size-5 text-muted-foreground" />}
|
|
81
|
-
</div>
|
|
82
|
-
{title && (
|
|
83
|
-
<h3 className="text-sm font-medium">{title}</h3>
|
|
84
|
-
)}
|
|
85
|
-
{description && (
|
|
86
|
-
<p className="max-w-sm text-sm text-muted-foreground">{description}</p>
|
|
87
|
-
)}
|
|
88
|
-
{action}
|
|
89
|
-
{children}
|
|
90
|
-
</div>
|
|
91
|
-
)
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// ---------------------------------------------------------------------------
|
|
95
|
-
// DataErrorState
|
|
96
|
-
// ---------------------------------------------------------------------------
|
|
97
|
-
|
|
98
|
-
interface DataErrorStateProps extends React.ComponentProps<"div"> {
|
|
99
|
-
title?: string
|
|
100
|
-
/** Error message or description */
|
|
101
|
-
message?: string
|
|
102
|
-
/** Callback invoked when the retry button is clicked */
|
|
103
|
-
onRetry?: () => void
|
|
104
|
-
/** Label for the retry button */
|
|
105
|
-
retryLabel?: string
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function DataErrorState({
|
|
109
|
-
className,
|
|
110
|
-
title = "Something went wrong",
|
|
111
|
-
message,
|
|
112
|
-
onRetry,
|
|
113
|
-
retryLabel = "Retry",
|
|
114
|
-
children,
|
|
115
|
-
...props
|
|
116
|
-
}: DataErrorStateProps) {
|
|
117
|
-
return (
|
|
118
|
-
<div
|
|
119
|
-
role="alert"
|
|
120
|
-
data-slot="data-error-state"
|
|
121
|
-
className={cn(
|
|
122
|
-
"flex flex-col items-center justify-center gap-3 p-6 text-center",
|
|
123
|
-
className
|
|
124
|
-
)}
|
|
125
|
-
{...props}
|
|
126
|
-
>
|
|
127
|
-
<div className="flex size-10 items-center justify-center rounded-lg bg-destructive/10">
|
|
128
|
-
<AlertCircle className="size-5 text-destructive" />
|
|
129
|
-
</div>
|
|
130
|
-
{title && (
|
|
131
|
-
<h3 className="text-sm font-medium">{title}</h3>
|
|
132
|
-
)}
|
|
133
|
-
{message && (
|
|
134
|
-
<p className="max-w-sm text-sm text-muted-foreground">{message}</p>
|
|
135
|
-
)}
|
|
136
|
-
{onRetry && (
|
|
137
|
-
<Button variant="outline" size="sm" onClick={onRetry}>
|
|
138
|
-
{retryLabel}
|
|
139
|
-
</Button>
|
|
140
|
-
)}
|
|
141
|
-
{children}
|
|
142
|
-
</div>
|
|
143
|
-
)
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
export {
|
|
147
|
-
DataLoadingState,
|
|
148
|
-
DataEmptyState,
|
|
149
|
-
DataErrorState,
|
|
150
|
-
type DataLoadingStateProps,
|
|
151
|
-
type DataEmptyStateProps,
|
|
152
|
-
type DataErrorStateProps,
|
|
153
|
-
}
|