@otfdashkit/ui 0.1.0 → 0.1.2

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.
Files changed (115) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +99 -0
  3. package/dist/index.js +302 -1926
  4. package/dist/index.mjs +234 -1869
  5. package/package.json +24 -5
  6. package/src/advanced/BulkActions/BulkActions.tsx +2 -2
  7. package/src/advanced/CommandBar/CommandBar.tsx +2 -2
  8. package/src/advanced/Filters/Filters.tsx +6 -6
  9. package/src/advanced/Kanban/Kanban.tsx +1 -1
  10. package/src/advanced/ToggleButton/ToggleButton.tsx +1 -1
  11. package/src/advanced/bulk-actions.tsx +1 -46
  12. package/src/advanced/command-bar.tsx +1 -115
  13. package/src/advanced/filters.tsx +1 -103
  14. package/src/advanced/kanban.tsx +1 -95
  15. package/src/advanced/toggle-button.tsx +1 -78
  16. package/src/blocks/ChatDetail/ChatDetail.tsx +4 -4
  17. package/src/blocks/FeedbackModal/FeedbackModal.tsx +3 -3
  18. package/src/blocks/FileCards/FileCards.tsx +2 -2
  19. package/src/blocks/FilesList/FilesList.tsx +3 -3
  20. package/src/blocks/IntegrationCard/IntegrationCard.tsx +3 -3
  21. package/src/blocks/InviteModal/InviteModal.tsx +7 -7
  22. package/src/blocks/ManageTagsModal/ManageTagsModal.tsx +4 -4
  23. package/src/blocks/MessagesCard/MessagesCard.tsx +3 -3
  24. package/src/blocks/MetricCard/MetricCard.tsx +3 -3
  25. package/src/blocks/NotificationSettings/NotificationSettings.tsx +4 -4
  26. package/src/blocks/OrganizationMenu/OrganizationMenu.tsx +30 -11
  27. package/src/blocks/RolesMenu/RolesMenu.tsx +4 -4
  28. package/src/blocks/SelectUsersModal/SelectUsersModal.tsx +5 -5
  29. package/src/blocks/SidebarLayoutDashboard/SidebarLayoutDashboard.tsx +5 -5
  30. package/src/blocks/SidebarLayoutGroups/SidebarLayoutGroups.tsx +2 -2
  31. package/src/blocks/SidebarLayoutMinimal/SidebarLayoutMinimal.tsx +3 -3
  32. package/src/blocks/SidebarLayoutSearch/SidebarLayoutSearch.tsx +3 -3
  33. package/src/blocks/SidebarLayoutUser/SidebarLayoutUser.tsx +4 -4
  34. package/src/blocks/SortableTaskList/SortableTaskList.tsx +3 -3
  35. package/src/blocks/StackedLayoutBranded/StackedLayoutBranded.tsx +4 -4
  36. package/src/blocks/StackedLayoutTabs/StackedLayoutTabs.tsx +4 -4
  37. package/src/blocks/TaskCard/TaskCard.tsx +4 -4
  38. package/src/blocks/UserMenu/UserMenu.tsx +3 -3
  39. package/src/blocks/WorkspaceMembers/WorkspaceMembers.tsx +5 -5
  40. package/src/blocks/chat-detail.tsx +1 -73
  41. package/src/blocks/feedback-modal.tsx +1 -68
  42. package/src/blocks/file-cards.tsx +1 -56
  43. package/src/blocks/files-list.tsx +1 -72
  44. package/src/blocks/integration-card.tsx +1 -50
  45. package/src/blocks/invite-modal.tsx +1 -69
  46. package/src/blocks/manage-tags-modal.tsx +1 -63
  47. package/src/blocks/messages-card.tsx +1 -59
  48. package/src/blocks/metric-card.tsx +1 -79
  49. package/src/blocks/notification-settings.tsx +1 -61
  50. package/src/blocks/organization-menu.tsx +1 -85
  51. package/src/blocks/roles-menu.tsx +1 -61
  52. package/src/blocks/select-users-modal.tsx +1 -64
  53. package/src/blocks/sidebar-layout-dashboard.tsx +1 -97
  54. package/src/blocks/sidebar-layout-groups.tsx +1 -79
  55. package/src/blocks/sidebar-layout-minimal.tsx +1 -73
  56. package/src/blocks/sidebar-layout-search.tsx +1 -79
  57. package/src/blocks/sidebar-layout-user.tsx +1 -82
  58. package/src/blocks/sortable-task-list.tsx +1 -70
  59. package/src/blocks/stacked-layout-branded.tsx +1 -64
  60. package/src/blocks/stacked-layout-tabs.tsx +1 -80
  61. package/src/blocks/task-card.tsx +1 -88
  62. package/src/blocks/user-menu.tsx +1 -62
  63. package/src/blocks/workspace-members.tsx +1 -61
  64. package/src/charts/sparkline.tsx +1 -1
  65. package/src/components/DataGrid/DataGrid.tsx +1 -1
  66. package/src/components/DataTable/DataTable.tsx +4 -4
  67. package/src/components/EmptyState/EmptyState.tsx +6 -22
  68. package/src/components/Persona/Persona.tsx +1 -1
  69. package/src/components/Stat/Stat.tsx +1 -1
  70. package/src/components/Stepper/Stepper.tsx +13 -2
  71. package/src/components/banner.tsx +1 -203
  72. package/src/components/breadcrumb.tsx +1 -58
  73. package/src/components/command-item.tsx +1 -36
  74. package/src/components/data-grid.tsx +1 -125
  75. package/src/components/data-table.tsx +1 -139
  76. package/src/components/empty-state.tsx +1 -31
  77. package/src/components/hotkeys.tsx +1 -31
  78. package/src/components/icon-badge.tsx +1 -35
  79. package/src/components/loading-overlay.tsx +1 -38
  80. package/src/components/persona.tsx +1 -38
  81. package/src/components/property-list.tsx +1 -29
  82. package/src/components/stat.tsx +1 -51
  83. package/src/components/stepper.tsx +1 -69
  84. package/src/components/structured-list.tsx +1 -51
  85. package/src/components/timeline.tsx +1 -69
  86. package/src/components/toaster.tsx +1 -42
  87. package/src/data/DataList.tsx +1 -1
  88. package/src/engagement/Tour/Tour.tsx +1 -1
  89. package/src/engagement/beacon.tsx +1 -50
  90. package/src/engagement/tour.tsx +1 -106
  91. package/src/forms/ArrayField/ArrayField.tsx +2 -2
  92. package/src/forms/AutoForm/AutoForm.tsx +9 -8
  93. package/src/forms/DatePicker/DatePicker.tsx +3 -3
  94. package/src/forms/FloatingLabelInput/FloatingLabelInput.tsx +104 -0
  95. package/src/forms/FloatingLabelInput/index.ts +1 -0
  96. package/src/forms/PasswordInput/PasswordInput.tsx +2 -2
  97. package/src/forms/SearchInput/SearchInput.tsx +2 -2
  98. package/src/forms/StepForm/StepForm.tsx +2 -2
  99. package/src/forms/array-field.tsx +1 -61
  100. package/src/forms/auto-form.tsx +1 -133
  101. package/src/forms/date-picker.tsx +1 -109
  102. package/src/forms/field.tsx +1 -62
  103. package/src/forms/file-upload.tsx +1 -101
  104. package/src/forms/floating-label-input.tsx +1 -0
  105. package/src/forms/form.tsx +1 -57
  106. package/src/forms/object-field.tsx +1 -53
  107. package/src/forms/password-input.tsx +1 -54
  108. package/src/forms/search-input.tsx +1 -64
  109. package/src/forms/step-form.tsx +1 -113
  110. package/src/index.ts +6 -3
  111. package/src/primitives/Button/Button.tsx +18 -0
  112. package/src/primitives/code-block.tsx +1 -1
  113. package/src/primitives/comparison.tsx +1 -1
  114. package/src/primitives/qr-code.tsx +5 -1
  115. package/src/themes/base.css +18 -0
@@ -1,64 +1 @@
1
- import React, { useState } from 'react'
2
- import { Search, X } from 'lucide-react'
3
- import { cn } from '../utils/cn'
4
- import { type InputProps } from '../primitives/input'
5
-
6
- export interface SearchInputProps extends Omit<InputProps, 'onChange'> {
7
- shortcut?: string
8
- onClear?: () => void
9
- onChange?: (value: string) => void
10
- }
11
-
12
- export const SearchInput = React.forwardRef<HTMLInputElement, SearchInputProps>(
13
- ({ className, shortcut, onClear, onChange, value: valueProp, defaultValue, ...props }, ref) => {
14
- const [internalValue, setInternalValue] = useState(defaultValue ?? '')
15
- const isControlled = valueProp !== undefined
16
- const value = isControlled ? String(valueProp) : String(internalValue)
17
-
18
- function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
19
- if (!isControlled) setInternalValue(e.target.value)
20
- onChange?.(e.target.value)
21
- }
22
-
23
- function handleClear() {
24
- if (!isControlled) setInternalValue('')
25
- onChange?.('')
26
- onClear?.()
27
- }
28
-
29
- return (
30
- <div className="relative flex items-center">
31
- <Search className="pointer-events-none absolute left-2.5 h-4 w-4 text-[hsl(var(--muted-foreground))]" />
32
- <input
33
- ref={ref}
34
- value={value}
35
- onChange={handleChange}
36
- className={cn(
37
- 'flex h-9 w-full rounded-md border border-[hsl(var(--input))] bg-transparent pl-8 pr-8 text-sm shadow-sm transition-colors',
38
- 'placeholder:text-[hsl(var(--muted-foreground))]',
39
- 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--ring))]',
40
- 'disabled:cursor-not-allowed disabled:opacity-50',
41
- className
42
- )}
43
- {...props}
44
- />
45
- <div className="absolute right-2.5 flex items-center">
46
- {value ? (
47
- <button
48
- type="button"
49
- onClick={handleClear}
50
- className="text-[hsl(var(--muted-foreground))] hover:text-[hsl(var(--foreground))] transition-colors"
51
- >
52
- <X className="h-4 w-4" />
53
- </button>
54
- ) : shortcut ? (
55
- <kbd className="pointer-events-none rounded border border-[hsl(var(--border))] px-1.5 py-0.5 text-[10px] text-[hsl(var(--muted-foreground))]">
56
- {shortcut}
57
- </kbd>
58
- ) : null}
59
- </div>
60
- </div>
61
- )
62
- }
63
- )
64
- SearchInput.displayName = 'SearchInput'
1
+ export * from './SearchInput'
@@ -1,113 +1 @@
1
- import React, { createContext, useContext, useState } from 'react'
2
- import { Button } from '../primitives/button'
3
- import { cn } from '../utils/cn'
4
-
5
- interface StepFormContextValue {
6
- currentStep: number
7
- totalSteps: number
8
- steps: string[]
9
- next: () => void
10
- prev: () => void
11
- isFirst: boolean
12
- isLast: boolean
13
- }
14
-
15
- const StepFormContext = createContext<StepFormContextValue | null>(null)
16
-
17
- function useStepForm() {
18
- const ctx = useContext(StepFormContext)
19
- if (!ctx) throw new Error('useStepForm must be used within StepForm')
20
- return ctx
21
- }
22
-
23
- export interface StepFormProps {
24
- steps: string[]
25
- onSubmit: () => void
26
- children: React.ReactNode
27
- className?: string
28
- }
29
-
30
- export function StepForm({ steps, onSubmit, children, className }: StepFormProps) {
31
- const [currentStep, setCurrentStep] = useState(0)
32
- const totalSteps = steps.length
33
-
34
- const ctx: StepFormContextValue = {
35
- currentStep,
36
- totalSteps,
37
- steps,
38
- next: () => setCurrentStep(s => Math.min(s + 1, totalSteps - 1)),
39
- prev: () => setCurrentStep(s => Math.max(s - 1, 0)),
40
- isFirst: currentStep === 0,
41
- isLast: currentStep === totalSteps - 1,
42
- }
43
-
44
- const childArray = React.Children.toArray(children)
45
- const currentChild = childArray[currentStep]
46
-
47
- return (
48
- <StepFormContext.Provider value={ctx}>
49
- <div className={cn('flex flex-col gap-6', className)}>
50
- <StepIndicator steps={steps} currentStep={currentStep} />
51
- <div>{currentChild}</div>
52
- <StepFormNavigation onSubmit={onSubmit} />
53
- </div>
54
- </StepFormContext.Provider>
55
- )
56
- }
57
-
58
- function StepIndicator({ steps, currentStep }: { steps: string[]; currentStep: number }) {
59
- return (
60
- <div className="flex items-center gap-2">
61
- {steps.map((label, i) => (
62
- <React.Fragment key={i}>
63
- {i > 0 && <div className={cn('h-px flex-1 bg-[hsl(var(--border))]', i <= currentStep && 'bg-[hsl(var(--primary))]')} />}
64
- <div className="flex flex-col items-center gap-1">
65
- <div className={cn(
66
- 'flex h-7 w-7 items-center justify-center rounded-full text-xs font-medium border transition-colors',
67
- i < currentStep && 'bg-[hsl(var(--primary))] border-[hsl(var(--primary))] text-[hsl(var(--primary-foreground))]',
68
- i === currentStep && 'border-[hsl(var(--primary))] text-[hsl(var(--primary))]',
69
- i > currentStep && 'border-[hsl(var(--border))] text-[hsl(var(--muted-foreground))]'
70
- )}>{i + 1}</div>
71
- <span className="hidden text-[10px] text-[hsl(var(--muted-foreground))] sm:block">{label}</span>
72
- </div>
73
- </React.Fragment>
74
- ))}
75
- </div>
76
- )
77
- }
78
-
79
- export interface StepFormStepProps {
80
- title: string
81
- description?: string
82
- children: React.ReactNode
83
- }
84
-
85
- export function StepFormStep({ title, description, children }: StepFormStepProps) {
86
- return (
87
- <div className="flex flex-col gap-4">
88
- <div>
89
- <h3 className="text-base font-semibold text-[hsl(var(--foreground))]">{title}</h3>
90
- {description && <p className="text-sm text-[hsl(var(--muted-foreground))]">{description}</p>}
91
- </div>
92
- {children}
93
- </div>
94
- )
95
- }
96
-
97
- export interface StepFormNavigationProps {
98
- onSubmit?: () => void
99
- submitLabel?: string
100
- }
101
-
102
- export function StepFormNavigation({ onSubmit, submitLabel = 'Submit' }: StepFormNavigationProps) {
103
- const { prev, next, isFirst, isLast } = useStepForm()
104
- return (
105
- <div className="flex justify-between">
106
- <Button type="button" variant="outline" onClick={prev} disabled={isFirst}>Previous</Button>
107
- {isLast
108
- ? <Button type="button" onClick={onSubmit}>{submitLabel}</Button>
109
- : <Button type="button" onClick={next}>Next</Button>
110
- }
111
- </div>
112
- )
113
- }
1
+ export * from './StepForm'
package/src/index.ts CHANGED
@@ -23,7 +23,7 @@ export * from './primitives/context-menu'
23
23
  export * from './primitives/dialog'
24
24
  export * from './primitives/drawer'
25
25
  export * from './primitives/dropdown-menu'
26
- export * from './primitives/form'
26
+ // export * from './primitives/form' // conflicts with forms/form.tsx (Form, FormField, etc.)
27
27
  export * from './primitives/hover-card'
28
28
  export * from './primitives/input-otp'
29
29
  export * from './primitives/input'
@@ -59,7 +59,7 @@ export * from './primitives/tooltip'
59
59
  // components
60
60
  export * from './components/banner'
61
61
  export * from './components/breadcrumb'
62
- export * from './components/command-item'
62
+ export { CommandListItem } from './components/command-item'
63
63
  export * from './components/data-grid'
64
64
  export * from './components/data-table'
65
65
  export * from './components/empty-state'
@@ -132,6 +132,7 @@ export * from './forms/color-picker'
132
132
  export * from './forms/date-picker'
133
133
  export * from './forms/field'
134
134
  export * from './forms/file-upload'
135
+ export * from './forms/floating-label-input'
135
136
  export * from './forms/form'
136
137
  export * from './forms/object-field'
137
138
  export * from './forms/password-input'
@@ -153,7 +154,9 @@ export * from './layouts/stack'
153
154
  export { PageLayout } from './layout/PageLayout'
154
155
  export type { PageHeaderProps } from './layout/PageLayout'
155
156
  export { PageContainer, PageMain } from './layout/PageContainer'
156
- export * from './nav'
157
+ export type { CommandPaletteProps } from './nav/CommandPalette'
158
+ export { CommandPaletteProvider, useCommandPalette, CommandPalette } from './nav/CommandPalette'
159
+ export * from './nav/HotkeysProvider'
157
160
  export * from './feedback'
158
161
  export * from './text'
159
162
  export * from './backgrounds'
@@ -43,6 +43,24 @@ const buttonVariants = cva(
43
43
  'hover:border-border/60 hover:bg-accent',
44
44
  'active:shadow-none',
45
45
  ].join(' '),
46
+ /** Shimmer — animated conic gradient sweep with a hover highlight.
47
+ * Loud + premium; reserve for primary CTAs and pricing pages, not
48
+ * for in-product UI (gets tiring fast). Cross-platform parity with
49
+ * @otfdashkit/ui-native via the same `shimmer` variant key. */
50
+ shimmer: [
51
+ 'relative isolate overflow-hidden',
52
+ 'bg-primary text-primary-foreground',
53
+ 'shadow-[0_1px_0_rgba(255,255,255,0.18)_inset,0_-1px_0_rgba(0,0,0,0.25)_inset]',
54
+ 'hover:bg-primary/95',
55
+ // Continuous conic-gradient sweep behind the surface.
56
+ 'before:absolute before:inset-[-1px] before:rounded-[inherit] before:-z-10',
57
+ 'before:bg-[conic-gradient(from_0deg,transparent_0deg,transparent_70deg,rgba(255,255,255,0.55)_90deg,transparent_110deg,transparent_360deg)]',
58
+ 'before:animate-[shimmer-rotate_2.6s_linear_infinite]',
59
+ // Diagonal gloss that sweeps on hover.
60
+ 'after:absolute after:inset-0 after:rounded-[inherit] after:pointer-events-none',
61
+ 'after:bg-[linear-gradient(115deg,transparent_30%,rgba(255,255,255,0.22)_50%,transparent_70%)]',
62
+ 'after:translate-x-[-120%] hover:after:translate-x-[120%] after:transition-transform after:duration-[900ms] after:ease-out',
63
+ ].join(' '),
46
64
  },
47
65
  size: {
48
66
  sm: 'h-8 px-3 text-xs rounded-md',
@@ -106,7 +106,7 @@ export const CodeBlock = React.forwardRef<HTMLDivElement, CodeBlockProps>(
106
106
  return (
107
107
  <div
108
108
  ref={(node) => {
109
- containerRef.current = node
109
+ (containerRef as React.MutableRefObject<HTMLDivElement | null>).current = node
110
110
  if (typeof ref === 'function') ref(node)
111
111
  else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = node
112
112
  }}
@@ -100,7 +100,7 @@ export const Comparison = React.forwardRef<HTMLDivElement, ComparisonProps>(
100
100
  return (
101
101
  <div
102
102
  ref={(node) => {
103
- containerRef.current = node
103
+ (containerRef as React.MutableRefObject<HTMLDivElement | null>).current = node
104
104
  if (typeof ref === 'function') ref(node)
105
105
  else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = node
106
106
  }}
@@ -20,7 +20,11 @@ export type QrCodeProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children'>
20
20
  src: string
21
21
  height: number
22
22
  width: number
23
- excavate?: boolean
23
+ excavate: boolean
24
+ x?: number
25
+ y?: number
26
+ opacity?: number
27
+ crossOrigin?: 'anonymous' | 'use-credentials' | ''
24
28
  }
25
29
  }
26
30
 
@@ -23,3 +23,21 @@ h1, h2, h3, h4, h5, h6 {
23
23
  line-height: var(--line-height-heading, 1.2);
24
24
  font-weight: var(--font-weight-heading, 600);
25
25
  }
26
+
27
+ /* ── Animations shipped with the SDK ────────────────────────────────────────
28
+ Consumers get these automatically by importing '@otfdashkit/ui/styles'.
29
+ Keep keyframe names unique to avoid collision with consumer-defined ones. */
30
+
31
+ /* Conic-gradient shimmer rotation — used by Button variant="shimmer".
32
+ Animation: 360deg sweep, 2.6s linear, infinite. */
33
+ @keyframes shimmer-rotate {
34
+ 0% { --shimmer-angle: 0deg; transform: rotate(0deg); }
35
+ 100% { --shimmer-angle: 360deg; transform: rotate(360deg); }
36
+ }
37
+
38
+ /* Concentric ripple expand — reserved for future use (RippleLoader, ping).
39
+ The existing motion/Ripple is click-triggered; this is for ambient pulses. */
40
+ @keyframes pulse-ring {
41
+ 0% { transform: scale(0.4); opacity: 0.8; }
42
+ 100% { transform: scale(1.6); opacity: 0; }
43
+ }