feat(admin-ui): codemod @nstart/ui → @/ui (Stage 2.2)
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import { useAuth } from 'react-oidc-context'
|
import { useAuth } from 'react-oidc-context'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Button, IconButton } from '@nstart/ui'
|
import { Button, IconButton } from '@/ui'
|
||||||
import { SignInIcon, SignOutIcon, UserIcon } from '@phosphor-icons/react'
|
import { SignInIcon, SignOutIcon, UserIcon } from '@phosphor-icons/react'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import {
|
|||||||
TextInput,
|
TextInput,
|
||||||
type SelectOption,
|
type SelectOption,
|
||||||
type TabItem,
|
type TabItem,
|
||||||
} from '@nstart/ui'
|
} from '@/ui'
|
||||||
import type { CreateRecordRequest, FlattenedRecord, JsonSchema } from '@/api/client'
|
import type { CreateRecordRequest, FlattenedRecord, JsonSchema } from '@/api/client'
|
||||||
import { useReferencedRecords } from '@/api/queries'
|
import { useReferencedRecords } from '@/api/queries'
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useEffect, useRef, useState } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Alert, Button, FormActions, Modal } from '@nstart/ui'
|
import { Alert, Button, FormActions, Modal } from '@/ui'
|
||||||
import L from 'leaflet'
|
import L from 'leaflet'
|
||||||
import 'leaflet/dist/leaflet.css'
|
import 'leaflet/dist/leaflet.css'
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useEffect, useMemo, useState } from 'react'
|
import { useEffect, useMemo, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Alert, Badge, Button, LoadingBlock, Modal, TextInput } from '@nstart/ui'
|
import { Alert, Badge, Button, LoadingBlock, Modal, TextInput } from '@/ui'
|
||||||
import { WarningIcon, XCircleIcon } from '@phosphor-icons/react'
|
import { WarningIcon, XCircleIcon } from '@phosphor-icons/react'
|
||||||
import { useCascadePreview } from '@/api/queries'
|
import { useCascadePreview } from '@/api/queries'
|
||||||
import { useCascadeCloseRecord } from '@/api/mutations'
|
import { useCascadeCloseRecord } from '@/api/mutations'
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Link } from '@tanstack/react-router'
|
import { Link } from '@tanstack/react-router'
|
||||||
import { Badge, Panel } from '@nstart/ui'
|
import { Badge, Panel } from '@/ui'
|
||||||
import { ArrowRightIcon } from '@phosphor-icons/react'
|
import { ArrowRightIcon } from '@phosphor-icons/react'
|
||||||
import { useDictionaryDependents } from '@/api/queries'
|
import { useDictionaryDependents } from '@/api/queries'
|
||||||
import type { OnCloseAction } from '@/api/client'
|
import type { OnCloseAction } from '@/api/client'
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
import { Link } from '@tanstack/react-router'
|
import { Link } from '@tanstack/react-router'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Badge } from '@nstart/ui'
|
import { Badge } from '@/ui'
|
||||||
import { useDictionaryDependents, useDictionaries } from '@/api/queries'
|
import { useDictionaryDependents, useDictionaries } from '@/api/queries'
|
||||||
import type { DictionaryDetail, DictionaryDefinition, JsonSchema } from '@/api/client'
|
import type { DictionaryDetail, DictionaryDefinition, JsonSchema } from '@/api/client'
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Link } from '@tanstack/react-router'
|
import { Link } from '@tanstack/react-router'
|
||||||
import { Alert, Badge, Button, LoadingBlock } from '@nstart/ui'
|
import { Alert, Badge, Button, LoadingBlock } from '@/ui'
|
||||||
import { CaretLeftIcon, CaretRightIcon, ArrowSquareOutIcon } from '@phosphor-icons/react'
|
import { CaretLeftIcon, CaretRightIcon, ArrowSquareOutIcon } from '@phosphor-icons/react'
|
||||||
import { useRecordDependents } from '@/api/queries'
|
import { useRecordDependents } from '@/api/queries'
|
||||||
import type { OnCloseAction } from '@/api/client'
|
import type { OnCloseAction } from '@/api/client'
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Alert, Badge, Drawer, LoadingBlock } from '@nstart/ui'
|
import { Alert, Badge, Drawer, LoadingBlock } from '@/ui'
|
||||||
import { useRecordHistory } from '@/api/queries'
|
import { useRecordHistory } from '@/api/queries'
|
||||||
import { RecordDependentsPanel } from '@/components/lineage/RecordDependentsPanel'
|
import { RecordDependentsPanel } from '@/components/lineage/RecordDependentsPanel'
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import {
|
|||||||
TextInput,
|
TextInput,
|
||||||
type SelectOption,
|
type SelectOption,
|
||||||
type TabItem,
|
type TabItem,
|
||||||
} from '@nstart/ui'
|
} from '@/ui'
|
||||||
import { useCreateDictionary, useUpdateDictionary } from '@/api/mutations'
|
import { useCreateDictionary, useUpdateDictionary } from '@/api/mutations'
|
||||||
import { dictionaryDetailQuery, useDictionaries } from '@/api/queries'
|
import { dictionaryDetailQuery, useDictionaries } from '@/api/queries'
|
||||||
import type { CreateDictionaryRequest, DataScope, DictionaryDetail } from '@/api/client'
|
import type { CreateDictionaryRequest, DataScope, DictionaryDetail } from '@/api/client'
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Badge, Tabs, type TabItem } from '@nstart/ui'
|
import { Badge, Tabs, type TabItem } from '@/ui'
|
||||||
import { generateEventPreviews } from './eventPreview'
|
import { generateEventPreviews } from './eventPreview'
|
||||||
import type { DataScope, JsonSchema } from '@/api/client'
|
import type { DataScope, JsonSchema } from '@/api/client'
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
TextInput,
|
TextInput,
|
||||||
TextArea,
|
TextArea,
|
||||||
type SelectOption,
|
type SelectOption,
|
||||||
} from '@nstart/ui'
|
} from '@/ui'
|
||||||
import { TrashIcon, ArrowUpIcon, ArrowDownIcon } from '@phosphor-icons/react'
|
import { TrashIcon, ArrowUpIcon, ArrowDownIcon } from '@phosphor-icons/react'
|
||||||
import type { PropertyDef, PropertyKind } from './types'
|
import type { PropertyDef, PropertyKind } from './types'
|
||||||
import { PROPERTY_KINDS } from './types'
|
import { PROPERTY_KINDS } from './types'
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Button, EmptyState } from '@nstart/ui'
|
import { Button, EmptyState } from '@/ui'
|
||||||
import { PlusIcon } from '@phosphor-icons/react'
|
import { PlusIcon } from '@phosphor-icons/react'
|
||||||
import { PropertyEditor } from './PropertyEditor'
|
import { PropertyEditor } from './PropertyEditor'
|
||||||
import { newPropertyDef, type PropertyDef } from './types'
|
import { newPropertyDef, type PropertyDef } from './types'
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Button } from '@nstart/ui'
|
import { Button } from '@/ui'
|
||||||
import { ArrowClockwise, BookOpen, X } from '@phosphor-icons/react'
|
import { ArrowClockwise, BookOpen, X } from '@phosphor-icons/react'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { useAppVersion } from './useAppVersion'
|
import { useAppVersion } from './useAppVersion'
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { StrictMode } from 'react'
|
|||||||
import { createRoot } from 'react-dom/client'
|
import { createRoot } from 'react-dom/client'
|
||||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||||
import { RouterProvider, createRouter } from '@tanstack/react-router'
|
import { RouterProvider, createRouter } from '@tanstack/react-router'
|
||||||
import { NStartUiProvider, DatePickerProvider, DATE_PICKER_LOCALE_RU } from '@nstart/ui'
|
import { NStartUiProvider, DatePickerProvider, DATE_PICKER_LOCALE_RU } from '@/ui'
|
||||||
import { AuthProvider } from 'react-oidc-context'
|
import { AuthProvider } from 'react-oidc-context'
|
||||||
import { routeTree } from './routeTree.gen'
|
import { routeTree } from './routeTree.gen'
|
||||||
import { oidcAuthConfig } from '@/auth/oidcConfig'
|
import { oidcAuthConfig } from '@/auth/oidcConfig'
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { createRootRouteWithContext, Link, Outlet } from '@tanstack/react-router'
|
import { createRootRouteWithContext, Link, Outlet } from '@tanstack/react-router'
|
||||||
import type { QueryClient } from '@tanstack/react-query'
|
import type { QueryClient } from '@tanstack/react-query'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { LanguageSwitch } from '@nstart/ui'
|
import { LanguageSwitch } from '@/ui'
|
||||||
import { AuthBadge } from '@/auth/AuthBadge'
|
import { AuthBadge } from '@/auth/AuthBadge'
|
||||||
import { useCanMutate } from '@/auth/useCanMutate'
|
import { useCanMutate } from '@/auth/useCanMutate'
|
||||||
import { ThemeSwitch } from '@/components/layout/ThemeSwitch'
|
import { ThemeSwitch } from '@/components/layout/ThemeSwitch'
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import {
|
|||||||
TableHeaderCell,
|
TableHeaderCell,
|
||||||
TableRow,
|
TableRow,
|
||||||
TextInput,
|
TextInput,
|
||||||
} from '@nstart/ui'
|
} from '@/ui'
|
||||||
import {
|
import {
|
||||||
ArrowsClockwiseIcon,
|
ArrowsClockwiseIcon,
|
||||||
CaretDownIcon,
|
CaretDownIcon,
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import {
|
|||||||
TableHeaderCell,
|
TableHeaderCell,
|
||||||
TableRow,
|
TableRow,
|
||||||
TextInput,
|
TextInput,
|
||||||
} from '@nstart/ui'
|
} from '@/ui'
|
||||||
import { PlusIcon, PencilSimpleIcon, XCircleIcon, GearIcon, ClockCounterClockwiseIcon, MapTrifoldIcon, TrashIcon, CheckCircleIcon, WarningIcon, XIcon, DownloadSimpleIcon, CaretLeftIcon, CaretRightIcon } from '@phosphor-icons/react'
|
import { PlusIcon, PencilSimpleIcon, XCircleIcon, GearIcon, ClockCounterClockwiseIcon, MapTrifoldIcon, TrashIcon, CheckCircleIcon, WarningIcon, XIcon, DownloadSimpleIcon, CaretLeftIcon, CaretRightIcon } from '@phosphor-icons/react'
|
||||||
import {
|
import {
|
||||||
useDictionaryDetail,
|
useDictionaryDetail,
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
import { useDeferredValue, useMemo, useState } from 'react'
|
import { useDeferredValue, useMemo, useState } from 'react'
|
||||||
import { createFileRoute, Link, useNavigate } from '@tanstack/react-router'
|
import { createFileRoute, Link, useNavigate } from '@tanstack/react-router'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Alert, Badge, Button, EmptyState, LoadingBlock, PageHeader, SearchInput } from '@nstart/ui'
|
import { Alert, Badge, Button, EmptyState, LoadingBlock, PageHeader, SearchInput } from '@/ui'
|
||||||
import { PlusIcon } from '@phosphor-icons/react'
|
import { PlusIcon } from '@phosphor-icons/react'
|
||||||
import { useQueries } from '@tanstack/react-query'
|
import { useQueries } from '@tanstack/react-query'
|
||||||
import { dictionaryDependentsQuery, useDictionaries, useDictionaryDependents } from '@/api/queries'
|
import { dictionaryDependentsQuery, useDictionaries, useDictionaryDependents } from '@/api/queries'
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import {
|
|||||||
TableHead,
|
TableHead,
|
||||||
TableHeaderCell,
|
TableHeaderCell,
|
||||||
TableRow,
|
TableRow,
|
||||||
} from '@nstart/ui'
|
} from '@/ui'
|
||||||
import { useMyDrafts } from '@/api/queries'
|
import { useMyDrafts } from '@/api/queries'
|
||||||
import { useWithdrawDraft } from '@/api/mutations'
|
import { useWithdrawDraft } from '@/api/mutations'
|
||||||
import type { DraftOperation, DraftStatus } from '@/api/client'
|
import type { DraftOperation, DraftStatus } from '@/api/client'
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import {
|
|||||||
TableHead,
|
TableHead,
|
||||||
TableHeaderCell,
|
TableHeaderCell,
|
||||||
TableRow,
|
TableRow,
|
||||||
} from '@nstart/ui'
|
} from '@/ui'
|
||||||
import { ArrowsClockwiseIcon } from '@phosphor-icons/react'
|
import { ArrowsClockwiseIcon } from '@phosphor-icons/react'
|
||||||
import { useDlq, useOutboxStats } from '@/api/queries'
|
import { useDlq, useOutboxStats } from '@/api/queries'
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import {
|
|||||||
TableRow,
|
TableRow,
|
||||||
TextArea,
|
TextArea,
|
||||||
TextInput,
|
TextInput,
|
||||||
} from '@nstart/ui'
|
} from '@/ui'
|
||||||
import { CheckCircleIcon, XCircleIcon } from '@phosphor-icons/react'
|
import { CheckCircleIcon, XCircleIcon } from '@phosphor-icons/react'
|
||||||
import { useDraft, useLiveRecord, useReviewQueue } from '@/api/queries'
|
import { useDraft, useLiveRecord, useReviewQueue } from '@/api/queries'
|
||||||
import { useApproveDraft, useRejectDraft } from '@/api/mutations'
|
import { useApproveDraft, useRejectDraft } from '@/api/mutations'
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
PageHeader,
|
PageHeader,
|
||||||
Panel,
|
Panel,
|
||||||
SearchInput,
|
SearchInput,
|
||||||
} from '@nstart/ui'
|
} from '@/ui'
|
||||||
import { useSearch } from '@/api/queries'
|
import { useSearch } from '@/api/queries'
|
||||||
|
|
||||||
type SearchSearch = { q?: string }
|
type SearchSearch = { q?: string }
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import {
|
|||||||
TableHead,
|
TableHead,
|
||||||
TableHeaderCell,
|
TableHeaderCell,
|
||||||
TableRow,
|
TableRow,
|
||||||
} from '@nstart/ui'
|
} from '@/ui'
|
||||||
import {
|
import {
|
||||||
ArrowClockwiseIcon,
|
ArrowClockwiseIcon,
|
||||||
ArrowsClockwiseIcon,
|
ArrowsClockwiseIcon,
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import {
|
|||||||
TextArea,
|
TextArea,
|
||||||
TextInput,
|
TextInput,
|
||||||
type SelectOption,
|
type SelectOption,
|
||||||
} from '@nstart/ui'
|
} from '@/ui'
|
||||||
import {
|
import {
|
||||||
CopyIcon,
|
CopyIcon,
|
||||||
PlusIcon,
|
PlusIcon,
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ const alertVariants = cva(
|
|||||||
success: 'border-l-green bg-green-bg text-ink',
|
success: 'border-l-green bg-green-bg text-ink',
|
||||||
warning: 'border-l-warn bg-warn-bg text-ink',
|
warning: 'border-l-warn bg-warn-bg text-ink',
|
||||||
danger: 'border-l-pink bg-pink-bg text-ink',
|
danger: 'border-l-pink bg-pink-bg text-ink',
|
||||||
|
// Alias для nstart-compat: error === danger визуально.
|
||||||
|
error: 'border-l-pink bg-pink-bg text-ink',
|
||||||
neutral: 'border-l-line bg-surface-2 text-ink',
|
neutral: 'border-l-line bg-surface-2 text-ink',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -25,15 +27,22 @@ const alertVariants = cva(
|
|||||||
export type AlertProps = React.HTMLAttributes<HTMLDivElement> &
|
export type AlertProps = React.HTMLAttributes<HTMLDivElement> &
|
||||||
VariantProps<typeof alertVariants> & {
|
VariantProps<typeof alertVariants> & {
|
||||||
title?: React.ReactNode
|
title?: React.ReactNode
|
||||||
|
/** Right-aligned slot для action button(s) inside alert. */
|
||||||
|
action?: React.ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Alert = React.forwardRef<HTMLDivElement, AlertProps>(
|
export const Alert = React.forwardRef<HTMLDivElement, AlertProps>(
|
||||||
function Alert({ className, variant, title, children, ...props }, ref) {
|
function Alert({ className, variant, title, action, children, ...props }, ref) {
|
||||||
return (
|
return (
|
||||||
<div ref={ref} role="alert" className={cn(alertVariants({ variant }), className)} {...props}>
|
<div ref={ref} role="alert" className={cn(alertVariants({ variant }), className)} {...props}>
|
||||||
|
<div className="flex items-start justify-between gap-3">
|
||||||
|
<div className="min-w-0 flex-1">
|
||||||
{title && <div className="font-medium mb-0.5">{title}</div>}
|
{title && <div className="font-medium mb-0.5">{title}</div>}
|
||||||
<div className="text-ink-2 text-[13px] leading-snug">{children}</div>
|
<div className="text-ink-2 text-[13px] leading-snug">{children}</div>
|
||||||
</div>
|
</div>
|
||||||
|
{action && <div className="shrink-0 flex items-center gap-2">{action}</div>}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -12,6 +12,13 @@ const badgeVariants = cva(
|
|||||||
success: 'bg-green-bg text-green',
|
success: 'bg-green-bg text-green',
|
||||||
warning: 'bg-warn-bg text-warn',
|
warning: 'bg-warn-bg text-warn',
|
||||||
danger: 'bg-pink-bg text-pink',
|
danger: 'bg-pink-bg text-pink',
|
||||||
|
// Aliases для nstart-compat: error == danger, neutral == default,
|
||||||
|
// info == accent.
|
||||||
|
error: 'bg-pink-bg text-pink',
|
||||||
|
neutral: 'bg-surface-2 text-ink-2 border border-line',
|
||||||
|
info: 'bg-accent-bg text-accent',
|
||||||
|
// Alias для nstart-compat — старый Badge variant='primary' эквивалентен accent.
|
||||||
|
primary: 'bg-accent text-on-accent',
|
||||||
outline: 'border border-line text-ink-2',
|
outline: 'border border-line text-ink-2',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -61,21 +61,44 @@ export type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> &
|
|||||||
asChild?: boolean
|
asChild?: boolean
|
||||||
leftIcon?: React.ReactNode
|
leftIcon?: React.ReactNode
|
||||||
rightIcon?: React.ReactNode
|
rightIcon?: React.ReactNode
|
||||||
|
/** Loading state — disables button + replaces leftIcon с inline spinner. */
|
||||||
|
loading?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||||
function Button(
|
function Button(
|
||||||
{ className, variant, size, asChild, leftIcon, rightIcon, children, ...props },
|
{
|
||||||
|
className,
|
||||||
|
variant,
|
||||||
|
size,
|
||||||
|
asChild,
|
||||||
|
leftIcon,
|
||||||
|
rightIcon,
|
||||||
|
loading,
|
||||||
|
disabled,
|
||||||
|
children,
|
||||||
|
...props
|
||||||
|
},
|
||||||
ref,
|
ref,
|
||||||
) {
|
) {
|
||||||
const Comp = asChild ? Slot : 'button'
|
const Comp = asChild ? Slot : 'button'
|
||||||
|
const renderedLeftIcon = loading ? (
|
||||||
|
<svg className="animate-spin size-3.5" viewBox="0 0 24 24" aria-hidden>
|
||||||
|
<circle cx="12" cy="12" r="10" fill="none" stroke="currentColor" strokeOpacity="0.25" strokeWidth="4" />
|
||||||
|
<path d="M4 12a8 8 0 0 1 8-8" fill="none" stroke="currentColor" strokeWidth="4" strokeLinecap="round" />
|
||||||
|
</svg>
|
||||||
|
) : (
|
||||||
|
leftIcon
|
||||||
|
)
|
||||||
return (
|
return (
|
||||||
<Comp
|
<Comp
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(buttonVariants({ variant, size }), className)}
|
className={cn(buttonVariants({ variant, size }), className)}
|
||||||
|
disabled={disabled || loading}
|
||||||
|
aria-busy={loading || undefined}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{leftIcon}
|
{renderedLeftIcon}
|
||||||
{children}
|
{children}
|
||||||
{rightIcon}
|
{rightIcon}
|
||||||
</Comp>
|
</Comp>
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
import * as React from 'react'
|
||||||
|
import {
|
||||||
|
Sheet,
|
||||||
|
SheetContent,
|
||||||
|
SheetHeader,
|
||||||
|
SheetTitle,
|
||||||
|
SheetDescription,
|
||||||
|
} from './sheet'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drawer — adapter с @nstart/ui-style API над Radix Sheet (slide-over).
|
||||||
|
* Используется существующим кодом для side panels (record drawer, history,
|
||||||
|
* review preview).
|
||||||
|
*
|
||||||
|
* Props mapping:
|
||||||
|
* isOpen → Sheet.open
|
||||||
|
* onClose → Sheet.onOpenChange
|
||||||
|
* title → SheetTitle
|
||||||
|
* side → SheetContent.side (right default)
|
||||||
|
* widthClassName → custom className на SheetContent (override defaults)
|
||||||
|
* size → SheetContent.size shorthand (sm/md/lg/xl)
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type DrawerProps = {
|
||||||
|
isOpen: boolean
|
||||||
|
onClose: () => void
|
||||||
|
title?: React.ReactNode
|
||||||
|
description?: React.ReactNode
|
||||||
|
side?: 'left' | 'right' | 'top' | 'bottom'
|
||||||
|
size?: 'sm' | 'md' | 'lg' | 'xl'
|
||||||
|
widthClassName?: string
|
||||||
|
children?: React.ReactNode
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Drawer({
|
||||||
|
isOpen,
|
||||||
|
onClose,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
side = 'right',
|
||||||
|
size,
|
||||||
|
widthClassName,
|
||||||
|
children,
|
||||||
|
}: DrawerProps) {
|
||||||
|
return (
|
||||||
|
<Sheet
|
||||||
|
open={isOpen}
|
||||||
|
onOpenChange={(open) => {
|
||||||
|
if (!open) onClose()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SheetContent
|
||||||
|
side={side}
|
||||||
|
size={size}
|
||||||
|
className={cn('overflow-y-auto', widthClassName)}
|
||||||
|
>
|
||||||
|
{(title || description) && (
|
||||||
|
<SheetHeader>
|
||||||
|
{title && <SheetTitle>{title}</SheetTitle>}
|
||||||
|
{description && <SheetDescription>{description}</SheetDescription>}
|
||||||
|
</SheetHeader>
|
||||||
|
)}
|
||||||
|
{children}
|
||||||
|
</SheetContent>
|
||||||
|
</Sheet>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -4,27 +4,71 @@ import { cn } from '@/lib/utils'
|
|||||||
/**
|
/**
|
||||||
* Text input — single-line. Использует наши tokens, focus-ring через accent.
|
* Text input — single-line. Использует наши tokens, focus-ring через accent.
|
||||||
*
|
*
|
||||||
* Wrap'итесь в {@code <Label>} выше для accessibility. Для search input'а
|
* Поддерживает 2 режима:
|
||||||
* с иконкой см. {@link SearchInput}.
|
* - "bare" (default) — просто <input>, для inline использования в кастомных
|
||||||
|
* layout'ах (см. SearchInput, FormGrid с FieldLabel separately).
|
||||||
|
* - "field" — когда передан label / hint / error, рендерится FormField
|
||||||
|
* обёртка с label сверху + hint/error снизу. Match'ит @nstart/ui TextInput API.
|
||||||
*/
|
*/
|
||||||
export type InputProps = React.InputHTMLAttributes<HTMLInputElement>
|
export type InputProps = React.InputHTMLAttributes<HTMLInputElement> & {
|
||||||
|
/** Если задан — рендерится field-обёртка с label выше. */
|
||||||
|
label?: React.ReactNode
|
||||||
|
/** Optional helper text under input. */
|
||||||
|
hint?: React.ReactNode
|
||||||
|
/** Error message — overrides hint визуально, accent в pink. */
|
||||||
|
error?: React.ReactNode
|
||||||
|
/** Wrapper className когда rendering field-mode. */
|
||||||
|
containerClassName?: string
|
||||||
|
}
|
||||||
|
|
||||||
export const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
export const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||||
function Input({ className, type = 'text', ...props }, ref) {
|
function Input(
|
||||||
return (
|
{ className, type = 'text', label, hint, error, required, containerClassName, id, ...props },
|
||||||
|
ref,
|
||||||
|
) {
|
||||||
|
const autoId = React.useId()
|
||||||
|
const inputId = id ?? autoId
|
||||||
|
const inputEl = (
|
||||||
<input
|
<input
|
||||||
|
id={inputId}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
type={type}
|
type={type}
|
||||||
|
required={required}
|
||||||
|
aria-required={required || undefined}
|
||||||
|
aria-invalid={Boolean(error) || undefined}
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex h-9 w-full rounded-md border border-line bg-surface px-3 py-1 text-sm text-ink',
|
'flex h-9 w-full rounded-md border border-line bg-surface px-3 py-1 text-sm text-ink',
|
||||||
'placeholder:text-mute',
|
'placeholder:text-mute',
|
||||||
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-bg',
|
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-bg',
|
||||||
'disabled:cursor-not-allowed disabled:opacity-50',
|
'disabled:cursor-not-allowed disabled:opacity-50',
|
||||||
'file:border-0 file:bg-transparent file:text-sm file:font-medium',
|
'file:border-0 file:bg-transparent file:text-sm file:font-medium',
|
||||||
|
error && 'border-pink focus-visible:ring-pink',
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (!label && !hint && !error) return inputEl
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={cn('flex flex-col gap-1', containerClassName)}>
|
||||||
|
{label && (
|
||||||
|
<label
|
||||||
|
htmlFor={inputId}
|
||||||
|
className="text-2xs font-medium font-display uppercase tracking-[0.10em] text-mute leading-none"
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
{required && <span className="text-pink ml-0.5">*</span>}
|
||||||
|
</label>
|
||||||
|
)}
|
||||||
|
{inputEl}
|
||||||
|
{error ? (
|
||||||
|
<span className="text-xs text-pink">{error}</span>
|
||||||
|
) : hint ? (
|
||||||
|
<span className="text-xs text-mute">{hint}</span>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,23 +4,37 @@ import { cn } from '@/lib/utils'
|
|||||||
/**
|
/**
|
||||||
* LoadingBlock — central spinner с подписью. Заменяет {@code @nstart/ui}
|
* LoadingBlock — central spinner с подписью. Заменяет {@code @nstart/ui}
|
||||||
* LoadingBlock. Для inline placeholder используйте Skeleton.
|
* LoadingBlock. Для inline placeholder используйте Skeleton.
|
||||||
|
*
|
||||||
|
* Size variants:
|
||||||
|
* - sm: small inline spinner (py-4)
|
||||||
|
* - md: default centered (py-12)
|
||||||
|
* - lg: prominent (py-20)
|
||||||
*/
|
*/
|
||||||
export type LoadingBlockProps = React.HTMLAttributes<HTMLDivElement> & {
|
export type LoadingBlockProps = React.HTMLAttributes<HTMLDivElement> & {
|
||||||
label?: React.ReactNode
|
label?: React.ReactNode
|
||||||
|
size?: 'sm' | 'md' | 'lg'
|
||||||
}
|
}
|
||||||
|
|
||||||
export function LoadingBlock({ className, label, ...props }: LoadingBlockProps) {
|
const SIZES = {
|
||||||
|
sm: { wrapper: 'py-4', icon: 'size-3' },
|
||||||
|
md: { wrapper: 'py-12', icon: 'size-5' },
|
||||||
|
lg: { wrapper: 'py-20', icon: 'size-8' },
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export function LoadingBlock({ className, label, size = 'md', ...props }: LoadingBlockProps) {
|
||||||
|
const s = SIZES[size]
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
role="status"
|
role="status"
|
||||||
aria-busy="true"
|
aria-busy="true"
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex flex-col items-center justify-center gap-2 py-12 text-mute',
|
'flex flex-col items-center justify-center gap-2 text-mute',
|
||||||
|
s.wrapper,
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<Loader2 className="size-5 animate-spin text-accent" />
|
<Loader2 className={cn('animate-spin text-accent', s.icon)} />
|
||||||
{label && <span className="text-sm">{label}</span>}
|
{label && <span className="text-sm">{label}</span>}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
import * as React from 'react'
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
DialogDescription,
|
||||||
|
} from './dialog'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modal — adapter с @nstart/ui-style API над Radix Dialog. Используется
|
||||||
|
* существующим кодом (см. dictionaries.$name.tsx, webhooks, reviews etc.) —
|
||||||
|
* упрощает codemod без рефактора каждого callsite.
|
||||||
|
*
|
||||||
|
* Props mapping:
|
||||||
|
* isOpen → Dialog.open
|
||||||
|
* onClose → Dialog.onOpenChange (false case)
|
||||||
|
* title → DialogTitle children
|
||||||
|
* description → DialogDescription
|
||||||
|
* maxWidth → DialogContent size (mapped: max-w-md→sm, max-w-lg→md, max-w-2xl→lg, max-w-4xl→xl)
|
||||||
|
* children → DialogContent body
|
||||||
|
*
|
||||||
|
* Новый код может использовать Dialog напрямую — он остаётся exported.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const SIZE_MAP: Record<string, 'sm' | 'md' | 'lg' | 'xl' | 'full'> = {
|
||||||
|
'max-w-sm': 'sm',
|
||||||
|
'max-w-md': 'sm',
|
||||||
|
'max-w-lg': 'md',
|
||||||
|
'max-w-xl': 'md',
|
||||||
|
'max-w-2xl': 'lg',
|
||||||
|
'max-w-3xl': 'lg',
|
||||||
|
'max-w-4xl': 'xl',
|
||||||
|
'max-w-5xl': 'xl',
|
||||||
|
'max-w-6xl': 'full',
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ModalProps = {
|
||||||
|
isOpen: boolean
|
||||||
|
onClose: () => void
|
||||||
|
title?: React.ReactNode
|
||||||
|
description?: React.ReactNode
|
||||||
|
maxWidth?: string
|
||||||
|
size?: 'sm' | 'md' | 'lg' | 'xl' | 'full'
|
||||||
|
children?: React.ReactNode
|
||||||
|
hideClose?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Modal({
|
||||||
|
isOpen,
|
||||||
|
onClose,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
maxWidth,
|
||||||
|
size,
|
||||||
|
hideClose,
|
||||||
|
children,
|
||||||
|
}: ModalProps) {
|
||||||
|
const resolved = size ?? (maxWidth ? SIZE_MAP[maxWidth] : undefined) ?? 'md'
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
open={isOpen}
|
||||||
|
onOpenChange={(open) => {
|
||||||
|
if (!open) onClose()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DialogContent size={resolved} hideClose={hideClose}>
|
||||||
|
{(title || description) && (
|
||||||
|
<DialogHeader>
|
||||||
|
{title && <DialogTitle>{title}</DialogTitle>}
|
||||||
|
{description && <DialogDescription>{description}</DialogDescription>}
|
||||||
|
</DialogHeader>
|
||||||
|
)}
|
||||||
|
{children}
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -3,11 +3,15 @@ import { cn } from '@/lib/utils'
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* PageHeader — title + optional description + actions slot. Use в верху route'а.
|
* PageHeader — title + optional description + actions slot. Use в верху route'а.
|
||||||
|
*
|
||||||
|
* breadcrumb prop рендерится тонкой строкой ВЫШЕ title (cap-style).
|
||||||
|
* Обычно JSX с <Link>ами через separator: "Справочники / Космические аппараты".
|
||||||
*/
|
*/
|
||||||
export type PageHeaderProps = React.HTMLAttributes<HTMLDivElement> & {
|
export type PageHeaderProps = React.HTMLAttributes<HTMLDivElement> & {
|
||||||
title: React.ReactNode
|
title: React.ReactNode
|
||||||
description?: React.ReactNode
|
description?: React.ReactNode
|
||||||
actions?: React.ReactNode
|
actions?: React.ReactNode
|
||||||
|
breadcrumb?: React.ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PageHeader({
|
export function PageHeader({
|
||||||
@@ -15,11 +19,17 @@ export function PageHeader({
|
|||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
actions,
|
actions,
|
||||||
|
breadcrumb,
|
||||||
children,
|
children,
|
||||||
...props
|
...props
|
||||||
}: PageHeaderProps) {
|
}: PageHeaderProps) {
|
||||||
return (
|
return (
|
||||||
<div className={cn('flex flex-col gap-1 mb-4', className)} {...props}>
|
<div className={cn('flex flex-col gap-1 mb-4', className)} {...props}>
|
||||||
|
{breadcrumb && (
|
||||||
|
<div className="text-2xs font-display uppercase tracking-[0.10em] text-mute leading-tight mb-1">
|
||||||
|
{breadcrumb}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div className="flex items-start justify-between gap-3 flex-wrap">
|
<div className="flex items-start justify-between gap-3 flex-wrap">
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<h1 className="text-lg font-semibold text-ink leading-tight truncate">{title}</h1>
|
<h1 className="text-lg font-semibold text-ink leading-tight truncate">{title}</h1>
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import * as React from 'react'
|
||||||
|
import {
|
||||||
|
Tabs as RadixTabs,
|
||||||
|
TabsList as RadixTabsList,
|
||||||
|
TabsTrigger as RadixTabsTrigger,
|
||||||
|
} from './tabs'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TabItem-based single-component API над Radix Tabs. Замена @nstart/ui Tabs
|
||||||
|
* с теми же props ({@code items, value, onValueChange}).
|
||||||
|
*
|
||||||
|
* Использование (legacy):
|
||||||
|
* <Tabs items={[{id: 'a', label: 'A'}, {id: 'b', label: 'B'}]}
|
||||||
|
* value={active} onValueChange={setActive} />
|
||||||
|
*
|
||||||
|
* Для content panels используйте TabsContent с radix Tabs root напрямую —
|
||||||
|
* этот adapter рендерит только tab bar.
|
||||||
|
*
|
||||||
|
* Новый код может использовать `<Tabs.Root>...<TabsList><TabsTrigger value="a">A</...`
|
||||||
|
* directly из ui/components/tabs.tsx.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type TabItem = {
|
||||||
|
id: string
|
||||||
|
label: React.ReactNode
|
||||||
|
disabled?: boolean
|
||||||
|
/** Right-aligned content в tab (badge, indicator). */
|
||||||
|
trailing?: React.ReactNode
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TabsSimpleProps = {
|
||||||
|
items: ReadonlyArray<TabItem>
|
||||||
|
value: string
|
||||||
|
onValueChange: (id: string) => void
|
||||||
|
className?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function TabsSimple({ items, value, onValueChange, className }: TabsSimpleProps) {
|
||||||
|
return (
|
||||||
|
<RadixTabs value={value} onValueChange={onValueChange} className={className}>
|
||||||
|
<RadixTabsList>
|
||||||
|
{items.map((item) => (
|
||||||
|
<RadixTabsTrigger key={item.id} value={item.id} disabled={item.disabled}>
|
||||||
|
<span className="inline-flex items-center gap-1.5">
|
||||||
|
{item.label}
|
||||||
|
{item.trailing}
|
||||||
|
</span>
|
||||||
|
</RadixTabsTrigger>
|
||||||
|
))}
|
||||||
|
</RadixTabsList>
|
||||||
|
</RadixTabs>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,40 +1,59 @@
|
|||||||
/**
|
/**
|
||||||
* Barrel re-export для shadcn-style UI primitives.
|
* Barrel re-export для UI primitives.
|
||||||
*
|
*
|
||||||
* <p>Это единая точка входа для UI компонентов в admin-ui. Цель — постепенно
|
* <p>Стратегия миграции (Phase 2 stack migration):
|
||||||
* переключить все импорты с {@code @nstart/ui} на {@code @/ui}, и затем
|
* <ul>
|
||||||
* удалить @nstart/ui из package.json.
|
* <li>{@code @nstart/ui} остаётся подключённым — все его компоненты
|
||||||
|
* pass-through через этот barrel, чтобы существующий код работал без
|
||||||
|
* рефактора props (Checkbox.label/description, Modal.panelClassName,
|
||||||
|
* FormActions.align, и т.п.).</li>
|
||||||
|
* <li>shadcn-style primitives в {@code ./components/*} добавлены как
|
||||||
|
* параллельный набор. Новый код использует их через alias'ы где они
|
||||||
|
* чище nstart'а ({@code Button}, {@code Badge}, {@code Alert} с
|
||||||
|
* Tailwind v4 tokens; {@code Cap}, {@code ScopeBadge}, {@code ScopeDot},
|
||||||
|
* {@code ScopeStrip} — handoff design system primitives).</li>
|
||||||
|
* <li>Phase 3: компоненты которые имеют bug'и или missing features в nstart
|
||||||
|
* (Combobox vs MultiSelect, TanStack Table vs Table) — заменяются
|
||||||
|
* per-file rewrite.</li>
|
||||||
|
* <li>Phase 4: @nstart/ui удаляется из package.json когда все callsites
|
||||||
|
* переписаны.</li>
|
||||||
|
* </ul>
|
||||||
*
|
*
|
||||||
* <p>Phase 2 миграции (handoff plan): новые компоненты — Radix primitives +
|
* <p>Текущая семантика: import {X} from '@/ui' — Х берётся приоритетно из
|
||||||
* Tailwind v4 tokens. Phase 3 — каждый touched файл переносится с {@code
|
* наших shadcn primitives (overrides ниже), иначе passthrough из @nstart/ui.
|
||||||
* @nstart/ui} на {@code @/ui} имена. Phase 4 — pkg removed.
|
* Этот файл — single source of truth для UI imports.
|
||||||
*
|
|
||||||
* <p>Все компоненты используют наши design tokens (--color-ink, --color-accent
|
|
||||||
* etc.) через @theme inline в styles.css.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Buttons + actions
|
// === Полная re-export из @nstart/ui — все компоненты, hooks, locale const ===
|
||||||
|
// Дальше будут selective overrides где наши shadcn primitives лучше.
|
||||||
|
export * from '@nstart/ui'
|
||||||
|
|
||||||
|
// === Overrides: наши shadcn primitives с Tailwind v4 tokens ===
|
||||||
|
// Эти именованные re-export'ы перекрывают одноимённые из @nstart/ui выше
|
||||||
|
// (TS resolves last declaration → наши берут верх). Mostly cosmetic — общий
|
||||||
|
// API design сохранён, добавлены теневые props (loading, error-variant и т.д.).
|
||||||
export { Button, buttonVariants, type ButtonProps } from './components/button'
|
export { Button, buttonVariants, type ButtonProps } from './components/button'
|
||||||
export { IconButton, type IconButtonProps } from './components/icon-button'
|
|
||||||
|
|
||||||
// Inputs
|
|
||||||
export { Input, type InputProps } from './components/input'
|
|
||||||
export { Label } from './components/label'
|
|
||||||
export { SearchInput, type SearchInputProps } from './components/search-input'
|
|
||||||
|
|
||||||
// Form layout
|
|
||||||
export { FormActions, type FormActionsProps } from './components/form-actions'
|
|
||||||
|
|
||||||
// Status / feedback
|
|
||||||
export { Badge, type BadgeProps } from './components/badge'
|
export { Badge, type BadgeProps } from './components/badge'
|
||||||
export { Alert, type AlertProps } from './components/alert'
|
export { Alert, type AlertProps } from './components/alert'
|
||||||
export { Skeleton } from './components/skeleton'
|
|
||||||
export { LoadingBlock, type LoadingBlockProps } from './components/loading-block'
|
|
||||||
export { EmptyState, type EmptyStateProps } from './components/empty-state'
|
|
||||||
|
|
||||||
// Surfaces
|
// === Handoff design system primitives — новые компоненты без nstart-аналога ===
|
||||||
|
export { Cap, type CapProps } from './components/cap'
|
||||||
export {
|
export {
|
||||||
Card,
|
ScopeDot,
|
||||||
|
ScopeBadge,
|
||||||
|
ScopeStrip,
|
||||||
|
type DataScope as ScopeKind,
|
||||||
|
} from './components/scope'
|
||||||
|
|
||||||
|
// === shadcn primitives для НОВОГО кода (Phase 3) ===
|
||||||
|
// Эти именованные exports НЕ конфликтуют с nstart (имена не пересекаются).
|
||||||
|
// Используются в редизайне catalog/editor/drawer per handoff README.
|
||||||
|
export { IconButton as ShadcnIconButton, type IconButtonProps } from './components/icon-button'
|
||||||
|
export { Input as ShadcnInput, type InputProps as ShadcnInputProps } from './components/input'
|
||||||
|
export { Label as ShadcnLabel } from './components/label'
|
||||||
|
export { SearchInput as ShadcnSearchInput, type SearchInputProps as ShadcnSearchInputProps } from './components/search-input'
|
||||||
|
export {
|
||||||
|
Card as ShadcnCard,
|
||||||
CardHeader,
|
CardHeader,
|
||||||
CardTitle,
|
CardTitle,
|
||||||
CardDescription,
|
CardDescription,
|
||||||
@@ -42,9 +61,7 @@ export {
|
|||||||
CardFooter,
|
CardFooter,
|
||||||
} from './components/card'
|
} from './components/card'
|
||||||
export { Separator } from './components/separator'
|
export { Separator } from './components/separator'
|
||||||
export { PageHeader, type PageHeaderProps } from './components/page-header'
|
export { Skeleton } from './components/skeleton'
|
||||||
|
|
||||||
// Overlays
|
|
||||||
export {
|
export {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
@@ -82,9 +99,13 @@ export {
|
|||||||
TooltipTrigger,
|
TooltipTrigger,
|
||||||
TooltipContent,
|
TooltipContent,
|
||||||
} from './components/tooltip'
|
} from './components/tooltip'
|
||||||
|
// Tabs из shadcn — composition API.
|
||||||
// Navigation
|
export {
|
||||||
export { Tabs, TabsList, TabsTrigger, TabsContent } from './components/tabs'
|
Tabs as ShadcnTabsRoot,
|
||||||
|
TabsList as ShadcnTabsList,
|
||||||
|
TabsTrigger as ShadcnTabsTrigger,
|
||||||
|
TabsContent as ShadcnTabsContent,
|
||||||
|
} from './components/tabs'
|
||||||
export {
|
export {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
@@ -101,25 +122,4 @@ export {
|
|||||||
DropdownMenuSubContent,
|
DropdownMenuSubContent,
|
||||||
DropdownMenuRadioGroup,
|
DropdownMenuRadioGroup,
|
||||||
} from './components/dropdown-menu'
|
} from './components/dropdown-menu'
|
||||||
|
export { Switch as ShadcnSwitch } from './components/switch'
|
||||||
// Form controls
|
|
||||||
export { Checkbox } from './components/checkbox'
|
|
||||||
export { Switch } from './components/switch'
|
|
||||||
|
|
||||||
// Domain-specific atoms (handoff design system)
|
|
||||||
export { Cap, type CapProps } from './components/cap'
|
|
||||||
export {
|
|
||||||
ScopeDot,
|
|
||||||
ScopeBadge,
|
|
||||||
ScopeStrip,
|
|
||||||
type DataScope,
|
|
||||||
} from './components/scope'
|
|
||||||
|
|
||||||
// === @nstart/ui compatibility aliases ===
|
|
||||||
// Чтобы упростить миграцию touched файлов: перевод import только-source,
|
|
||||||
// not всего code. Каждый alias документирован, как соотносится с новым API.
|
|
||||||
|
|
||||||
export { Card as Panel } from './components/card'
|
|
||||||
export { Dialog as Modal } from './components/dialog'
|
|
||||||
export { Sheet as Drawer } from './components/sheet'
|
|
||||||
export { Input as TextInput } from './components/input'
|
|
||||||
|
|||||||
Reference in New Issue
Block a user