sparkdesign 0.4.7 → 0.4.9
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/cli/registry/AGENTS.md +1 -1
- package/cli/registry/agent-manifest.json +3996 -67
- package/cli/registry/basic/accordion.tsx +79 -0
- package/cli/registry/basic/alert-dialog.tsx +3 -6
- package/cli/registry/basic/badge.tsx +49 -0
- package/cli/registry/basic/button.tsx +32 -14
- package/cli/registry/basic/card.tsx +20 -8
- package/cli/registry/basic/collapsible-card.tsx +12 -5
- package/cli/registry/basic/combobox.tsx +104 -46
- package/cli/registry/basic/context-menu.tsx +2 -3
- package/cli/registry/basic/date-picker.tsx +78 -7
- package/cli/registry/basic/dialog.tsx +3 -8
- package/cli/registry/basic/drawer.tsx +3 -5
- package/cli/registry/basic/dropdown-menu.tsx +2 -3
- package/cli/registry/basic/ellipsis-text.tsx +151 -0
- package/cli/registry/basic/form.tsx +186 -0
- package/cli/registry/basic/hover-card.tsx +2 -3
- package/cli/registry/basic/icon-button.tsx +29 -14
- package/cli/registry/basic/input-group.tsx +4 -4
- package/cli/registry/basic/input.tsx +29 -13
- package/cli/registry/basic/popover.tsx +2 -3
- package/cli/registry/basic/select.tsx +24 -4
- package/cli/registry/basic/sidebar.tsx +665 -0
- package/cli/registry/basic/sonner.tsx +10 -10
- package/cli/registry/basic/spinner.tsx +20 -5
- package/cli/registry/basic/textarea.tsx +30 -12
- package/cli/registry/basic/tooltip.tsx +2 -1
- package/cli/registry/chat/chat-input/compound.tsx +1 -0
- package/cli/registry/chat/user-question/compound.tsx +2 -0
- package/cli/registry/meta.json +250 -30
- package/dist/registry/basic/accordion.d.ts +15 -0
- package/dist/registry/basic/alert-dialog.d.ts +1 -1
- package/dist/registry/basic/avatar.d.ts +1 -1
- package/dist/registry/basic/badge.d.ts +23 -0
- package/dist/registry/basic/button.d.ts +3 -1
- package/dist/registry/basic/card.d.ts +9 -4
- package/dist/registry/basic/combobox.d.ts +20 -9
- package/dist/registry/basic/date-picker.d.ts +18 -9
- package/dist/registry/basic/dialog.d.ts +1 -1
- package/dist/registry/basic/ellipsis-text.d.ts +45 -0
- package/dist/registry/basic/form.d.ts +23 -0
- package/dist/registry/basic/icon-button.d.ts +17 -3
- package/dist/registry/basic/input-group.d.ts +5 -3
- package/dist/registry/basic/input.d.ts +8 -3
- package/dist/registry/basic/item.d.ts +3 -3
- package/dist/registry/basic/resizable.d.ts +48 -48
- package/dist/registry/basic/select.d.ts +7 -2
- package/dist/registry/basic/sidebar.d.ts +72 -0
- package/dist/registry/basic/spinner.d.ts +6 -2
- package/dist/registry/basic/tag.d.ts +1 -1
- package/dist/registry/basic/textarea.d.ts +9 -3
- package/dist/registry/basic/toggle.d.ts +1 -1
- package/dist/scale/computed.css +11 -0
- package/dist/scale/config.css +11 -0
- package/dist/scale/presets/compact.css +7 -0
- package/dist/scale/presets/dense.css +7 -0
- package/dist/scale/presets/sharp.css +7 -0
- package/dist/scale/presets/soft.css +7 -0
- package/dist/spark-design.cjs.js +34 -37
- package/dist/spark-design.es.js +7200 -4933
- package/dist/sparkdesign.css +1 -1
- package/dist/src/components/basic/Accordion/index.d.ts +13 -0
- package/dist/src/components/basic/Badge/index.d.ts +13 -0
- package/dist/src/components/basic/EllipsisText/index.d.ts +4 -36
- package/dist/src/components/basic/Form/index.d.ts +12 -0
- package/dist/src/components/basic/Sidebar/index.d.ts +13 -0
- package/dist/src/components/index.d.ts +7 -3
- package/dist/src/lib/index.d.ts +1 -1
- package/dist/src/lib/motion.d.ts +79 -0
- package/dist/theme-base.css +22 -0
- package/dist/themes/dark-mint.css +6 -0
- package/dist/themes/dark-parchment.css +6 -0
- package/dist/themes/light-parchment.css +6 -0
- package/dist/tokens/scale/computed.css +11 -0
- package/dist/tokens/scale/config.css +11 -0
- package/dist/tokens/scale/presets/compact.css +7 -0
- package/dist/tokens/scale/presets/dense.css +7 -0
- package/dist/tokens/scale/presets/sharp.css +7 -0
- package/dist/tokens/scale/presets/soft.css +7 -0
- package/dist/tokens/theme-base.css +22 -0
- package/dist/tokens/themes/dark-mint.css +6 -0
- package/dist/tokens/themes/dark-parchment.css +6 -0
- package/dist/tokens/themes/light-parchment.css +6 -0
- package/docs/agent/component-selection.md +106 -4
- package/package.json +8 -3
- package/registry/agent-manifest.json +3996 -67
- package/cli/registry/chat/user-question/UserQuestionCard.tsx +0 -198
- package/cli/registry/chat/user-question/UserQuestionFooter.tsx +0 -66
- package/cli/registry/chat/user-question/UserQuestionHeader.tsx +0 -64
- package/cli/registry/chat/user-question/useUserQuestionState.ts +0 -165
- package/dist/registry/chat/user-question/UserQuestionCard.d.ts +0 -36
- package/dist/registry/chat/user-question/UserQuestionFooter.d.ts +0 -24
- package/dist/registry/chat/user-question/UserQuestionHeader.d.ts +0 -26
- package/dist/registry/chat/user-question/useUserQuestionState.d.ts +0 -26
- package/dist/src/components/basic/CollapsibleSection/index.d.ts +0 -43
- package/dist/src/components/chat/Response/StreamingMarkdownBlock.d.ts +0 -12
|
@@ -3,6 +3,7 @@ import { motion } from 'framer-motion'
|
|
|
3
3
|
import * as DialogPrimitive from '@radix-ui/react-dialog'
|
|
4
4
|
import { cva, type VariantProps } from 'class-variance-authority'
|
|
5
5
|
import { cn } from '@/lib/utils'
|
|
6
|
+
import { MOTION_FADE, MOTION_DURATION, MOTION_EASE } from '@/lib/motion'
|
|
6
7
|
import { CloseLine } from './icons-inline'
|
|
7
8
|
import { getThemeFromDocument } from './theme-from-document'
|
|
8
9
|
|
|
@@ -18,10 +19,7 @@ const DrawerOverlay = React.forwardRef<
|
|
|
18
19
|
<DialogPrimitive.Overlay ref={ref} asChild {...props}>
|
|
19
20
|
<motion.div
|
|
20
21
|
className={cn('fixed inset-0 z-50 bg-bg-mask/60', className)}
|
|
21
|
-
|
|
22
|
-
animate={{ opacity: 1 }}
|
|
23
|
-
exit={{ opacity: 0 }}
|
|
24
|
-
transition={{ duration: 0.15 }}
|
|
22
|
+
{...MOTION_FADE}
|
|
25
23
|
/>
|
|
26
24
|
</DialogPrimitive.Overlay>
|
|
27
25
|
))
|
|
@@ -83,7 +81,7 @@ const DrawerContent = React.forwardRef<
|
|
|
83
81
|
initial={motionProps.initial}
|
|
84
82
|
animate={motionProps.animate}
|
|
85
83
|
exit={motionProps.exit}
|
|
86
|
-
transition={{ duration:
|
|
84
|
+
transition={{ duration: MOTION_DURATION.slow, ease: MOTION_EASE.standard }}
|
|
87
85
|
>
|
|
88
86
|
{children}
|
|
89
87
|
{showCloseButton && (
|
|
@@ -3,6 +3,7 @@ import { motion } from 'framer-motion'
|
|
|
3
3
|
import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'
|
|
4
4
|
import { cva, type VariantProps } from 'class-variance-authority'
|
|
5
5
|
import { cn } from '@/lib/utils'
|
|
6
|
+
import { MOTION_SCALE_IN } from '@/lib/motion'
|
|
6
7
|
import { ArrowRightLine, CheckLine } from './icons-inline'
|
|
7
8
|
import { getThemeFromDocument } from './theme-from-document'
|
|
8
9
|
|
|
@@ -42,9 +43,7 @@ const DropdownMenuContent = React.forwardRef<
|
|
|
42
43
|
{...props}
|
|
43
44
|
>
|
|
44
45
|
<motion.div
|
|
45
|
-
|
|
46
|
-
animate={{ opacity: 1 }}
|
|
47
|
-
transition={{ duration: 0.15, ease: [0.4, 0, 0.2, 1] }}
|
|
46
|
+
{...MOTION_SCALE_IN}
|
|
48
47
|
>
|
|
49
48
|
{children}
|
|
50
49
|
</motion.div>
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useCallback,
|
|
3
|
+
useEffect,
|
|
4
|
+
useRef,
|
|
5
|
+
useState,
|
|
6
|
+
forwardRef,
|
|
7
|
+
type ReactNode,
|
|
8
|
+
type CSSProperties,
|
|
9
|
+
} from 'react'
|
|
10
|
+
import { clsx } from 'clsx'
|
|
11
|
+
import { Tooltip } from './tooltip'
|
|
12
|
+
|
|
13
|
+
export interface EllipsisTextProps {
|
|
14
|
+
/** Text or inline content to display. */
|
|
15
|
+
children: ReactNode
|
|
16
|
+
/**
|
|
17
|
+
* Maximum visible lines before truncation.
|
|
18
|
+
* @default 1
|
|
19
|
+
*/
|
|
20
|
+
lines?: number
|
|
21
|
+
/** Extra className for the text node. */
|
|
22
|
+
className?: string
|
|
23
|
+
/**
|
|
24
|
+
* Tooltip placement when overflow is detected.
|
|
25
|
+
* @default 'top'
|
|
26
|
+
*/
|
|
27
|
+
placement?: 'top' | 'bottom' | 'left' | 'right'
|
|
28
|
+
/** Extra className for Tooltip content. */
|
|
29
|
+
tooltipClassName?: string
|
|
30
|
+
/** Custom tooltip content. Defaults to children. */
|
|
31
|
+
tooltipContent?: ReactNode
|
|
32
|
+
/**
|
|
33
|
+
* Disable tooltip even when content overflows.
|
|
34
|
+
* @default false
|
|
35
|
+
*/
|
|
36
|
+
disabled?: boolean
|
|
37
|
+
/** Inline style for the text node. */
|
|
38
|
+
style?: CSSProperties
|
|
39
|
+
/**
|
|
40
|
+
* Rendered text element.
|
|
41
|
+
* @default 'span'
|
|
42
|
+
*/
|
|
43
|
+
as?: 'span' | 'div' | 'p'
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function setRef<T>(ref: React.Ref<T> | undefined, value: T | null) {
|
|
47
|
+
if (!ref) return
|
|
48
|
+
if (typeof ref === 'function') ref(value)
|
|
49
|
+
else (ref as React.MutableRefObject<T | null>).current = value
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const EllipsisText = forwardRef<HTMLElement, EllipsisTextProps>(
|
|
53
|
+
(
|
|
54
|
+
{
|
|
55
|
+
children,
|
|
56
|
+
lines = 1,
|
|
57
|
+
className = '',
|
|
58
|
+
placement = 'top',
|
|
59
|
+
tooltipClassName = '',
|
|
60
|
+
tooltipContent,
|
|
61
|
+
disabled = false,
|
|
62
|
+
style,
|
|
63
|
+
as: Component = 'span',
|
|
64
|
+
},
|
|
65
|
+
ref
|
|
66
|
+
) => {
|
|
67
|
+
const textRef = useRef<HTMLElement>(null)
|
|
68
|
+
const [isOverflowing, setIsOverflowing] = useState(false)
|
|
69
|
+
|
|
70
|
+
const checkOverflow = useCallback(() => {
|
|
71
|
+
const el = textRef.current
|
|
72
|
+
if (!el) return
|
|
73
|
+
const overflowing =
|
|
74
|
+
lines === 1
|
|
75
|
+
? el.scrollWidth > el.clientWidth
|
|
76
|
+
: el.scrollHeight > el.clientHeight
|
|
77
|
+
setIsOverflowing(overflowing)
|
|
78
|
+
}, [lines])
|
|
79
|
+
|
|
80
|
+
useEffect(() => {
|
|
81
|
+
const raf = requestAnimationFrame(() => checkOverflow())
|
|
82
|
+
const el = textRef.current
|
|
83
|
+
if (!el) return () => cancelAnimationFrame(raf)
|
|
84
|
+
const ro = new ResizeObserver(() => checkOverflow())
|
|
85
|
+
ro.observe(el)
|
|
86
|
+
window.addEventListener('resize', checkOverflow)
|
|
87
|
+
return () => {
|
|
88
|
+
cancelAnimationFrame(raf)
|
|
89
|
+
ro.disconnect()
|
|
90
|
+
window.removeEventListener('resize', checkOverflow)
|
|
91
|
+
}
|
|
92
|
+
}, [checkOverflow, children])
|
|
93
|
+
|
|
94
|
+
const ellipsisStyle: CSSProperties =
|
|
95
|
+
lines === 1
|
|
96
|
+
? {
|
|
97
|
+
display: 'block',
|
|
98
|
+
overflow: 'hidden',
|
|
99
|
+
textOverflow: 'ellipsis',
|
|
100
|
+
whiteSpace: 'nowrap',
|
|
101
|
+
...style,
|
|
102
|
+
}
|
|
103
|
+
: {
|
|
104
|
+
overflow: 'hidden',
|
|
105
|
+
display: '-webkit-box',
|
|
106
|
+
WebkitLineClamp: lines,
|
|
107
|
+
WebkitBoxOrient: 'vertical',
|
|
108
|
+
...style,
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const refCallback = useCallback(
|
|
112
|
+
(el: HTMLElement | null) => {
|
|
113
|
+
setRef(textRef, el)
|
|
114
|
+
setRef(ref, el)
|
|
115
|
+
},
|
|
116
|
+
[ref]
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
const triggerNode = (
|
|
120
|
+
<Component
|
|
121
|
+
ref={refCallback}
|
|
122
|
+
className={className}
|
|
123
|
+
style={ellipsisStyle}
|
|
124
|
+
>
|
|
125
|
+
{children}
|
|
126
|
+
</Component>
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
const useTooltip = isOverflowing && !disabled
|
|
130
|
+
if (useTooltip) {
|
|
131
|
+
return (
|
|
132
|
+
<Tooltip
|
|
133
|
+
content={tooltipContent ?? children}
|
|
134
|
+
side={placement}
|
|
135
|
+
contentClassName={clsx(tooltipClassName)}
|
|
136
|
+
>
|
|
137
|
+
<span
|
|
138
|
+
ref={refCallback}
|
|
139
|
+
className={className}
|
|
140
|
+
style={ellipsisStyle}
|
|
141
|
+
>
|
|
142
|
+
{children}
|
|
143
|
+
</span>
|
|
144
|
+
</Tooltip>
|
|
145
|
+
)
|
|
146
|
+
}
|
|
147
|
+
return triggerNode
|
|
148
|
+
}
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
EllipsisText.displayName = 'EllipsisText'
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import * as LabelPrimitive from "@radix-ui/react-label"
|
|
5
|
+
import { Slot } from "@radix-ui/react-slot"
|
|
6
|
+
import {
|
|
7
|
+
Controller,
|
|
8
|
+
FormProvider,
|
|
9
|
+
useFormContext,
|
|
10
|
+
type ControllerProps,
|
|
11
|
+
type FieldPath,
|
|
12
|
+
type FieldValues,
|
|
13
|
+
} from "react-hook-form"
|
|
14
|
+
|
|
15
|
+
import { cn } from "@/lib/utils"
|
|
16
|
+
import { Label } from "./label"
|
|
17
|
+
|
|
18
|
+
const Form = FormProvider
|
|
19
|
+
|
|
20
|
+
type FormFieldContextValue<
|
|
21
|
+
TFieldValues extends FieldValues = FieldValues,
|
|
22
|
+
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
|
|
23
|
+
> = {
|
|
24
|
+
name: TName
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const FormFieldContext = React.createContext<FormFieldContextValue>(
|
|
28
|
+
{} as FormFieldContextValue
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
function FormField<
|
|
32
|
+
TFieldValues extends FieldValues = FieldValues,
|
|
33
|
+
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
|
|
34
|
+
>({ ...props }: ControllerProps<TFieldValues, TName>) {
|
|
35
|
+
return (
|
|
36
|
+
<FormFieldContext.Provider value={{ name: props.name }}>
|
|
37
|
+
<Controller {...props} />
|
|
38
|
+
</FormFieldContext.Provider>
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
type FormItemContextValue = {
|
|
43
|
+
id: string
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const FormItemContext = React.createContext<FormItemContextValue>(
|
|
47
|
+
{} as FormItemContextValue
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
function useFormField() {
|
|
51
|
+
const fieldContext = React.useContext(FormFieldContext)
|
|
52
|
+
const itemContext = React.useContext(FormItemContext)
|
|
53
|
+
const { getFieldState, formState } = useFormContext()
|
|
54
|
+
|
|
55
|
+
if (!fieldContext.name) {
|
|
56
|
+
throw new Error("useFormField should be used within <FormField>")
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const fieldState = getFieldState(fieldContext.name, formState)
|
|
60
|
+
|
|
61
|
+
const { id } = itemContext
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
id,
|
|
65
|
+
name: fieldContext.name,
|
|
66
|
+
formItemId: `${id}-form-item`,
|
|
67
|
+
formDescriptionId: `${id}-form-item-description`,
|
|
68
|
+
formMessageId: `${id}-form-item-message`,
|
|
69
|
+
...fieldState,
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const FormItem = React.forwardRef<
|
|
74
|
+
HTMLDivElement,
|
|
75
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
76
|
+
>(({ className, ...props }, ref) => {
|
|
77
|
+
const id = React.useId()
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<FormItemContext.Provider value={{ id }}>
|
|
81
|
+
<div
|
|
82
|
+
ref={ref}
|
|
83
|
+
data-slot="form-item"
|
|
84
|
+
className={cn("space-y-2", className)}
|
|
85
|
+
{...props}
|
|
86
|
+
/>
|
|
87
|
+
</FormItemContext.Provider>
|
|
88
|
+
)
|
|
89
|
+
})
|
|
90
|
+
FormItem.displayName = "FormItem"
|
|
91
|
+
|
|
92
|
+
const FormLabel = React.forwardRef<
|
|
93
|
+
React.ElementRef<typeof LabelPrimitive.Root>,
|
|
94
|
+
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
|
|
95
|
+
>(({ className, ...props }, ref) => {
|
|
96
|
+
const { error, formItemId } = useFormField()
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
<Label
|
|
100
|
+
ref={ref}
|
|
101
|
+
data-slot="form-label"
|
|
102
|
+
data-error={!!error}
|
|
103
|
+
className={cn("data-[error=true]:text-error", className)}
|
|
104
|
+
htmlFor={formItemId}
|
|
105
|
+
{...props}
|
|
106
|
+
/>
|
|
107
|
+
)
|
|
108
|
+
})
|
|
109
|
+
FormLabel.displayName = "FormLabel"
|
|
110
|
+
|
|
111
|
+
const FormControl = React.forwardRef<
|
|
112
|
+
React.ElementRef<typeof Slot>,
|
|
113
|
+
React.ComponentPropsWithoutRef<typeof Slot>
|
|
114
|
+
>(({ ...props }, ref) => {
|
|
115
|
+
const { error, formItemId, formDescriptionId, formMessageId } = useFormField()
|
|
116
|
+
|
|
117
|
+
return (
|
|
118
|
+
<Slot
|
|
119
|
+
ref={ref}
|
|
120
|
+
data-slot="form-control"
|
|
121
|
+
id={formItemId}
|
|
122
|
+
aria-describedby={
|
|
123
|
+
!error
|
|
124
|
+
? `${formDescriptionId}`
|
|
125
|
+
: `${formDescriptionId} ${formMessageId}`
|
|
126
|
+
}
|
|
127
|
+
aria-invalid={!!error}
|
|
128
|
+
{...props}
|
|
129
|
+
/>
|
|
130
|
+
)
|
|
131
|
+
})
|
|
132
|
+
FormControl.displayName = "FormControl"
|
|
133
|
+
|
|
134
|
+
const FormDescription = React.forwardRef<
|
|
135
|
+
HTMLParagraphElement,
|
|
136
|
+
React.HTMLAttributes<HTMLParagraphElement>
|
|
137
|
+
>(({ className, ...props }, ref) => {
|
|
138
|
+
const { formDescriptionId } = useFormField()
|
|
139
|
+
|
|
140
|
+
return (
|
|
141
|
+
<p
|
|
142
|
+
ref={ref}
|
|
143
|
+
id={formDescriptionId}
|
|
144
|
+
data-slot="form-description"
|
|
145
|
+
className={cn("text-sm text-text-tertiary", className)}
|
|
146
|
+
{...props}
|
|
147
|
+
/>
|
|
148
|
+
)
|
|
149
|
+
})
|
|
150
|
+
FormDescription.displayName = "FormDescription"
|
|
151
|
+
|
|
152
|
+
const FormMessage = React.forwardRef<
|
|
153
|
+
HTMLParagraphElement,
|
|
154
|
+
React.HTMLAttributes<HTMLParagraphElement>
|
|
155
|
+
>(({ className, children, ...props }, ref) => {
|
|
156
|
+
const { error, formMessageId } = useFormField()
|
|
157
|
+
const body = error ? String(error?.message ?? "") : children
|
|
158
|
+
|
|
159
|
+
if (!body) {
|
|
160
|
+
return null
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return (
|
|
164
|
+
<p
|
|
165
|
+
ref={ref}
|
|
166
|
+
id={formMessageId}
|
|
167
|
+
data-slot="form-message"
|
|
168
|
+
className={cn("text-sm font-medium text-error", className)}
|
|
169
|
+
{...props}
|
|
170
|
+
>
|
|
171
|
+
{body}
|
|
172
|
+
</p>
|
|
173
|
+
)
|
|
174
|
+
})
|
|
175
|
+
FormMessage.displayName = "FormMessage"
|
|
176
|
+
|
|
177
|
+
export {
|
|
178
|
+
useFormField,
|
|
179
|
+
Form,
|
|
180
|
+
FormItem,
|
|
181
|
+
FormLabel,
|
|
182
|
+
FormControl,
|
|
183
|
+
FormDescription,
|
|
184
|
+
FormMessage,
|
|
185
|
+
FormField,
|
|
186
|
+
}
|
|
@@ -2,6 +2,7 @@ import * as React from 'react'
|
|
|
2
2
|
import { motion } from 'framer-motion'
|
|
3
3
|
import * as HoverCardPrimitive from '@radix-ui/react-hover-card'
|
|
4
4
|
import { cn } from '@/lib/utils'
|
|
5
|
+
import { MOTION_SCALE_IN } from '@/lib/motion'
|
|
5
6
|
import { getThemeFromDocument } from './theme-from-document'
|
|
6
7
|
|
|
7
8
|
const HoverCard = HoverCardPrimitive.Root
|
|
@@ -41,9 +42,7 @@ const HoverCardContent = React.forwardRef<
|
|
|
41
42
|
{...props}
|
|
42
43
|
>
|
|
43
44
|
<motion.div
|
|
44
|
-
|
|
45
|
-
animate={{ opacity: 1, y: 0 }}
|
|
46
|
-
transition={{ duration: 0.15, ease: [0.4, 0, 0.2, 1] }}
|
|
45
|
+
{...MOTION_SCALE_IN}
|
|
47
46
|
>
|
|
48
47
|
{children}
|
|
49
48
|
</motion.div>
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { forwardRef } from 'react'
|
|
2
2
|
import type { ButtonHTMLAttributes, ReactNode } from 'react'
|
|
3
|
+
import { Slot } from 'radix-ui'
|
|
3
4
|
import { cva, type VariantProps } from 'class-variance-authority'
|
|
4
5
|
import { cn } from '@/lib/utils'
|
|
5
6
|
|
|
6
7
|
const iconButtonVariants = cva(
|
|
7
|
-
'flex-none shrink-0 inline-flex items-center justify-center box-border transition-
|
|
8
|
+
'flex-none shrink-0 inline-flex items-center justify-center box-border transition-[color,background-color,border-color,box-shadow,transform] duration-200 active:scale-[0.98] focus:outline-none disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer [&>*]:flex [&>*]:items-center [&>*]:justify-center [&>*]:size-full [&>*]:[&>svg]:block [&>*]:[&>svg]:leading-none',
|
|
8
9
|
{
|
|
9
10
|
variants: {
|
|
10
11
|
variant: {
|
|
@@ -13,6 +14,7 @@ const iconButtonVariants = cva(
|
|
|
13
14
|
tertiary: 'bg-fill-secondary text-text hover:bg-fill',
|
|
14
15
|
ghost: 'bg-transparent text-text-secondary hover:bg-fill-secondary hover:text-text',
|
|
15
16
|
iconOnly: 'bg-transparent text-text-secondary hover:text-text',
|
|
17
|
+
destructive: 'bg-error text-text-on-primary hover:bg-error-hover',
|
|
16
18
|
},
|
|
17
19
|
rounded: {
|
|
18
20
|
square: 'rounded',
|
|
@@ -32,10 +34,19 @@ const iconButtonVariants = cva(
|
|
|
32
34
|
}
|
|
33
35
|
)
|
|
34
36
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
type IconButtonAccessibleName =
|
|
38
|
+
| { 'aria-label': string; 'aria-labelledby'?: string; title?: string }
|
|
39
|
+
| { 'aria-label'?: string; 'aria-labelledby': string; title?: string }
|
|
40
|
+
| { 'aria-label'?: string; 'aria-labelledby'?: string; title: string }
|
|
41
|
+
|
|
42
|
+
export type IconButtonProps = Omit<
|
|
43
|
+
ButtonHTMLAttributes<HTMLButtonElement>,
|
|
44
|
+
'aria-label' | 'aria-labelledby' | 'title'
|
|
45
|
+
> &
|
|
46
|
+
VariantProps<typeof iconButtonVariants> &
|
|
47
|
+
IconButtonAccessibleName & {
|
|
38
48
|
icon: ReactNode
|
|
49
|
+
asChild?: boolean
|
|
39
50
|
}
|
|
40
51
|
|
|
41
52
|
export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
|
|
@@ -46,20 +57,24 @@ export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
|
|
|
46
57
|
rounded = 'square',
|
|
47
58
|
icon,
|
|
48
59
|
disabled = false,
|
|
60
|
+
asChild = false,
|
|
49
61
|
className,
|
|
50
62
|
...props
|
|
51
63
|
},
|
|
52
64
|
ref
|
|
53
|
-
) =>
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
65
|
+
) => {
|
|
66
|
+
const Comp = asChild ? Slot.Root : 'button'
|
|
67
|
+
return (
|
|
68
|
+
<Comp
|
|
69
|
+
ref={ref}
|
|
70
|
+
className={cn(iconButtonVariants({ variant, size, rounded }), className)}
|
|
71
|
+
disabled={disabled}
|
|
72
|
+
{...props}
|
|
73
|
+
>
|
|
74
|
+
<span className="inline-flex shrink-0 size-full items-center justify-center">{icon}</span>
|
|
75
|
+
</Comp>
|
|
76
|
+
)
|
|
77
|
+
}
|
|
63
78
|
)
|
|
64
79
|
IconButton.displayName = 'IconButton'
|
|
65
80
|
|
|
@@ -3,8 +3,8 @@ import { cva, type VariantProps } from "class-variance-authority"
|
|
|
3
3
|
|
|
4
4
|
import { cn } from "@/lib/utils"
|
|
5
5
|
import { Button } from "./button"
|
|
6
|
-
import { Input } from "./input"
|
|
7
|
-
import { Textarea } from "./textarea"
|
|
6
|
+
import { Input, type InputProps } from "./input"
|
|
7
|
+
import { Textarea, type TextareaProps } from "./textarea"
|
|
8
8
|
|
|
9
9
|
function InputGroup({ className, ...props }: React.ComponentProps<"div">) {
|
|
10
10
|
return (
|
|
@@ -129,7 +129,7 @@ function InputGroupText({ className, ...props }: React.ComponentProps<"span">) {
|
|
|
129
129
|
function InputGroupInput({
|
|
130
130
|
className,
|
|
131
131
|
...props
|
|
132
|
-
}:
|
|
132
|
+
}: InputProps) {
|
|
133
133
|
return (
|
|
134
134
|
<Input
|
|
135
135
|
data-slot="input-group-control"
|
|
@@ -145,7 +145,7 @@ function InputGroupInput({
|
|
|
145
145
|
function InputGroupTextarea({
|
|
146
146
|
className,
|
|
147
147
|
...props
|
|
148
|
-
}:
|
|
148
|
+
}: TextareaProps) {
|
|
149
149
|
return (
|
|
150
150
|
<Textarea
|
|
151
151
|
data-slot="input-group-control"
|
|
@@ -1,27 +1,43 @@
|
|
|
1
1
|
import * as React from 'react'
|
|
2
|
+
import { cva, type VariantProps } from 'class-variance-authority'
|
|
2
3
|
import { cn } from '@/lib/utils'
|
|
3
4
|
|
|
4
|
-
|
|
5
|
+
const inputVariants = cva(
|
|
6
|
+
[
|
|
7
|
+
'flex w-full min-w-0 rounded-lg border border-border-tertiary bg-bg-container text-text transition-colors',
|
|
8
|
+
'placeholder:text-text-tertiary',
|
|
9
|
+
'file:border-0 file:bg-transparent file:font-medium file:text-text',
|
|
10
|
+
'outline-none focus:outline-none focus:ring-0 focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0',
|
|
11
|
+
'focus:border-border-secondary focus-visible:border-border-secondary',
|
|
12
|
+
'disabled:cursor-not-allowed disabled:opacity-50',
|
|
13
|
+
'aria-invalid:border-error aria-invalid:ring-0',
|
|
14
|
+
].join(' '),
|
|
15
|
+
{
|
|
16
|
+
variants: {
|
|
17
|
+
size: {
|
|
18
|
+
sm: 'h-7 px-2 py-0.5 text-xs file:text-xs',
|
|
19
|
+
md: 'h-9 px-3 py-1 text-sm file:text-sm',
|
|
20
|
+
lg: 'h-11 px-4 py-1.5 text-base file:text-base',
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
defaultVariants: { size: 'md' },
|
|
24
|
+
}
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
export interface InputProps
|
|
28
|
+
extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'>,
|
|
29
|
+
VariantProps<typeof inputVariants> {}
|
|
5
30
|
|
|
6
31
|
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
7
|
-
({ className, type, ...props }, ref) => (
|
|
32
|
+
({ className, type, size = 'md', ...props }, ref) => (
|
|
8
33
|
<input
|
|
9
34
|
type={type}
|
|
10
35
|
ref={ref}
|
|
11
|
-
className={cn(
|
|
12
|
-
'flex h-9 w-full min-w-0 rounded-lg border border-border-tertiary bg-bg-container px-3 py-1 text-sm text-text transition-colors',
|
|
13
|
-
'placeholder:text-text-tertiary',
|
|
14
|
-
'file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-text',
|
|
15
|
-
'outline-none focus:outline-none focus:ring-0 focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0',
|
|
16
|
-
'focus:border-border-secondary focus-visible:border-border-secondary',
|
|
17
|
-
'disabled:cursor-not-allowed disabled:opacity-50',
|
|
18
|
-
'aria-invalid:border-error aria-invalid:ring-0',
|
|
19
|
-
className,
|
|
20
|
-
)}
|
|
36
|
+
className={cn(inputVariants({ size }), className)}
|
|
21
37
|
{...props}
|
|
22
38
|
/>
|
|
23
39
|
),
|
|
24
40
|
)
|
|
25
41
|
Input.displayName = 'Input'
|
|
26
42
|
|
|
27
|
-
export { Input }
|
|
43
|
+
export { Input, inputVariants }
|
|
@@ -2,6 +2,7 @@ import * as React from 'react'
|
|
|
2
2
|
import { motion } from 'framer-motion'
|
|
3
3
|
import * as PopoverPrimitive from '@radix-ui/react-popover'
|
|
4
4
|
import { cn } from '@/lib/utils'
|
|
5
|
+
import { MOTION_SCALE_IN } from '@/lib/motion'
|
|
5
6
|
import { getThemeFromDocument } from './theme-from-document'
|
|
6
7
|
|
|
7
8
|
const Popover = PopoverPrimitive.Root
|
|
@@ -42,9 +43,7 @@ const PopoverContent = React.forwardRef<
|
|
|
42
43
|
{...props}
|
|
43
44
|
>
|
|
44
45
|
<motion.div
|
|
45
|
-
|
|
46
|
-
animate={{ opacity: 1, y: 0 }}
|
|
47
|
-
transition={{ duration: 0.15, ease: [0.4, 0, 0.2, 1] }}
|
|
46
|
+
{...MOTION_SCALE_IN}
|
|
48
47
|
>
|
|
49
48
|
{children}
|
|
50
49
|
</motion.div>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as React from 'react'
|
|
2
2
|
import * as SelectPrimitive from '@radix-ui/react-select'
|
|
3
|
+
import { cva, type VariantProps } from 'class-variance-authority'
|
|
3
4
|
import { cn } from '@/lib/utils'
|
|
4
5
|
import { ArrowDownSLine, ArrowUpLine, CheckLine } from './icons-inline'
|
|
5
6
|
import { getThemeFromDocument } from './theme-from-document'
|
|
@@ -12,21 +13,39 @@ const Select = SelectPrimitive.Root
|
|
|
12
13
|
const SelectGroup = SelectPrimitive.Group
|
|
13
14
|
const SelectValue = SelectPrimitive.Value
|
|
14
15
|
|
|
16
|
+
const selectTriggerVariants = cva(
|
|
17
|
+
[
|
|
18
|
+
'flex w-full items-center justify-between gap-2 whitespace-nowrap rounded-lg border border-border-tertiary bg-bg-container text-text placeholder:text-muted-foreground transition-colors disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',
|
|
19
|
+
'focus:border-border-secondary focus-visible:border-border-secondary data-[state=open]:border-border-secondary',
|
|
20
|
+
].join(' '),
|
|
21
|
+
{
|
|
22
|
+
variants: {
|
|
23
|
+
size: {
|
|
24
|
+
sm: 'h-7 px-2 py-0.5 text-xs',
|
|
25
|
+
md: 'h-9 px-3 py-2 text-sm',
|
|
26
|
+
lg: 'h-11 px-4 py-2.5 text-base',
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
defaultVariants: { size: 'md' },
|
|
30
|
+
}
|
|
31
|
+
)
|
|
32
|
+
|
|
15
33
|
export interface SelectTriggerProps
|
|
16
|
-
extends React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger
|
|
34
|
+
extends Omit<React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>, 'size'>,
|
|
35
|
+
VariantProps<typeof selectTriggerVariants> {
|
|
17
36
|
triggerIcon?: React.ReactNode
|
|
37
|
+
size?: 'sm' | 'md' | 'lg'
|
|
18
38
|
}
|
|
19
39
|
|
|
20
40
|
const SelectTrigger = React.forwardRef<
|
|
21
41
|
React.ElementRef<typeof SelectPrimitive.Trigger>,
|
|
22
42
|
SelectTriggerProps
|
|
23
|
-
>(({ className, children, disabled, triggerIcon, ...props }, ref) => (
|
|
43
|
+
>(({ className, children, disabled, triggerIcon, size = 'md', ...props }, ref) => (
|
|
24
44
|
<SelectPrimitive.Trigger
|
|
25
45
|
ref={ref}
|
|
26
46
|
disabled={disabled}
|
|
27
47
|
className={cn(
|
|
28
|
-
|
|
29
|
-
'focus:border-border-secondary focus-visible:border-border-secondary data-[state=open]:border-border-secondary',
|
|
48
|
+
selectTriggerVariants({ size }),
|
|
30
49
|
FOCUS_RESET,
|
|
31
50
|
className
|
|
32
51
|
)}
|
|
@@ -175,4 +194,5 @@ export {
|
|
|
175
194
|
SelectSeparator,
|
|
176
195
|
SelectScrollUpButton,
|
|
177
196
|
SelectScrollDownButton,
|
|
197
|
+
selectTriggerVariants,
|
|
178
198
|
}
|