@goplusvn/core 0.1.0 → 0.1.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/package.json +2 -1
- package/src/assets/erp_wallpaper.png +0 -0
- package/src/assets/goeat_logo.png +0 -0
- package/src/audit/audit-manager.ts +139 -0
- package/src/audit/index.ts +11 -0
- package/src/audit/memory-audit-logger.ts +86 -0
- package/src/audit/types.ts +50 -0
- package/src/auth/auth-service.ts +97 -0
- package/src/auth/index.ts +266 -0
- package/src/code-generation/index.ts +69 -0
- package/src/configs/auth-routes.ts +17 -0
- package/src/configs/crud.ts +136 -0
- package/src/configs/data/navigations.ts +781 -0
- package/src/configs/data/oauth-links.ts +10 -0
- package/src/configs/entities/material-categories.config.ts +125 -0
- package/src/configs/i18n.ts +12 -0
- package/src/configs/index.ts +26 -0
- package/src/configs/status.ts +25 -0
- package/src/configs/themes.ts +100 -0
- package/src/crud/components/crud-bulk-actions.tsx +91 -0
- package/src/crud/components/crud-card-view.tsx +241 -0
- package/src/crud/components/crud-context.tsx +122 -0
- package/src/crud/components/crud-delete-dialog.tsx +145 -0
- package/src/crud/components/crud-dialog.tsx +406 -0
- package/src/crud/components/crud-empty-state.tsx +104 -0
- package/src/crud/components/crud-export-button.tsx +170 -0
- package/src/crud/components/crud-field-renderer.tsx +653 -0
- package/src/crud/components/crud-filter-chips.tsx +102 -0
- package/src/crud/components/crud-filters/checkbox-filter.tsx +97 -0
- package/src/crud/components/crud-filters/datetime-filter.tsx +83 -0
- package/src/crud/components/crud-filters/filter-builder.tsx +66 -0
- package/src/crud/components/crud-filters/index.tsx +76 -0
- package/src/crud/components/crud-filters/radio-filter.tsx +86 -0
- package/src/crud/components/crud-filters/select-filter.tsx +141 -0
- package/src/crud/components/crud-filters/text-filter.tsx +86 -0
- package/src/crud/components/crud-form.tsx +642 -0
- package/src/crud/components/crud-import-dialog.tsx +440 -0
- package/src/crud/components/crud-infinite-scroll.tsx +116 -0
- package/src/crud/components/crud-page.tsx +1017 -0
- package/src/crud/components/crud-provider.tsx +277 -0
- package/src/crud/components/crud-row-actions.tsx +189 -0
- package/src/crud/components/crud-search.tsx +82 -0
- package/src/crud/components/crud-sheet.tsx +336 -0
- package/src/crud/components/crud-table-skeleton.tsx +26 -0
- package/src/crud/components/crud-table-toolbar.tsx +91 -0
- package/src/crud/components/crud-table.tsx +352 -0
- package/src/crud/components/crud-virtual-table.tsx +55 -0
- package/src/crud/components/index.tsx +20 -0
- package/src/crud/crud-filters/checkbox-filter.tsx +87 -0
- package/src/crud/crud-filters/datetime-filter.tsx +82 -0
- package/src/crud/crud-filters/filter-builder.tsx +64 -0
- package/src/crud/crud-filters/index.tsx +78 -0
- package/src/crud/crud-filters/radio-filter.tsx +79 -0
- package/src/crud/crud-filters/select-filter.tsx +148 -0
- package/src/crud/crud-filters/text-filter.tsx +81 -0
- package/src/crud/index.ts +43 -0
- package/src/crud/lib/crud-service.test.ts +334 -0
- package/src/crud/lib/crud-service.ts +358 -0
- package/src/crud/lib/crud-utils.test.ts +354 -0
- package/src/crud/lib/crud-utils.ts +299 -0
- package/src/crud/lib/crud-validator.ts +247 -0
- package/src/crud/lib/data-loader.ts +234 -0
- package/src/crud/lib/field-calculator.ts +241 -0
- package/src/crud/lib/field-formatter.ts +240 -0
- package/src/crud/lib/import-export-service.test.ts +290 -0
- package/src/crud/lib/import-export-service.ts +352 -0
- package/src/crud/lib/import-server-utils.ts +109 -0
- package/src/crud/lib/lazy-loader.ts +241 -0
- package/src/crud/lib/parse-filters.ts +85 -0
- package/src/crud/lib/permissions.ts +52 -0
- package/src/crud/lib/serialize-config.ts +60 -0
- package/src/crud/lib/stream-loader.ts +145 -0
- package/src/crud/lib/translate-config.ts +335 -0
- package/src/crud/lib/types.ts +11 -0
- package/src/crud/pages/entity-crud-page.tsx +144 -0
- package/src/crud/server.ts +8 -0
- package/src/home/constants.tsx +142 -0
- package/src/home/feature-showcase.tsx +171 -0
- package/src/home/home-page.tsx +191 -0
- package/src/home/hooks/index.ts +1 -0
- package/src/home/hooks/useWidgetPreferences.ts +167 -0
- package/src/home/index.ts +33 -0
- package/src/home/quick-access-dialog.tsx +271 -0
- package/src/home/quick-access-menu.tsx +267 -0
- package/src/home/types.ts +140 -0
- package/src/home/welcome-card.tsx +92 -0
- package/src/home/widget-container.tsx +258 -0
- package/src/home/widgets/base-widget.tsx +200 -0
- package/src/home/widgets/customers-widget.tsx +74 -0
- package/src/home/widgets/index.ts +6 -0
- package/src/home/widgets/orders-widget.tsx +87 -0
- package/src/home/widgets/revenue-widget.tsx +71 -0
- package/src/home/widgets/stock-widget.tsx +109 -0
- package/src/hooks/index.tsx +598 -0
- package/src/hooks/use-tenant.test.tsx +30 -0
- package/src/hooks/use-tenant.ts +5 -0
- package/src/index.ts +17 -0
- package/src/infrastructure/__tests__/architecture-verification.spec.ts +103 -0
- package/src/infrastructure/api-service.ts +317 -0
- package/src/infrastructure/cache/cache-manager.ts +107 -0
- package/src/infrastructure/cache/cache.ts +120 -0
- package/src/infrastructure/cache/index.ts +8 -0
- package/src/infrastructure/cache/types.ts +48 -0
- package/src/infrastructure/cron/cron-manager.ts +239 -0
- package/src/infrastructure/cron/index.ts +6 -0
- package/src/infrastructure/cron/types.ts +41 -0
- package/src/infrastructure/event-bus/event-bus.ts +145 -0
- package/src/infrastructure/event-bus/index.ts +2 -0
- package/src/infrastructure/event-bus/types.ts +22 -0
- package/src/infrastructure/index.ts +32 -0
- package/src/infrastructure/lock/decorators.ts +67 -0
- package/src/infrastructure/lock/index.ts +2 -0
- package/src/infrastructure/lock/lock-manager.ts +33 -0
- package/src/infrastructure/logger/index.ts +2 -0
- package/src/infrastructure/logger/logger.ts +96 -0
- package/src/infrastructure/logger/types.ts +25 -0
- package/src/layout/index.tsx +185 -0
- package/src/navigation/index.ts +91 -0
- package/src/notification/index.ts +14 -0
- package/src/notification/notification-service.ts +120 -0
- package/src/notification/storage/in-memory.ts +56 -0
- package/src/notification/storage/index.ts +1 -0
- package/src/notification/types.ts +51 -0
- package/src/organization/branch-service.ts +299 -0
- package/src/organization/branches.config.ts +154 -0
- package/src/organization/index.ts +5 -0
- package/src/plugin/apps-registry.ts +97 -0
- package/src/plugin/index.ts +5 -0
- package/src/plugin/types.ts +41 -0
- package/src/providers/index.tsx +109 -0
- package/src/providers/tenant-provider.tsx +45 -0
- package/src/rbac/components/roles/role-card.tsx +158 -0
- package/src/rbac/components/roles/role-stats-cards.tsx +29 -0
- package/src/rbac/components/roles/role-toolbar.tsx +123 -0
- package/src/rbac/hooks/use-role-operations.ts +159 -0
- package/src/rbac/hooks/use-roles-data.ts +59 -0
- package/src/rbac/index.ts +297 -0
- package/src/rbac/lib/permission-helpers.ts +63 -0
- package/src/rbac/pages/action-list-page.tsx +25 -0
- package/src/rbac/pages/resource-list-page.tsx +25 -0
- package/src/rbac/pages/role-list-page.tsx +378 -0
- package/src/rbac/permission-service.ts +140 -0
- package/src/rbac/permissions.ts +135 -0
- package/src/rbac/resource-service.ts +115 -0
- package/src/rbac/resource-validator.ts +119 -0
- package/src/rbac/role-service.ts +165 -0
- package/src/rbac/server.ts +16 -0
- package/src/rbac/types.ts +38 -0
- package/src/schemas/action.schema.ts +66 -0
- package/src/schemas/branch.schema.ts +52 -0
- package/src/schemas/coming-soon-schema.ts +9 -0
- package/src/schemas/company.schema.ts +44 -0
- package/src/schemas/forgot-passward-schema.ts +9 -0
- package/src/schemas/index.ts +30 -0
- package/src/schemas/material-category.schema.ts +43 -0
- package/src/schemas/material-pricing.schema.ts +74 -0
- package/src/schemas/material.schema.ts +76 -0
- package/src/schemas/materials.ts +52 -0
- package/src/schemas/new-passward-schema.ts +15 -0
- package/src/schemas/partner-company.schema.ts +149 -0
- package/src/schemas/register-schema.ts +36 -0
- package/src/schemas/resource.schema.ts +133 -0
- package/src/schemas/role.schema.ts +11 -0
- package/src/schemas/sign-in-schema.ts +24 -0
- package/src/schemas/supplier-pricing.schema.ts +15 -0
- package/src/schemas/supplier.schema.ts +120 -0
- package/src/schemas/system-category-group.schema.ts +67 -0
- package/src/schemas/system-category.schema.ts +77 -0
- package/src/schemas/system-config.schema.ts +118 -0
- package/src/schemas/uom.schema.ts +75 -0
- package/src/schemas/user-supplier.schema.ts +179 -0
- package/src/schemas/user.schema.ts +18 -0
- package/src/schemas/verify-email-schema.ts +9 -0
- package/src/schemas/warehouse.schema.ts +49 -0
- package/src/system/components/categories/category-list.tsx +529 -0
- package/src/system/components/categories/category-manager.tsx +89 -0
- package/src/system/components/categories/group-sidebar.tsx +308 -0
- package/src/system/components/settings/setting-dialogs.tsx +197 -0
- package/src/system/components/settings/setting-field.tsx +291 -0
- package/src/system/components/settings/setting-form-dialog.tsx +308 -0
- package/src/system/components/settings/settings-groups.ts +80 -0
- package/src/system/components/settings/settings-search.tsx +71 -0
- package/src/system/components/settings/settings-section.tsx +74 -0
- package/src/system/components/settings/settings-sidebar.tsx +81 -0
- package/src/system/constants.ts +3 -0
- package/src/system/index.ts +150 -0
- package/src/system/job-manager.ts +176 -0
- package/src/system/pages/components/categories/category-list.tsx +537 -0
- package/src/system/pages/components/categories/category-manager.tsx +90 -0
- package/src/system/pages/components/categories/group-sidebar.tsx +311 -0
- package/src/system/pages/components/settings/sales-rules-settings.tsx +222 -0
- package/src/system/pages/components/settings/setting-dialogs.tsx +197 -0
- package/src/system/pages/components/settings/setting-field.tsx +292 -0
- package/src/system/pages/components/settings/setting-form-dialog.tsx +308 -0
- package/src/system/pages/components/settings/settings-groups.ts +87 -0
- package/src/system/pages/components/settings/settings-page.tsx +372 -0
- package/src/system/pages/components/settings/settings-search.tsx +71 -0
- package/src/system/pages/components/settings/settings-section.tsx +74 -0
- package/src/system/pages/components/settings/settings-sidebar.tsx +81 -0
- package/src/system/pages/components/settings/system-settings.tsx +244 -0
- package/src/system/pages/system-category-page.tsx +15 -0
- package/src/system/pages/system-settings-page.tsx +380 -0
- package/src/system/schemas/system-category-group.schema.ts +46 -0
- package/src/system/schemas/system-category.schema.ts +56 -0
- package/src/system/services/settings-service.ts +127 -0
- package/src/system/services/system-category-service.ts +63 -0
- package/src/system/types.ts +45 -0
- package/src/types/index.ts +703 -0
- package/src/ui/auth/auth-layout.tsx +135 -0
- package/src/ui/auth/forgot-password-form.tsx +98 -0
- package/src/ui/auth/index.tsx +7 -0
- package/src/ui/auth/new-password-form.tsx +107 -0
- package/src/ui/auth/oauth-links.tsx +30 -0
- package/src/ui/auth/register-form.tsx +202 -0
- package/src/ui/auth/sign-in-form.tsx +238 -0
- package/src/ui/auth/verify-email-form.tsx +104 -0
- package/src/ui/crud/index.tsx +10 -0
- package/src/ui/data-display/accordion.tsx +65 -0
- package/src/ui/data-display/aspect-ratio.tsx +11 -0
- package/src/ui/data-display/avatar.tsx +163 -0
- package/src/ui/data-display/bento-grid.tsx +77 -0
- package/src/ui/data-display/carousel.tsx +249 -0
- package/src/ui/data-display/chart.tsx +363 -0
- package/src/ui/data-display/code-block-highlight.tsx +54 -0
- package/src/ui/data-display/collapsible.tsx +42 -0
- package/src/ui/data-display/compact-stat-bar.tsx +149 -0
- package/src/ui/data-display/data-table/data-table-context.tsx +255 -0
- package/src/ui/data-display/data-table/data-table-empty-state.tsx +133 -0
- package/src/ui/data-display/data-table/data-table-skeleton.tsx +145 -0
- package/src/ui/data-display/data-table/data-table-toolbar.tsx +353 -0
- package/src/ui/data-display/data-table/data-table.tsx +597 -0
- package/src/ui/data-display/data-table/index.ts +44 -0
- package/src/ui/data-display/data-table-column-header.tsx +75 -0
- package/src/ui/data-display/data-table-pagination.tsx +130 -0
- package/src/ui/data-display/data-table-view-options.tsx +59 -0
- package/src/ui/data-display/formatted-number-input.tsx +210 -0
- package/src/ui/data-display/highlight.tsx +20 -0
- package/src/ui/data-display/hover-card.tsx +48 -0
- package/src/ui/data-display/index.tsx +50 -0
- package/src/ui/data-display/iphone-15-pro.tsx +114 -0
- package/src/ui/data-display/kanban/index.ts +4 -0
- package/src/ui/data-display/kanban/kanban-board.tsx +192 -0
- package/src/ui/data-display/kanban/kanban-column.tsx +74 -0
- package/src/ui/data-display/kanban/kanban-item.tsx +50 -0
- package/src/ui/data-display/kanban/kanban-types.ts +21 -0
- package/src/ui/data-display/kpi-card.tsx +68 -0
- package/src/ui/data-display/media-grid.tsx +110 -0
- package/src/ui/data-display/safari.tsx +175 -0
- package/src/ui/data-display/show-more-text.tsx +55 -0
- package/src/ui/data-display/tabs.tsx +68 -0
- package/src/ui/data-display/timeline.tsx +256 -0
- package/src/ui/feedback/alert.tsx +60 -0
- package/src/ui/feedback/context-menu.tsx +245 -0
- package/src/ui/feedback/drawer.tsx +132 -0
- package/src/ui/feedback/error-dialog.tsx +273 -0
- package/src/ui/feedback/index.tsx +183 -0
- package/src/ui/feedback/progress.tsx +32 -0
- package/src/ui/feedback/sheet.tsx +148 -0
- package/src/ui/feedback/sonner.tsx +36 -0
- package/src/ui/forms/command.tsx +157 -0
- package/src/ui/forms/date-picker.tsx +73 -0
- package/src/ui/forms/date-range-picker.tsx +76 -0
- package/src/ui/forms/date-time-picker.tsx +109 -0
- package/src/ui/forms/editor/editor-menu-bar.tsx +394 -0
- package/src/ui/forms/editor/index.tsx +130 -0
- package/src/ui/forms/editor/multi-select-example.tsx +1234 -0
- package/src/ui/forms/emoji-picker.tsx +109 -0
- package/src/ui/forms/file-dropzone.tsx +169 -0
- package/src/ui/forms/file-thumbnail.tsx +29 -0
- package/src/ui/forms/index.tsx +201 -0
- package/src/ui/forms/input-file.tsx +99 -0
- package/src/ui/forms/input-group.tsx +46 -0
- package/src/ui/forms/input-otp.tsx +81 -0
- package/src/ui/forms/input-phone.tsx +172 -0
- package/src/ui/forms/input-spin.tsx +116 -0
- package/src/ui/forms/input-tags.tsx +219 -0
- package/src/ui/forms/input-time.tsx +42 -0
- package/src/ui/forms/multi-select.tsx +629 -0
- package/src/ui/forms/multiple-date-picker.tsx +74 -0
- package/src/ui/forms/radio-group.tsx +42 -0
- package/src/ui/forms/rating.tsx +158 -0
- package/src/ui/forms/time-picker.tsx +57 -0
- package/src/ui/index.tsx +17 -0
- package/src/ui/layout/animated-list.tsx +77 -0
- package/src/ui/layout/animated-sidebar.tsx +294 -0
- package/src/ui/layout/command-menu.tsx +355 -0
- package/src/ui/layout/customizer.tsx +324 -0
- package/src/ui/layout/footer.tsx +43 -0
- package/src/ui/layout/full-screen-toggle.tsx +52 -0
- package/src/ui/layout/header-breadcrumb.tsx +77 -0
- package/src/ui/layout/horizontal-layout-header.tsx +83 -0
- package/src/ui/layout/horizontal-layout.tsx +50 -0
- package/src/ui/layout/index.tsx +25 -0
- package/src/ui/layout/language-dropdown.tsx +103 -0
- package/src/ui/layout/logo.tsx +63 -0
- package/src/ui/layout/main-layout.tsx +57 -0
- package/src/ui/layout/mode-dropdown.tsx +58 -0
- package/src/ui/layout/notification-dropdown.tsx +127 -0
- package/src/ui/layout/page-tabs.tsx +306 -0
- package/src/ui/layout/route-cache.tsx +214 -0
- package/src/ui/layout/sidebar-group-icon-menu.tsx +195 -0
- package/src/ui/layout/sidebar.tsx +279 -0
- package/src/ui/layout/tab-content-cache.tsx +201 -0
- package/src/ui/layout/tab-navigation-provider.tsx +536 -0
- package/src/ui/layout/toggle-mobile-sidebar.tsx +33 -0
- package/src/ui/layout/top-bar-header-menubar.tsx +412 -0
- package/src/ui/layout/user-dropdown.tsx +188 -0
- package/src/ui/layout/vertical-layout-header.tsx +65 -0
- package/src/ui/layout/vertical-layout.tsx +47 -0
- package/src/ui/management/audit-log-page.tsx +209 -0
- package/src/ui/management/cache-management.tsx +349 -0
- package/src/ui/management/index.ts +3 -0
- package/src/ui/management/job-management.tsx +308 -0
- package/src/ui/pages/not-found.tsx +30 -0
- package/src/ui/primitives/badge.tsx +66 -0
- package/src/ui/primitives/breadcrumb.tsx +103 -0
- package/src/ui/primitives/button.tsx +129 -0
- package/src/ui/primitives/calendar.tsx +74 -0
- package/src/ui/primitives/card.tsx +86 -0
- package/src/ui/primitives/checkbox.tsx +31 -0
- package/src/ui/primitives/client.ts +30 -0
- package/src/ui/primitives/combobox.tsx +290 -0
- package/src/ui/primitives/dialog.tsx +121 -0
- package/src/ui/primitives/dropdown-menu.tsx +239 -0
- package/src/ui/primitives/dynamic-icon.tsx +24 -0
- package/src/ui/primitives/index.tsx +134 -0
- package/src/ui/primitives/input-number.tsx +131 -0
- package/src/ui/primitives/input.tsx +22 -0
- package/src/ui/primitives/keyboard.tsx +23 -0
- package/src/ui/primitives/label.tsx +24 -0
- package/src/ui/primitives/menubar.tsx +262 -0
- package/src/ui/primitives/navigation-menu.tsx +157 -0
- package/src/ui/primitives/pagination.tsx +118 -0
- package/src/ui/primitives/popover.tsx +56 -0
- package/src/ui/primitives/prefetch-link.tsx +60 -0
- package/src/ui/primitives/resizable.tsx +59 -0
- package/src/ui/primitives/scroll-area.tsx +63 -0
- package/src/ui/primitives/select.tsx +172 -0
- package/src/ui/primitives/separator.tsx +51 -0
- package/src/ui/primitives/sidebar.tsx +844 -0
- package/src/ui/primitives/slider.tsx +27 -0
- package/src/ui/primitives/status-badge.tsx +47 -0
- package/src/ui/primitives/sticky-layout.tsx +50 -0
- package/src/ui/primitives/switch.tsx +29 -0
- package/src/ui/primitives/table.tsx +116 -0
- package/src/ui/primitives/tabs.tsx +55 -0
- package/src/ui/primitives/toggle-group.tsx +70 -0
- package/src/ui/primitives/toggle.tsx +47 -0
- package/src/ui/primitives/tooltip.tsx +59 -0
- package/src/user/components/dangerous-zone.tsx +34 -0
- package/src/user/components/delete-account-form.tsx +40 -0
- package/src/user/components/index.ts +4 -0
- package/src/user/components/profile-info-form.tsx +390 -0
- package/src/user/components/profile-info.tsx +32 -0
- package/src/user/components/unified-profile-dialog.tsx +1019 -0
- package/src/user/components/user-stats.tsx +27 -0
- package/src/user/components/user-toolbar.tsx +137 -0
- package/src/user/components/users-card-view.tsx +253 -0
- package/src/user/index.ts +11 -0
- package/src/user/pages/user-list-page.tsx +234 -0
- package/src/user/pages/users-client-page.tsx +385 -0
- package/src/user/profile-page.tsx +19 -0
- package/src/user/schemas.ts +68 -0
- package/src/user/types.ts +34 -0
- package/src/user/user-service.ts +538 -0
- package/src/utils/index.ts +906 -0
- package/src/workflow/activity-timeline.tsx +412 -0
- package/src/workflow/approval-workflow.tsx +31 -0
- package/src/workflow/index.ts +2 -0
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import type { ComponentProps } from "react";
|
|
5
|
+
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
|
6
|
+
import { Check, ChevronRight, Dot } from "lucide-react";
|
|
7
|
+
import { cn } from "../../utils";
|
|
8
|
+
|
|
9
|
+
export function DropdownMenu({
|
|
10
|
+
...props
|
|
11
|
+
}: ComponentProps<typeof DropdownMenuPrimitive.Root>) {
|
|
12
|
+
return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function DropdownMenuPortal({
|
|
16
|
+
...props
|
|
17
|
+
}: ComponentProps<typeof DropdownMenuPrimitive.Portal>) {
|
|
18
|
+
return (
|
|
19
|
+
<DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function DropdownMenuTrigger({
|
|
24
|
+
className,
|
|
25
|
+
...props
|
|
26
|
+
}: ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {
|
|
27
|
+
return (
|
|
28
|
+
<DropdownMenuPrimitive.Trigger
|
|
29
|
+
data-slot="dropdown-menu-trigger"
|
|
30
|
+
className={cn("cursor-pointer", className)}
|
|
31
|
+
{...props}
|
|
32
|
+
/>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function DropdownMenuGroup({
|
|
37
|
+
...props
|
|
38
|
+
}: ComponentProps<typeof DropdownMenuPrimitive.Group>) {
|
|
39
|
+
return (
|
|
40
|
+
<DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function DropdownMenuRadioGroup({
|
|
45
|
+
...props
|
|
46
|
+
}: ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {
|
|
47
|
+
return (
|
|
48
|
+
<DropdownMenuPrimitive.RadioGroup
|
|
49
|
+
data-slot="dropdown-menu-radio-group"
|
|
50
|
+
{...props}
|
|
51
|
+
/>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function DropdownMenuSub({
|
|
56
|
+
...props
|
|
57
|
+
}: ComponentProps<typeof DropdownMenuPrimitive.Sub>) {
|
|
58
|
+
return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
type DropdownMenuSubTriggerProps = ComponentProps<
|
|
62
|
+
typeof DropdownMenuPrimitive.SubTrigger
|
|
63
|
+
> & {
|
|
64
|
+
inset?: boolean;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export function DropdownMenuSubTrigger({
|
|
68
|
+
className,
|
|
69
|
+
inset,
|
|
70
|
+
children,
|
|
71
|
+
...props
|
|
72
|
+
}: DropdownMenuSubTriggerProps) {
|
|
73
|
+
return (
|
|
74
|
+
<DropdownMenuPrimitive.SubTrigger
|
|
75
|
+
data-slot="dropdown-menu-sub-trigger"
|
|
76
|
+
data-inset={inset}
|
|
77
|
+
className={cn(
|
|
78
|
+
"cursor-pointer flex items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:ps-8 focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
|
|
79
|
+
className,
|
|
80
|
+
)}
|
|
81
|
+
{...props}
|
|
82
|
+
>
|
|
83
|
+
{children}
|
|
84
|
+
<ChevronRight className="ms-auto h-4 w-4 rtl:-scale-100" />
|
|
85
|
+
</DropdownMenuPrimitive.SubTrigger>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function DropdownMenuSubContent({
|
|
90
|
+
className,
|
|
91
|
+
...props
|
|
92
|
+
}: ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {
|
|
93
|
+
return (
|
|
94
|
+
<DropdownMenuPrimitive.SubContent
|
|
95
|
+
data-slot="dropdown-menu-sub-content"
|
|
96
|
+
className={cn(
|
|
97
|
+
"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",
|
|
98
|
+
className,
|
|
99
|
+
)}
|
|
100
|
+
{...props}
|
|
101
|
+
/>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function DropdownMenuContent({
|
|
106
|
+
className,
|
|
107
|
+
sideOffset = 4,
|
|
108
|
+
...props
|
|
109
|
+
}: ComponentProps<typeof DropdownMenuPrimitive.Content>) {
|
|
110
|
+
return (
|
|
111
|
+
<DropdownMenuPrimitive.Portal>
|
|
112
|
+
<DropdownMenuPrimitive.Content
|
|
113
|
+
data-slot="dropdown-menu-content"
|
|
114
|
+
sideOffset={sideOffset}
|
|
115
|
+
className={cn(
|
|
116
|
+
"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",
|
|
117
|
+
className,
|
|
118
|
+
)}
|
|
119
|
+
{...props}
|
|
120
|
+
/>
|
|
121
|
+
</DropdownMenuPrimitive.Portal>
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function DropdownMenuItem({
|
|
126
|
+
className,
|
|
127
|
+
inset,
|
|
128
|
+
...props
|
|
129
|
+
}: ComponentProps<typeof DropdownMenuPrimitive.Item> & {
|
|
130
|
+
inset?: boolean;
|
|
131
|
+
}) {
|
|
132
|
+
return (
|
|
133
|
+
<DropdownMenuPrimitive.Item
|
|
134
|
+
data-slot="dropdown-menu-item"
|
|
135
|
+
data-inset={inset}
|
|
136
|
+
className={cn(
|
|
137
|
+
"relative flex cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm outline-hidden transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 data-[inset]:ps-8",
|
|
138
|
+
className,
|
|
139
|
+
)}
|
|
140
|
+
{...props}
|
|
141
|
+
/>
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export function DropdownMenuCheckboxItem({
|
|
146
|
+
className,
|
|
147
|
+
children,
|
|
148
|
+
checked,
|
|
149
|
+
...props
|
|
150
|
+
}: ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) {
|
|
151
|
+
return (
|
|
152
|
+
<DropdownMenuPrimitive.CheckboxItem
|
|
153
|
+
data-slot="dropdown-menu-checkbox-item"
|
|
154
|
+
className={cn(
|
|
155
|
+
"relative flex cursor-pointer select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-hidden transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50",
|
|
156
|
+
className,
|
|
157
|
+
)}
|
|
158
|
+
checked={checked}
|
|
159
|
+
{...props}
|
|
160
|
+
>
|
|
161
|
+
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
|
162
|
+
<DropdownMenuPrimitive.ItemIndicator>
|
|
163
|
+
<Check className="h-4 w-4" />
|
|
164
|
+
</DropdownMenuPrimitive.ItemIndicator>
|
|
165
|
+
</span>
|
|
166
|
+
{children}
|
|
167
|
+
</DropdownMenuPrimitive.CheckboxItem>
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export function DropdownMenuRadioItem({
|
|
172
|
+
className,
|
|
173
|
+
children,
|
|
174
|
+
...props
|
|
175
|
+
}: ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {
|
|
176
|
+
return (
|
|
177
|
+
<DropdownMenuPrimitive.RadioItem
|
|
178
|
+
data-slot="dropdown-menu-radio-item"
|
|
179
|
+
className={cn(
|
|
180
|
+
"relative flex cursor-pointer select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-hidden transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50",
|
|
181
|
+
className,
|
|
182
|
+
)}
|
|
183
|
+
{...props}
|
|
184
|
+
>
|
|
185
|
+
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
|
186
|
+
<DropdownMenuPrimitive.ItemIndicator>
|
|
187
|
+
<Dot className="h-4 w-4 fill-current" />
|
|
188
|
+
</DropdownMenuPrimitive.ItemIndicator>
|
|
189
|
+
</span>
|
|
190
|
+
{children}
|
|
191
|
+
</DropdownMenuPrimitive.RadioItem>
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export function DropdownMenuLabel({
|
|
196
|
+
className,
|
|
197
|
+
inset,
|
|
198
|
+
...props
|
|
199
|
+
}: ComponentProps<typeof DropdownMenuPrimitive.Label> & {
|
|
200
|
+
inset?: boolean;
|
|
201
|
+
}) {
|
|
202
|
+
return (
|
|
203
|
+
<DropdownMenuPrimitive.Label
|
|
204
|
+
data-slot="dropdown-menu-label"
|
|
205
|
+
data-inset={inset}
|
|
206
|
+
className={cn(
|
|
207
|
+
"px-2 py-1.5 text-sm font-semibold data-[inset]:ps-8",
|
|
208
|
+
className,
|
|
209
|
+
)}
|
|
210
|
+
{...props}
|
|
211
|
+
/>
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export function DropdownMenuSeparator({
|
|
216
|
+
className,
|
|
217
|
+
...props
|
|
218
|
+
}: ComponentProps<typeof DropdownMenuPrimitive.Separator>) {
|
|
219
|
+
return (
|
|
220
|
+
<DropdownMenuPrimitive.Separator
|
|
221
|
+
data-slot="dropdown-menu-separator"
|
|
222
|
+
className={cn("-mx-1 my-1 h-px bg-muted", className)}
|
|
223
|
+
{...props}
|
|
224
|
+
/>
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export function DropdownMenuShortcut({
|
|
229
|
+
className,
|
|
230
|
+
...props
|
|
231
|
+
}: ComponentProps<"span">) {
|
|
232
|
+
return (
|
|
233
|
+
<span
|
|
234
|
+
data-slot="dropdown-menu-shortcut"
|
|
235
|
+
className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
|
|
236
|
+
{...props}
|
|
237
|
+
/>
|
|
238
|
+
);
|
|
239
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// Refer to Lucide documentation for more details https://lucide.dev/guide/packages/lucide-react
|
|
4
|
+
import { icons } from "lucide-react";
|
|
5
|
+
|
|
6
|
+
import type { LucideProps } from "lucide-react";
|
|
7
|
+
|
|
8
|
+
export type DynamicIconNameType = keyof typeof icons;
|
|
9
|
+
|
|
10
|
+
interface DynamicIconProps extends LucideProps {
|
|
11
|
+
name?: DynamicIconNameType;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Component to render a dynamic Lucide icon based on its name.
|
|
15
|
+
export function DynamicIcon({ name, ...props }: DynamicIconProps) {
|
|
16
|
+
if (!name) return null;
|
|
17
|
+
|
|
18
|
+
const LucideIcon = icons[name]; // Dynamically retrieve the icon by name.
|
|
19
|
+
|
|
20
|
+
// Return null if the icon name is invalid.
|
|
21
|
+
if (!LucideIcon) return null;
|
|
22
|
+
|
|
23
|
+
return <LucideIcon {...props} />;
|
|
24
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
// @goerp/core/ui/primitives
|
|
2
|
+
// Primitive UI components (Server Compatible)
|
|
3
|
+
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
import { cn } from "../../utils";
|
|
6
|
+
import { Button } from "./button";
|
|
7
|
+
import type { ButtonProps } from "./button";
|
|
8
|
+
|
|
9
|
+
export * from "./badge";
|
|
10
|
+
export * from "./button";
|
|
11
|
+
export * from "./input";
|
|
12
|
+
export * from "./checkbox";
|
|
13
|
+
|
|
14
|
+
// ============================================================================
|
|
15
|
+
// Textarea
|
|
16
|
+
// ============================================================================
|
|
17
|
+
|
|
18
|
+
export interface TextareaProps
|
|
19
|
+
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
|
|
20
|
+
|
|
21
|
+
export const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
|
22
|
+
({ className, ...props }, ref) => {
|
|
23
|
+
return (
|
|
24
|
+
<textarea
|
|
25
|
+
className={cn(
|
|
26
|
+
"flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
|
27
|
+
className,
|
|
28
|
+
)}
|
|
29
|
+
ref={ref}
|
|
30
|
+
{...props}
|
|
31
|
+
/>
|
|
32
|
+
);
|
|
33
|
+
},
|
|
34
|
+
);
|
|
35
|
+
Textarea.displayName = "Textarea";
|
|
36
|
+
|
|
37
|
+
export * from "./card";
|
|
38
|
+
export * from "./separator";
|
|
39
|
+
|
|
40
|
+
// ============================================================================
|
|
41
|
+
// Spinner / Loading
|
|
42
|
+
// ============================================================================
|
|
43
|
+
|
|
44
|
+
export interface SpinnerProps {
|
|
45
|
+
size?: "sm" | "md" | "lg";
|
|
46
|
+
className?: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function Spinner({ size = "md", className }: SpinnerProps) {
|
|
50
|
+
const sizeClasses = {
|
|
51
|
+
sm: "h-4 w-4",
|
|
52
|
+
md: "h-6 w-6",
|
|
53
|
+
lg: "h-8 w-8",
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<div
|
|
58
|
+
className={cn(
|
|
59
|
+
"animate-spin rounded-full border-2 border-current border-t-transparent",
|
|
60
|
+
sizeClasses[size],
|
|
61
|
+
className,
|
|
62
|
+
)}
|
|
63
|
+
/>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface ButtonLoadingProps extends ButtonProps {
|
|
68
|
+
isLoading?: boolean;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export const ButtonLoading = React.forwardRef<
|
|
72
|
+
HTMLButtonElement,
|
|
73
|
+
ButtonLoadingProps
|
|
74
|
+
>(({ className, isLoading, children, disabled, ...props }, ref) => {
|
|
75
|
+
return (
|
|
76
|
+
<Button
|
|
77
|
+
className={cn("gap-2", className)}
|
|
78
|
+
disabled={isLoading || disabled}
|
|
79
|
+
ref={ref}
|
|
80
|
+
{...props}
|
|
81
|
+
>
|
|
82
|
+
{isLoading && <Spinner size="sm" />}
|
|
83
|
+
{children}
|
|
84
|
+
</Button>
|
|
85
|
+
);
|
|
86
|
+
});
|
|
87
|
+
ButtonLoading.displayName = "ButtonLoading";
|
|
88
|
+
|
|
89
|
+
// ============================================================================
|
|
90
|
+
// Skeleton
|
|
91
|
+
// ============================================================================
|
|
92
|
+
|
|
93
|
+
export function Skeleton({
|
|
94
|
+
className,
|
|
95
|
+
...props
|
|
96
|
+
}: React.HTMLAttributes<HTMLDivElement>) {
|
|
97
|
+
return (
|
|
98
|
+
<div
|
|
99
|
+
className={cn("animate-pulse rounded-md bg-muted", className)}
|
|
100
|
+
{...props}
|
|
101
|
+
/>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Data Display
|
|
106
|
+
export * from "./card"; // Added
|
|
107
|
+
export * from "./table";
|
|
108
|
+
export * from "./dropdown-menu";
|
|
109
|
+
|
|
110
|
+
// Feedback
|
|
111
|
+
export * from "./dialog";
|
|
112
|
+
|
|
113
|
+
// Layout
|
|
114
|
+
export * from "./tabs";
|
|
115
|
+
|
|
116
|
+
export * from "./breadcrumb";
|
|
117
|
+
export * from "./keyboard";
|
|
118
|
+
export * from "./pagination";
|
|
119
|
+
export * from "./status-badge";
|
|
120
|
+
export * from "./sidebar";
|
|
121
|
+
export * from "./popover";
|
|
122
|
+
export * from "./scroll-area";
|
|
123
|
+
export * from "./calendar";
|
|
124
|
+
export * from "./resizable";
|
|
125
|
+
export * from "./slider";
|
|
126
|
+
export * from "./switch";
|
|
127
|
+
export * from "./tooltip";
|
|
128
|
+
export * from "./select";
|
|
129
|
+
export * from "./menubar";
|
|
130
|
+
export * from "./navigation-menu";
|
|
131
|
+
export * from "./toggle";
|
|
132
|
+
export * from "./toggle-group";
|
|
133
|
+
export * from "./combobox";
|
|
134
|
+
export * from "./label";
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
|
|
5
|
+
import { cn } from "../../utils";
|
|
6
|
+
|
|
7
|
+
import { Input } from "./input";
|
|
8
|
+
|
|
9
|
+
interface InputNumberProps
|
|
10
|
+
extends Omit<
|
|
11
|
+
React.InputHTMLAttributes<HTMLInputElement>,
|
|
12
|
+
"onChange" | "value"
|
|
13
|
+
> {
|
|
14
|
+
value?: number | string | null;
|
|
15
|
+
onChange?: (value: number | null) => void;
|
|
16
|
+
decimalScale?: number;
|
|
17
|
+
suffix?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const InputNumber = React.forwardRef<HTMLInputElement, InputNumberProps>(
|
|
21
|
+
({ value, onChange, className, decimalScale = 0, suffix, ...props }, ref) => {
|
|
22
|
+
// Internal string state to handle formatting
|
|
23
|
+
const [displayValue, setDisplayValue] = React.useState("");
|
|
24
|
+
|
|
25
|
+
// Helper to parse displayed string to number
|
|
26
|
+
const parseDisplayValue = (val: string) => {
|
|
27
|
+
// Remove dots (thousands), replace comma with dot (decimal)
|
|
28
|
+
const clean = val.replace(/\./g, "").replace(",", ".");
|
|
29
|
+
return Number(clean);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const formatNumber = React.useCallback(
|
|
33
|
+
(num: number) => {
|
|
34
|
+
return new Intl.NumberFormat("vi-VN", {
|
|
35
|
+
maximumFractionDigits: decimalScale,
|
|
36
|
+
minimumFractionDigits: 0,
|
|
37
|
+
}).format(num);
|
|
38
|
+
},
|
|
39
|
+
[decimalScale],
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
// Update display value when prop value changes
|
|
43
|
+
React.useEffect(() => {
|
|
44
|
+
if (value === null || value === undefined || value === "") {
|
|
45
|
+
setDisplayValue("");
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const numValue = Number(value);
|
|
50
|
+
if (isNaN(numValue)) return;
|
|
51
|
+
|
|
52
|
+
// Avoid overriding user input if they match numerically
|
|
53
|
+
const currentNum = parseDisplayValue(displayValue);
|
|
54
|
+
if (currentNum !== numValue) {
|
|
55
|
+
setDisplayValue(formatNumber(numValue));
|
|
56
|
+
}
|
|
57
|
+
}, [value, decimalScale, displayValue, formatNumber]);
|
|
58
|
+
|
|
59
|
+
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
60
|
+
const rawValue = e.target.value;
|
|
61
|
+
|
|
62
|
+
// Allow digits and one comma
|
|
63
|
+
let cleanVal = rawValue.replace(/[^0-9,]/g, "");
|
|
64
|
+
|
|
65
|
+
// Handle multiple commas - keep only first
|
|
66
|
+
const parts = cleanVal.split(",");
|
|
67
|
+
if (parts.length > 2) {
|
|
68
|
+
cleanVal = parts[0] + "," + parts.slice(1).join("");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (cleanVal === "") {
|
|
72
|
+
setDisplayValue("");
|
|
73
|
+
onChange?.(null);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Split integer and decimal parts
|
|
78
|
+
const [integerPart, decimalPart] = cleanVal.split(",");
|
|
79
|
+
|
|
80
|
+
let formattedInteger = integerPart;
|
|
81
|
+
if (integerPart) {
|
|
82
|
+
formattedInteger = new Intl.NumberFormat("vi-VN").format(
|
|
83
|
+
Number(integerPart),
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
let newDisplayValue = formattedInteger;
|
|
88
|
+
|
|
89
|
+
// Check decimal scale truncation
|
|
90
|
+
let finalDecimalPart = decimalPart;
|
|
91
|
+
|
|
92
|
+
if (decimalPart !== undefined) {
|
|
93
|
+
if (decimalScale !== undefined && decimalPart.length > decimalScale) {
|
|
94
|
+
finalDecimalPart = decimalPart.substring(0, decimalScale);
|
|
95
|
+
}
|
|
96
|
+
newDisplayValue += "," + finalDecimalPart;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
setDisplayValue(newDisplayValue);
|
|
100
|
+
|
|
101
|
+
// Calculate numeric value for parent
|
|
102
|
+
let numStr = integerPart;
|
|
103
|
+
if (finalDecimalPart !== undefined) {
|
|
104
|
+
numStr += "." + finalDecimalPart;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const numValue = Number(numStr.replace(/\./g, ""));
|
|
108
|
+
onChange?.(numValue);
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
return (
|
|
112
|
+
<div className="relative">
|
|
113
|
+
<Input
|
|
114
|
+
{...props}
|
|
115
|
+
ref={ref}
|
|
116
|
+
type="text"
|
|
117
|
+
inputMode="numeric"
|
|
118
|
+
value={displayValue}
|
|
119
|
+
onChange={handleChange}
|
|
120
|
+
className={cn("pr-8", className)}
|
|
121
|
+
/>
|
|
122
|
+
{suffix && (
|
|
123
|
+
<div className="absolute inset-y-0 right-0 flex items-center pr-3 pointer-events-none text-muted-foreground text-sm">
|
|
124
|
+
{suffix}
|
|
125
|
+
</div>
|
|
126
|
+
)}
|
|
127
|
+
</div>
|
|
128
|
+
);
|
|
129
|
+
},
|
|
130
|
+
);
|
|
131
|
+
InputNumber.displayName = "InputNumber";
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { cn } from "../../utils";
|
|
3
|
+
|
|
4
|
+
export interface InputProps
|
|
5
|
+
extends React.InputHTMLAttributes<HTMLInputElement> {}
|
|
6
|
+
|
|
7
|
+
export const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
8
|
+
({ className, type, ...props }, ref) => {
|
|
9
|
+
return (
|
|
10
|
+
<input
|
|
11
|
+
type={type}
|
|
12
|
+
className={cn(
|
|
13
|
+
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
|
14
|
+
className,
|
|
15
|
+
)}
|
|
16
|
+
ref={ref}
|
|
17
|
+
{...props}
|
|
18
|
+
/>
|
|
19
|
+
);
|
|
20
|
+
},
|
|
21
|
+
);
|
|
22
|
+
Input.displayName = "Input";
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ComponentProps } from "react";
|
|
2
|
+
|
|
3
|
+
import { cn } from "../../utils";
|
|
4
|
+
|
|
5
|
+
export function Keyboard({
|
|
6
|
+
className,
|
|
7
|
+
children,
|
|
8
|
+
...props
|
|
9
|
+
}: ComponentProps<"kbd">) {
|
|
10
|
+
return (
|
|
11
|
+
<kbd
|
|
12
|
+
data-slot="keyboard"
|
|
13
|
+
className={cn(
|
|
14
|
+
"pointer-events-none select-none h-5 inline-flex items-center gap-x-1 px-1.5 bg-muted text-sm text-muted-foreground font-mono border rounded-sm",
|
|
15
|
+
"before:content-['⌘']",
|
|
16
|
+
className,
|
|
17
|
+
)}
|
|
18
|
+
{...props}
|
|
19
|
+
>
|
|
20
|
+
{children}
|
|
21
|
+
</kbd>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import type { ComponentProps } from "react";
|
|
5
|
+
import * as LabelPrimitive from "@radix-ui/react-label";
|
|
6
|
+
import { cn } from "../../utils";
|
|
7
|
+
|
|
8
|
+
export interface LabelProps
|
|
9
|
+
extends ComponentProps<typeof LabelPrimitive.Root> {}
|
|
10
|
+
|
|
11
|
+
export const Label = React.forwardRef<
|
|
12
|
+
React.ElementRef<typeof LabelPrimitive.Root>,
|
|
13
|
+
LabelProps
|
|
14
|
+
>(({ className, ...props }, ref) => (
|
|
15
|
+
<LabelPrimitive.Root
|
|
16
|
+
ref={ref}
|
|
17
|
+
className={cn(
|
|
18
|
+
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
|
|
19
|
+
className,
|
|
20
|
+
)}
|
|
21
|
+
{...props}
|
|
22
|
+
/>
|
|
23
|
+
));
|
|
24
|
+
Label.displayName = LabelPrimitive.Root.displayName;
|