b44ui 0.0.7 → 0.0.8

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.
@@ -724,9 +724,9 @@ packages:
724
724
  peerDependencies:
725
725
  marked: '>=4 <18'
726
726
 
727
- marked@15.0.12:
728
- resolution: {integrity: sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==}
729
- engines: {node: '>= 18'}
727
+ marked@17.0.4:
728
+ resolution: {integrity: sha512-NOmVMM+KAokHMvjWmC5N/ZOvgmSWuqJB8FoYI019j4ogb/PeRMKoKIjReZ2w3376kkA8dSJIP8uD993Kxc0iRQ==}
729
+ engines: {node: '>= 20'}
730
730
  hasBin: true
731
731
 
732
732
  ms@2.1.3:
@@ -1251,8 +1251,8 @@ snapshots:
1251
1251
  dependencies:
1252
1252
  clsx: 2.1.1
1253
1253
  highlight.js: 11.11.1
1254
- marked: 15.0.12
1255
- marked-highlight: 2.2.3(marked@15.0.12)
1254
+ marked: 17.0.4
1255
+ marked-highlight: 2.2.3(marked@17.0.4)
1256
1256
  react: 19.2.4
1257
1257
  tailwind-merge: 3.5.0
1258
1258
 
@@ -1396,11 +1396,11 @@ snapshots:
1396
1396
  dependencies:
1397
1397
  '@jridgewell/sourcemap-codec': 1.5.5
1398
1398
 
1399
- marked-highlight@2.2.3(marked@15.0.12):
1399
+ marked-highlight@2.2.3(marked@17.0.4):
1400
1400
  dependencies:
1401
- marked: 15.0.12
1401
+ marked: 17.0.4
1402
1402
 
1403
- marked@15.0.12: {}
1403
+ marked@17.0.4: {}
1404
1404
 
1405
1405
  ms@2.1.3: {}
1406
1406
 
@@ -76,22 +76,22 @@ export default function YACS() {
76
76
  <Grid cols={3} cn="h-full">
77
77
 
78
78
  {/* calendar */}
79
- <Card cn="col-span-2 row-span-1 p-4 overflow-hidden flex flex-col">
79
+ <Card cnIgnoreWrongUsage="col-span-2 row-span-1 p-4 overflow-hidden flex flex-col">
80
80
  <D cn="grid flex-1" style={{ gridTemplateColumns: `60px repeat(5, 1fr)` }}>
81
81
  {/* hour labels */}
82
- <D cn="flex flex-col justify-between text-sm text-zinc-500 pr-2">
82
+ <D cnIgnoreWrongUsage="flex flex-col justify-between text-sm text-zinc-500 pr-2">
83
83
  {hours.map(h => <span key={h}>{h > 12 ? h - 12 : h}{h >= 12 ? 'pm' : 'am'}</span>)}
84
84
  </D>
85
85
  {/* day columns */}
86
- {days.map(day => <D key={day} cn="relative border-l border-zinc-800">
87
- <Muted cn="text-center block text-sm mb-1">{day}</Muted>
86
+ {days.map(day => <D key={day} cnIgnoreWrongUsage="relative border-l border-zinc-800">
87
+ <Muted cnIgnoreWrongUsage="text-center block text-sm mb-1">{day}</Muted>
88
88
  {/* hour gridlines */}
89
- {hours.map(h => <D key={h} cn="border-t border-zinc-800/50 left-0 right-0 absolute" style={{ top: `${h*8}%` }} />)}
89
+ {hours.map(h => <D key={h} cnIgnoreWrongUsage="border-t border-zinc-800/50 left-0 right-0 absolute" style={{ top: `${h*8}%` }} />)}
90
90
  {/* events */}
91
91
  {events.filter(e => e.meeting.day === day).map((e, i) => {
92
92
  const top = ((e.meeting.start - 540) / (13 * 60)) * 100
93
93
  const height = ((e.meeting.end - e.meeting.start) / (13 * 60)) * 100
94
- return <D key={i} cn={`absolute left-0.5 right-0.5 rounded text-sm px-1 text-white ${colors[e.colorIdx % colors.length]}`}
94
+ return <D key={i} cnIgnoreWrongUsage={`absolute left-0.5 right-0.5 rounded text-sm px-1 text-white ${colors[e.colorIdx % colors.length]}`}
95
95
  style={{ top: `${top}%`, height: `${height}%` }}>
96
96
  {e.code}
97
97
  </D>
@@ -108,7 +108,7 @@ export default function YACS() {
108
108
  <Input grow placeholder="search..." value={query} onChange={e => setQuery(e.target.value)} />
109
109
  <Select><option>2026W</option><option>2026S</option></Select>
110
110
  </Row>
111
- <D cn="space-y-3 max-h-48 overflow-y-auto flex-row">
111
+ <D cnIgnoreWrongUsage="space-y-3 max-h-48 overflow-y-auto flex-row">
112
112
  {results.map(c => <Btn key={c.code} click={() => addCourse(c)} grow>
113
113
  {c.code} — {c.name}
114
114
  </Btn>)}
package/index.tsx CHANGED
@@ -26,11 +26,15 @@ const colorCn = (c: Color) => colorMap[c]
26
26
 
27
27
  export const CN = (...inputs: ClassValue[]) => twMerge(clsx(inputs))
28
28
 
29
+ const warnCn = (cn: any) => typeof cn === 'string' && cn.length > 24 && console.warn(`long cn detected (${cn.length} chars). please avoid using cn. you SHOULD use b44ui builtins instead. you SHOULD NOT use cn to add unnecessary visual enhancements. you MUST NOT have long cns. if you choose to ignore these requirements (ie. because you cannot achieve this otherwise) you MUST instead use <... cnIgnoreWrongUsage="styles..">\n cn="${cn}"`)
30
+ const rcn = ({ cn, cnIgnoreWrongUsage }: DProps) => { warnCn(cn); return cn ?? cnIgnoreWrongUsage }
31
+
29
32
  const sc = (n?: number) => n !== undefined ? n * 4 : undefined // tailwind scale -> px
30
33
 
31
34
  export type DProps = {
32
35
  children?: ReactNode
33
36
  cn?: any
37
+ cnIgnoreWrongUsage?: any
34
38
  style?: React.CSSProperties
35
39
  grow?: boolean
36
40
  gap?: number
@@ -44,83 +48,129 @@ const dStyle = ({ gap, p, style }: DProps): React.CSSProperties | undefined => {
44
48
  }
45
49
 
46
50
  export const D = (props: DProps) =>
47
- <div className={CN(props.cn, props.grow && "flex-1")} style={dStyle(props)}>{props.children}</div>
51
+ <div className={CN(props.cn ?? props.cnIgnoreWrongUsage, props.grow && "flex-1")} style={dStyle(props)}>{props.children}</div>
48
52
 
49
- export const App = ({ children, center = true, width, cn, gap, p }: DProps & { center?: boolean, width?: number }) => {
53
+ export const App = (props: DProps & { center?: boolean, width?: number }) => {
54
+ const { children, center = true, width, gap, p } = props
55
+ const c = rcn(props)
50
56
  const inner = Children.map(children, c => typeof c == 'string' ? <Md>{c.trim()}</Md> : c)
51
- return <D cn={["min-h-screen w-full bg-[#111] text-[#eee] font-[Inter]", center && "flex justify-center items-center", cn]} gap={gap} p={p}>
57
+ return <D cn={CN("min-h-screen w-full bg-[#111] text-[#eee] font-[Inter]", center && "flex justify-center items-center", c)} gap={gap} p={p}>
52
58
  {center ? <div className="max-w-full px-5 py-10 space-y-5 *:mx-auto" style={{ width }}>{inner}</div> : inner}
53
59
  </D>
54
60
  }
55
61
 
56
- export const Centered = ({ children, cn, grow, gap, p, width = 700 }: DProps & { width?: number }) =>
57
- <D cn={["mx-auto max-w-full px-6", cn]} grow={grow} gap={gap} p={p} style={{ width }}>{children}</D>
62
+ export const Centered = (props: DProps & { width?: number }) => {
63
+ const { children, grow, gap, p, width = 700 } = props
64
+ return <D cn={CN("mx-auto max-w-full px-6", rcn(props))} grow={grow} gap={gap} p={p} style={{ width }}>{children}</D>
65
+ }
58
66
 
59
- export const Block = ({ label, children, row, dashed, cn, grow, gap, p }: DProps & { label?: ReactNode, row?: boolean, dashed?: boolean }) =>
60
- <D cn={["rounded flex flex-col items-center", dashed && "border border-dashed border-zinc-700", cn]} grow={grow} gap={gap ?? 4} p={p ?? 4}>
67
+ export const Block = (props: DProps & { label?: ReactNode, row?: boolean, dashed?: boolean }) => {
68
+ const { label, children, row, dashed, grow, gap, p } = props
69
+ 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}>
61
70
  {label && <span className="opacity-75">{label}</span>}
62
71
  <div className={CN(row ? "flex-row" : "flex-col", "flex items-center")} style={{ gap: sc(gap ?? 4) }}>{children}</div>
63
72
  </D>
73
+ }
64
74
 
65
- export const BlockSm = ({ children, dashed, cn, grow, gap, p }: DProps & { dashed?: boolean }) =>
66
- <D cn={["rounded text-sm", dashed && "border border-dashed border-zinc-700", cn]} grow={grow} gap={gap} p={p ?? 2}
75
+ export const BlockSm = (props: DProps & { dashed?: boolean }) => {
76
+ const { children, dashed, grow, gap, p } = props
77
+ return <D cn={CN("rounded text-sm", dashed && "border border-dashed border-zinc-700", rcn(props))} grow={grow} gap={gap} p={p ?? 2}
67
78
  style={{ paddingLeft: sc(3), paddingRight: sc(3) }}>{children}</D>
79
+ }
68
80
 
69
- export const Chip = ({ children, cn, click }: DProps & { click?: () => void }) =>
70
- <span className={CN("bg-zinc-800 rounded px-2 py-0.5 text-xs", click && "cursor-pointer hover:bg-zinc-700", cn)}
81
+ export const Chip = (props: DProps & { click?: () => void }) => {
82
+ const { children, click } = props
83
+ return <span className={CN("bg-zinc-800 rounded px-2 py-0.5 text-xs", click && "cursor-pointer hover:bg-zinc-700", rcn(props))}
71
84
  onClick={click}>{children}</span>
85
+ }
72
86
 
73
- export const Card = ({ children, cn, grow, gap, p }: DProps) =>
74
- <D cn={["rounded border border-zinc-700 bg-zinc-900", cn]} grow={grow} gap={gap ?? 4} p={p ?? 4}
87
+ export const Card = (props: DProps) => {
88
+ const { children, grow, gap, p } = props
89
+ return <D cn={CN("rounded border border-zinc-700 bg-zinc-900", rcn(props))} grow={grow} gap={gap ?? 4} p={p ?? 4}
75
90
  style={{ display: 'flex', flexDirection: 'column' }}>{children}</D>
91
+ }
76
92
 
77
- export const Col = ({ children, cn, grow, gap, p }: DProps) =>
78
- <D cn={["flex flex-col", cn]} grow={grow} gap={gap ?? 4} p={p}>{children}</D>
93
+ export const Col = (props: DProps) => {
94
+ const { children, grow, gap, p } = props
95
+ return <D cn={CN("flex flex-col", rcn(props))} grow={grow} gap={gap ?? 4} p={p}>{children}</D>
96
+ }
79
97
 
80
- export const Popover = ({ children, text, color, cn }: DProps & { text: ReactNode, color?: Color }) => {
98
+ export const Popover = (props: DProps & { text: ReactNode, color?: Color }) => {
99
+ const { children, text, color } = props
100
+ const c = rcn(props)
81
101
  const [open, setOpen] = useState(false)
82
102
  return <span className="relative inline-block" onMouseEnter={() => setOpen(true)} onMouseLeave={() => setOpen(false)}>
83
- <span className={CN("cursor-pointer", color && tintCn(color), color && "border-b-2", cn)}>{children}</span>
103
+ <span className={CN("cursor-pointer", color && tintCn(color), color && "border-b-2", c)}>{children}</span>
84
104
  {open && <div className="absolute left-0 top-full z-10 mt-1">
85
105
  <Card cn="w-64 shadow-lg text-sm" p={3}>{text}</Card>
86
106
  </div>}
87
107
  </span>
88
108
  }
89
109
 
90
- export const Muted = ({ children, cn, grow }: DProps) =>
91
- <span className={CN("text-sm text-zinc-400", grow && "flex-1", cn)}>{children}</span>
110
+ export const Muted = (props: DProps) => {
111
+ const { children, grow } = props
112
+ return <span className={CN("text-sm text-zinc-400", grow && "flex-1", rcn(props))}>{children}</span>
113
+ }
92
114
 
93
- export const Btn = ({ children, cn, grow, gap, p, click, color, ghost, sm, ...rest }: DProps & { click?: () => void, color?: Color, ghost?: boolean, sm?: boolean } & React.ButtonHTMLAttributes<HTMLButtonElement>) =>
94
- <button className={CN("rounded cursor-pointer", sm ? "px-3 py-1 text-xs" : "px-4 py-2 text-sm",
95
- ghost ? "bg-transparent text-zinc-400 hover:bg-zinc-800" : color ? colorCn(color) : "bg-zinc-800 hover:bg-zinc-700", grow && "flex-1", cn)}
115
+ export const Btn = ({ children, grow, gap, p, click, color, ghost, sm, ...rest }: DProps & { click?: () => void, color?: Color, ghost?: boolean, sm?: boolean } & React.ButtonHTMLAttributes<HTMLButtonElement>) => {
116
+ const c = rcn(rest as DProps)
117
+ return <button className={CN("rounded cursor-pointer", sm ? "px-3 py-1 text-xs" : "px-4 py-2 text-sm",
118
+ ghost ? "bg-transparent text-zinc-400 hover:bg-zinc-800" : color ? colorCn(color) : "bg-zinc-800 hover:bg-zinc-700", grow && "flex-1", c)}
96
119
  style={dStyle({ gap, p })} onClick={click} {...rest}>{children}</button>
120
+ }
97
121
 
98
- export const Tint = ({ children, color, cn, grow, gap, p }: DProps & { color: Color }) =>
99
- <D cn={["rounded text-sm", tintCn(color), cn]} grow={grow} gap={gap} p={p ?? 3}>{children}</D>
122
+ export const Tint = (props: DProps & { color: Color }) => {
123
+ const { children, color, grow, gap, p } = props
124
+ return <D cn={CN("rounded text-sm", tintCn(color), rcn(props))} grow={grow} gap={gap} p={p ?? 3}>{children}</D>
125
+ }
100
126
 
101
- export const Row = ({ children, ratio, align, cn, grow, gap, p }: DProps & { ratio?: number, align?: 'mid' | 'start' | 'end' }) =>
102
- <div className={CN("flex items-center justify-center", align === 'mid' && "justify-between", align == 'end' && "justify-end", align == 'start' && "justify-start", grow && "flex-1", cn)}
127
+ export const Row = (props: DProps & { ratio?: number, align?: 'mid' | 'start' | 'end' }) => {
128
+ const { children, ratio, align, grow, gap, p } = props
129
+ 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))}
103
130
  style={{ gap: sc(gap ?? 4), ...(p !== undefined && { padding: sc(p) }), ...(ratio ? { width: `${ratio * 100}%` } : {}) }}>{children}</div>
131
+ }
104
132
 
105
- export const Toolbar = ({ children, cn, gap, p }: DProps) =>
106
- <Row cn={["border-b border-zinc-700", cn]} gap={gap} p={p ?? 2} align="mid">{children}</Row>
133
+ export const Toolbar = (props: DProps) => {
134
+ const { children, gap, p } = props
135
+ return <Row cn={CN("border-b border-zinc-700", rcn(props))} gap={gap} p={p ?? 2} align="mid">{children}</Row>
136
+ }
107
137
 
108
- export const Modal = ({ children, open, cn, gap, p }: DProps & { open: boolean }) =>
109
- open ? <div className="fixed inset-0 flex items-center justify-center bg-black/50 z-50">
110
- <Card cn={["max-h-[80vh] overflow-y-auto w-lg", cn]} gap={gap} p={p}>{children}</Card>
138
+ export const Modal = (props: DProps & { open: boolean }) => {
139
+ const { children, open, gap, p } = props
140
+ return open ? <div className="fixed inset-0 flex items-center justify-center bg-black/50 z-50">
141
+ <Card cn={CN("max-h-[80vh] overflow-y-auto w-lg", rcn(props))} gap={gap} p={p}>{children}</Card>
111
142
  </div> : null
143
+ }
112
144
 
113
- export const Input = ({ cn, grow, ...rest }: { cn?: any, grow?: boolean } & React.InputHTMLAttributes<HTMLInputElement>) =>
114
- <input className={CN("rounded bg-zinc-800 border border-zinc-700 px-3 py-2 text-sm outline-none", grow && "flex-1", cn)} {...rest} />
145
+ export const Input = ({ cn, cnIgnoreWrongUsage, grow, ...rest }: DProps & React.InputHTMLAttributes<HTMLInputElement>) => {
146
+ const c = rcn({ cn, cnIgnoreWrongUsage })
147
+ 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} />
148
+ }
115
149
 
116
- export const Textarea = ({ cn, grow, ...rest }: { cn?: any, grow?: boolean } & React.TextareaHTMLAttributes<HTMLTextAreaElement>) =>
117
- <textarea className={CN("rounded bg-zinc-800 border border-zinc-700 px-3 py-2 text-sm outline-none w-full", grow && "flex-1", cn)} {...rest} />
150
+ export const Textarea = ({ cn, cnIgnoreWrongUsage, grow, ...rest }: DProps & React.TextareaHTMLAttributes<HTMLTextAreaElement>) => {
151
+ const c = rcn({ cn, cnIgnoreWrongUsage })
152
+ 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} />
153
+ }
118
154
 
119
- export const Select = ({ cn, grow, ...rest }: { cn?: any, grow?: boolean } & React.SelectHTMLAttributes<HTMLSelectElement>) =>
120
- <select className={CN("rounded bg-zinc-800 border border-zinc-700 px-3 py-2 text-sm outline-none cursor-pointer", grow && "flex-1", cn)} {...rest} />
155
+ export const Select = ({ cn, cnIgnoreWrongUsage, grow, ...rest }: DProps & React.SelectHTMLAttributes<HTMLSelectElement>) => {
156
+ const c = rcn({ cn, cnIgnoreWrongUsage })
157
+ 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} />
158
+ }
159
+
160
+ export const Grid = (props: DProps & { cols?: number }) => {
161
+ const { children, cols, grow, gap, p } = props
162
+ 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>
163
+ }
121
164
 
122
- export const Grid = ({ children, cols, cn, grow, gap, p }: DProps & { cols?: number }) =>
123
- <D cn={["grid ui-grid", cn]} grow={grow} p={p} style={{ gap: sc(gap ?? 4), '--cols': cols ?? Children.count(children) } as React.CSSProperties}>{children}</D>
165
+ export const Code = (props: DProps & { highlight?: string }) => {
166
+ const { children, highlight } = props
167
+ const c = rcn(props)
168
+ const html = useMemo(() => highlight ? hljs.highlight(children as string, { language: highlight }).value : '', [children, highlight])
169
+ if (highlight) return <pre className={CN("rounded bg-zinc-900 border border-zinc-700 p-3 text-sm overflow-x-auto", c)}>
170
+ <code className={`hljs language-${highlight}`} dangerouslySetInnerHTML={{ __html: html }} />
171
+ </pre>
172
+ return <code className={CN("bg-zinc-800 rounded px-1.5 py-0.5 text-sm font-mono", c)}>{children}</code>
173
+ }
124
174
 
125
175
  const marked = new Marked(markedHighlight({ langPrefix: "hljs language-", highlight: c => hljs.highlightAuto(c).value }))
126
176
  export const Md = ({ children, className }: { children: string, className?: string }) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "b44ui",
3
- "version": "0.0.7",
3
+ "version": "0.0.8",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "dev": "npm run dev --prefix example"
@@ -12,8 +12,8 @@
12
12
  "dependencies": {
13
13
  "clsx": "^2.1.1",
14
14
  "highlight.js": "^11.11.0",
15
- "marked": "^15.0.0",
16
- "marked-highlight": "^2.2.0",
15
+ "marked": "^17.0.0",
16
+ "marked-highlight": "^2.2.3",
17
17
  "tailwind-merge": "^3.0.0"
18
18
  },
19
19
  "peerDependencies": {