7onic 0.1.22 → 0.1.23

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 +173 -55
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -10068,6 +10068,28 @@ export type BadgeColor = 'default' | 'primary' | 'success' | 'warning' | 'error'
10068
10068
  export type BadgeSize = 'sm' | 'default' | 'lg'
10069
10069
  export type BadgeRadius = 'sm' | 'base' | 'md' | 'lg' | 'full'
10070
10070
 
10071
+ const REACT_LAZY_TYPE = Symbol.for('react.lazy')
10072
+
10073
+ // asChild: Slot merges props only into a single child element, so the dot and
10074
+ // icon must go inside that child, not next to it. Lazy children (from Server
10075
+ // Components) are resolved the same way Radix Slot does.
10076
+ function renderInsideChild(
10077
+ children: React.ReactNode,
10078
+ render: (content: React.ReactNode) => React.ReactNode
10079
+ ): React.ReactNode {
10080
+ let child: unknown = children
10081
+ const resolve = (React as { use?: (usable: unknown) => unknown }).use
10082
+ if (
10083
+ typeof child === 'object' && child !== null &&
10084
+ (child as { $$typeof?: symbol }).$$typeof === REACT_LAZY_TYPE &&
10085
+ typeof resolve === 'function'
10086
+ ) {
10087
+ child = resolve((child as { _payload: unknown })._payload)
10088
+ }
10089
+ if (!React.isValidElement<{ children?: React.ReactNode }>(child)) return render(children)
10090
+ return React.cloneElement(child, undefined, render(child.props.children))
10091
+ }
10092
+
10071
10093
  export interface BadgeProps
10072
10094
  extends React.HTMLAttributes<HTMLSpanElement>,
10073
10095
  VariantProps<typeof badgeVariants> {
@@ -10079,7 +10101,7 @@ export interface BadgeProps
10079
10101
  icon?: React.ReactNode
10080
10102
  /** Show a status dot before text */
10081
10103
  dot?: boolean
10082
- /** Show a remove button */
10104
+ /** Show a remove button (not rendered with asChild \u2014 a button inside a link is invalid HTML) */
10083
10105
  removable?: boolean
10084
10106
  /** Callback when remove button is clicked */
10085
10107
  onRemove?: () => void
@@ -10113,17 +10135,8 @@ const Badge = React.forwardRef<HTMLSpanElement, BadgeProps>(
10113
10135
  // Dot color: in solid variant use currentColor (white/foreground), otherwise use semantic color
10114
10136
  const dotColor = variant === 'solid' ? 'bg-current' : dotColorMap[color]
10115
10137
 
10116
- return (
10117
- <Comp
10118
- ref={ref}
10119
- className={cn(
10120
- badgeVariants({ size, radius }),
10121
- colorClasses,
10122
- outlineClasses,
10123
- className
10124
- )}
10125
- {...props}
10126
- >
10138
+ const renderContent = (content: React.ReactNode) => (
10139
+ <>
10127
10140
  {dot && (
10128
10141
  <span
10129
10142
  className={cn('shrink-0 rounded-full', badgeDotSizes[resolvedSize], dotColor)}
@@ -10138,8 +10151,9 @@ const Badge = React.forwardRef<HTMLSpanElement, BadgeProps>(
10138
10151
  {icon}
10139
10152
  </span>
10140
10153
  )}
10141
- {children}
10142
- {removable && (
10154
+ {content}
10155
+ {/* A button inside the asChild element (usually a link) would be invalid HTML */}
10156
+ {removable && !asChild && (
10143
10157
  <button
10144
10158
  type="button"
10145
10159
  className="shrink-0 -mr-0.5 ml-0.5 rounded-full p-0.5 opacity-70 hover:opacity-100 transition-opacity focus-visible:focus-ring"
@@ -10161,6 +10175,21 @@ const Badge = React.forwardRef<HTMLSpanElement, BadgeProps>(
10161
10175
  </svg>
10162
10176
  </button>
10163
10177
  )}
10178
+ </>
10179
+ )
10180
+
10181
+ return (
10182
+ <Comp
10183
+ ref={ref}
10184
+ className={cn(
10185
+ badgeVariants({ size, radius }),
10186
+ colorClasses,
10187
+ outlineClasses,
10188
+ className
10189
+ )}
10190
+ {...props}
10191
+ >
10192
+ {asChild ? renderInsideChild(children, renderContent) : renderContent(children)}
10164
10193
  </Comp>
10165
10194
  )
10166
10195
  }
@@ -10651,6 +10680,28 @@ const buttonVariants = cva(
10651
10680
  }
10652
10681
  )
10653
10682
 
10683
+ const REACT_LAZY_TYPE = Symbol.for('react.lazy')
10684
+
10685
+ // asChild: Slot merges props only into a single child element, so icons and
10686
+ // wrappers must go inside that child, not next to it. Lazy children (from
10687
+ // Server Components) are resolved the same way Radix Slot does.
10688
+ function renderInsideChild(
10689
+ children: React.ReactNode,
10690
+ render: (content: React.ReactNode) => React.ReactNode
10691
+ ): React.ReactNode {
10692
+ let child: unknown = children
10693
+ const resolve = (React as { use?: (usable: unknown) => unknown }).use
10694
+ if (
10695
+ typeof child === 'object' && child !== null &&
10696
+ (child as { $$typeof?: symbol }).$$typeof === REACT_LAZY_TYPE &&
10697
+ typeof resolve === 'function'
10698
+ ) {
10699
+ child = resolve((child as { _payload: unknown })._payload)
10700
+ }
10701
+ if (!React.isValidElement<{ children?: React.ReactNode }>(child)) return render(children)
10702
+ return React.cloneElement(child, undefined, render(child.props.children))
10703
+ }
10704
+
10654
10705
  export interface ButtonProps
10655
10706
  extends React.ButtonHTMLAttributes<HTMLButtonElement>,
10656
10707
  VariantProps<typeof buttonVariants> {
@@ -10717,6 +10768,27 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
10717
10768
  variant === 'ghost' ? 'font-semibold' : ''
10718
10769
  ) : ''
10719
10770
 
10771
+ const renderContent = (content: React.ReactNode) => loading ? (
10772
+ <>
10773
+ <svg
10774
+ className={cn(iconSizeClass, 'animate-spin')}
10775
+ fill="none"
10776
+ viewBox="0 0 24 24"
10777
+ aria-hidden="true"
10778
+ >
10779
+ <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
10780
+ <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" />
10781
+ </svg>
10782
+ <span>{content}</span>
10783
+ </>
10784
+ ) : (
10785
+ <>
10786
+ {leftIcon && <span className={cn(iconSizeClass, '[&>svg]:w-full [&>svg]:h-full')} aria-hidden="true">{leftIcon}</span>}
10787
+ {content}
10788
+ {rightIcon && <span className={cn(iconSizeClass, '[&>svg]:w-full [&>svg]:h-full')} aria-hidden="true">{rightIcon}</span>}
10789
+ </>
10790
+ )
10791
+
10720
10792
  return (
10721
10793
  <Comp
10722
10794
  className={cn(buttonVariants({ variant, size, radius, fullWidth }), variant === 'solid' && solidColorMap[color], pressEffect !== false && 'active:scale-pressed', fontWeightClass, selectedStyles, className)}
@@ -10726,26 +10798,7 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
10726
10798
  aria-pressed={selected || undefined}
10727
10799
  {...props}
10728
10800
  >
10729
- {loading ? (
10730
- <>
10731
- <svg
10732
- className={cn(iconSizeClass, 'animate-spin')}
10733
- fill="none"
10734
- viewBox="0 0 24 24"
10735
- aria-hidden="true"
10736
- >
10737
- <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
10738
- <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" />
10739
- </svg>
10740
- <span>{children}</span>
10741
- </>
10742
- ) : (
10743
- <>
10744
- {leftIcon && <span className={cn(iconSizeClass, '[&>svg]:w-full [&>svg]:h-full')} aria-hidden="true">{leftIcon}</span>}
10745
- {children}
10746
- {rightIcon && <span className={cn(iconSizeClass, '[&>svg]:w-full [&>svg]:h-full')} aria-hidden="true">{rightIcon}</span>}
10747
- </>
10748
- )}
10801
+ {asChild ? renderInsideChild(children, renderContent) : renderContent(children)}
10749
10802
  </Comp>
10750
10803
  )
10751
10804
  }
@@ -14260,6 +14313,28 @@ const iconButtonVariants = cva(
14260
14313
  }
14261
14314
  )
14262
14315
 
14316
+ const REACT_LAZY_TYPE = Symbol.for('react.lazy')
14317
+
14318
+ // asChild: Slot merges props only into a single child element, so the icon
14319
+ // wrapper must go inside that child, not around it. Lazy children (from
14320
+ // Server Components) are resolved the same way Radix Slot does.
14321
+ function renderInsideChild(
14322
+ children: React.ReactNode,
14323
+ render: (content: React.ReactNode) => React.ReactNode
14324
+ ): React.ReactNode {
14325
+ let child: unknown = children
14326
+ const resolve = (React as { use?: (usable: unknown) => unknown }).use
14327
+ if (
14328
+ typeof child === 'object' && child !== null &&
14329
+ (child as { $$typeof?: symbol }).$$typeof === REACT_LAZY_TYPE &&
14330
+ typeof resolve === 'function'
14331
+ ) {
14332
+ child = resolve((child as { _payload: unknown })._payload)
14333
+ }
14334
+ if (!React.isValidElement<{ children?: React.ReactNode }>(child)) return render(children)
14335
+ return React.cloneElement(child, undefined, render(child.props.children))
14336
+ }
14337
+
14263
14338
  export interface IconButtonProps
14264
14339
  extends React.ButtonHTMLAttributes<HTMLButtonElement>,
14265
14340
  VariantProps<typeof iconButtonVariants> {
@@ -14293,6 +14368,22 @@ const IconButton = React.forwardRef<HTMLButtonElement, IconButtonProps>(
14293
14368
  lg: 'icon-lg', // 24px
14294
14369
  }[size || 'default']
14295
14370
 
14371
+ const renderContent = (content: React.ReactNode) => loading ? (
14372
+ <svg
14373
+ className={cn(iconSize, 'animate-spin')}
14374
+ fill="none"
14375
+ viewBox="0 0 24 24"
14376
+ aria-hidden="true"
14377
+ >
14378
+ <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
14379
+ <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" />
14380
+ </svg>
14381
+ ) : (
14382
+ <span className={cn(iconSize, '[&>svg]:w-full [&>svg]:h-full')} aria-hidden="true">
14383
+ {content}
14384
+ </span>
14385
+ )
14386
+
14296
14387
  return (
14297
14388
  <Comp
14298
14389
  className={cn(iconButtonVariants({ variant, size, radius }), variant === 'solid' && solidColorMap[color], pressEffect !== false && 'active:scale-pressed', className)}
@@ -14301,21 +14392,7 @@ const IconButton = React.forwardRef<HTMLButtonElement, IconButtonProps>(
14301
14392
  aria-busy={loading || undefined}
14302
14393
  {...props}
14303
14394
  >
14304
- {loading ? (
14305
- <svg
14306
- className={cn(iconSize, 'animate-spin')}
14307
- fill="none"
14308
- viewBox="0 0 24 24"
14309
- aria-hidden="true"
14310
- >
14311
- <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
14312
- <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" />
14313
- </svg>
14314
- ) : (
14315
- <span className={cn(iconSize, '[&>svg]:w-full [&>svg]:h-full')} aria-hidden="true">
14316
- {children}
14317
- </span>
14318
- )}
14395
+ {asChild ? renderInsideChild(children, renderContent) : renderContent(children)}
14319
14396
  </Comp>
14320
14397
  )
14321
14398
  }
@@ -15349,6 +15426,30 @@ function ChevronRightIcon({ className }: { className?: string }) {
15349
15426
  )
15350
15427
  }
15351
15428
 
15429
+ // \u2500\u2500\u2500 asChild Content \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
15430
+
15431
+ const REACT_LAZY_TYPE = Symbol.for('react.lazy')
15432
+
15433
+ // asChild: Slot merges props only into a single child element, so the icon and
15434
+ // text wrapper must go inside that child, not next to it. Lazy children (from
15435
+ // Server Components) are resolved the same way Radix Slot does.
15436
+ function renderInsideChild(
15437
+ children: React.ReactNode,
15438
+ render: (content: React.ReactNode) => React.ReactNode
15439
+ ): React.ReactNode {
15440
+ let child: unknown = children
15441
+ const resolve = (React as { use?: (usable: unknown) => unknown }).use
15442
+ if (
15443
+ typeof child === 'object' && child !== null &&
15444
+ (child as { $$typeof?: symbol }).$$typeof === REACT_LAZY_TYPE &&
15445
+ typeof resolve === 'function'
15446
+ ) {
15447
+ child = resolve((child as { _payload: unknown })._payload)
15448
+ }
15449
+ if (!React.isValidElement<{ children?: React.ReactNode }>(child)) return render(children)
15450
+ return React.cloneElement(child, undefined, render(child.props.children))
15451
+ }
15452
+
15352
15453
  // \u2500\u2500\u2500 Radius Configuration \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
15353
15454
 
15354
15455
  type NavigationMenuRadius = 'sm' | 'md' | 'lg' | 'xl'
@@ -15834,9 +15935,21 @@ const NavigationMenuLink = React.forwardRef<HTMLAnchorElement, NavigationMenuLin
15834
15935
  // \u2500\u2500 Vertical mode \u2500\u2500
15835
15936
 
15836
15937
  const Comp = asChild ? Slot : 'a'
15938
+ const iconNode = icon && <span className={cn('shrink-0', s.icon)}>{icon}</span>
15939
+ // With asChild the text lives inside the child element; use it for the collapsed tooltip too
15940
+ const childText = asChild && React.isValidElement<{ children?: React.ReactNode }>(children)
15941
+ ? children.props.children
15942
+ : children
15837
15943
 
15838
15944
  // Content-level links (sub-menu items): compact, indented
15839
15945
  if (inContent) {
15946
+ const renderContent = (content: React.ReactNode) => (
15947
+ <>
15948
+ {iconNode}
15949
+ {!collapsed && content}
15950
+ </>
15951
+ )
15952
+
15840
15953
  return (
15841
15954
  <Comp
15842
15955
  ref={ref}
@@ -15853,13 +15966,19 @@ const NavigationMenuLink = React.forwardRef<HTMLAnchorElement, NavigationMenuLin
15853
15966
  {...(active ? { 'aria-current': 'page' as const } : {})}
15854
15967
  {...props}
15855
15968
  >
15856
- {icon && <span className={cn('shrink-0', s.icon)}>{icon}</span>}
15857
- {!collapsed && children}
15969
+ {asChild ? renderInsideChild(children, renderContent) : renderContent(children)}
15858
15970
  </Comp>
15859
15971
  )
15860
15972
  }
15861
15973
 
15862
15974
  // Top-level vertical links
15975
+ const renderContent = (content: React.ReactNode) => (
15976
+ <>
15977
+ {iconNode}
15978
+ {!collapsed && <span className="truncate">{content}</span>}
15979
+ </>
15980
+ )
15981
+
15863
15982
  return (
15864
15983
  <Comp
15865
15984
  ref={ref}
@@ -15876,11 +15995,10 @@ const NavigationMenuLink = React.forwardRef<HTMLAnchorElement, NavigationMenuLin
15876
15995
  className
15877
15996
  )}
15878
15997
  {...(active ? { 'aria-current': 'page' as const } : {})}
15879
- {...(collapsed && typeof children === 'string' ? { title: children } : {})}
15998
+ {...(collapsed && typeof childText === 'string' ? { title: childText } : {})}
15880
15999
  {...props}
15881
16000
  >
15882
- {icon && <span className={cn('shrink-0', s.icon)}>{icon}</span>}
15883
- {!collapsed && <span className="truncate">{children}</span>}
16001
+ {asChild ? renderInsideChild(children, renderContent) : renderContent(children)}
15884
16002
  </Comp>
15885
16003
  )
15886
16004
  }
@@ -21909,7 +22027,7 @@ function showCompanionHints(names) {
21909
22027
 
21910
22028
  // cli/src/index.ts
21911
22029
  var import_picocolors4 = __toESM(require_picocolors());
21912
- var VERSION = "0.1.22";
22030
+ var VERSION = "0.1.23";
21913
22031
  var HELP = `
21914
22032
  ${import_picocolors4.default.bold("7onic")} \u2014 Add 7onic design system components to your project
21915
22033
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "7onic",
3
- "version": "0.1.22",
3
+ "version": "0.1.23",
4
4
  "description": "CLI for adding 7onic design system components to your project",
5
5
  "bin": {
6
6
  "7onic": "./dist/index.js"