b44ui 0.0.11 → 0.0.12
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/index.tsx +113 -12
- package/package.json +1 -1
- package/readme.md +9 -4
package/index.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ReactNode, Children, useMemo, useState } from "react"
|
|
1
|
+
import { type ReactNode, Children, useMemo, useRef, useState } from "react"
|
|
2
2
|
import { Marked } from "marked"
|
|
3
3
|
import { markedHighlight } from "marked-highlight"
|
|
4
4
|
import hljs from "highlight.js"
|
|
@@ -6,13 +6,14 @@ import type { ClassValue } from "clsx"
|
|
|
6
6
|
import clsx from "clsx"
|
|
7
7
|
import { twMerge } from "tailwind-merge"
|
|
8
8
|
|
|
9
|
-
export type Color = 'red' | 'blue' | 'orange' | 'purple' | 'yellow'
|
|
9
|
+
export type Color = 'red' | 'blue' | 'orange' | 'purple' | 'yellow' | 'green'
|
|
10
10
|
const tintMap: Record<Color, string> = {
|
|
11
11
|
red: 'bg-red-500/20 border-red-500',
|
|
12
12
|
blue: 'bg-blue-500/20 border-blue-500',
|
|
13
13
|
orange: 'bg-orange-500/20 border-orange-500',
|
|
14
14
|
purple: 'bg-purple-500/20 border-purple-500',
|
|
15
15
|
yellow: 'bg-yellow-500/20 border-yellow-500',
|
|
16
|
+
green: 'bg-green-500/20 border-green-500',
|
|
16
17
|
}
|
|
17
18
|
const colorMap: Record<Color, string> = {
|
|
18
19
|
red: 'bg-red-600 hover:bg-red-500',
|
|
@@ -20,6 +21,7 @@ const colorMap: Record<Color, string> = {
|
|
|
20
21
|
orange: 'bg-orange-600 hover:bg-orange-500',
|
|
21
22
|
purple: 'bg-purple-600 hover:bg-purple-500',
|
|
22
23
|
yellow: 'bg-yellow-600 hover:bg-yellow-500',
|
|
24
|
+
green: 'bg-green-600 hover:bg-green-500',
|
|
23
25
|
}
|
|
24
26
|
const tintCn = (c: Color) => tintMap[c]
|
|
25
27
|
const colorCn = (c: Color) => colorMap[c]
|
|
@@ -39,12 +41,13 @@ export type DProps = {
|
|
|
39
41
|
grow?: boolean
|
|
40
42
|
gap?: number
|
|
41
43
|
p?: number
|
|
44
|
+
wd?: number
|
|
42
45
|
}
|
|
43
46
|
|
|
44
|
-
const dStyle = ({ gap, p, style }: DProps): React.CSSProperties | undefined => {
|
|
47
|
+
const dStyle = ({ gap, p, wd, style }: DProps): React.CSSProperties | undefined => {
|
|
45
48
|
const g = sc(gap), pd = sc(p)
|
|
46
|
-
if (!g && !pd && !style) return undefined
|
|
47
|
-
return { ...(g !== undefined && { gap: g }), ...(pd !== undefined && { padding: pd }), ...style }
|
|
49
|
+
if (!g && !pd && wd === undefined && !style) return undefined
|
|
50
|
+
return { ...(g !== undefined && { gap: g }), ...(pd !== undefined && { padding: pd }), ...(wd !== undefined && { width: `${wd * 100}%` }), ...style }
|
|
48
51
|
}
|
|
49
52
|
|
|
50
53
|
export const D = (props: DProps) =>
|
|
@@ -64,6 +67,23 @@ export const Centered = (props: DProps & { width?: number }) => {
|
|
|
64
67
|
return <D cn={CN("mx-auto max-w-full px-6", rcn(props))} grow={grow} gap={gap} p={p} style={{ width }}>{children}</D>
|
|
65
68
|
}
|
|
66
69
|
|
|
70
|
+
export const TabList = (props: DProps) => {
|
|
71
|
+
const { children, grow, gap, p } = props
|
|
72
|
+
return <D cn={CN("flex items-end gap-4", rcn(props))} grow={grow} gap={gap} p={p}>{children}</D>
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export const Tab = ({ title, active, click, grow, gap, p, ...rest }: DProps & { title: ReactNode, active?: boolean, click?: () => void } & React.ButtonHTMLAttributes<HTMLButtonElement>) => {
|
|
76
|
+
const c = rcn(rest as DProps)
|
|
77
|
+
return <button
|
|
78
|
+
className={CN("cursor-pointer border-b-2 pb-1.5 text-sm font-medium", active ? "border-zinc-100 text-zinc-100" : "border-transparent text-zinc-400 hover:text-zinc-200", grow && "flex-1", c)}
|
|
79
|
+
style={dStyle({ gap, p, wd: rest.wd, style: rest.style })}
|
|
80
|
+
onClick={click}
|
|
81
|
+
role="tab"
|
|
82
|
+
aria-selected={active}
|
|
83
|
+
{...rest}
|
|
84
|
+
>{title}</button>
|
|
85
|
+
}
|
|
86
|
+
|
|
67
87
|
export const Block = (props: DProps & { label?: ReactNode, row?: boolean, dashed?: boolean }) => {
|
|
68
88
|
const { label, children, row, dashed, grow, gap, p } = props
|
|
69
89
|
return <D cn={CN("rounded flex flex-col items-center", dashed && "border border-dashed border-zinc-700", rcn(props))} grow={grow} gap={gap ?? 4} p={p ?? 4}>
|
|
@@ -79,8 +99,9 @@ export const BlockSm = (props: DProps & { dashed?: boolean }) => {
|
|
|
79
99
|
}
|
|
80
100
|
|
|
81
101
|
export const Chip = (props: DProps & { click?: () => void }) => {
|
|
82
|
-
const { children, click } = props
|
|
102
|
+
const { children, click, grow, gap, p, wd, style } = props
|
|
83
103
|
return <span className={CN("bg-zinc-800 rounded px-2 py-0.5 text-xs", click && "cursor-pointer hover:bg-zinc-700", rcn(props))}
|
|
104
|
+
style={dStyle({ gap, p, wd, style })}
|
|
84
105
|
onClick={click}>{children}</span>
|
|
85
106
|
}
|
|
86
107
|
|
|
@@ -144,7 +165,7 @@ export const Btn = ({ children, grow, gap, p, click, color, ghost, sm, ...rest }
|
|
|
144
165
|
const c = rcn(rest as DProps)
|
|
145
166
|
return <button className={CN("rounded cursor-pointer", sm ? "px-3 py-1 text-xs" : "px-4 py-2 text-sm",
|
|
146
167
|
ghost ? "bg-transparent text-zinc-400 hover:bg-zinc-800" : color ? colorCn(color) : "bg-zinc-800 hover:bg-zinc-700", grow && "flex-1", c)}
|
|
147
|
-
style={dStyle({ gap, p })} onClick={click} {...rest}>{children}</button>
|
|
168
|
+
style={dStyle({ gap, p, wd: rest.wd, style: rest.style })} onClick={click} {...rest}>{children}</button>
|
|
148
169
|
}
|
|
149
170
|
|
|
150
171
|
export const Tint = (props: DProps & { color: Color }) => {
|
|
@@ -153,9 +174,9 @@ export const Tint = (props: DProps & { color: Color }) => {
|
|
|
153
174
|
}
|
|
154
175
|
|
|
155
176
|
export const Row = (props: DProps & { ratio?: number, align?: 'mid' | 'start' | 'end' }) => {
|
|
156
|
-
const { children, ratio, align, grow, gap, p } = props
|
|
177
|
+
const { children, ratio, align, grow, gap, p, wd, style } = props
|
|
157
178
|
return <div className={CN("flex items-center justify-center", align === 'mid' && "justify-between", align == 'end' && "justify-end", align == 'start' && "justify-start", grow && "flex-1", rcn(props))}
|
|
158
|
-
style={{ gap:
|
|
179
|
+
style={{ ...dStyle({ gap: gap ?? 4, p, wd, style }), ...(ratio ? { width: `${ratio * 100}%` } : {}) }}>{children}</div>
|
|
159
180
|
}
|
|
160
181
|
|
|
161
182
|
export const Toolbar = (props: DProps) => {
|
|
@@ -172,17 +193,17 @@ export const Modal = (props: DProps & { open: boolean }) => {
|
|
|
172
193
|
|
|
173
194
|
export const Input = ({ cn, cnIgnoreWrongUsage, grow, ...rest }: DProps & React.InputHTMLAttributes<HTMLInputElement>) => {
|
|
174
195
|
const c = rcn({ cn, cnIgnoreWrongUsage })
|
|
175
|
-
return <input className={CN("rounded bg-zinc-800 border border-zinc-700 px-3 py-2 text-sm outline-none", grow && "flex-1", c)} {...rest} />
|
|
196
|
+
return <input className={CN("rounded bg-zinc-800 border border-zinc-700 px-3 py-2 text-sm outline-none", grow && "flex-1", c)} style={dStyle({ gap: rest.gap, p: rest.p, wd: rest.wd, style: rest.style })} {...rest} />
|
|
176
197
|
}
|
|
177
198
|
|
|
178
199
|
export const Textarea = ({ cn, cnIgnoreWrongUsage, grow, ...rest }: DProps & React.TextareaHTMLAttributes<HTMLTextAreaElement>) => {
|
|
179
200
|
const c = rcn({ cn, cnIgnoreWrongUsage })
|
|
180
|
-
return <textarea className={CN("rounded bg-zinc-800 border border-zinc-700 px-3 py-2 text-sm outline-none w-full", grow && "flex-1", c)} {...rest} />
|
|
201
|
+
return <textarea className={CN("rounded bg-zinc-800 border border-zinc-700 px-3 py-2 text-sm outline-none w-full", grow && "flex-1", c)} style={dStyle({ gap: rest.gap, p: rest.p, wd: rest.wd, style: rest.style })} {...rest} />
|
|
181
202
|
}
|
|
182
203
|
|
|
183
204
|
export const Select = ({ cn, cnIgnoreWrongUsage, grow, ...rest }: DProps & React.SelectHTMLAttributes<HTMLSelectElement>) => {
|
|
184
205
|
const c = rcn({ cn, cnIgnoreWrongUsage })
|
|
185
|
-
return <select className={CN("rounded bg-zinc-800 border border-zinc-700 px-3 py-2 text-sm outline-none cursor-pointer", grow && "flex-1", c)} {...rest} />
|
|
206
|
+
return <select className={CN("rounded bg-zinc-800 border border-zinc-700 px-3 py-2 text-sm outline-none cursor-pointer", grow && "flex-1", c)} style={dStyle({ gap: rest.gap, p: rest.p, wd: rest.wd, style: rest.style })} {...rest} />
|
|
186
207
|
}
|
|
187
208
|
|
|
188
209
|
export const Grid = (props: DProps & { cols?: number }) => {
|
|
@@ -190,6 +211,86 @@ export const Grid = (props: DProps & { cols?: number }) => {
|
|
|
190
211
|
return <D cn={CN("grid ui-grid", rcn(props))} grow={grow} p={p} style={{ gap: sc(gap ?? 4), '--cols': cols ?? Children.count(children) } as React.CSSProperties}>{children}</D>
|
|
191
212
|
}
|
|
192
213
|
|
|
214
|
+
export const Hr = ({ vertical, color = 'gray', grow, gap, p, ...rest }: DProps & { vertical?: boolean, color?: Color | 'gray' }) => {
|
|
215
|
+
const c = rcn(rest as DProps)
|
|
216
|
+
const border = color === 'gray' ? "border-zinc-700" : ({
|
|
217
|
+
red: "border-red-500",
|
|
218
|
+
blue: "border-blue-500",
|
|
219
|
+
orange: "border-orange-500",
|
|
220
|
+
purple: "border-purple-500",
|
|
221
|
+
yellow: "border-yellow-500",
|
|
222
|
+
green: "border-green-500",
|
|
223
|
+
} satisfies Record<Color, string>)[color]
|
|
224
|
+
|
|
225
|
+
return <div
|
|
226
|
+
className={CN(vertical ? "self-stretch border-l" : "w-full border-t", border, grow && "flex-1", c)}
|
|
227
|
+
style={dStyle({ gap, p, wd: rest.wd, style: rest.style })}
|
|
228
|
+
aria-hidden="true"
|
|
229
|
+
/>
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export const Progress = ({ value, color = 'blue', dot, grow, gap, p, ...rest }: DProps & { value: number, color?: Color, dot?: boolean }) => {
|
|
233
|
+
const c = rcn(rest as DProps)
|
|
234
|
+
const v = Math.max(0, Math.min(1, value))
|
|
235
|
+
const fill = color === 'red' ? 'bg-red-500'
|
|
236
|
+
: color === 'orange' ? 'bg-orange-500'
|
|
237
|
+
: color === 'purple' ? 'bg-purple-500'
|
|
238
|
+
: color === 'yellow' ? 'bg-yellow-500'
|
|
239
|
+
: color === 'green' ? 'bg-green-500'
|
|
240
|
+
: 'bg-blue-500'
|
|
241
|
+
|
|
242
|
+
if (dot) return <div
|
|
243
|
+
className={CN("rounded-full border border-zinc-700 bg-zinc-800 overflow-hidden", grow && "flex-1", c)}
|
|
244
|
+
style={dStyle({ gap, p, wd: rest.wd, style: { aspectRatio: '1 / 1', ...rest.style } })}
|
|
245
|
+
>
|
|
246
|
+
<div className={CN("h-full rounded-full", fill)} style={{ opacity: v ? 1 : 0.2 }} />
|
|
247
|
+
</div>
|
|
248
|
+
|
|
249
|
+
return <div
|
|
250
|
+
className={CN("h-2 overflow-hidden rounded-full bg-zinc-800 border border-zinc-700", grow && "flex-1", c)}
|
|
251
|
+
style={dStyle({ gap, p, wd: rest.wd, style: rest.style })}
|
|
252
|
+
>
|
|
253
|
+
<div className={CN("h-full rounded-full", fill)} style={{ width: `${v * 100}%` }} />
|
|
254
|
+
</div>
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export const Dropzone = ({ children, onFiles, multiple, accept, click, ...rest }: DProps & { onFiles: (files: File[]) => void, multiple?: boolean, accept?: string, click?: () => void }) => {
|
|
258
|
+
const input = useRef<HTMLInputElement>(null)
|
|
259
|
+
const c = rcn(rest)
|
|
260
|
+
const push = (list: FileList | null) => {
|
|
261
|
+
const files = list ? Array.from(list) : []
|
|
262
|
+
if (files.length) onFiles(files)
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return <div
|
|
266
|
+
className={CN("contents", c)}
|
|
267
|
+
onClick={e => {
|
|
268
|
+
click?.()
|
|
269
|
+
input.current?.click()
|
|
270
|
+
rest.onClick?.(e as any)
|
|
271
|
+
}}
|
|
272
|
+
onDragOver={e => {
|
|
273
|
+
e.preventDefault()
|
|
274
|
+
rest.onDragOver?.(e)
|
|
275
|
+
}}
|
|
276
|
+
onDrop={e => {
|
|
277
|
+
e.preventDefault()
|
|
278
|
+
push(e.dataTransfer.files)
|
|
279
|
+
rest.onDrop?.(e)
|
|
280
|
+
}}
|
|
281
|
+
>
|
|
282
|
+
<input
|
|
283
|
+
ref={input}
|
|
284
|
+
hidden
|
|
285
|
+
type="file"
|
|
286
|
+
multiple={multiple}
|
|
287
|
+
accept={accept}
|
|
288
|
+
onChange={e => push(e.target.files)}
|
|
289
|
+
/>
|
|
290
|
+
{children}
|
|
291
|
+
</div>
|
|
292
|
+
}
|
|
293
|
+
|
|
193
294
|
export const Code = (props: DProps & { highlight?: string }) => {
|
|
194
295
|
const { children, highlight } = props
|
|
195
296
|
const c = rcn(props)
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -28,14 +28,19 @@ export default defineConfig({
|
|
|
28
28
|
|-----------|-------|-------------|
|
|
29
29
|
| `App` | `center`, `width`, `cn` | Root layout, dark background, wraps strings in `Md` |
|
|
30
30
|
| `Centered` | `width`, `cn`, `grow` | Centered max-width container |
|
|
31
|
-
| `D` | `cn`, `style`, `grow` | Plain div with `cn` |
|
|
32
|
-
| `Row` | `align`, `ratio`, `cn`, `grow` | Flex row, `align`: `start \| mid \| end` |
|
|
33
|
-
| `Col` | `cn`, `grow` | Flex column |
|
|
31
|
+
| `D` | `cn`, `style`, `grow`, `wd` | Plain div with `cn` |
|
|
32
|
+
| `Row` | `align`, `ratio`, `cn`, `grow`, `wd` | Flex row, `align`: `start \| mid \| end` |
|
|
33
|
+
| `Col` | `cn`, `grow`, `wd` | Flex column |
|
|
34
34
|
| `Code` | `highlight` | Code block |
|
|
35
35
|
| `Grid` | `cols`, `cn`, `grow` | CSS grid, defaults to one column per child |
|
|
36
36
|
| `Card` | `cn`, `grow` | Bordered zinc-900 card |
|
|
37
37
|
| `Block` | `label`, `row`, `dashed`, `cn`, `grow` | Padded container with optional label |
|
|
38
38
|
| `BlockSm` | `dashed`, `cn`, `grow` | Smaller padded container |
|
|
39
|
+
| `TabList` | `gap`, `p`, `wd` | Simple tab row wrapper |
|
|
40
|
+
| `Tab` | `title`, `active`, `click`, `wd` | String-first tab primitive |
|
|
41
|
+
| `Hr` | `vertical`, `color`, `wd` | Horizontal or vertical divider |
|
|
42
|
+
| `Progress` | `value`, `color`, `dot`, `wd` | Progress bar or dot |
|
|
43
|
+
| `Dropzone` | `onFiles`, `multiple`, `accept` | Hidden file input wrapper for click/drop |
|
|
39
44
|
| `Btn` | `click`, `color`, `ghost`, `cn`, `grow` | Button, supports `Color` and ghost style |
|
|
40
45
|
| `A` | `href`, `click`, `cn`, `grow` | Link-styled anchor, works with `onClick` or `href` |
|
|
41
46
|
| `Chip` | `click`, `cn` | Small inline badge, clickable if `click` provided |
|
|
@@ -48,6 +53,6 @@ export default defineConfig({
|
|
|
48
53
|
| `Popover` | `text`, `color`, `cn` | Hover popover |
|
|
49
54
|
| `Md` | `className` | Markdown renderer with syntax highlighting |
|
|
50
55
|
|
|
51
|
-
`Color`: `red \| blue \| orange \| purple \| yellow`
|
|
56
|
+
`Color`: `red \| blue \| orange \| purple \| yellow \| green`
|
|
52
57
|
|
|
53
58
|
All components accept `cn` for additional Tailwind classes (merged via `tailwind-merge`).
|