@waveso/ui 0.0.9 → 0.0.10

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/dist/badge.d.ts CHANGED
@@ -4,7 +4,7 @@ import { useRender } from '@base-ui/react/use-render';
4
4
  import { VariantProps } from 'class-variance-authority';
5
5
 
6
6
  declare const badgeVariants: (props?: ({
7
- variant?: "link" | "default" | "solid" | "outline" | "secondary" | "ghost" | "success" | "destructive" | "warning" | null | undefined;
7
+ variant?: "default" | "destructive" | "link" | "solid" | "outline" | "secondary" | "ghost" | "success" | "warning" | null | undefined;
8
8
  } & class_variance_authority_types.ClassProp) | undefined) => string;
9
9
  type BadgeProps = useRender.ComponentProps<"span"> & VariantProps<typeof badgeVariants>;
10
10
  declare function Badge({ className, variant, render, ...props }: BadgeProps): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>;
package/dist/button.d.ts CHANGED
@@ -5,8 +5,8 @@ import { Button as Button$1 } from '@base-ui/react/button';
5
5
  import { VariantProps } from 'class-variance-authority';
6
6
 
7
7
  declare const buttonVariants: (props?: ({
8
- variant?: "link" | "default" | "solid" | "outline" | "secondary" | "ghost" | "success" | "destructive" | null | undefined;
9
- size?: "default" | "sm" | "lg" | "xs" | "icon" | "icon-xs" | "icon-sm" | "icon-lg" | null | undefined;
8
+ variant?: "default" | "destructive" | "link" | "solid" | "outline" | "secondary" | "ghost" | "success" | null | undefined;
9
+ size?: "default" | "xs" | "sm" | "lg" | "icon" | "icon-xs" | "icon-sm" | "icon-lg" | null | undefined;
10
10
  } & class_variance_authority_types.ClassProp) | undefined) => string;
11
11
  type ButtonProps = React.ComponentProps<typeof Button$1> & VariantProps<typeof buttonVariants>;
12
12
  declare function Button({ className, variant, size, ...props }: ButtonProps): react_jsx_runtime.JSX.Element;
@@ -15,6 +15,10 @@ interface GradientRevealTextProps {
15
15
  fontFamily?: string;
16
16
  /** Spotlight radius multiplier relative to text height. Default: 0.6 */
17
17
  spotlightSize?: number;
18
+ /** Stroke width in px. Default: auto (1.5% of text height) */
19
+ strokeWidth?: number;
20
+ /** Base stroke color. Default: neutral-200 (light) / neutral-800 (dark) via Tailwind */
21
+ baseColor?: string;
18
22
  className?: string;
19
23
  }
20
24
  /**
@@ -30,6 +34,6 @@ interface GradientRevealTextProps {
30
34
  * <GradientRevealText text="BRAND" colors={["#ff0000", "#00ff00"]} />
31
35
  * ```
32
36
  */
33
- declare function GradientRevealText({ text, duration, colors, baseOpacity, hoverOpacity, fontFamily, spotlightSize, className, }: GradientRevealTextProps): react_jsx_runtime.JSX.Element;
37
+ declare function GradientRevealText({ text, duration, colors, baseOpacity, hoverOpacity, fontFamily, spotlightSize, strokeWidth: strokeWidthPx, baseColor, className, }: GradientRevealTextProps): react_jsx_runtime.JSX.Element;
34
38
 
35
39
  export { GradientRevealText, type GradientRevealTextProps };
@@ -17,6 +17,8 @@ function GradientRevealText({
17
17
  hoverOpacity = 0.7,
18
18
  fontFamily = "Helvetica Neue, Helvetica, Arial, sans-serif",
19
19
  spotlightSize = 0.6,
20
+ strokeWidth: strokeWidthPx,
21
+ baseColor,
20
22
  className
21
23
  }) {
22
24
  const uid = useId();
@@ -88,7 +90,7 @@ function GradientRevealText({
88
90
  setHovered(true);
89
91
  };
90
92
  const spotlightR = vb.h * spotlightSize;
91
- const strokeW = vb.h * 0.015;
93
+ const strokeW = strokeWidthPx ?? vb.h * 0.015;
92
94
  const initCx = vb.x + 0.5 * vb.w;
93
95
  const initCy = vb.y + 0.5 * vb.h;
94
96
  const gradientId = `grad-${uid}`;
@@ -171,9 +173,10 @@ function GradientRevealText({
171
173
  y: "50%",
172
174
  textAnchor: "middle",
173
175
  dominantBaseline: "central",
174
- className: "font-bold stroke-neutral-200 dark:stroke-neutral-800",
176
+ className: baseColor ? "font-bold" : "font-bold stroke-neutral-200 dark:stroke-neutral-800",
175
177
  style: {
176
178
  ...textStyle,
179
+ ...baseColor ? { stroke: baseColor } : {},
177
180
  opacity: hovered ? hoverOpacity : baseOpacity,
178
181
  transition: "opacity 0.3s ease"
179
182
  },
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/gradient-reveal-text.tsx"],"names":[],"mappings":"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","file":"gradient-reveal-text.js","sourcesContent":["\"use client\"\n\nimport { useRef, useEffect, useState, useId, useCallback } from \"react\"\nimport { cn } from \"./lib/utils\"\n\ninterface GradientRevealTextProps {\n /** The text to display */\n text: string\n /** Spotlight follow speed in seconds. Default: 0 (instant) */\n duration?: number\n /** Gradient colors for the reveal effect. Default: rainbow */\n colors?: string[]\n /** Base stroke opacity when not hovered. Default: 0.3 */\n baseOpacity?: number\n /** Hovered stroke opacity. Default: 0.7 */\n hoverOpacity?: number\n /** Font family for SVG text. Default: Helvetica Neue */\n fontFamily?: string\n /** Spotlight radius multiplier relative to text height. Default: 0.6 */\n spotlightSize?: number\n className?: string\n}\n\nconst DEFAULT_COLORS = [\n \"#eab308\",\n \"#ef4444\",\n \"#3b82f6\",\n \"#06b6d4\",\n \"#8b5cf6\",\n]\n\n/**\n * Large decorative text with a gradient spotlight that follows the cursor.\n *\n * Renders as an SVG that auto-sizes to fit the text with zero padding.\n * The gradient reveal effect activates on hover — a circular spotlight\n * follows the mouse, revealing rainbow-colored strokes beneath.\n *\n * @example\n * ```tsx\n * <GradientRevealText text=\"HELLO\" />\n * <GradientRevealText text=\"BRAND\" colors={[\"#ff0000\", \"#00ff00\"]} />\n * ```\n */\nfunction GradientRevealText({\n text,\n duration = 0,\n colors = DEFAULT_COLORS,\n baseOpacity = 0.3,\n hoverOpacity = 0.7,\n fontFamily = \"Helvetica Neue, Helvetica, Arial, sans-serif\",\n spotlightSize = 0.6,\n className,\n}: GradientRevealTextProps) {\n const uid = useId()\n const svgRef = useRef<SVGSVGElement>(null)\n const textRef = useRef<SVGTextElement>(null)\n const gradientRef = useRef<SVGRadialGradientElement>(null)\n\n const [vb, setVb] = useState({ x: 0, y: 0, w: 100, h: 20 })\n const [measured, setMeasured] = useState(false)\n const [hovered, setHovered] = useState(false)\n\n // Target position (where cursor is) and current animated position\n const targetPos = useRef({ cx: 0.5, cy: 0.5 })\n const currentPos = useRef({ cx: 0.5, cy: 0.5 })\n const rafId = useRef<number>(0)\n\n // Measure text bbox → set viewBox to fit exactly\n const measure = useCallback(() => {\n const el = textRef.current\n if (!el) return\n const bbox = el.getBBox()\n if (bbox.width === 0) return\n\n setVb({ x: bbox.x, y: bbox.y, w: bbox.width, h: bbox.height })\n setMeasured(true)\n }, [])\n\n useEffect(() => {\n measure()\n document.fonts?.ready?.then(measure)\n }, [text, measure])\n\n // Update the SVG gradient attributes directly (no React re-render)\n const applyGradientPos = useCallback((cx: number, cy: number) => {\n const el = gradientRef.current\n if (!el) return\n const svgCx = vb.x + cx * vb.w\n const svgCy = vb.y + cy * vb.h\n el.setAttribute(\"cx\", String(svgCx))\n el.setAttribute(\"cy\", String(svgCy))\n }, [vb])\n\n // RAF loop for smooth follow\n useEffect(() => {\n if (duration <= 0) return\n\n // Lerp factor: higher = faster catch-up. Derived from duration.\n const speed = 1 - Math.pow(0.001, 1 / (duration * 60))\n\n const tick = () => {\n const cur = currentPos.current\n const tgt = targetPos.current\n cur.cx += (tgt.cx - cur.cx) * speed\n cur.cy += (tgt.cy - cur.cy) * speed\n applyGradientPos(cur.cx, cur.cy)\n rafId.current = requestAnimationFrame(tick)\n }\n\n rafId.current = requestAnimationFrame(tick)\n return () => cancelAnimationFrame(rafId.current)\n }, [duration, applyGradientPos])\n\n const updatePos = (e: React.MouseEvent<SVGSVGElement>) => {\n const svg = svgRef.current\n if (!svg) return\n const rect = svg.getBoundingClientRect()\n const cx = (e.clientX - rect.left) / rect.width\n const cy = (e.clientY - rect.top) / rect.height\n targetPos.current = { cx, cy }\n\n // If no smooth follow, apply instantly\n if (duration <= 0) {\n currentPos.current = { cx, cy }\n applyGradientPos(cx, cy)\n }\n }\n\n const handleMouseEnter = (e: React.MouseEvent<SVGSVGElement>) => {\n // Snap to entry point — no lerp on first frame\n const svg = svgRef.current\n if (svg) {\n const rect = svg.getBoundingClientRect()\n const cx = (e.clientX - rect.left) / rect.width\n const cy = (e.clientY - rect.top) / rect.height\n targetPos.current = { cx, cy }\n currentPos.current = { cx, cy }\n applyGradientPos(cx, cy)\n }\n setHovered(true)\n }\n\n // Derived values\n const spotlightR = vb.h * spotlightSize\n const strokeW = vb.h * 0.015\n const initCx = vb.x + 0.5 * vb.w\n const initCy = vb.y + 0.5 * vb.h\n\n // Unique SVG IDs\n const gradientId = `grad-${uid}`\n const maskId = `mask-${uid}`\n const revealId = `reveal-${uid}`\n\n // Evenly distribute color stops\n const stops = colors.map((color, i) => ({\n offset: `${(i / Math.max(colors.length - 1, 1)) * 100}%`,\n color,\n }))\n\n const textStyle = {\n fontSize: \"1em\",\n fontFamily,\n fill: \"none\",\n strokeWidth: strokeW,\n strokeLinejoin: \"round\" as const,\n strokeLinecap: \"round\" as const,\n paintOrder: \"stroke fill\" as const,\n }\n\n return (\n <svg\n ref={svgRef}\n data-slot=\"gradient-reveal-text\"\n width=\"100%\"\n viewBox={`${vb.x} ${vb.y} ${vb.w} ${vb.h}`}\n preserveAspectRatio=\"xMidYMid meet\"\n xmlns=\"http://www.w3.org/2000/svg\"\n onMouseEnter={handleMouseEnter}\n onMouseLeave={() => setHovered(false)}\n onMouseMove={updatePos}\n className={cn(\"select-none\", className)}\n style={{ opacity: measured ? 1 : 0 }}\n aria-hidden\n >\n <defs>\n <linearGradient id={gradientId} x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"0%\">\n {hovered &&\n stops.map((s) => (\n <stop key={s.offset} offset={s.offset} stopColor={s.color} />\n ))}\n </linearGradient>\n\n <radialGradient\n ref={gradientRef}\n id={revealId}\n gradientUnits=\"userSpaceOnUse\"\n r={spotlightR}\n cx={initCx}\n cy={initCy}\n >\n <stop offset=\"0%\" stopColor=\"white\" />\n <stop offset=\"100%\" stopColor=\"black\" />\n </radialGradient>\n\n <mask id={maskId}>\n <rect\n x={vb.x - vb.w}\n y={vb.y - vb.h}\n width={vb.w * 3}\n height={vb.h * 3}\n fill={`url(#${revealId})`}\n />\n </mask>\n </defs>\n\n {/* Hidden text for measurement */}\n <text\n ref={textRef}\n x=\"50%\"\n y=\"50%\"\n textAnchor=\"middle\"\n dominantBaseline=\"central\"\n className=\"font-bold\"\n style={{ fontSize: \"1em\", fontFamily, visibility: \"hidden\" }}\n >\n {text}\n </text>\n\n {/* Base stroke — subtle outline */}\n <text\n x=\"50%\"\n y=\"50%\"\n textAnchor=\"middle\"\n dominantBaseline=\"central\"\n className=\"font-bold stroke-neutral-200 dark:stroke-neutral-800\"\n style={{\n ...textStyle,\n opacity: hovered ? hoverOpacity : baseOpacity,\n transition: \"opacity 0.3s ease\",\n }}\n >\n {text}\n </text>\n\n {/* Gradient reveal on hover */}\n <text\n x=\"50%\"\n y=\"50%\"\n textAnchor=\"middle\"\n dominantBaseline=\"central\"\n mask={`url(#${maskId})`}\n className=\"font-bold\"\n style={{\n ...textStyle,\n stroke: `url(#${gradientId})`,\n }}\n >\n {text}\n </text>\n </svg>\n )\n}\n\nexport { GradientRevealText }\nexport type { GradientRevealTextProps }\n"]}
1
+ {"version":3,"sources":["../src/gradient-reveal-text.tsx"],"names":[],"mappings":"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","file":"gradient-reveal-text.js","sourcesContent":["\"use client\"\n\nimport { useRef, useEffect, useState, useId, useCallback } from \"react\"\nimport { cn } from \"./lib/utils\"\n\ninterface GradientRevealTextProps {\n /** The text to display */\n text: string\n /** Spotlight follow speed in seconds. Default: 0 (instant) */\n duration?: number\n /** Gradient colors for the reveal effect. Default: rainbow */\n colors?: string[]\n /** Base stroke opacity when not hovered. Default: 0.3 */\n baseOpacity?: number\n /** Hovered stroke opacity. Default: 0.7 */\n hoverOpacity?: number\n /** Font family for SVG text. Default: Helvetica Neue */\n fontFamily?: string\n /** Spotlight radius multiplier relative to text height. Default: 0.6 */\n spotlightSize?: number\n /** Stroke width in px. Default: auto (1.5% of text height) */\n strokeWidth?: number\n /** Base stroke color. Default: neutral-200 (light) / neutral-800 (dark) via Tailwind */\n baseColor?: string\n className?: string\n}\n\nconst DEFAULT_COLORS = [\n \"#eab308\",\n \"#ef4444\",\n \"#3b82f6\",\n \"#06b6d4\",\n \"#8b5cf6\",\n]\n\n/**\n * Large decorative text with a gradient spotlight that follows the cursor.\n *\n * Renders as an SVG that auto-sizes to fit the text with zero padding.\n * The gradient reveal effect activates on hover — a circular spotlight\n * follows the mouse, revealing rainbow-colored strokes beneath.\n *\n * @example\n * ```tsx\n * <GradientRevealText text=\"HELLO\" />\n * <GradientRevealText text=\"BRAND\" colors={[\"#ff0000\", \"#00ff00\"]} />\n * ```\n */\nfunction GradientRevealText({\n text,\n duration = 0,\n colors = DEFAULT_COLORS,\n baseOpacity = 0.3,\n hoverOpacity = 0.7,\n fontFamily = \"Helvetica Neue, Helvetica, Arial, sans-serif\",\n spotlightSize = 0.6,\n strokeWidth: strokeWidthPx,\n baseColor,\n className,\n}: GradientRevealTextProps) {\n const uid = useId()\n const svgRef = useRef<SVGSVGElement>(null)\n const textRef = useRef<SVGTextElement>(null)\n const gradientRef = useRef<SVGRadialGradientElement>(null)\n\n const [vb, setVb] = useState({ x: 0, y: 0, w: 100, h: 20 })\n const [measured, setMeasured] = useState(false)\n const [hovered, setHovered] = useState(false)\n\n // Target position (where cursor is) and current animated position\n const targetPos = useRef({ cx: 0.5, cy: 0.5 })\n const currentPos = useRef({ cx: 0.5, cy: 0.5 })\n const rafId = useRef<number>(0)\n\n // Measure text bbox → set viewBox to fit exactly\n const measure = useCallback(() => {\n const el = textRef.current\n if (!el) return\n const bbox = el.getBBox()\n if (bbox.width === 0) return\n\n setVb({ x: bbox.x, y: bbox.y, w: bbox.width, h: bbox.height })\n setMeasured(true)\n }, [])\n\n useEffect(() => {\n measure()\n document.fonts?.ready?.then(measure)\n }, [text, measure])\n\n // Update the SVG gradient attributes directly (no React re-render)\n const applyGradientPos = useCallback((cx: number, cy: number) => {\n const el = gradientRef.current\n if (!el) return\n const svgCx = vb.x + cx * vb.w\n const svgCy = vb.y + cy * vb.h\n el.setAttribute(\"cx\", String(svgCx))\n el.setAttribute(\"cy\", String(svgCy))\n }, [vb])\n\n // RAF loop for smooth follow\n useEffect(() => {\n if (duration <= 0) return\n\n // Lerp factor: higher = faster catch-up. Derived from duration.\n const speed = 1 - Math.pow(0.001, 1 / (duration * 60))\n\n const tick = () => {\n const cur = currentPos.current\n const tgt = targetPos.current\n cur.cx += (tgt.cx - cur.cx) * speed\n cur.cy += (tgt.cy - cur.cy) * speed\n applyGradientPos(cur.cx, cur.cy)\n rafId.current = requestAnimationFrame(tick)\n }\n\n rafId.current = requestAnimationFrame(tick)\n return () => cancelAnimationFrame(rafId.current)\n }, [duration, applyGradientPos])\n\n const updatePos = (e: React.MouseEvent<SVGSVGElement>) => {\n const svg = svgRef.current\n if (!svg) return\n const rect = svg.getBoundingClientRect()\n const cx = (e.clientX - rect.left) / rect.width\n const cy = (e.clientY - rect.top) / rect.height\n targetPos.current = { cx, cy }\n\n // If no smooth follow, apply instantly\n if (duration <= 0) {\n currentPos.current = { cx, cy }\n applyGradientPos(cx, cy)\n }\n }\n\n const handleMouseEnter = (e: React.MouseEvent<SVGSVGElement>) => {\n // Snap to entry point — no lerp on first frame\n const svg = svgRef.current\n if (svg) {\n const rect = svg.getBoundingClientRect()\n const cx = (e.clientX - rect.left) / rect.width\n const cy = (e.clientY - rect.top) / rect.height\n targetPos.current = { cx, cy }\n currentPos.current = { cx, cy }\n applyGradientPos(cx, cy)\n }\n setHovered(true)\n }\n\n // Derived values\n const spotlightR = vb.h * spotlightSize\n const strokeW = strokeWidthPx ?? vb.h * 0.015\n const initCx = vb.x + 0.5 * vb.w\n const initCy = vb.y + 0.5 * vb.h\n\n // Unique SVG IDs\n const gradientId = `grad-${uid}`\n const maskId = `mask-${uid}`\n const revealId = `reveal-${uid}`\n\n // Evenly distribute color stops\n const stops = colors.map((color, i) => ({\n offset: `${(i / Math.max(colors.length - 1, 1)) * 100}%`,\n color,\n }))\n\n const textStyle = {\n fontSize: \"1em\",\n fontFamily,\n fill: \"none\",\n strokeWidth: strokeW,\n strokeLinejoin: \"round\" as const,\n strokeLinecap: \"round\" as const,\n paintOrder: \"stroke fill\" as const,\n }\n\n return (\n <svg\n ref={svgRef}\n data-slot=\"gradient-reveal-text\"\n width=\"100%\"\n viewBox={`${vb.x} ${vb.y} ${vb.w} ${vb.h}`}\n preserveAspectRatio=\"xMidYMid meet\"\n xmlns=\"http://www.w3.org/2000/svg\"\n onMouseEnter={handleMouseEnter}\n onMouseLeave={() => setHovered(false)}\n onMouseMove={updatePos}\n className={cn(\"select-none\", className)}\n style={{ opacity: measured ? 1 : 0 }}\n aria-hidden\n >\n <defs>\n <linearGradient id={gradientId} x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"0%\">\n {hovered &&\n stops.map((s) => (\n <stop key={s.offset} offset={s.offset} stopColor={s.color} />\n ))}\n </linearGradient>\n\n <radialGradient\n ref={gradientRef}\n id={revealId}\n gradientUnits=\"userSpaceOnUse\"\n r={spotlightR}\n cx={initCx}\n cy={initCy}\n >\n <stop offset=\"0%\" stopColor=\"white\" />\n <stop offset=\"100%\" stopColor=\"black\" />\n </radialGradient>\n\n <mask id={maskId}>\n <rect\n x={vb.x - vb.w}\n y={vb.y - vb.h}\n width={vb.w * 3}\n height={vb.h * 3}\n fill={`url(#${revealId})`}\n />\n </mask>\n </defs>\n\n {/* Hidden text for measurement */}\n <text\n ref={textRef}\n x=\"50%\"\n y=\"50%\"\n textAnchor=\"middle\"\n dominantBaseline=\"central\"\n className=\"font-bold\"\n style={{ fontSize: \"1em\", fontFamily, visibility: \"hidden\" }}\n >\n {text}\n </text>\n\n {/* Base stroke — subtle outline */}\n <text\n x=\"50%\"\n y=\"50%\"\n textAnchor=\"middle\"\n dominantBaseline=\"central\"\n className={baseColor ? \"font-bold\" : \"font-bold stroke-neutral-200 dark:stroke-neutral-800\"}\n style={{\n ...textStyle,\n ...(baseColor ? { stroke: baseColor } : {}),\n opacity: hovered ? hoverOpacity : baseOpacity,\n transition: \"opacity 0.3s ease\",\n }}\n >\n {text}\n </text>\n\n {/* Gradient reveal on hover */}\n <text\n x=\"50%\"\n y=\"50%\"\n textAnchor=\"middle\"\n dominantBaseline=\"central\"\n mask={`url(#${maskId})`}\n className=\"font-bold\"\n style={{\n ...textStyle,\n stroke: `url(#${gradientId})`,\n }}\n >\n {text}\n </text>\n </svg>\n )\n}\n\nexport { GradientRevealText }\nexport type { GradientRevealTextProps }\n"]}
@@ -19,7 +19,7 @@ declare const inputGroupAddonVariants: (props?: ({
19
19
  } & class_variance_authority_types.ClassProp) | undefined) => string;
20
20
  declare function InputGroupAddon({ className, align, ...props }: InputGroupAddonProps): react_jsx_runtime.JSX.Element;
21
21
  declare const inputGroupButtonVariants: (props?: ({
22
- size?: "sm" | "xs" | "icon-xs" | "icon-sm" | null | undefined;
22
+ size?: "xs" | "sm" | "icon-xs" | "icon-sm" | null | undefined;
23
23
  } & class_variance_authority_types.ClassProp) | undefined) => string;
24
24
  declare function InputGroupButton({ className, type, variant, size, ...props }: InputGroupButtonProps): react_jsx_runtime.JSX.Element;
25
25
  declare function InputGroupText({ className, ...props }: InputGroupTextProps): react_jsx_runtime.JSX.Element;
package/dist/item.d.ts CHANGED
@@ -8,10 +8,10 @@ import '@base-ui/react/separator';
8
8
 
9
9
  declare const itemVariants: (props?: ({
10
10
  variant?: "default" | "outline" | "muted" | null | undefined;
11
- size?: "default" | "sm" | "xs" | null | undefined;
11
+ size?: "default" | "xs" | "sm" | null | undefined;
12
12
  } & class_variance_authority_types.ClassProp) | undefined) => string;
13
13
  declare const itemMediaVariants: (props?: ({
14
- variant?: "image" | "default" | "icon" | null | undefined;
14
+ variant?: "default" | "image" | "icon" | null | undefined;
15
15
  } & class_variance_authority_types.ClassProp) | undefined) => string;
16
16
  type ItemGroupProps = React.ComponentProps<"div">;
17
17
  type ItemSeparatorProps = React.ComponentProps<typeof Separator>;
package/dist/tabs.d.ts CHANGED
@@ -5,7 +5,7 @@ import { Tabs as Tabs$1 } from '@base-ui/react/tabs';
5
5
  import { VariantProps } from 'class-variance-authority';
6
6
 
7
7
  declare const tabsListVariants: (props?: ({
8
- variant?: "line" | "default" | null | undefined;
8
+ variant?: "default" | "line" | null | undefined;
9
9
  } & class_variance_authority_types.ClassProp) | undefined) => string;
10
10
  type TabsProps = React.ComponentProps<typeof Tabs$1.Root>;
11
11
  type TabsListBaseProps = React.ComponentProps<typeof Tabs$1.List>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@waveso/ui",
3
- "version": "0.0.9",
3
+ "version": "0.0.10",
4
4
  "description": "Wave UI component library built on Base UI and Tailwind CSS",
5
5
  "type": "module",
6
6
  "sideEffects": [