@startsimpli/ui 0.1.0 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-27YUQBOE.mjs +3954 -0
- package/dist/chunk-27YUQBOE.mjs.map +1 -0
- package/dist/chunk-G2AM3DBU.mjs +1026 -0
- package/dist/chunk-G2AM3DBU.mjs.map +1 -0
- package/dist/chunk-G4XBXCFH.mjs +63 -0
- package/dist/chunk-G4XBXCFH.mjs.map +1 -0
- package/dist/chunk-LZOMFHX3.mjs +35 -0
- package/dist/chunk-LZOMFHX3.mjs.map +1 -0
- package/dist/chunk-QYXFLOO7.mjs +210 -0
- package/dist/chunk-QYXFLOO7.mjs.map +1 -0
- package/dist/components/index.d.mts +472 -0
- package/dist/components/index.d.ts +472 -0
- package/dist/components/index.js +5149 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/index.mjs +6 -0
- package/dist/components/index.mjs.map +1 -0
- package/dist/components/unified-table/index.d.mts +725 -0
- package/dist/components/unified-table/index.d.ts +725 -0
- package/dist/components/unified-table/index.js +4000 -0
- package/dist/components/unified-table/index.js.map +1 -0
- package/dist/components/unified-table/index.mjs +5 -0
- package/dist/components/unified-table/index.mjs.map +1 -0
- package/dist/index.d.mts +26 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +5448 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +12 -0
- package/dist/index.mjs.map +1 -0
- package/dist/theme/index.d.mts +20 -0
- package/dist/theme/index.d.ts +20 -0
- package/dist/theme/index.js +245 -0
- package/dist/theme/index.js.map +1 -0
- package/dist/theme/index.mjs +9 -0
- package/dist/theme/index.mjs.map +1 -0
- package/dist/utils/index.d.mts +38 -0
- package/dist/utils/index.d.ts +38 -0
- package/dist/utils/index.js +72 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/index.mjs +4 -0
- package/dist/utils/index.mjs.map +1 -0
- package/package.json +62 -21
- package/src/__mocks__/next/navigation.js +18 -0
- package/src/components/__tests__/safe-html.test.tsx +45 -0
- package/src/components/__tests__/states.test.tsx +94 -0
- package/src/components/__tests__/status-badge.test.tsx +101 -0
- package/src/components/__tests__/toast.test.tsx +124 -0
- package/src/components/badge/StatusBadge.tsx +55 -0
- package/src/components/badge/index.ts +2 -0
- package/src/components/dialog/BaseDialog.tsx +184 -0
- package/src/components/dialog/index.ts +8 -0
- package/src/components/index.ts +25 -0
- package/src/components/loading/DashboardSkeleton.tsx +27 -0
- package/src/components/loading/TableSkeleton.tsx +63 -0
- package/src/components/loading/index.ts +4 -0
- package/src/components/safe-html.tsx +18 -0
- package/src/components/states/EmptyState.tsx +48 -0
- package/src/components/states/ErrorState.tsx +76 -0
- package/src/components/states/index.ts +4 -0
- package/src/components/toast/Toaster.tsx +72 -0
- package/src/components/toast/index.ts +5 -0
- package/src/components/toast/use-notify.ts +45 -0
- package/src/components/toast/use-toast.ts +150 -0
- package/src/components/ui/api-error-boundary.tsx +64 -0
- package/src/components/ui/feature-gate.tsx +87 -0
- package/src/components/ui/index.ts +4 -0
- package/src/components/ui/page-loader.tsx +31 -0
- package/src/components/ui/query-provider.tsx +30 -0
- package/src/components/unified-table/components/Toolbar/StandardTableToolbar.tsx +1 -1
- package/src/components/unified-table/hooks/useFilters.ts +1 -0
- package/src/components/unified-table/hooks/usePagination.ts +1 -0
- package/src/components/unified-table/hooks/useSelection.ts +2 -1
- package/src/components/unified-table/hooks/useTableKeyboard.ts +2 -1
- package/src/components/unified-table/hooks/useTablePreferences.ts +1 -0
- package/src/components/unified-table/hooks/useTableState.ts +1 -0
- package/src/components/unified-table/hooks/useTableURL.test.tsx +1 -1
- package/src/components/unified-table/index.ts +4 -0
- package/src/components/wizard/StepIndicator.tsx +60 -0
- package/src/components/wizard/index.ts +2 -0
- package/src/theme/tailwind.config.d.ts +3 -0
- package/tailwind.preset.js +87 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { cn } from "../../lib/utils"
|
|
3
|
+
|
|
4
|
+
interface PageLoaderProps {
|
|
5
|
+
/** Number of skeleton rows to show. Default: 5. */
|
|
6
|
+
rows?: number
|
|
7
|
+
className?: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Page-level skeleton loader. Renders animated skeleton rows as a loading placeholder.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* if (loading) return <PageLoader />
|
|
15
|
+
*/
|
|
16
|
+
export function PageLoader({ rows = 5, className }: PageLoaderProps) {
|
|
17
|
+
return (
|
|
18
|
+
<div className={cn("w-full space-y-3 p-4", className)} aria-busy="true" aria-label="Loading">
|
|
19
|
+
<div className="h-8 w-1/3 rounded-md bg-muted animate-pulse" />
|
|
20
|
+
<div className="space-y-2">
|
|
21
|
+
{Array.from({ length: rows }).map((_, i) => (
|
|
22
|
+
<div
|
|
23
|
+
key={i}
|
|
24
|
+
className="h-12 w-full rounded-md bg-muted animate-pulse"
|
|
25
|
+
style={{ opacity: 1 - i * 0.1 }}
|
|
26
|
+
/>
|
|
27
|
+
))}
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
4
|
+
import { useState } from 'react';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Shared QueryClient provider with consistent defaults.
|
|
8
|
+
*
|
|
9
|
+
* - staleTime: 5 minutes (avoids unnecessary refetches)
|
|
10
|
+
* - refetchOnWindowFocus: false (explicit control over refetches)
|
|
11
|
+
*/
|
|
12
|
+
export function QueryProvider({ children }: { children: React.ReactNode }) {
|
|
13
|
+
const [queryClient] = useState(
|
|
14
|
+
() =>
|
|
15
|
+
new QueryClient({
|
|
16
|
+
defaultOptions: {
|
|
17
|
+
queries: {
|
|
18
|
+
staleTime: 5 * 60 * 1000,
|
|
19
|
+
refetchOnWindowFocus: false,
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
})
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<QueryClientProvider client={queryClient}>
|
|
27
|
+
{children}
|
|
28
|
+
</QueryClientProvider>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
@@ -21,7 +21,7 @@ export interface StandardTableToolbarProps<TData> {
|
|
|
21
21
|
searchPlaceholder?: string
|
|
22
22
|
searchValue?: string
|
|
23
23
|
onSearchChange?: (value: string) => void
|
|
24
|
-
searchInputRef?: RefObject<HTMLInputElement>
|
|
24
|
+
searchInputRef?: RefObject<HTMLInputElement | null>
|
|
25
25
|
searchAutoFocus?: boolean
|
|
26
26
|
|
|
27
27
|
// Column visibility
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
'use client'
|
|
1
2
|
import { useState, useCallback, useEffect, useRef } from 'react'
|
|
2
3
|
import { UseSelectionReturn } from '../types'
|
|
3
4
|
|
|
@@ -40,7 +41,7 @@ export function useSelection({
|
|
|
40
41
|
}, [onSelectionChange, onSelectAllPages])
|
|
41
42
|
|
|
42
43
|
// Sync external state to internal when in controlled mode
|
|
43
|
-
const prevExternalIdsRef = useRef<Set<string> | undefined>()
|
|
44
|
+
const prevExternalIdsRef = useRef<Set<string> | undefined>(undefined)
|
|
44
45
|
useEffect(() => {
|
|
45
46
|
if (externalSelectedIds !== undefined && externalSelectedIds !== prevExternalIdsRef.current) {
|
|
46
47
|
setInternalSelectedIds(new Set(externalSelectedIds))
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
'use client'
|
|
1
2
|
import { useEffect, useCallback, useRef, useState, RefObject } from 'react'
|
|
2
3
|
|
|
3
4
|
export interface UseTableKeyboardProps<TData> {
|
|
@@ -8,7 +9,7 @@ export interface UseTableKeyboardProps<TData> {
|
|
|
8
9
|
onToggleAll?: () => void
|
|
9
10
|
onRowClick?: (row: TData) => void
|
|
10
11
|
onDelete?: (ids: Set<string>) => void
|
|
11
|
-
tableRef: RefObject<HTMLElement>
|
|
12
|
+
tableRef: RefObject<HTMLElement | null>
|
|
12
13
|
enabled?: boolean
|
|
13
14
|
}
|
|
14
15
|
|
|
@@ -7,7 +7,7 @@ const mockReplace = jest.fn()
|
|
|
7
7
|
const mockSearchParams = new URLSearchParams()
|
|
8
8
|
const mockPathname = '/test-path'
|
|
9
9
|
|
|
10
|
-
jest.mock('next/navigation
|
|
10
|
+
jest.mock('next/navigation', () => ({
|
|
11
11
|
useSearchParams: jest.fn(() => mockSearchParams),
|
|
12
12
|
useRouter: jest.fn(() => ({
|
|
13
13
|
replace: mockReplace,
|
|
@@ -14,3 +14,7 @@ export { MOBILE_BREAKPOINT } from './components/MobileView'
|
|
|
14
14
|
|
|
15
15
|
export * from './hooks'
|
|
16
16
|
export * from './utils'
|
|
17
|
+
|
|
18
|
+
// Toolbar components
|
|
19
|
+
export { StandardTableToolbar } from './components/Toolbar'
|
|
20
|
+
export type { StandardTableToolbarProps } from './components/Toolbar'
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import { Check } from 'lucide-react'
|
|
3
|
+
|
|
4
|
+
export interface StepConfig {
|
|
5
|
+
label: string
|
|
6
|
+
description?: string
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface StepIndicatorProps {
|
|
10
|
+
steps: StepConfig[]
|
|
11
|
+
currentIndex: number
|
|
12
|
+
className?: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function StepIndicator({ steps, currentIndex, className = '' }: StepIndicatorProps) {
|
|
16
|
+
return (
|
|
17
|
+
<ol className={`flex items-center gap-0 ${className}`}>
|
|
18
|
+
{steps.map((step, index) => {
|
|
19
|
+
const isCompleted = index < currentIndex
|
|
20
|
+
const isActive = index === currentIndex
|
|
21
|
+
const isLast = index === steps.length - 1
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<li key={index} className={`flex items-center ${!isLast ? 'flex-1' : ''}`}>
|
|
25
|
+
<div className="flex flex-col items-center">
|
|
26
|
+
<div
|
|
27
|
+
className={[
|
|
28
|
+
'flex h-8 w-8 items-center justify-center rounded-full border-2 text-sm font-medium transition-colors',
|
|
29
|
+
isCompleted
|
|
30
|
+
? 'border-primary-600 bg-primary-600 text-white'
|
|
31
|
+
: isActive
|
|
32
|
+
? 'border-primary-600 bg-white text-primary-600'
|
|
33
|
+
: 'border-gray-300 bg-white text-gray-400',
|
|
34
|
+
].join(' ')}
|
|
35
|
+
>
|
|
36
|
+
{isCompleted ? <Check className="h-4 w-4" /> : index + 1}
|
|
37
|
+
</div>
|
|
38
|
+
<span
|
|
39
|
+
className={[
|
|
40
|
+
'mt-1 text-xs font-medium',
|
|
41
|
+
isActive ? 'text-primary-600' : isCompleted ? 'text-gray-600' : 'text-gray-400',
|
|
42
|
+
].join(' ')}
|
|
43
|
+
>
|
|
44
|
+
{step.label}
|
|
45
|
+
</span>
|
|
46
|
+
</div>
|
|
47
|
+
{!isLast && (
|
|
48
|
+
<div
|
|
49
|
+
className={[
|
|
50
|
+
'h-0.5 flex-1 mx-2 mb-4 transition-colors',
|
|
51
|
+
isCompleted ? 'bg-primary-600' : 'bg-gray-200',
|
|
52
|
+
].join(' ')}
|
|
53
|
+
/>
|
|
54
|
+
)}
|
|
55
|
+
</li>
|
|
56
|
+
)
|
|
57
|
+
})}
|
|
58
|
+
</ol>
|
|
59
|
+
)
|
|
60
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/** @type {import('tailwindcss').Config} */
|
|
2
|
+
module.exports = {
|
|
3
|
+
darkMode: ['class'],
|
|
4
|
+
theme: {
|
|
5
|
+
extend: {
|
|
6
|
+
colors: {
|
|
7
|
+
background: 'hsl(var(--background))',
|
|
8
|
+
foreground: 'hsl(var(--foreground))',
|
|
9
|
+
card: {
|
|
10
|
+
DEFAULT: 'hsl(var(--card))',
|
|
11
|
+
foreground: 'hsl(var(--card-foreground))',
|
|
12
|
+
},
|
|
13
|
+
popover: {
|
|
14
|
+
DEFAULT: 'hsl(var(--popover))',
|
|
15
|
+
foreground: 'hsl(var(--popover-foreground))',
|
|
16
|
+
},
|
|
17
|
+
primary: {
|
|
18
|
+
DEFAULT: 'hsl(var(--primary))',
|
|
19
|
+
foreground: 'hsl(var(--primary-foreground))',
|
|
20
|
+
},
|
|
21
|
+
secondary: {
|
|
22
|
+
DEFAULT: 'hsl(var(--secondary))',
|
|
23
|
+
foreground: 'hsl(var(--secondary-foreground))',
|
|
24
|
+
},
|
|
25
|
+
muted: {
|
|
26
|
+
DEFAULT: 'hsl(var(--muted))',
|
|
27
|
+
foreground: 'hsl(var(--muted-foreground))',
|
|
28
|
+
},
|
|
29
|
+
accent: {
|
|
30
|
+
DEFAULT: 'hsl(var(--accent))',
|
|
31
|
+
foreground: 'hsl(var(--accent-foreground))',
|
|
32
|
+
},
|
|
33
|
+
destructive: {
|
|
34
|
+
DEFAULT: 'hsl(var(--destructive))',
|
|
35
|
+
foreground: 'hsl(var(--destructive-foreground))',
|
|
36
|
+
},
|
|
37
|
+
border: 'hsl(var(--border))',
|
|
38
|
+
input: 'hsl(var(--input))',
|
|
39
|
+
ring: 'hsl(var(--ring))',
|
|
40
|
+
},
|
|
41
|
+
borderRadius: {
|
|
42
|
+
sm: 'var(--radius-sm)',
|
|
43
|
+
md: 'var(--radius-md)',
|
|
44
|
+
lg: 'var(--radius-lg)',
|
|
45
|
+
xl: 'var(--radius-xl)',
|
|
46
|
+
full: 'var(--radius-full)',
|
|
47
|
+
DEFAULT: 'var(--radius)',
|
|
48
|
+
},
|
|
49
|
+
boxShadow: {
|
|
50
|
+
sm: 'var(--shadow-sm)',
|
|
51
|
+
DEFAULT: 'var(--shadow-md)',
|
|
52
|
+
md: 'var(--shadow-md)',
|
|
53
|
+
lg: 'var(--shadow-lg)',
|
|
54
|
+
xl: 'var(--shadow-xl)',
|
|
55
|
+
none: 'none',
|
|
56
|
+
},
|
|
57
|
+
fontFamily: {
|
|
58
|
+
sans: ['var(--font-sans)', 'ui-sans-serif', 'system-ui', 'sans-serif'],
|
|
59
|
+
mono: ['var(--font-mono)', 'ui-monospace', 'monospace'],
|
|
60
|
+
heading: ['var(--font-heading, var(--font-sans))', 'ui-sans-serif', 'sans-serif'],
|
|
61
|
+
},
|
|
62
|
+
transitionDuration: {
|
|
63
|
+
fast: 'var(--duration-fast)',
|
|
64
|
+
DEFAULT: 'var(--duration-normal)',
|
|
65
|
+
slow: 'var(--duration-slow)',
|
|
66
|
+
},
|
|
67
|
+
borderWidth: {
|
|
68
|
+
DEFAULT: 'var(--border-width)',
|
|
69
|
+
},
|
|
70
|
+
keyframes: {
|
|
71
|
+
'accordion-down': {
|
|
72
|
+
from: { height: '0' },
|
|
73
|
+
to: { height: 'var(--radix-accordion-content-height)' },
|
|
74
|
+
},
|
|
75
|
+
'accordion-up': {
|
|
76
|
+
from: { height: 'var(--radix-accordion-content-height)' },
|
|
77
|
+
to: { height: '0' },
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
animation: {
|
|
81
|
+
'accordion-down': 'accordion-down 0.2s ease-out',
|
|
82
|
+
'accordion-up': 'accordion-up 0.2s ease-out',
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
plugins: [],
|
|
87
|
+
}
|