myoperator-ui 0.0.39 → 0.0.41

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 (2) hide show
  1. package/dist/index.js +541 -381
  2. package/package.json +3 -2
package/dist/index.js CHANGED
@@ -54,11 +54,27 @@ function prefixTailwindClasses(content, prefix) {
54
54
  });
55
55
  }
56
56
  async function getRegistry(prefix = "") {
57
- const badgeContent = prefixTailwindClasses(`import * as React from "react"
57
+ return {
58
+ "badge": {
59
+ name: "badge",
60
+ description: "A status badge component with active, failed, and disabled variants",
61
+ dependencies: [
62
+ "class-variance-authority",
63
+ "clsx",
64
+ "tailwind-merge"
65
+ ],
66
+ files: [
67
+ {
68
+ name: "badge.tsx",
69
+ content: prefixTailwindClasses(`import * as React from "react"
58
70
  import { cva, type VariantProps } from "class-variance-authority"
59
71
 
60
72
  import { cn } from "@/lib/utils"
61
73
 
74
+ /**
75
+ * Badge variants for status indicators.
76
+ * Pill-shaped badges with different colors for different states.
77
+ */
62
78
  const badgeVariants = cva(
63
79
  "inline-flex items-center justify-center rounded-full text-sm font-semibold transition-colors whitespace-nowrap",
64
80
  {
@@ -82,10 +98,23 @@ const badgeVariants = cva(
82
98
  }
83
99
  )
84
100
 
101
+ /**
102
+ * Badge component for displaying status indicators.
103
+ *
104
+ * @example
105
+ * \`\`\`tsx
106
+ * <Badge variant="active">Active</Badge>
107
+ * <Badge variant="failed">Failed</Badge>
108
+ * <Badge variant="disabled">Disabled</Badge>
109
+ * <Badge variant="active" leftIcon={<CheckIcon />}>Active</Badge>
110
+ * \`\`\`
111
+ */
85
112
  export interface BadgeProps
86
113
  extends React.HTMLAttributes<HTMLDivElement>,
87
114
  VariantProps<typeof badgeVariants> {
115
+ /** Icon displayed on the left side of the badge text */
88
116
  leftIcon?: React.ReactNode
117
+ /** Icon displayed on the right side of the badge text */
89
118
  rightIcon?: React.ReactNode
90
119
  }
91
120
 
@@ -107,199 +136,499 @@ const Badge = React.forwardRef<HTMLDivElement, BadgeProps>(
107
136
  Badge.displayName = "Badge"
108
137
 
109
138
  export { Badge, badgeVariants }
110
- `, prefix);
111
- const tagContent = prefixTailwindClasses(`import * as React from "react"
139
+ `, prefix)
140
+ }
141
+ ]
142
+ },
143
+ "button": {
144
+ name: "button",
145
+ description: "A customizable button component with variants, sizes, and icons",
146
+ dependencies: [
147
+ "@radix-ui/react-slot",
148
+ "class-variance-authority",
149
+ "clsx",
150
+ "tailwind-merge",
151
+ "lucide-react"
152
+ ],
153
+ files: [
154
+ {
155
+ name: "button.tsx",
156
+ content: prefixTailwindClasses(`import * as React from "react"
157
+ import { Slot } from "@radix-ui/react-slot"
112
158
  import { cva, type VariantProps } from "class-variance-authority"
159
+ import { Loader2 } from "lucide-react"
113
160
 
114
161
  import { cn } from "@/lib/utils"
115
162
 
116
- const tagVariants = cva(
117
- "inline-flex items-center justify-center rounded text-sm transition-colors",
163
+ const buttonVariants = cva(
164
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
118
165
  {
119
166
  variants: {
120
167
  variant: {
121
- default: "bg-[#F3F4F6] text-[#333333]",
122
- primary: "bg-[#343E55]/10 text-[#343E55]",
123
- secondary: "bg-[#E5E7EB] text-[#374151]",
124
- success: "bg-[#E5FFF5] text-[#00A651]",
125
- warning: "bg-[#FFF8E5] text-[#F59E0B]",
126
- error: "bg-[#FFECEC] text-[#FF3B3B]",
168
+ default: "bg-[#343E55] text-white hover:bg-[#343E55]/90",
169
+ destructive:
170
+ "bg-destructive text-destructive-foreground hover:bg-destructive/90",
171
+ outline:
172
+ "border border-[#343E55] bg-transparent text-[#343E55] hover:bg-[#343E55] hover:text-white",
173
+ secondary:
174
+ "bg-[#343E55]/20 text-[#343E55] hover:bg-[#343E55]/30",
175
+ ghost: "hover:bg-[#343E55]/10 hover:text-[#343E55]",
176
+ link: "text-[#343E55] underline-offset-4 hover:underline",
127
177
  },
128
178
  size: {
129
- default: "px-2 py-1",
130
- sm: "px-1.5 py-0.5 text-xs",
131
- lg: "px-3 py-1.5",
132
- },
133
- interactive: {
134
- true: "cursor-pointer hover:bg-[#E5E7EB] active:bg-[#D1D5DB]",
135
- false: "",
136
- },
137
- selected: {
138
- true: "ring-2 ring-[#343E55] ring-offset-1",
139
- false: "",
179
+ default: "py-2.5 px-4",
180
+ sm: "py-2 px-3 text-xs",
181
+ lg: "py-3 px-6",
182
+ icon: "p-2.5",
140
183
  },
141
184
  },
142
185
  defaultVariants: {
143
186
  variant: "default",
144
187
  size: "default",
145
- interactive: false,
146
- selected: false,
147
188
  },
148
189
  }
149
190
  )
150
191
 
151
- export interface TagProps
152
- extends React.HTMLAttributes<HTMLSpanElement>,
153
- VariantProps<typeof tagVariants> {
154
- label?: string
155
- interactive?: boolean
156
- selected?: boolean
192
+ /**
193
+ * Button component for user interactions.
194
+ *
195
+ * @example
196
+ * \`\`\`tsx
197
+ * <Button variant="default" size="default">
198
+ * Click me
199
+ * </Button>
200
+ * \`\`\`
201
+ */
202
+ export interface ButtonProps
203
+ extends React.ButtonHTMLAttributes<HTMLButtonElement>,
204
+ VariantProps<typeof buttonVariants> {
205
+ /** Render as child element using Radix Slot */
206
+ asChild?: boolean
207
+ /** Icon displayed on the left side of the button text */
208
+ leftIcon?: React.ReactNode
209
+ /** Icon displayed on the right side of the button text */
210
+ rightIcon?: React.ReactNode
211
+ /** Shows loading spinner and disables button */
212
+ loading?: boolean
213
+ /** Text shown during loading state */
214
+ loadingText?: string
157
215
  }
158
216
 
159
- const Tag = React.forwardRef<HTMLSpanElement, TagProps>(
160
- ({ className, variant, size, interactive, selected, label, children, ...props }, ref) => {
217
+ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
218
+ ({
219
+ className,
220
+ variant,
221
+ size,
222
+ asChild = false,
223
+ leftIcon,
224
+ rightIcon,
225
+ loading = false,
226
+ loadingText,
227
+ children,
228
+ disabled,
229
+ ...props
230
+ }, ref) => {
231
+ const Comp = asChild ? Slot : "button"
232
+
161
233
  return (
162
- <span
163
- className={cn(tagVariants({ variant, size, interactive, selected, className }))}
234
+ <Comp
235
+ className={cn(buttonVariants({ variant, size, className }))}
164
236
  ref={ref}
165
- role={interactive ? "button" : undefined}
166
- tabIndex={interactive ? 0 : undefined}
167
- aria-selected={selected}
237
+ disabled={disabled || loading}
168
238
  {...props}
169
239
  >
170
- {label && (
171
- <span className="font-semibold mr-1">{label}</span>
240
+ {loading ? (
241
+ <>
242
+ <Loader2 className="animate-spin" />
243
+ {loadingText || children}
244
+ </>
245
+ ) : (
246
+ <>
247
+ {leftIcon}
248
+ {children}
249
+ {rightIcon}
250
+ </>
172
251
  )}
173
- <span className="font-normal">{children}</span>
174
- </span>
252
+ </Comp>
175
253
  )
176
254
  }
177
255
  )
178
- Tag.displayName = "Tag"
256
+ Button.displayName = "Button"
179
257
 
180
- export { Tag, tagVariants }
181
- `, prefix);
182
- const tableContent = prefixTailwindClasses(`import * as React from "react"
183
- import { cva, type VariantProps } from "class-variance-authority"
258
+ export { Button, buttonVariants }
259
+ `, prefix)
260
+ }
261
+ ]
262
+ },
263
+ "dropdown-menu": {
264
+ name: "dropdown-menu",
265
+ description: "A dropdown menu component for displaying actions and options",
266
+ dependencies: [
267
+ "@radix-ui/react-dropdown-menu",
268
+ "clsx",
269
+ "tailwind-merge",
270
+ "lucide-react"
271
+ ],
272
+ files: [
273
+ {
274
+ name: "dropdown-menu.tsx",
275
+ content: prefixTailwindClasses(`import * as React from "react"
276
+ import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
277
+ import { Check, ChevronRight, Circle } from "lucide-react"
184
278
 
185
279
  import { cn } from "@/lib/utils"
186
280
 
187
- /**
188
- * Table size variants for row height.
189
- */
190
- const tableVariants = cva(
191
- "w-full caption-bottom text-sm",
192
- {
193
- variants: {
194
- size: {
195
- sm: "[&_td]:py-2 [&_th]:py-2",
196
- md: "[&_td]:py-3 [&_th]:py-3",
197
- lg: "[&_td]:py-4 [&_th]:py-4",
198
- },
199
- },
200
- defaultVariants: {
201
- size: "md",
202
- },
203
- }
204
- )
281
+ const DropdownMenu = DropdownMenuPrimitive.Root
205
282
 
206
- export interface TableProps
207
- extends React.HTMLAttributes<HTMLTableElement>,
208
- VariantProps<typeof tableVariants> {
209
- /** Remove outer border from the table */
210
- withoutBorder?: boolean
211
- }
283
+ const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
212
284
 
213
- const Table = React.forwardRef<HTMLTableElement, TableProps>(
214
- ({ className, size, withoutBorder, ...props }, ref) => (
215
- <div className={cn(
216
- "relative w-full overflow-auto",
217
- !withoutBorder && "rounded-lg border border-[#E5E7EB]"
218
- )}>
219
- <table
220
- ref={ref}
221
- className={cn(tableVariants({ size, className }))}
222
- {...props}
223
- />
224
- </div>
225
- )
226
- )
227
- Table.displayName = "Table"
285
+ const DropdownMenuGroup = DropdownMenuPrimitive.Group
228
286
 
229
- const TableHeader = React.forwardRef<
230
- HTMLTableSectionElement,
231
- React.HTMLAttributes<HTMLTableSectionElement>
232
- >(({ className, ...props }, ref) => (
233
- <thead
234
- ref={ref}
235
- className={cn("bg-[#F9FAFB] [&_tr]:border-b", className)}
236
- {...props}
237
- />
238
- ))
239
- TableHeader.displayName = "TableHeader"
287
+ const DropdownMenuPortal = DropdownMenuPrimitive.Portal
240
288
 
241
- const TableBody = React.forwardRef<
242
- HTMLTableSectionElement,
243
- React.HTMLAttributes<HTMLTableSectionElement>
244
- >(({ className, ...props }, ref) => (
245
- <tbody
289
+ const DropdownMenuSub = DropdownMenuPrimitive.Sub
290
+
291
+ const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup
292
+
293
+ const DropdownMenuSubTrigger = React.forwardRef<
294
+ React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
295
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
296
+ inset?: boolean
297
+ }
298
+ >(({ className, inset, children, ...props }, ref) => (
299
+ <DropdownMenuPrimitive.SubTrigger
246
300
  ref={ref}
247
- className={cn("[&_tr:last-child]:border-0", className)}
301
+ className={cn(
302
+ "flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-[#F3F4F6] data-[state=open]:bg-[#F3F4F6]",
303
+ inset && "pl-8",
304
+ className
305
+ )}
248
306
  {...props}
249
- />
307
+ >
308
+ {children}
309
+ <ChevronRight className="ml-auto h-4 w-4" />
310
+ </DropdownMenuPrimitive.SubTrigger>
250
311
  ))
251
- TableBody.displayName = "TableBody"
312
+ DropdownMenuSubTrigger.displayName =
313
+ DropdownMenuPrimitive.SubTrigger.displayName
252
314
 
253
- const TableFooter = React.forwardRef<
254
- HTMLTableSectionElement,
255
- React.HTMLAttributes<HTMLTableSectionElement>
315
+ const DropdownMenuSubContent = React.forwardRef<
316
+ React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
317
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
256
318
  >(({ className, ...props }, ref) => (
257
- <tfoot
319
+ <DropdownMenuPrimitive.SubContent
258
320
  ref={ref}
259
321
  className={cn(
260
- "border-t bg-[#F9FAFB] font-medium [&>tr]:last:border-b-0",
322
+ "z-50 min-w-[8rem] overflow-hidden rounded-md border border-[#E5E7EB] bg-white p-1 text-[#333333] shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
261
323
  className
262
324
  )}
263
325
  {...props}
264
326
  />
265
327
  ))
266
- TableFooter.displayName = "TableFooter"
267
-
268
- export interface TableRowProps extends React.HTMLAttributes<HTMLTableRowElement> {
269
- /** Highlight the row with a colored background */
270
- highlighted?: boolean
271
- }
328
+ DropdownMenuSubContent.displayName =
329
+ DropdownMenuPrimitive.SubContent.displayName
272
330
 
273
- const TableRow = React.forwardRef<HTMLTableRowElement, TableRowProps>(
274
- ({ className, highlighted, ...props }, ref) => (
275
- <tr
331
+ const DropdownMenuContent = React.forwardRef<
332
+ React.ElementRef<typeof DropdownMenuPrimitive.Content>,
333
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
334
+ >(({ className, sideOffset = 4, ...props }, ref) => (
335
+ <DropdownMenuPrimitive.Portal>
336
+ <DropdownMenuPrimitive.Content
276
337
  ref={ref}
338
+ sideOffset={sideOffset}
277
339
  className={cn(
278
- "border-b border-[#E5E7EB] transition-colors",
279
- highlighted
280
- ? "bg-[#EBF5FF]"
281
- : "hover:bg-[#F9FAFB]/50 data-[state=selected]:bg-[#F3F4F6]",
340
+ "z-50 min-w-[8rem] overflow-hidden rounded-md border border-[#E5E7EB] bg-white p-1 text-[#333333] shadow-md",
341
+ "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
282
342
  className
283
343
  )}
284
344
  {...props}
285
345
  />
286
- )
287
- )
288
- TableRow.displayName = "TableRow"
289
-
290
- export interface TableHeadProps extends React.ThHTMLAttributes<HTMLTableCellElement> {
291
- /** Make this column sticky on horizontal scroll */
292
- sticky?: boolean
293
- /** Sort direction indicator */
294
- sortDirection?: 'asc' | 'desc' | null
295
- /** Show info icon with tooltip */
296
- infoTooltip?: string
297
- }
346
+ </DropdownMenuPrimitive.Portal>
347
+ ))
348
+ DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
298
349
 
299
- const TableHead = React.forwardRef<HTMLTableCellElement, TableHeadProps>(
300
- ({ className, sticky, sortDirection, infoTooltip, children, ...props }, ref) => (
301
- <th
302
- ref={ref}
350
+ const DropdownMenuItem = React.forwardRef<
351
+ React.ElementRef<typeof DropdownMenuPrimitive.Item>,
352
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
353
+ inset?: boolean
354
+ }
355
+ >(({ className, inset, ...props }, ref) => (
356
+ <DropdownMenuPrimitive.Item
357
+ ref={ref}
358
+ className={cn(
359
+ "relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-[#F3F4F6] focus:text-[#333333] data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
360
+ inset && "pl-8",
361
+ className
362
+ )}
363
+ {...props}
364
+ />
365
+ ))
366
+ DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
367
+
368
+ const DropdownMenuCheckboxItem = React.forwardRef<
369
+ React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
370
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>
371
+ >(({ className, children, checked, ...props }, ref) => (
372
+ <DropdownMenuPrimitive.CheckboxItem
373
+ ref={ref}
374
+ className={cn(
375
+ "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-[#F3F4F6] focus:text-[#333333] data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
376
+ className
377
+ )}
378
+ checked={checked}
379
+ {...props}
380
+ >
381
+ <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
382
+ <DropdownMenuPrimitive.ItemIndicator>
383
+ <Check className="h-4 w-4" />
384
+ </DropdownMenuPrimitive.ItemIndicator>
385
+ </span>
386
+ {children}
387
+ </DropdownMenuPrimitive.CheckboxItem>
388
+ ))
389
+ DropdownMenuCheckboxItem.displayName =
390
+ DropdownMenuPrimitive.CheckboxItem.displayName
391
+
392
+ const DropdownMenuRadioItem = React.forwardRef<
393
+ React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
394
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
395
+ >(({ className, children, ...props }, ref) => (
396
+ <DropdownMenuPrimitive.RadioItem
397
+ ref={ref}
398
+ className={cn(
399
+ "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-[#F3F4F6] focus:text-[#333333] data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
400
+ className
401
+ )}
402
+ {...props}
403
+ >
404
+ <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
405
+ <DropdownMenuPrimitive.ItemIndicator>
406
+ <Circle className="h-2 w-2 fill-current" />
407
+ </DropdownMenuPrimitive.ItemIndicator>
408
+ </span>
409
+ {children}
410
+ </DropdownMenuPrimitive.RadioItem>
411
+ ))
412
+ DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName
413
+
414
+ const DropdownMenuLabel = React.forwardRef<
415
+ React.ElementRef<typeof DropdownMenuPrimitive.Label>,
416
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
417
+ inset?: boolean
418
+ }
419
+ >(({ className, inset, ...props }, ref) => (
420
+ <DropdownMenuPrimitive.Label
421
+ ref={ref}
422
+ className={cn(
423
+ "px-2 py-1.5 text-sm font-semibold",
424
+ inset && "pl-8",
425
+ className
426
+ )}
427
+ {...props}
428
+ />
429
+ ))
430
+ DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
431
+
432
+ const DropdownMenuSeparator = React.forwardRef<
433
+ React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
434
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
435
+ >(({ className, ...props }, ref) => (
436
+ <DropdownMenuPrimitive.Separator
437
+ ref={ref}
438
+ className={cn("-mx-1 my-1 h-px bg-[#E5E7EB]", className)}
439
+ {...props}
440
+ />
441
+ ))
442
+ DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
443
+
444
+ const DropdownMenuShortcut = ({
445
+ className,
446
+ ...props
447
+ }: React.HTMLAttributes<HTMLSpanElement>) => {
448
+ return (
449
+ <span
450
+ className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
451
+ {...props}
452
+ />
453
+ )
454
+ }
455
+ DropdownMenuShortcut.displayName = "DropdownMenuShortcut"
456
+
457
+ export {
458
+ DropdownMenu,
459
+ DropdownMenuTrigger,
460
+ DropdownMenuContent,
461
+ DropdownMenuItem,
462
+ DropdownMenuCheckboxItem,
463
+ DropdownMenuRadioItem,
464
+ DropdownMenuLabel,
465
+ DropdownMenuSeparator,
466
+ DropdownMenuShortcut,
467
+ DropdownMenuGroup,
468
+ DropdownMenuPortal,
469
+ DropdownMenuSub,
470
+ DropdownMenuSubContent,
471
+ DropdownMenuSubTrigger,
472
+ DropdownMenuRadioGroup,
473
+ }
474
+ `, prefix)
475
+ }
476
+ ]
477
+ },
478
+ "table": {
479
+ name: "table",
480
+ description: "A composable table component with size variants, loading/empty states, sticky columns, and sorting support",
481
+ dependencies: [
482
+ "class-variance-authority",
483
+ "clsx",
484
+ "tailwind-merge"
485
+ ],
486
+ files: [
487
+ {
488
+ name: "table.tsx",
489
+ content: prefixTailwindClasses(`import * as React from "react"
490
+ import { cva, type VariantProps } from "class-variance-authority"
491
+
492
+ import { cn } from "@/lib/utils"
493
+
494
+ /**
495
+ * Table size variants for row height.
496
+ */
497
+ const tableVariants = cva(
498
+ "w-full caption-bottom text-sm",
499
+ {
500
+ variants: {
501
+ size: {
502
+ sm: "[&_td]:py-2 [&_th]:py-2",
503
+ md: "[&_td]:py-3 [&_th]:py-3",
504
+ lg: "[&_td]:py-4 [&_th]:py-4",
505
+ },
506
+ },
507
+ defaultVariants: {
508
+ size: "md",
509
+ },
510
+ }
511
+ )
512
+
513
+ /**
514
+ * Table component for displaying tabular data.
515
+ *
516
+ * @example
517
+ * \`\`\`tsx
518
+ * <Table size="md" withoutBorder>
519
+ * <TableHeader>
520
+ * <TableRow>
521
+ * <TableHead>Name</TableHead>
522
+ * <TableHead>Status</TableHead>
523
+ * </TableRow>
524
+ * </TableHeader>
525
+ * <TableBody>
526
+ * <TableRow>
527
+ * <TableCell>Item 1</TableCell>
528
+ * <TableCell><Badge variant="active">Active</Badge></TableCell>
529
+ * </TableRow>
530
+ * </TableBody>
531
+ * </Table>
532
+ * \`\`\`
533
+ */
534
+
535
+ export interface TableProps
536
+ extends React.HTMLAttributes<HTMLTableElement>,
537
+ VariantProps<typeof tableVariants> {
538
+ /** Remove outer border from the table */
539
+ withoutBorder?: boolean
540
+ }
541
+
542
+ const Table = React.forwardRef<HTMLTableElement, TableProps>(
543
+ ({ className, size, withoutBorder, ...props }, ref) => (
544
+ <div className={cn(
545
+ "relative w-full overflow-auto",
546
+ !withoutBorder && "rounded-lg border border-[#E5E7EB]"
547
+ )}>
548
+ <table
549
+ ref={ref}
550
+ className={cn(tableVariants({ size, className }))}
551
+ {...props}
552
+ />
553
+ </div>
554
+ )
555
+ )
556
+ Table.displayName = "Table"
557
+
558
+ const TableHeader = React.forwardRef<
559
+ HTMLTableSectionElement,
560
+ React.HTMLAttributes<HTMLTableSectionElement>
561
+ >(({ className, ...props }, ref) => (
562
+ <thead
563
+ ref={ref}
564
+ className={cn("bg-[#F9FAFB] [&_tr]:border-b", className)}
565
+ {...props}
566
+ />
567
+ ))
568
+ TableHeader.displayName = "TableHeader"
569
+
570
+ const TableBody = React.forwardRef<
571
+ HTMLTableSectionElement,
572
+ React.HTMLAttributes<HTMLTableSectionElement>
573
+ >(({ className, ...props }, ref) => (
574
+ <tbody
575
+ ref={ref}
576
+ className={cn("[&_tr:last-child]:border-0", className)}
577
+ {...props}
578
+ />
579
+ ))
580
+ TableBody.displayName = "TableBody"
581
+
582
+ const TableFooter = React.forwardRef<
583
+ HTMLTableSectionElement,
584
+ React.HTMLAttributes<HTMLTableSectionElement>
585
+ >(({ className, ...props }, ref) => (
586
+ <tfoot
587
+ ref={ref}
588
+ className={cn(
589
+ "border-t bg-[#F9FAFB] font-medium [&>tr]:last:border-b-0",
590
+ className
591
+ )}
592
+ {...props}
593
+ />
594
+ ))
595
+ TableFooter.displayName = "TableFooter"
596
+
597
+ export interface TableRowProps extends React.HTMLAttributes<HTMLTableRowElement> {
598
+ /** Highlight the row with a colored background */
599
+ highlighted?: boolean
600
+ }
601
+
602
+ const TableRow = React.forwardRef<HTMLTableRowElement, TableRowProps>(
603
+ ({ className, highlighted, ...props }, ref) => (
604
+ <tr
605
+ ref={ref}
606
+ className={cn(
607
+ "border-b border-[#E5E7EB] transition-colors",
608
+ highlighted
609
+ ? "bg-[#EBF5FF]"
610
+ : "hover:bg-[#F9FAFB]/50 data-[state=selected]:bg-[#F3F4F6]",
611
+ className
612
+ )}
613
+ {...props}
614
+ />
615
+ )
616
+ )
617
+ TableRow.displayName = "TableRow"
618
+
619
+ export interface TableHeadProps extends React.ThHTMLAttributes<HTMLTableCellElement> {
620
+ /** Make this column sticky on horizontal scroll */
621
+ sticky?: boolean
622
+ /** Sort direction indicator */
623
+ sortDirection?: 'asc' | 'desc' | null
624
+ /** Show info icon with tooltip */
625
+ infoTooltip?: string
626
+ }
627
+
628
+ const TableHead = React.forwardRef<HTMLTableCellElement, TableHeadProps>(
629
+ ({ className, sticky, sortDirection, infoTooltip, children, ...props }, ref) => (
630
+ <th
631
+ ref={ref}
303
632
  className={cn(
304
633
  "h-12 px-4 text-left align-middle font-medium text-[#6B7280] text-xs uppercase tracking-wider [&:has([role=checkbox])]:pr-0",
305
634
  sticky && "sticky left-0 bg-[#F9FAFB] z-10",
@@ -437,278 +766,109 @@ export {
437
766
  TableAvatar,
438
767
  tableVariants,
439
768
  }
440
- `, prefix);
441
- const buttonContent = prefixTailwindClasses(`import * as React from "react"
442
- import { Slot } from "@radix-ui/react-slot"
769
+ `, prefix)
770
+ }
771
+ ]
772
+ },
773
+ "tag": {
774
+ name: "tag",
775
+ description: "A tag component for event labels with optional bold label prefix",
776
+ dependencies: [
777
+ "class-variance-authority",
778
+ "clsx",
779
+ "tailwind-merge"
780
+ ],
781
+ files: [
782
+ {
783
+ name: "tag.tsx",
784
+ content: prefixTailwindClasses(`import * as React from "react"
443
785
  import { cva, type VariantProps } from "class-variance-authority"
444
- import { Loader2 } from "lucide-react"
445
786
 
446
787
  import { cn } from "@/lib/utils"
447
788
 
448
- const buttonVariants = cva(
449
- "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#1e293b] focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
789
+ /**
790
+ * Tag variants for event labels and categories.
791
+ * Rounded rectangle tags with optional bold labels.
792
+ */
793
+ const tagVariants = cva(
794
+ "inline-flex items-center justify-center rounded text-sm transition-colors",
450
795
  {
451
796
  variants: {
452
797
  variant: {
453
- default: "bg-[#343E55] text-white border-0 hover:bg-[#343E55]/90",
454
- destructive:
455
- "bg-[#ef4444] text-white border-0 hover:bg-[#ef4444]/90",
456
- outline:
457
- "border border-[#343E55] bg-transparent text-[#343E55] hover:bg-[#343E55] hover:text-white",
458
- secondary:
459
- "bg-[#343E55]/20 text-[#343E55] border-0 hover:bg-[#343E55]/30",
460
- ghost: "border-0 hover:bg-[#343E55]/10 hover:text-[#343E55]",
461
- link: "text-[#343E55] border-0 underline-offset-4 hover:underline",
798
+ default: "bg-[#F3F4F6] text-[#333333]",
799
+ primary: "bg-[#343E55]/10 text-[#343E55]",
800
+ secondary: "bg-[#E5E7EB] text-[#374151]",
801
+ success: "bg-[#E5FFF5] text-[#00A651]",
802
+ warning: "bg-[#FFF8E5] text-[#F59E0B]",
803
+ error: "bg-[#FFECEC] text-[#FF3B3B]",
462
804
  },
463
805
  size: {
464
- default: "h-10 px-4 py-2",
465
- sm: "h-9 rounded-md px-3",
466
- lg: "h-11 rounded-md px-8",
467
- icon: "h-10 w-10",
806
+ default: "px-2 py-1",
807
+ sm: "px-1.5 py-0.5 text-xs",
808
+ lg: "px-3 py-1.5",
809
+ },
810
+ interactive: {
811
+ true: "cursor-pointer hover:bg-[#E5E7EB] active:bg-[#D1D5DB]",
812
+ false: "",
813
+ },
814
+ selected: {
815
+ true: "ring-2 ring-[#343E55] ring-offset-1",
816
+ false: "",
468
817
  },
469
818
  },
470
819
  defaultVariants: {
471
820
  variant: "default",
472
821
  size: "default",
822
+ interactive: false,
823
+ selected: false,
473
824
  },
474
825
  }
475
826
  )
476
827
 
477
- export interface ButtonProps
478
- extends React.ButtonHTMLAttributes<HTMLButtonElement>,
479
- VariantProps<typeof buttonVariants> {
480
- asChild?: boolean
481
- leftIcon?: React.ReactNode
482
- rightIcon?: React.ReactNode
483
- loading?: boolean
484
- loadingText?: string
828
+ /**
829
+ * Tag component for displaying event labels and categories.
830
+ *
831
+ * @example
832
+ * \`\`\`tsx
833
+ * <Tag>After Call Event</Tag>
834
+ * <Tag label="In Call Event:">Start of call, Bridge, Call ended</Tag>
835
+ * <Tag interactive onClick={() => console.log('clicked')}>Clickable</Tag>
836
+ * \`\`\`
837
+ */
838
+ export interface TagProps
839
+ extends React.HTMLAttributes<HTMLSpanElement>,
840
+ VariantProps<typeof tagVariants> {
841
+ /** Bold label prefix displayed before the content */
842
+ label?: string
843
+ /** Make the tag clickable with hover/active states */
844
+ interactive?: boolean
845
+ /** Show selected state with ring outline */
846
+ selected?: boolean
485
847
  }
486
848
 
487
- const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
488
- ({
489
- className,
490
- variant,
491
- size,
492
- asChild = false,
493
- leftIcon,
494
- rightIcon,
495
- loading = false,
496
- loadingText,
497
- children,
498
- disabled,
499
- ...props
500
- }, ref) => {
501
- const Comp = asChild ? Slot : "button"
502
-
849
+ const Tag = React.forwardRef<HTMLSpanElement, TagProps>(
850
+ ({ className, variant, size, interactive, selected, label, children, ...props }, ref) => {
503
851
  return (
504
- <Comp
505
- className={cn(buttonVariants({ variant, size, className }))}
852
+ <span
853
+ className={cn(tagVariants({ variant, size, interactive, selected, className }))}
506
854
  ref={ref}
507
- disabled={disabled || loading}
855
+ role={interactive ? "button" : undefined}
856
+ tabIndex={interactive ? 0 : undefined}
857
+ aria-selected={selected}
508
858
  {...props}
509
859
  >
510
- {loading ? (
511
- <>
512
- <Loader2 className="animate-spin" />
513
- {loadingText || children}
514
- </>
515
- ) : (
516
- <>
517
- {leftIcon}
518
- {children}
519
- {rightIcon}
520
- </>
860
+ {label && (
861
+ <span className="font-semibold mr-1">{label}</span>
521
862
  )}
522
- </Comp>
863
+ <span className="font-normal">{children}</span>
864
+ </span>
523
865
  )
524
866
  }
525
867
  )
526
- Button.displayName = "Button"
527
-
528
- export { Button, buttonVariants }
529
- `, prefix);
530
- const dropdownMenuContent = prefixTailwindClasses(`import * as React from "react"
531
- import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
532
- import { Check, ChevronRight, Circle } from "lucide-react"
533
-
534
- import { cn } from "@/lib/utils"
535
-
536
- const DropdownMenu = DropdownMenuPrimitive.Root
537
- const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
538
- const DropdownMenuGroup = DropdownMenuPrimitive.Group
539
- const DropdownMenuPortal = DropdownMenuPrimitive.Portal
540
- const DropdownMenuSub = DropdownMenuPrimitive.Sub
541
- const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup
542
-
543
- const DropdownMenuContent = React.forwardRef<
544
- React.ElementRef<typeof DropdownMenuPrimitive.Content>,
545
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
546
- >(({ className, sideOffset = 4, ...props }, ref) => (
547
- <DropdownMenuPrimitive.Portal>
548
- <DropdownMenuPrimitive.Content
549
- ref={ref}
550
- sideOffset={sideOffset}
551
- className={cn(
552
- "z-50 min-w-[8rem] overflow-hidden rounded-md border border-[#E5E7EB] bg-white p-1 text-[#333333] shadow-md",
553
- className
554
- )}
555
- {...props}
556
- />
557
- </DropdownMenuPrimitive.Portal>
558
- ))
559
- DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
560
-
561
- const DropdownMenuItem = React.forwardRef<
562
- React.ElementRef<typeof DropdownMenuPrimitive.Item>,
563
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
564
- inset?: boolean
565
- }
566
- >(({ className, inset, ...props }, ref) => (
567
- <DropdownMenuPrimitive.Item
568
- ref={ref}
569
- className={cn(
570
- "relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-[#F3F4F6] focus:text-[#333333] data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
571
- inset && "pl-8",
572
- className
573
- )}
574
- {...props}
575
- />
576
- ))
577
- DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
578
-
579
- const DropdownMenuLabel = React.forwardRef<
580
- React.ElementRef<typeof DropdownMenuPrimitive.Label>,
581
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
582
- inset?: boolean
583
- }
584
- >(({ className, inset, ...props }, ref) => (
585
- <DropdownMenuPrimitive.Label
586
- ref={ref}
587
- className={cn(
588
- "px-2 py-1.5 text-sm font-semibold",
589
- inset && "pl-8",
590
- className
591
- )}
592
- {...props}
593
- />
594
- ))
595
- DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
596
-
597
- const DropdownMenuSeparator = React.forwardRef<
598
- React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
599
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
600
- >(({ className, ...props }, ref) => (
601
- <DropdownMenuPrimitive.Separator
602
- ref={ref}
603
- className={cn("-mx-1 my-1 h-px bg-[#E5E7EB]", className)}
604
- {...props}
605
- />
606
- ))
607
- DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
608
-
609
- const DropdownMenuShortcut = ({
610
- className,
611
- ...props
612
- }: React.HTMLAttributes<HTMLSpanElement>) => {
613
- return (
614
- <span
615
- className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
616
- {...props}
617
- />
618
- )
619
- }
620
- DropdownMenuShortcut.displayName = "DropdownMenuShortcut"
868
+ Tag.displayName = "Tag"
621
869
 
622
- export {
623
- DropdownMenu,
624
- DropdownMenuTrigger,
625
- DropdownMenuContent,
626
- DropdownMenuItem,
627
- DropdownMenuLabel,
628
- DropdownMenuSeparator,
629
- DropdownMenuShortcut,
630
- DropdownMenuGroup,
631
- DropdownMenuPortal,
632
- DropdownMenuSub,
633
- DropdownMenuRadioGroup,
634
- }
635
- `, prefix);
636
- return {
637
- button: {
638
- name: "button",
639
- description: "A customizable button component with variants, sizes, and icons",
640
- dependencies: [
641
- "@radix-ui/react-slot",
642
- "class-variance-authority",
643
- "clsx",
644
- "tailwind-merge",
645
- "lucide-react"
646
- ],
647
- files: [
648
- {
649
- name: "button.tsx",
650
- content: buttonContent
651
- }
652
- ]
653
- },
654
- badge: {
655
- name: "badge",
656
- description: "A status badge component with active, failed, and disabled variants",
657
- dependencies: [
658
- "class-variance-authority",
659
- "clsx",
660
- "tailwind-merge"
661
- ],
662
- files: [
663
- {
664
- name: "badge.tsx",
665
- content: badgeContent
666
- }
667
- ]
668
- },
669
- tag: {
670
- name: "tag",
671
- description: "A tag component for event labels with optional bold label prefix",
672
- dependencies: [
673
- "class-variance-authority",
674
- "clsx",
675
- "tailwind-merge"
676
- ],
677
- files: [
678
- {
679
- name: "tag.tsx",
680
- content: tagContent
681
- }
682
- ]
683
- },
684
- table: {
685
- name: "table",
686
- description: "A composable table component with size variants, loading/empty states, sticky columns, and sorting support",
687
- dependencies: [
688
- "class-variance-authority",
689
- "clsx",
690
- "tailwind-merge"
691
- ],
692
- files: [
693
- {
694
- name: "table.tsx",
695
- content: tableContent
696
- }
697
- ]
698
- },
699
- "dropdown-menu": {
700
- name: "dropdown-menu",
701
- description: "A dropdown menu component for displaying actions and options",
702
- dependencies: [
703
- "@radix-ui/react-dropdown-menu",
704
- "clsx",
705
- "tailwind-merge",
706
- "lucide-react"
707
- ],
708
- files: [
709
- {
710
- name: "dropdown-menu.tsx",
711
- content: dropdownMenuContent
870
+ export { Tag, tagVariants }
871
+ `, prefix)
712
872
  }
713
873
  ]
714
874
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "myoperator-ui",
3
- "version": "0.0.39",
3
+ "version": "0.0.41",
4
4
  "description": "CLI for adding myOperator UI components to your project",
5
5
  "type": "module",
6
6
  "exports": "./dist/index.js",
@@ -11,7 +11,8 @@
11
11
  "dist"
12
12
  ],
13
13
  "scripts": {
14
- "build": "tsup src/index.ts --format esm --dts",
14
+ "generate-registry": "node scripts/generate-registry.js",
15
+ "build": "npm run generate-registry && tsup src/index.ts --format esm --dts",
15
16
  "dev": "tsup src/index.ts --format esm --watch",
16
17
  "typecheck": "tsc --noEmit"
17
18
  },