@taicode/common-web 1.0.2 → 1.0.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/package.json +17 -5
- package/source/catalyst/alert.tsx +95 -0
- package/source/catalyst/auth-layout.tsx +11 -0
- package/source/catalyst/avatar.tsx +84 -0
- package/source/catalyst/badge.tsx +82 -0
- package/source/catalyst/button.tsx +204 -0
- package/source/catalyst/checkbox.tsx +157 -0
- package/source/catalyst/combobox.tsx +188 -0
- package/source/catalyst/description-list.tsx +37 -0
- package/source/catalyst/dialog.tsx +86 -0
- package/source/catalyst/divider.tsx +20 -0
- package/source/catalyst/dropdown.tsx +188 -0
- package/source/catalyst/fieldset.tsx +91 -0
- package/source/catalyst/heading.tsx +27 -0
- package/source/catalyst/input.tsx +94 -0
- package/source/catalyst/link.tsx +21 -0
- package/source/catalyst/listbox.tsx +177 -0
- package/source/catalyst/navbar.tsx +96 -0
- package/source/catalyst/pagination.tsx +98 -0
- package/source/catalyst/radio.tsx +142 -0
- package/source/catalyst/select.tsx +68 -0
- package/source/catalyst/sidebar-layout.tsx +82 -0
- package/source/catalyst/sidebar.tsx +142 -0
- package/source/catalyst/stacked-layout.tsx +79 -0
- package/source/catalyst/switch.tsx +195 -0
- package/source/catalyst/table.tsx +124 -0
- package/source/catalyst/text.tsx +40 -0
- package/source/catalyst/textarea.tsx +54 -0
- package/tsconfig.json +1 -1
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import * as Headless from '@headlessui/react'
|
|
2
|
+
import clsx from 'clsx'
|
|
3
|
+
import type React from 'react'
|
|
4
|
+
|
|
5
|
+
export function SwitchGroup({ className, ...props }: React.ComponentPropsWithoutRef<'div'>) {
|
|
6
|
+
return (
|
|
7
|
+
<div
|
|
8
|
+
data-slot="control"
|
|
9
|
+
{...props}
|
|
10
|
+
className={clsx(
|
|
11
|
+
className,
|
|
12
|
+
// Basic groups
|
|
13
|
+
'space-y-3 **:data-[slot=label]:font-normal',
|
|
14
|
+
// With descriptions
|
|
15
|
+
'has-data-[slot=description]:space-y-6 has-data-[slot=description]:**:data-[slot=label]:font-medium'
|
|
16
|
+
)}
|
|
17
|
+
/>
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function SwitchField({
|
|
22
|
+
className,
|
|
23
|
+
...props
|
|
24
|
+
}: { className?: string } & Omit<Headless.FieldProps, 'as' | 'className'>) {
|
|
25
|
+
return (
|
|
26
|
+
<Headless.Field
|
|
27
|
+
data-slot="field"
|
|
28
|
+
{...props}
|
|
29
|
+
className={clsx(
|
|
30
|
+
className,
|
|
31
|
+
// Base layout
|
|
32
|
+
'grid grid-cols-[1fr_auto] gap-x-8 gap-y-1 sm:grid-cols-[1fr_auto]',
|
|
33
|
+
// Control layout
|
|
34
|
+
'*:data-[slot=control]:col-start-2 *:data-[slot=control]:self-start sm:*:data-[slot=control]:mt-0.5',
|
|
35
|
+
// Label layout
|
|
36
|
+
'*:data-[slot=label]:col-start-1 *:data-[slot=label]:row-start-1',
|
|
37
|
+
// Description layout
|
|
38
|
+
'*:data-[slot=description]:col-start-1 *:data-[slot=description]:row-start-2',
|
|
39
|
+
// With description
|
|
40
|
+
'has-data-[slot=description]:**:data-[slot=label]:font-medium'
|
|
41
|
+
)}
|
|
42
|
+
/>
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const colors = {
|
|
47
|
+
'dark/zinc': [
|
|
48
|
+
'[--switch-bg-ring:var(--color-zinc-950)]/90 [--switch-bg:var(--color-zinc-900)] dark:[--switch-bg-ring:transparent] dark:[--switch-bg:var(--color-white)]/25',
|
|
49
|
+
'[--switch-ring:var(--color-zinc-950)]/90 [--switch-shadow:var(--color-black)]/10 [--switch:white] dark:[--switch-ring:var(--color-zinc-700)]/90',
|
|
50
|
+
],
|
|
51
|
+
'dark/white': [
|
|
52
|
+
'[--switch-bg-ring:var(--color-zinc-950)]/90 [--switch-bg:var(--color-zinc-900)] dark:[--switch-bg-ring:transparent] dark:[--switch-bg:var(--color-white)]',
|
|
53
|
+
'[--switch-ring:var(--color-zinc-950)]/90 [--switch-shadow:var(--color-black)]/10 [--switch:white] dark:[--switch-ring:transparent] dark:[--switch:var(--color-zinc-900)]',
|
|
54
|
+
],
|
|
55
|
+
dark: [
|
|
56
|
+
'[--switch-bg-ring:var(--color-zinc-950)]/90 [--switch-bg:var(--color-zinc-900)] dark:[--switch-bg-ring:var(--color-white)]/15',
|
|
57
|
+
'[--switch-ring:var(--color-zinc-950)]/90 [--switch-shadow:var(--color-black)]/10 [--switch:white]',
|
|
58
|
+
],
|
|
59
|
+
zinc: [
|
|
60
|
+
'[--switch-bg-ring:var(--color-zinc-700)]/90 [--switch-bg:var(--color-zinc-600)] dark:[--switch-bg-ring:transparent]',
|
|
61
|
+
'[--switch-shadow:var(--color-black)]/10 [--switch:white] [--switch-ring:var(--color-zinc-700)]/90',
|
|
62
|
+
],
|
|
63
|
+
white: [
|
|
64
|
+
'[--switch-bg-ring:var(--color-black)]/15 [--switch-bg:white] dark:[--switch-bg-ring:transparent]',
|
|
65
|
+
'[--switch-shadow:var(--color-black)]/10 [--switch-ring:transparent] [--switch:var(--color-zinc-950)]',
|
|
66
|
+
],
|
|
67
|
+
red: [
|
|
68
|
+
'[--switch-bg-ring:var(--color-red-700)]/90 [--switch-bg:var(--color-red-600)] dark:[--switch-bg-ring:transparent]',
|
|
69
|
+
'[--switch:white] [--switch-ring:var(--color-red-700)]/90 [--switch-shadow:var(--color-red-900)]/20',
|
|
70
|
+
],
|
|
71
|
+
orange: [
|
|
72
|
+
'[--switch-bg-ring:var(--color-orange-600)]/90 [--switch-bg:var(--color-orange-500)] dark:[--switch-bg-ring:transparent]',
|
|
73
|
+
'[--switch:white] [--switch-ring:var(--color-orange-600)]/90 [--switch-shadow:var(--color-orange-900)]/20',
|
|
74
|
+
],
|
|
75
|
+
amber: [
|
|
76
|
+
'[--switch-bg-ring:var(--color-amber-500)]/80 [--switch-bg:var(--color-amber-400)] dark:[--switch-bg-ring:transparent]',
|
|
77
|
+
'[--switch-ring:transparent] [--switch-shadow:transparent] [--switch:var(--color-amber-950)]',
|
|
78
|
+
],
|
|
79
|
+
yellow: [
|
|
80
|
+
'[--switch-bg-ring:var(--color-yellow-400)]/80 [--switch-bg:var(--color-yellow-300)] dark:[--switch-bg-ring:transparent]',
|
|
81
|
+
'[--switch-ring:transparent] [--switch-shadow:transparent] [--switch:var(--color-yellow-950)]',
|
|
82
|
+
],
|
|
83
|
+
lime: [
|
|
84
|
+
'[--switch-bg-ring:var(--color-lime-400)]/80 [--switch-bg:var(--color-lime-300)] dark:[--switch-bg-ring:transparent]',
|
|
85
|
+
'[--switch-ring:transparent] [--switch-shadow:transparent] [--switch:var(--color-lime-950)]',
|
|
86
|
+
],
|
|
87
|
+
green: [
|
|
88
|
+
'[--switch-bg-ring:var(--color-green-700)]/90 [--switch-bg:var(--color-green-600)] dark:[--switch-bg-ring:transparent]',
|
|
89
|
+
'[--switch:white] [--switch-ring:var(--color-green-700)]/90 [--switch-shadow:var(--color-green-900)]/20',
|
|
90
|
+
],
|
|
91
|
+
emerald: [
|
|
92
|
+
'[--switch-bg-ring:var(--color-emerald-600)]/90 [--switch-bg:var(--color-emerald-500)] dark:[--switch-bg-ring:transparent]',
|
|
93
|
+
'[--switch:white] [--switch-ring:var(--color-emerald-600)]/90 [--switch-shadow:var(--color-emerald-900)]/20',
|
|
94
|
+
],
|
|
95
|
+
teal: [
|
|
96
|
+
'[--switch-bg-ring:var(--color-teal-700)]/90 [--switch-bg:var(--color-teal-600)] dark:[--switch-bg-ring:transparent]',
|
|
97
|
+
'[--switch:white] [--switch-ring:var(--color-teal-700)]/90 [--switch-shadow:var(--color-teal-900)]/20',
|
|
98
|
+
],
|
|
99
|
+
cyan: [
|
|
100
|
+
'[--switch-bg-ring:var(--color-cyan-400)]/80 [--switch-bg:var(--color-cyan-300)] dark:[--switch-bg-ring:transparent]',
|
|
101
|
+
'[--switch-ring:transparent] [--switch-shadow:transparent] [--switch:var(--color-cyan-950)]',
|
|
102
|
+
],
|
|
103
|
+
sky: [
|
|
104
|
+
'[--switch-bg-ring:var(--color-sky-600)]/80 [--switch-bg:var(--color-sky-500)] dark:[--switch-bg-ring:transparent]',
|
|
105
|
+
'[--switch:white] [--switch-ring:var(--color-sky-600)]/80 [--switch-shadow:var(--color-sky-900)]/20',
|
|
106
|
+
],
|
|
107
|
+
blue: [
|
|
108
|
+
'[--switch-bg-ring:var(--color-blue-700)]/90 [--switch-bg:var(--color-blue-600)] dark:[--switch-bg-ring:transparent]',
|
|
109
|
+
'[--switch:white] [--switch-ring:var(--color-blue-700)]/90 [--switch-shadow:var(--color-blue-900)]/20',
|
|
110
|
+
],
|
|
111
|
+
indigo: [
|
|
112
|
+
'[--switch-bg-ring:var(--color-indigo-600)]/90 [--switch-bg:var(--color-indigo-500)] dark:[--switch-bg-ring:transparent]',
|
|
113
|
+
'[--switch:white] [--switch-ring:var(--color-indigo-600)]/90 [--switch-shadow:var(--color-indigo-900)]/20',
|
|
114
|
+
],
|
|
115
|
+
violet: [
|
|
116
|
+
'[--switch-bg-ring:var(--color-violet-600)]/90 [--switch-bg:var(--color-violet-500)] dark:[--switch-bg-ring:transparent]',
|
|
117
|
+
'[--switch:white] [--switch-ring:var(--color-violet-600)]/90 [--switch-shadow:var(--color-violet-900)]/20',
|
|
118
|
+
],
|
|
119
|
+
purple: [
|
|
120
|
+
'[--switch-bg-ring:var(--color-purple-600)]/90 [--switch-bg:var(--color-purple-500)] dark:[--switch-bg-ring:transparent]',
|
|
121
|
+
'[--switch:white] [--switch-ring:var(--color-purple-600)]/90 [--switch-shadow:var(--color-purple-900)]/20',
|
|
122
|
+
],
|
|
123
|
+
fuchsia: [
|
|
124
|
+
'[--switch-bg-ring:var(--color-fuchsia-600)]/90 [--switch-bg:var(--color-fuchsia-500)] dark:[--switch-bg-ring:transparent]',
|
|
125
|
+
'[--switch:white] [--switch-ring:var(--color-fuchsia-600)]/90 [--switch-shadow:var(--color-fuchsia-900)]/20',
|
|
126
|
+
],
|
|
127
|
+
pink: [
|
|
128
|
+
'[--switch-bg-ring:var(--color-pink-600)]/90 [--switch-bg:var(--color-pink-500)] dark:[--switch-bg-ring:transparent]',
|
|
129
|
+
'[--switch:white] [--switch-ring:var(--color-pink-600)]/90 [--switch-shadow:var(--color-pink-900)]/20',
|
|
130
|
+
],
|
|
131
|
+
rose: [
|
|
132
|
+
'[--switch-bg-ring:var(--color-rose-600)]/90 [--switch-bg:var(--color-rose-500)] dark:[--switch-bg-ring:transparent]',
|
|
133
|
+
'[--switch:white] [--switch-ring:var(--color-rose-600)]/90 [--switch-shadow:var(--color-rose-900)]/20',
|
|
134
|
+
],
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
type Color = keyof typeof colors
|
|
138
|
+
|
|
139
|
+
export function Switch({
|
|
140
|
+
color = 'dark/zinc',
|
|
141
|
+
className,
|
|
142
|
+
...props
|
|
143
|
+
}: {
|
|
144
|
+
color?: Color
|
|
145
|
+
className?: string
|
|
146
|
+
} & Omit<Headless.SwitchProps, 'as' | 'className' | 'children'>) {
|
|
147
|
+
return (
|
|
148
|
+
<Headless.Switch
|
|
149
|
+
data-slot="control"
|
|
150
|
+
{...props}
|
|
151
|
+
className={clsx(
|
|
152
|
+
className,
|
|
153
|
+
// Base styles
|
|
154
|
+
'group relative isolate inline-flex h-6 w-10 cursor-default rounded-full p-[3px] sm:h-5 sm:w-8',
|
|
155
|
+
// Transitions
|
|
156
|
+
'transition duration-0 ease-in-out data-changing:duration-200',
|
|
157
|
+
// Outline and background color in forced-colors mode so switch is still visible
|
|
158
|
+
'forced-colors:outline forced-colors:[--switch-bg:Highlight] dark:forced-colors:[--switch-bg:Highlight]',
|
|
159
|
+
// Unchecked
|
|
160
|
+
'bg-zinc-200 ring-1 ring-black/5 ring-inset dark:bg-white/5 dark:ring-white/15',
|
|
161
|
+
// Checked
|
|
162
|
+
'data-checked:bg-(--switch-bg) data-checked:ring-(--switch-bg-ring) dark:data-checked:bg-(--switch-bg) dark:data-checked:ring-(--switch-bg-ring)',
|
|
163
|
+
// Focus
|
|
164
|
+
'focus:not-data-focus:outline-hidden data-focus:outline-2 data-focus:outline-offset-2 data-focus:outline-blue-500',
|
|
165
|
+
// Hover
|
|
166
|
+
'data-hover:ring-black/15 data-hover:data-checked:ring-(--switch-bg-ring)',
|
|
167
|
+
'dark:data-hover:ring-white/25 dark:data-hover:data-checked:ring-(--switch-bg-ring)',
|
|
168
|
+
// Disabled
|
|
169
|
+
'data-disabled:bg-zinc-200 data-disabled:opacity-50 data-disabled:data-checked:bg-zinc-200 data-disabled:data-checked:ring-black/5',
|
|
170
|
+
'dark:data-disabled:bg-white/15 dark:data-disabled:data-checked:bg-white/15 dark:data-disabled:data-checked:ring-white/15',
|
|
171
|
+
// Color specific styles
|
|
172
|
+
colors[color]
|
|
173
|
+
)}
|
|
174
|
+
>
|
|
175
|
+
<span
|
|
176
|
+
aria-hidden="true"
|
|
177
|
+
className={clsx(
|
|
178
|
+
// Basic layout
|
|
179
|
+
'pointer-events-none relative inline-block size-4.5 rounded-full sm:size-3.5',
|
|
180
|
+
// Transition
|
|
181
|
+
'translate-x-0 transition duration-200 ease-in-out',
|
|
182
|
+
// Invisible border so the switch is still visible in forced-colors mode
|
|
183
|
+
'border border-transparent',
|
|
184
|
+
// Unchecked
|
|
185
|
+
'bg-white shadow-sm ring-1 ring-black/5',
|
|
186
|
+
// Checked
|
|
187
|
+
'group-data-checked:bg-(--switch) group-data-checked:shadow-(--switch-shadow) group-data-checked:ring-(--switch-ring)',
|
|
188
|
+
'group-data-checked:translate-x-4 sm:group-data-checked:translate-x-3',
|
|
189
|
+
// Disabled
|
|
190
|
+
'group-data-checked:group-data-disabled:bg-white group-data-checked:group-data-disabled:shadow-sm group-data-checked:group-data-disabled:ring-black/5'
|
|
191
|
+
)}
|
|
192
|
+
/>
|
|
193
|
+
</Headless.Switch>
|
|
194
|
+
)
|
|
195
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import clsx from 'clsx'
|
|
4
|
+
import type React from 'react'
|
|
5
|
+
import { createContext, useContext, useState } from 'react'
|
|
6
|
+
import { Link } from './link'
|
|
7
|
+
|
|
8
|
+
const TableContext = createContext<{ bleed: boolean; dense: boolean; grid: boolean; striped: boolean }>({
|
|
9
|
+
bleed: false,
|
|
10
|
+
dense: false,
|
|
11
|
+
grid: false,
|
|
12
|
+
striped: false,
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
export function Table({
|
|
16
|
+
bleed = false,
|
|
17
|
+
dense = false,
|
|
18
|
+
grid = false,
|
|
19
|
+
striped = false,
|
|
20
|
+
className,
|
|
21
|
+
children,
|
|
22
|
+
...props
|
|
23
|
+
}: { bleed?: boolean; dense?: boolean; grid?: boolean; striped?: boolean } & React.ComponentPropsWithoutRef<'div'>) {
|
|
24
|
+
return (
|
|
25
|
+
<TableContext.Provider value={{ bleed, dense, grid, striped } as React.ContextType<typeof TableContext>}>
|
|
26
|
+
<div className="flow-root">
|
|
27
|
+
<div {...props} className={clsx(className, '-mx-(--gutter) overflow-x-auto whitespace-nowrap')}>
|
|
28
|
+
<div className={clsx('inline-block min-w-full align-middle', !bleed && 'sm:px-(--gutter)')}>
|
|
29
|
+
<table className="min-w-full text-left text-sm/6 text-zinc-950 dark:text-white">{children}</table>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
</TableContext.Provider>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function TableHead({ className, ...props }: React.ComponentPropsWithoutRef<'thead'>) {
|
|
38
|
+
return <thead {...props} className={clsx(className, 'text-zinc-500 dark:text-zinc-400')} />
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function TableBody(props: React.ComponentPropsWithoutRef<'tbody'>) {
|
|
42
|
+
return <tbody {...props} />
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const TableRowContext = createContext<{ href?: string; target?: string; title?: string }>({
|
|
46
|
+
href: undefined,
|
|
47
|
+
target: undefined,
|
|
48
|
+
title: undefined,
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
export function TableRow({
|
|
52
|
+
href,
|
|
53
|
+
target,
|
|
54
|
+
title,
|
|
55
|
+
className,
|
|
56
|
+
...props
|
|
57
|
+
}: { href?: string; target?: string; title?: string } & React.ComponentPropsWithoutRef<'tr'>) {
|
|
58
|
+
let { striped } = useContext(TableContext)
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<TableRowContext.Provider value={{ href, target, title } as React.ContextType<typeof TableRowContext>}>
|
|
62
|
+
<tr
|
|
63
|
+
{...props}
|
|
64
|
+
className={clsx(
|
|
65
|
+
className,
|
|
66
|
+
href &&
|
|
67
|
+
'has-[[data-row-link][data-focus]]:outline-2 has-[[data-row-link][data-focus]]:-outline-offset-2 has-[[data-row-link][data-focus]]:outline-blue-500 dark:focus-within:bg-white/2.5',
|
|
68
|
+
striped && 'even:bg-zinc-950/2.5 dark:even:bg-white/2.5',
|
|
69
|
+
href && striped && 'hover:bg-zinc-950/5 dark:hover:bg-white/5',
|
|
70
|
+
href && !striped && 'hover:bg-zinc-950/2.5 dark:hover:bg-white/2.5'
|
|
71
|
+
)}
|
|
72
|
+
/>
|
|
73
|
+
</TableRowContext.Provider>
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function TableHeader({ className, ...props }: React.ComponentPropsWithoutRef<'th'>) {
|
|
78
|
+
let { bleed, grid } = useContext(TableContext)
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<th
|
|
82
|
+
{...props}
|
|
83
|
+
className={clsx(
|
|
84
|
+
className,
|
|
85
|
+
'border-b border-b-zinc-950/10 px-4 py-2 font-medium first:pl-(--gutter,--spacing(2)) last:pr-(--gutter,--spacing(2)) dark:border-b-white/10',
|
|
86
|
+
grid && 'border-l border-l-zinc-950/5 first:border-l-0 dark:border-l-white/5',
|
|
87
|
+
!bleed && 'sm:first:pl-1 sm:last:pr-1'
|
|
88
|
+
)}
|
|
89
|
+
/>
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function TableCell({ className, children, ...props }: React.ComponentPropsWithoutRef<'td'>) {
|
|
94
|
+
let { bleed, dense, grid, striped } = useContext(TableContext)
|
|
95
|
+
let { href, target, title } = useContext(TableRowContext)
|
|
96
|
+
let [cellRef, setCellRef] = useState<HTMLElement | null>(null)
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
<td
|
|
100
|
+
ref={href ? setCellRef : undefined}
|
|
101
|
+
{...props}
|
|
102
|
+
className={clsx(
|
|
103
|
+
className,
|
|
104
|
+
'relative px-4 first:pl-(--gutter,--spacing(2)) last:pr-(--gutter,--spacing(2))',
|
|
105
|
+
!striped && 'border-b border-zinc-950/5 dark:border-white/5',
|
|
106
|
+
grid && 'border-l border-l-zinc-950/5 first:border-l-0 dark:border-l-white/5',
|
|
107
|
+
dense ? 'py-2.5' : 'py-4',
|
|
108
|
+
!bleed && 'sm:first:pl-1 sm:last:pr-1'
|
|
109
|
+
)}
|
|
110
|
+
>
|
|
111
|
+
{href && (
|
|
112
|
+
<Link
|
|
113
|
+
data-row-link
|
|
114
|
+
href={href}
|
|
115
|
+
target={target}
|
|
116
|
+
aria-label={title}
|
|
117
|
+
tabIndex={cellRef?.previousElementSibling === null ? 0 : -1}
|
|
118
|
+
className="absolute inset-0 focus:outline-hidden"
|
|
119
|
+
/>
|
|
120
|
+
)}
|
|
121
|
+
{children}
|
|
122
|
+
</td>
|
|
123
|
+
)
|
|
124
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import clsx from 'clsx'
|
|
2
|
+
import { Link } from './link'
|
|
3
|
+
|
|
4
|
+
export function Text({ className, ...props }: React.ComponentPropsWithoutRef<'p'>) {
|
|
5
|
+
return (
|
|
6
|
+
<p
|
|
7
|
+
data-slot="text"
|
|
8
|
+
{...props}
|
|
9
|
+
className={clsx(className, 'text-base/6 text-zinc-500 sm:text-sm/6 dark:text-zinc-400')}
|
|
10
|
+
/>
|
|
11
|
+
)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function TextLink({ className, ...props }: React.ComponentPropsWithoutRef<typeof Link>) {
|
|
15
|
+
return (
|
|
16
|
+
<Link
|
|
17
|
+
{...props}
|
|
18
|
+
className={clsx(
|
|
19
|
+
className,
|
|
20
|
+
'text-zinc-950 underline decoration-zinc-950/50 data-hover:decoration-zinc-950 dark:text-white dark:decoration-white/50 dark:data-hover:decoration-white'
|
|
21
|
+
)}
|
|
22
|
+
/>
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function Strong({ className, ...props }: React.ComponentPropsWithoutRef<'strong'>) {
|
|
27
|
+
return <strong {...props} className={clsx(className, 'font-medium text-zinc-950 dark:text-white')} />
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function Code({ className, ...props }: React.ComponentPropsWithoutRef<'code'>) {
|
|
31
|
+
return (
|
|
32
|
+
<code
|
|
33
|
+
{...props}
|
|
34
|
+
className={clsx(
|
|
35
|
+
className,
|
|
36
|
+
'rounded-sm border border-zinc-950/10 bg-zinc-950/2.5 px-0.5 text-sm font-medium text-zinc-950 sm:text-[0.8125rem] dark:border-white/20 dark:bg-white/5 dark:text-white'
|
|
37
|
+
)}
|
|
38
|
+
/>
|
|
39
|
+
)
|
|
40
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import * as Headless from '@headlessui/react'
|
|
2
|
+
import clsx from 'clsx'
|
|
3
|
+
import React, { forwardRef } from 'react'
|
|
4
|
+
|
|
5
|
+
export const Textarea = forwardRef(function Textarea(
|
|
6
|
+
{
|
|
7
|
+
className,
|
|
8
|
+
resizable = true,
|
|
9
|
+
...props
|
|
10
|
+
}: { className?: string; resizable?: boolean } & Omit<Headless.TextareaProps, 'as' | 'className'>,
|
|
11
|
+
ref: React.ForwardedRef<HTMLTextAreaElement>
|
|
12
|
+
) {
|
|
13
|
+
return (
|
|
14
|
+
<span
|
|
15
|
+
data-slot="control"
|
|
16
|
+
className={clsx([
|
|
17
|
+
className,
|
|
18
|
+
// Basic layout
|
|
19
|
+
'relative block w-full',
|
|
20
|
+
// Background color + shadow applied to inset pseudo element, so shadow blends with border in light mode
|
|
21
|
+
'before:absolute before:inset-px before:rounded-[calc(var(--radius-lg)-1px)] before:bg-white before:shadow-sm',
|
|
22
|
+
// Background color is moved to control and shadow is removed in dark mode so hide `before` pseudo
|
|
23
|
+
'dark:before:hidden',
|
|
24
|
+
// Focus ring
|
|
25
|
+
'after:pointer-events-none after:absolute after:inset-0 after:rounded-lg after:ring-transparent after:ring-inset sm:focus-within:after:ring-2 sm:focus-within:after:ring-blue-500',
|
|
26
|
+
// Disabled state
|
|
27
|
+
'has-data-disabled:opacity-50 has-data-disabled:before:bg-zinc-950/5 has-data-disabled:before:shadow-none',
|
|
28
|
+
])}
|
|
29
|
+
>
|
|
30
|
+
<Headless.Textarea
|
|
31
|
+
ref={ref}
|
|
32
|
+
{...props}
|
|
33
|
+
className={clsx([
|
|
34
|
+
// Basic layout
|
|
35
|
+
'relative block h-full w-full appearance-none rounded-lg px-[calc(--spacing(3.5)-1px)] py-[calc(--spacing(2.5)-1px)] sm:px-[calc(--spacing(3)-1px)] sm:py-[calc(--spacing(1.5)-1px)]',
|
|
36
|
+
// Typography
|
|
37
|
+
'text-base/6 text-zinc-950 placeholder:text-zinc-500 sm:text-sm/6 dark:text-white',
|
|
38
|
+
// Border
|
|
39
|
+
'border border-zinc-950/10 data-hover:border-zinc-950/20 dark:border-white/10 dark:data-hover:border-white/20',
|
|
40
|
+
// Background color
|
|
41
|
+
'bg-transparent dark:bg-white/5',
|
|
42
|
+
// Hide default focus styles
|
|
43
|
+
'focus:outline-hidden',
|
|
44
|
+
// Invalid state
|
|
45
|
+
'data-invalid:border-red-500 data-invalid:data-hover:border-red-500 dark:data-invalid:border-red-600 dark:data-invalid:data-hover:border-red-600',
|
|
46
|
+
// Disabled state
|
|
47
|
+
'disabled:border-zinc-950/20 dark:disabled:border-white/15 dark:disabled:bg-white/2.5 dark:data-hover:disabled:border-white/15',
|
|
48
|
+
// Resizable
|
|
49
|
+
resizable ? 'resize-y' : 'resize-none',
|
|
50
|
+
])}
|
|
51
|
+
/>
|
|
52
|
+
</span>
|
|
53
|
+
)
|
|
54
|
+
})
|
package/tsconfig.json
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
/* Language and Environment */
|
|
14
14
|
"target": "es2017", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
|
15
15
|
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
|
16
|
-
|
|
16
|
+
"jsx": "preserve", /* Specify what JSX code is generated. */
|
|
17
17
|
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
|
|
18
18
|
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
|
19
19
|
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
|