@spark-ui/components 17.1.0 → 17.1.1

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.
@@ -1,7 +1,7 @@
1
- import { ToggleGroup } from '@base-ui/react/toggle-group';
1
+ import { RadioGroup } from '@base-ui/react/radio-group';
2
2
  import { ComponentProps, Ref } from 'react';
3
3
  import { SegmentedControlStylesProps } from './SegmentedControl.styles';
4
- export interface SegmentedControlProps extends Omit<ComponentProps<typeof ToggleGroup>, 'multiple' | 'value' | 'defaultValue' | 'onValueChange'>, SegmentedControlStylesProps {
4
+ export interface SegmentedControlProps extends Omit<ComponentProps<typeof RadioGroup>, 'value' | 'defaultValue' | 'onValueChange'>, SegmentedControlStylesProps {
5
5
  /**
6
6
  * The controlled selected value.
7
7
  */
@@ -13,10 +13,10 @@ export interface SegmentedControlProps extends Omit<ComponentProps<typeof Toggle
13
13
  /**
14
14
  * Callback fired when the selected value changes.
15
15
  */
16
- onValueChange?: (value: string | null) => void;
16
+ onValueChange?: (value: string) => void;
17
17
  ref?: Ref<HTMLDivElement>;
18
18
  }
19
19
  export declare const SegmentedControl: {
20
- ({ value, defaultValue, onValueChange, size, className, children, ref, ...rest }: SegmentedControlProps): import("react/jsx-runtime").JSX.Element;
20
+ ({ value, defaultValue, onValueChange, className, children, ref, ...rest }: SegmentedControlProps): import("react/jsx-runtime").JSX.Element;
21
21
  displayName: string;
22
22
  };
@@ -1,7 +1,5 @@
1
1
  import { VariantProps } from 'class-variance-authority';
2
2
  export declare const rootStyles: (props?: import('class-variance-authority/types').ClassProp | undefined) => string;
3
- export declare const itemStyles: (props?: ({
4
- size?: "sm" | "md" | "lg" | null | undefined;
5
- } & import('class-variance-authority/types').ClassProp) | undefined) => string;
3
+ export declare const itemStyles: (props?: import('class-variance-authority/types').ClassProp | undefined) => string;
6
4
  export declare const indicatorStyles: (props?: import('class-variance-authority/types').ClassProp | undefined) => string;
7
5
  export type SegmentedControlStylesProps = VariantProps<typeof itemStyles>;
@@ -1,7 +1,6 @@
1
1
  import { RefObject } from 'react';
2
- import { SegmentedControlStylesProps } from './SegmentedControl.styles';
3
- export interface SegmentedControlContextInterface extends Required<Pick<SegmentedControlStylesProps, 'size'>> {
4
- pressedValue: string | null;
2
+ export interface SegmentedControlContextInterface {
3
+ checkedValue: string | null;
5
4
  containerRef: RefObject<HTMLDivElement | null>;
6
5
  }
7
6
  export declare const SegmentedControlContext: import('react').Context<SegmentedControlContextInterface>;
@@ -1,6 +1,6 @@
1
- import { Toggle } from '@base-ui/react/toggle';
1
+ import { Radio } from '@base-ui/react/radio';
2
2
  import { ComponentProps, Ref } from 'react';
3
- export interface SegmentedControlItemProps extends Omit<ComponentProps<typeof Toggle>, 'value'> {
3
+ export interface SegmentedControlItemProps extends Omit<ComponentProps<typeof Radio.Root>, 'value'> {
4
4
  /**
5
5
  * A unique value that identifies this item within the segmented control.
6
6
  */
@@ -10,7 +10,7 @@ export interface SegmentedControlItemProps extends Omit<ComponentProps<typeof To
10
10
  * @default false
11
11
  */
12
12
  disabled?: boolean;
13
- ref?: Ref<HTMLButtonElement>;
13
+ ref?: Ref<HTMLElement>;
14
14
  }
15
15
  export declare const SegmentedControlItem: {
16
16
  ({ value, disabled, children, className, ref, ...rest }: SegmentedControlItemProps): import("react/jsx-runtime").JSX.Element;
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const u=require("react/jsx-runtime"),I=require("@base-ui/react/toggle-group"),N=require("@spark-ui/hooks/use-merge-refs"),s=require("react"),f=require("class-variance-authority"),j=require("@base-ui/react/toggle"),q=f.cva(["group inline-grid grid-flow-col auto-cols-fr","relative items-stretch min-w-max","rounded-xl","bg-surface border-md border-outline","p-sz-2"]),E=f.cva(["relative z-raised min-h-sz-44 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus focus-visible:ring-inset","flex flex-none items-center justify-center flex-col","px-lg","rounded-xl","cursor-pointer select-none","font-medium","transition-colors duration-150","outline-none","focus-visible:u-outline","disabled:cursor-not-allowed disabled:opacity-dim-3","not-disabled:hover:text-on-surface","aria-pressed:text-on-support-container","aria-pressed:font-bold"],{variants:{size:{sm:["h-sz-32 min-w-sz-32 text-caption"],md:["h-sz-36 min-w-sz-36 text-body-2"],lg:["h-sz-40 min-w-sz-40 text-body-1"]}},defaultVariants:{size:"md"}}),k=f.cva(["absolute z-base","rounded-xl","bg-support-container border-md border-support","transition-[left,top,width,height] duration-200 ease-in-out","pointer-events-none"]),b=s.createContext({}),v=()=>{const e=s.useContext(b);if(!e)throw Error("useSegmentedControlContext must be used within a SegmentedControlContext Provider");return e},M=e=>{let o=null;return s.Children.forEach(e,t=>{o===null&&s.isValidElement(t)&&typeof t.props.value=="string"&&(o=t.props.value)}),o},S=({value:e,defaultValue:o,onValueChange:t,size:r="md",className:l,children:n,ref:a,...p})=>{const d=s.useRef(null),[m,g]=s.useState(()=>o??M(n)),i=e!==void 0,c=i?e??null:m,w=V=>{const C=V[0]??null;i||g(C),t?.(C)},z=N.useMergeRefs(d,a),R=c!=null?[c]:[];return u.jsx(b.Provider,{value:{pressedValue:c,containerRef:d,size:r??"md"},children:u.jsx(I.ToggleGroup,{ref:z,multiple:!1,value:R,onValueChange:w,"data-spark-component":"segmented-control",className:q({className:l}),...p,children:n})})};S.displayName="SegmentedControl";const h=({className:e,ref:o,...t})=>{const{pressedValue:r,containerRef:l}=v(),[n,a]=s.useState(null);if(s.useEffect(()=>{const d=l.current;if(!d)return;const m=r?d.querySelector(`[data-value="${r}"]`):null;if(!m){a(null);return}const g=d.getBoundingClientRect(),i=m.getBoundingClientRect(),c=2;a({left:i.left-g.left-c,top:i.top-g.top-c,width:i.width,height:i.height})},[r,l]),!n)return null;const p={left:n.left,top:n.top,width:n.width,height:n.height};return u.jsx("span",{ref:o,"data-spark-component":"segmented-control-indicator","aria-hidden":!0,className:k({className:e}),style:p,...t})};h.displayName="SegmentedControl.Indicator";const x=({value:e,disabled:o=!1,children:t,className:r,ref:l,...n})=>{const{size:a}=v();return u.jsxs(j.Toggle,{ref:l,"data-spark-component":"segmented-control-item","data-value":e,value:e,disabled:o,className:E({size:a,className:r}),...n,children:[t,u.jsx("span",{"aria-hidden":"true",className:"bg-success pointer-events-none h-0 overflow-hidden font-bold content-[attr(data-text)/'']",children:t})]})};x.displayName="SegmentedControl.Item";const y=Object.assign(S,{Item:x,Indicator:h});y.displayName="SegmentedControl";x.displayName="SegmentedControl.Item";h.displayName="SegmentedControl.Indicator";exports.SegmentedControl=y;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const u=require("react/jsx-runtime"),k=require("@base-ui/react/radio-group"),E=require("@spark-ui/components/form-field"),F=require("@spark-ui/hooks/use-merge-refs"),r=require("react"),g=require("class-variance-authority"),z=require("@base-ui/react/radio"),B=g.cva(["default:self-start","group inline-grid grid-flow-col auto-cols-fr","relative items-stretch min-w-max","rounded-xl p-sm","bg-surface border-sm border-outline"]),M=g.cva(["relative z-raised min-h-sz-44 focus-visible:outline-none","flex flex-none items-center justify-center flex-col","default:px-lg default:py-md","rounded-[20px]","cursor-pointer select-none","font-medium","transition-colors duration-150","outline-none","focus-visible:u-outline","data-disabled:cursor-not-allowed data-disabled:opacity-dim-3","data-checked:text-on-support-container","data-checked:font-bold"]),P=g.cva(["absolute z-base","rounded-[20px]","bg-support-container border-md border-support","group-has-focus-visible:border-focus","transition-[left,top,width,height] duration-200 ease-in-out","pointer-events-none"]),v=r.createContext({}),G=()=>{const e=r.useContext(v);if(!e)throw Error("useSegmentedControlContext must be used within a SegmentedControlContext Provider");return e},O=e=>{let t=null;return r.Children.forEach(e,o=>{t===null&&r.isValidElement(o)&&typeof o.props.value=="string"&&(t=o.props.value)}),t},x=({value:e,defaultValue:t,onValueChange:o,className:s,children:i,ref:n,...m})=>{const f=r.useRef(null),d=F.useMergeRefs(f,n),c=O(i),a=e!==void 0,[l,p]=r.useState(()=>t??c),y=a?e??null:l,R=j=>{const b=j;a||p(b),o?.(b)},{labelId:I,description:w,isRequired:V,isInvalid:q,name:N}=E.useFormFieldControl();return u.jsx(v.Provider,{value:{checkedValue:y,containerRef:f},children:u.jsx(k.RadioGroup,{ref:d,value:a?e:void 0,defaultValue:a?void 0:t??c??void 0,onValueChange:R,"data-spark-component":"segmented-control",className:B({className:s}),"aria-labelledby":I,"aria-describedby":w,"aria-required":V||void 0,"aria-invalid":q||void 0,name:N,...m,children:i})})};x.displayName="SegmentedControl";const h=({className:e,ref:t,...o})=>{const{checkedValue:s,containerRef:i}=G(),[n,m]=r.useState(null);if(r.useEffect(()=>{const d=i.current;if(!d)return;const c=s?d.querySelector(`[data-value="${s}"]`):null;if(!c){m(null);return}const a=d.getBoundingClientRect(),l=c.getBoundingClientRect(),p=1;m({left:l.left-a.left-p,top:l.top-a.top-p,width:l.width,height:l.height})},[s,i]),!n)return null;const f={left:n.left,top:n.top,width:n.width,height:n.height};return u.jsx("span",{ref:t,"data-spark-component":"segmented-control-indicator","aria-hidden":!0,className:P({className:e}),style:f,...o})};h.displayName="SegmentedControl.Indicator";const C=({value:e,disabled:t=!1,children:o,className:s,ref:i,...n})=>u.jsxs(z.Radio.Root,{ref:i,"data-spark-component":"segmented-control-item","data-value":e,value:e,disabled:t,className:M({className:s}),...n,children:[o,u.jsx("span",{"aria-hidden":"true",className:"bg-success pointer-events-none h-0 overflow-hidden font-bold content-[attr(data-text)/'']",children:o})]});C.displayName="SegmentedControl.Item";const S=Object.assign(x,{Item:C,Indicator:h});S.displayName="SegmentedControl";C.displayName="SegmentedControl.Item";h.displayName="SegmentedControl.Indicator";exports.SegmentedControl=S;
2
2
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/segmented-control/SegmentedControl.styles.ts","../../src/segmented-control/SegmentedControlContext.tsx","../../src/segmented-control/SegmentedControl.tsx","../../src/segmented-control/SegmentedControlIndicator.tsx","../../src/segmented-control/SegmentedControlItem.tsx","../../src/segmented-control/index.ts"],"sourcesContent":["import { cva, VariantProps } from 'class-variance-authority'\n\nexport const rootStyles = cva([\n 'group inline-grid grid-flow-col auto-cols-fr',\n 'relative items-stretch min-w-max',\n 'rounded-xl',\n 'bg-surface border-md border-outline',\n 'p-sz-2',\n])\n\nexport const itemStyles = cva(\n [\n 'relative z-raised min-h-sz-44 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus focus-visible:ring-inset',\n 'flex flex-none items-center justify-center flex-col',\n 'px-lg',\n 'rounded-xl',\n 'cursor-pointer select-none',\n 'font-medium',\n 'transition-colors duration-150',\n 'outline-none',\n 'focus-visible:u-outline',\n 'disabled:cursor-not-allowed disabled:opacity-dim-3',\n 'not-disabled:hover:text-on-surface',\n 'aria-pressed:text-on-support-container',\n 'aria-pressed:font-bold',\n ],\n {\n variants: {\n /**\n * Change the size of the segmented control\n * @default md\n */\n size: {\n sm: ['h-sz-32 min-w-sz-32 text-caption'],\n md: ['h-sz-36 min-w-sz-36 text-body-2'],\n lg: ['h-sz-40 min-w-sz-40 text-body-1'],\n },\n },\n defaultVariants: {\n size: 'md',\n },\n }\n)\n\nexport const indicatorStyles = cva([\n 'absolute z-base',\n 'rounded-xl',\n 'bg-support-container border-md border-support',\n 'transition-[left,top,width,height] duration-200 ease-in-out',\n 'pointer-events-none',\n])\n\nexport type SegmentedControlStylesProps = VariantProps<typeof itemStyles>\n","import { createContext, RefObject, useContext } from 'react'\n\nimport type { SegmentedControlStylesProps } from './SegmentedControl.styles'\n\nexport interface SegmentedControlContextInterface\n extends Required<Pick<SegmentedControlStylesProps, 'size'>> {\n pressedValue: string | null\n containerRef: RefObject<HTMLDivElement | null>\n}\n\nexport const SegmentedControlContext = createContext<SegmentedControlContextInterface>(\n {} as SegmentedControlContextInterface\n)\n\nexport const useSegmentedControlContext = () => {\n const context = useContext(SegmentedControlContext)\n\n if (!context) {\n throw Error('useSegmentedControlContext must be used within a SegmentedControlContext Provider')\n }\n\n return context\n}\n","import { ToggleGroup } from '@base-ui/react/toggle-group'\nimport { useMergeRefs } from '@spark-ui/hooks/use-merge-refs'\nimport { Children, type ComponentProps, isValidElement, Ref, useRef, useState } from 'react'\n\nimport type { SegmentedControlStylesProps } from './SegmentedControl.styles'\nimport { rootStyles } from './SegmentedControl.styles'\nimport { SegmentedControlContext } from './SegmentedControlContext'\n\nexport interface SegmentedControlProps\n extends Omit<\n ComponentProps<typeof ToggleGroup>,\n 'multiple' | 'value' | 'defaultValue' | 'onValueChange'\n >,\n SegmentedControlStylesProps {\n /**\n * The controlled selected value.\n */\n value?: string\n /**\n * The uncontrolled default selected value.\n */\n defaultValue?: string\n /**\n * Callback fired when the selected value changes.\n */\n onValueChange?: (value: string | null) => void\n ref?: Ref<HTMLDivElement>\n}\n\nconst getFirstItemValue = (children: React.ReactNode): string | null => {\n let firstValue: string | null = null\n\n Children.forEach(children, child => {\n if (firstValue !== null) return\n if (isValidElement(child) && typeof (child.props as { value?: string }).value === 'string') {\n firstValue = (child.props as { value: string }).value\n }\n })\n\n return firstValue\n}\n\nexport const SegmentedControl = ({\n value,\n defaultValue,\n onValueChange,\n size = 'md',\n className,\n children,\n ref,\n ...rest\n}: SegmentedControlProps) => {\n const containerRef = useRef<HTMLDivElement | null>(null)\n const [internalValue, setInternalValue] = useState<string | null>(\n () => defaultValue ?? getFirstItemValue(children)\n )\n\n const isControlled = value !== undefined\n const pressedValue = isControlled ? (value ?? null) : internalValue\n\n const handleValueChange = (newValues: unknown[]) => {\n const next = (newValues[0] as string) ?? null\n\n if (!isControlled) {\n setInternalValue(next)\n }\n\n onValueChange?.(next)\n }\n\n const mergedRef = useMergeRefs(containerRef, ref)\n const groupValue = pressedValue != null ? [pressedValue] : []\n\n return (\n <SegmentedControlContext.Provider\n value={{\n pressedValue,\n containerRef,\n size: size ?? 'md',\n }}\n >\n <ToggleGroup\n ref={mergedRef}\n multiple={false}\n value={groupValue}\n onValueChange={handleValueChange}\n data-spark-component=\"segmented-control\"\n className={rootStyles({ className })}\n {...rest}\n >\n {children}\n </ToggleGroup>\n </SegmentedControlContext.Provider>\n )\n}\n\nSegmentedControl.displayName = 'SegmentedControl'\n","import { type ComponentProps, type CSSProperties, Ref, useEffect, useState } from 'react'\n\nimport { indicatorStyles } from './SegmentedControl.styles'\nimport { useSegmentedControlContext } from './SegmentedControlContext'\n\ninterface IndicatorRect {\n left: number\n top: number\n width: number\n height: number\n}\n\nexport interface SegmentedControlIndicatorProps extends ComponentProps<'span'> {\n ref?: Ref<HTMLSpanElement>\n}\n\nexport const SegmentedControlIndicator = ({\n className,\n ref,\n ...rest\n}: SegmentedControlIndicatorProps) => {\n const { pressedValue, containerRef } = useSegmentedControlContext()\n const [rect, setRect] = useState<IndicatorRect | null>(null)\n\n useEffect(() => {\n const container = containerRef.current\n\n if (!container) {\n return\n }\n\n const selectedItem = pressedValue\n ? container.querySelector<HTMLElement>(`[data-value=\"${pressedValue}\"]`)\n : null\n\n if (!selectedItem) {\n setRect(null)\n\n return\n }\n\n const containerRect = container.getBoundingClientRect()\n const itemRect = selectedItem.getBoundingClientRect()\n\n const borderWidth = 2\n\n setRect({\n left: itemRect.left - containerRect.left - borderWidth,\n top: itemRect.top - containerRect.top - borderWidth,\n width: itemRect.width,\n height: itemRect.height,\n })\n }, [pressedValue, containerRef])\n\n if (!rect) return null\n\n const style: CSSProperties = {\n left: rect.left,\n top: rect.top,\n width: rect.width,\n height: rect.height,\n }\n\n return (\n <span\n ref={ref}\n data-spark-component=\"segmented-control-indicator\"\n aria-hidden\n className={indicatorStyles({ className })}\n style={style}\n {...rest}\n />\n )\n}\n\nSegmentedControlIndicator.displayName = 'SegmentedControl.Indicator'\n","import { Toggle } from '@base-ui/react/toggle'\nimport { type ComponentProps, Ref } from 'react'\n\nimport { itemStyles } from './SegmentedControl.styles'\nimport { useSegmentedControlContext } from './SegmentedControlContext'\n\nexport interface SegmentedControlItemProps extends Omit<ComponentProps<typeof Toggle>, 'value'> {\n /**\n * A unique value that identifies this item within the segmented control.\n */\n value: string\n /**\n * When true, prevents the user from interacting with this item.\n * @default false\n */\n disabled?: boolean\n ref?: Ref<HTMLButtonElement>\n}\n\nexport const SegmentedControlItem = ({\n value,\n disabled = false,\n children,\n className,\n ref,\n ...rest\n}: SegmentedControlItemProps) => {\n const { size } = useSegmentedControlContext()\n\n return (\n <Toggle\n ref={ref}\n data-spark-component=\"segmented-control-item\"\n data-value={value}\n value={value}\n disabled={disabled}\n className={itemStyles({ size, className })}\n {...rest}\n >\n {children}\n <span\n aria-hidden=\"true\"\n className=\"bg-success pointer-events-none h-0 overflow-hidden font-bold content-[attr(data-text)/'']\"\n >\n {children}\n </span>\n </Toggle>\n )\n}\n\nSegmentedControlItem.displayName = 'SegmentedControl.Item'\n","import { SegmentedControl as Root } from './SegmentedControl'\nimport { SegmentedControlIndicator as Indicator } from './SegmentedControlIndicator'\nimport { SegmentedControlItem as Item } from './SegmentedControlItem'\n\nexport const SegmentedControl: typeof Root & {\n Item: typeof Item\n Indicator: typeof Indicator\n} = Object.assign(Root, {\n Item,\n Indicator,\n})\n\nSegmentedControl.displayName = 'SegmentedControl'\nItem.displayName = 'SegmentedControl.Item'\nIndicator.displayName = 'SegmentedControl.Indicator'\n\nexport type { SegmentedControlProps } from './SegmentedControl'\nexport type { SegmentedControlItemProps } from './SegmentedControlItem'\nexport type { SegmentedControlIndicatorProps } from './SegmentedControlIndicator'\n"],"names":["rootStyles","cva","itemStyles","indicatorStyles","SegmentedControlContext","createContext","useSegmentedControlContext","context","useContext","getFirstItemValue","children","firstValue","Children","child","isValidElement","SegmentedControl","value","defaultValue","onValueChange","size","className","ref","rest","containerRef","useRef","internalValue","setInternalValue","useState","isControlled","pressedValue","handleValueChange","newValues","next","mergedRef","useMergeRefs","groupValue","jsx","ToggleGroup","SegmentedControlIndicator","rect","setRect","useEffect","container","selectedItem","containerRect","itemRect","borderWidth","style","SegmentedControlItem","disabled","jsxs","Toggle","Root","Item","Indicator"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../src/segmented-control/SegmentedControl.styles.ts","../../src/segmented-control/SegmentedControlContext.tsx","../../src/segmented-control/SegmentedControl.tsx","../../src/segmented-control/SegmentedControlIndicator.tsx","../../src/segmented-control/SegmentedControlItem.tsx","../../src/segmented-control/index.ts"],"sourcesContent":["import { cva, VariantProps } from 'class-variance-authority'\n\nexport const rootStyles = cva([\n 'default:self-start',\n 'group inline-grid grid-flow-col auto-cols-fr',\n 'relative items-stretch min-w-max',\n 'rounded-xl p-sm',\n 'bg-surface border-sm border-outline',\n])\n\nexport const itemStyles = cva([\n 'relative z-raised min-h-sz-44 focus-visible:outline-none',\n 'flex flex-none items-center justify-center flex-col',\n 'default:px-lg default:py-md',\n 'rounded-[20px]',\n 'cursor-pointer select-none',\n 'font-medium',\n 'transition-colors duration-150',\n 'outline-none',\n 'focus-visible:u-outline',\n 'data-disabled:cursor-not-allowed data-disabled:opacity-dim-3',\n 'data-checked:text-on-support-container',\n 'data-checked:font-bold',\n])\n\nexport const indicatorStyles = cva([\n 'absolute z-base',\n 'rounded-[20px]',\n 'bg-support-container border-md border-support',\n 'group-has-focus-visible:border-focus',\n 'transition-[left,top,width,height] duration-200 ease-in-out',\n 'pointer-events-none',\n])\n\nexport type SegmentedControlStylesProps = VariantProps<typeof itemStyles>\n","import { createContext, RefObject, useContext } from 'react'\n\nexport interface SegmentedControlContextInterface {\n checkedValue: string | null\n containerRef: RefObject<HTMLDivElement | null>\n}\n\nexport const SegmentedControlContext = createContext<SegmentedControlContextInterface>(\n {} as SegmentedControlContextInterface\n)\n\nexport const useSegmentedControlContext = () => {\n const context = useContext(SegmentedControlContext)\n\n if (!context) {\n throw Error('useSegmentedControlContext must be used within a SegmentedControlContext Provider')\n }\n\n return context\n}\n","import { RadioGroup } from '@base-ui/react/radio-group'\nimport { useFormFieldControl } from '@spark-ui/components/form-field'\nimport { useMergeRefs } from '@spark-ui/hooks/use-merge-refs'\nimport { Children, type ComponentProps, isValidElement, Ref, useRef, useState } from 'react'\n\nimport type { SegmentedControlStylesProps } from './SegmentedControl.styles'\nimport { rootStyles } from './SegmentedControl.styles'\nimport { SegmentedControlContext } from './SegmentedControlContext'\n\nexport interface SegmentedControlProps\n extends Omit<ComponentProps<typeof RadioGroup>, 'value' | 'defaultValue' | 'onValueChange'>,\n SegmentedControlStylesProps {\n /**\n * The controlled selected value.\n */\n value?: string\n /**\n * The uncontrolled default selected value.\n */\n defaultValue?: string\n /**\n * Callback fired when the selected value changes.\n */\n onValueChange?: (value: string) => void\n ref?: Ref<HTMLDivElement>\n}\n\nconst getFirstItemValue = (children: React.ReactNode): string | null => {\n let firstValue: string | null = null\n\n Children.forEach(children, child => {\n if (firstValue !== null) return\n if (isValidElement(child) && typeof (child.props as { value?: string }).value === 'string') {\n firstValue = (child.props as { value: string }).value\n }\n })\n\n return firstValue\n}\n\nexport const SegmentedControl = ({\n value,\n defaultValue,\n onValueChange,\n className,\n children,\n ref,\n ...rest\n}: SegmentedControlProps) => {\n const containerRef = useRef<HTMLDivElement | null>(null)\n const mergedRef = useMergeRefs(containerRef, ref)\n\n const firstValue = getFirstItemValue(children)\n\n const isControlled = value !== undefined\n const [internalValue, setInternalValue] = useState<string | null>(\n () => defaultValue ?? firstValue\n )\n const checkedValue = isControlled ? (value ?? null) : internalValue\n\n const handleValueChange = (newValue: unknown) => {\n const next = newValue as string\n\n if (!isControlled) {\n setInternalValue(next)\n }\n\n onValueChange?.(next)\n }\n\n const { labelId, description, isRequired, isInvalid, name } = useFormFieldControl()\n\n return (\n <SegmentedControlContext.Provider\n value={{\n checkedValue,\n containerRef,\n }}\n >\n <RadioGroup\n ref={mergedRef}\n value={isControlled ? value : undefined}\n defaultValue={!isControlled ? (defaultValue ?? firstValue ?? undefined) : undefined}\n onValueChange={handleValueChange}\n data-spark-component=\"segmented-control\"\n className={rootStyles({ className })}\n aria-labelledby={labelId}\n aria-describedby={description}\n aria-required={isRequired || undefined}\n aria-invalid={isInvalid || undefined}\n name={name}\n {...rest}\n >\n {children}\n </RadioGroup>\n </SegmentedControlContext.Provider>\n )\n}\n\nSegmentedControl.displayName = 'SegmentedControl'\n","import { type ComponentProps, type CSSProperties, Ref, useEffect, useState } from 'react'\n\nimport { indicatorStyles } from './SegmentedControl.styles'\nimport { useSegmentedControlContext } from './SegmentedControlContext'\n\ninterface IndicatorRect {\n left: number\n top: number\n width: number\n height: number\n}\n\nexport interface SegmentedControlIndicatorProps extends ComponentProps<'span'> {\n ref?: Ref<HTMLSpanElement>\n}\n\nexport const SegmentedControlIndicator = ({\n className,\n ref,\n ...rest\n}: SegmentedControlIndicatorProps) => {\n const { checkedValue, containerRef } = useSegmentedControlContext()\n const [rect, setRect] = useState<IndicatorRect | null>(null)\n\n useEffect(() => {\n const container = containerRef.current\n\n if (!container) {\n return\n }\n\n const selectedItem = checkedValue\n ? container.querySelector<HTMLElement>(`[data-value=\"${checkedValue}\"]`)\n : null\n\n if (!selectedItem) {\n setRect(null)\n\n return\n }\n\n const containerRect = container.getBoundingClientRect()\n const itemRect = selectedItem.getBoundingClientRect()\n\n const rootBorderWidth = 1\n\n setRect({\n left: itemRect.left - containerRect.left - rootBorderWidth,\n top: itemRect.top - containerRect.top - rootBorderWidth,\n width: itemRect.width,\n height: itemRect.height,\n })\n }, [checkedValue, containerRef])\n\n if (!rect) return null\n\n const style: CSSProperties = {\n left: rect.left,\n top: rect.top,\n width: rect.width,\n height: rect.height,\n }\n\n return (\n <span\n ref={ref}\n data-spark-component=\"segmented-control-indicator\"\n aria-hidden\n className={indicatorStyles({ className })}\n style={style}\n {...rest}\n />\n )\n}\n\nSegmentedControlIndicator.displayName = 'SegmentedControl.Indicator'\n","import { Radio } from '@base-ui/react/radio'\nimport { type ComponentProps, Ref } from 'react'\n\nimport { itemStyles } from './SegmentedControl.styles'\n\nexport interface SegmentedControlItemProps\n extends Omit<ComponentProps<typeof Radio.Root>, 'value'> {\n /**\n * A unique value that identifies this item within the segmented control.\n */\n value: string\n /**\n * When true, prevents the user from interacting with this item.\n * @default false\n */\n disabled?: boolean\n ref?: Ref<HTMLElement>\n}\n\nexport const SegmentedControlItem = ({\n value,\n disabled = false,\n children,\n className,\n ref,\n ...rest\n}: SegmentedControlItemProps) => {\n return (\n <Radio.Root\n ref={ref}\n data-spark-component=\"segmented-control-item\"\n data-value={value}\n value={value}\n disabled={disabled}\n className={itemStyles({ className })}\n {...rest}\n >\n {children}\n <span\n aria-hidden=\"true\"\n className=\"bg-success pointer-events-none h-0 overflow-hidden font-bold content-[attr(data-text)/'']\"\n >\n {children}\n </span>\n </Radio.Root>\n )\n}\n\nSegmentedControlItem.displayName = 'SegmentedControl.Item'\n","import { SegmentedControl as Root } from './SegmentedControl'\nimport { SegmentedControlIndicator as Indicator } from './SegmentedControlIndicator'\nimport { SegmentedControlItem as Item } from './SegmentedControlItem'\n\nexport const SegmentedControl: typeof Root & {\n Item: typeof Item\n Indicator: typeof Indicator\n} = Object.assign(Root, {\n Item,\n Indicator,\n})\n\nSegmentedControl.displayName = 'SegmentedControl'\nItem.displayName = 'SegmentedControl.Item'\nIndicator.displayName = 'SegmentedControl.Indicator'\n\nexport type { SegmentedControlProps } from './SegmentedControl'\nexport type { SegmentedControlItemProps } from './SegmentedControlItem'\nexport type { SegmentedControlIndicatorProps } from './SegmentedControlIndicator'\n"],"names":["rootStyles","cva","itemStyles","indicatorStyles","SegmentedControlContext","createContext","useSegmentedControlContext","context","useContext","getFirstItemValue","children","firstValue","Children","child","isValidElement","SegmentedControl","value","defaultValue","onValueChange","className","ref","rest","containerRef","useRef","mergedRef","useMergeRefs","isControlled","internalValue","setInternalValue","useState","checkedValue","handleValueChange","newValue","next","labelId","description","isRequired","isInvalid","name","useFormFieldControl","jsx","RadioGroup","SegmentedControlIndicator","rect","setRect","useEffect","container","selectedItem","containerRect","itemRect","rootBorderWidth","style","SegmentedControlItem","disabled","jsxs","Radio","Root","Item","Indicator"],"mappings":"iVAEaA,EAAaC,EAAAA,IAAI,CAC5B,qBACA,+CACA,mCACA,kBACA,qCACF,CAAC,EAEYC,EAAaD,EAAAA,IAAI,CAC5B,2DACA,sDACA,8BACA,iBACA,6BACA,cACA,iCACA,eACA,0BACA,+DACA,yCACA,wBACF,CAAC,EAEYE,EAAkBF,EAAAA,IAAI,CACjC,kBACA,iBACA,gDACA,uCACA,8DACA,qBACF,CAAC,ECzBYG,EAA0BC,EAAAA,cACrC,CAAA,CACF,EAEaC,EAA6B,IAAM,CAC9C,MAAMC,EAAUC,EAAAA,WAAWJ,CAAuB,EAElD,GAAI,CAACG,EACH,MAAM,MAAM,mFAAmF,EAGjG,OAAOA,CACT,ECQME,EAAqBC,GAA6C,CACtE,IAAIC,EAA4B,KAEhCC,OAAAA,EAAAA,SAAS,QAAQF,EAAUG,GAAS,CAC9BF,IAAe,MACfG,EAAAA,eAAeD,CAAK,GAAK,OAAQA,EAAM,MAA6B,OAAU,WAChFF,EAAcE,EAAM,MAA4B,MAEpD,CAAC,EAEMF,CACT,EAEaI,EAAmB,CAAC,CAC/B,MAAAC,EACA,aAAAC,EACA,cAAAC,EACA,UAAAC,EACA,SAAAT,EACA,IAAAU,EACA,GAAGC,CACL,IAA6B,CAC3B,MAAMC,EAAeC,EAAAA,OAA8B,IAAI,EACjDC,EAAYC,EAAAA,aAAaH,EAAcF,CAAG,EAE1CT,EAAaF,EAAkBC,CAAQ,EAEvCgB,EAAeV,IAAU,OACzB,CAACW,EAAeC,CAAgB,EAAIC,EAAAA,SACxC,IAAMZ,GAAgBN,CAAA,EAElBmB,EAAeJ,EAAgBV,GAAS,KAAQW,EAEhDI,EAAqBC,GAAsB,CAC/C,MAAMC,EAAOD,EAERN,GACHE,EAAiBK,CAAI,EAGvBf,IAAgBe,CAAI,CACtB,EAEM,CAAE,QAAAC,EAAS,YAAAC,EAAa,WAAAC,EAAY,UAAAC,EAAW,KAAAC,CAAA,EAASC,sBAAA,EAE9D,OACEC,EAAAA,IAACpC,EAAwB,SAAxB,CACC,MAAO,CACL,aAAA0B,EACA,aAAAR,CAAA,EAGF,SAAAkB,EAAAA,IAACC,EAAAA,WAAA,CACC,IAAKjB,EACL,MAAOE,EAAeV,EAAQ,OAC9B,aAAeU,EAA2D,OAA3CT,GAAgBN,GAAc,OAC7D,cAAeoB,EACf,uBAAqB,oBACrB,UAAW/B,EAAW,CAAE,UAAAmB,EAAW,EACnC,kBAAiBe,EACjB,mBAAkBC,EAClB,gBAAeC,GAAc,OAC7B,eAAcC,GAAa,OAC3B,KAAAC,EACC,GAAGjB,EAEH,SAAAX,CAAA,CAAA,CACH,CAAA,CAGN,EAEAK,EAAiB,YAAc,mBCnFxB,MAAM2B,EAA4B,CAAC,CACxC,UAAAvB,EACA,IAAAC,EACA,GAAGC,CACL,IAAsC,CACpC,KAAM,CAAE,aAAAS,EAAc,aAAAR,CAAA,EAAiBhB,EAAA,EACjC,CAACqC,EAAMC,CAAO,EAAIf,EAAAA,SAA+B,IAAI,EAgC3D,GA9BAgB,EAAAA,UAAU,IAAM,CACd,MAAMC,EAAYxB,EAAa,QAE/B,GAAI,CAACwB,EACH,OAGF,MAAMC,EAAejB,EACjBgB,EAAU,cAA2B,gBAAgBhB,CAAY,IAAI,EACrE,KAEJ,GAAI,CAACiB,EAAc,CACjBH,EAAQ,IAAI,EAEZ,MACF,CAEA,MAAMI,EAAgBF,EAAU,sBAAA,EAC1BG,EAAWF,EAAa,sBAAA,EAExBG,EAAkB,EAExBN,EAAQ,CACN,KAAMK,EAAS,KAAOD,EAAc,KAAOE,EAC3C,IAAKD,EAAS,IAAMD,EAAc,IAAME,EACxC,MAAOD,EAAS,MAChB,OAAQA,EAAS,MAAA,CAClB,CACH,EAAG,CAACnB,EAAcR,CAAY,CAAC,EAE3B,CAACqB,EAAM,OAAO,KAElB,MAAMQ,EAAuB,CAC3B,KAAMR,EAAK,KACX,IAAKA,EAAK,IACV,MAAOA,EAAK,MACZ,OAAQA,EAAK,MAAA,EAGf,OACEH,EAAAA,IAAC,OAAA,CACC,IAAApB,EACA,uBAAqB,8BACrB,cAAW,GACX,UAAWjB,EAAgB,CAAE,UAAAgB,EAAW,EACxC,MAAAgC,EACC,GAAG9B,CAAA,CAAA,CAGV,EAEAqB,EAA0B,YAAc,6BCxDjC,MAAMU,EAAuB,CAAC,CACnC,MAAApC,EACA,SAAAqC,EAAW,GACX,SAAA3C,EACA,UAAAS,EACA,IAAAC,EACA,GAAGC,CACL,IAEIiC,EAAAA,KAACC,EAAAA,MAAM,KAAN,CACC,IAAAnC,EACA,uBAAqB,yBACrB,aAAYJ,EACZ,MAAAA,EACA,SAAAqC,EACA,UAAWnD,EAAW,CAAE,UAAAiB,EAAW,EAClC,GAAGE,EAEH,SAAA,CAAAX,EACD8B,EAAAA,IAAC,OAAA,CACC,cAAY,OACZ,UAAU,4FAET,SAAA9B,CAAA,CAAA,CACH,CAAA,CAAA,EAKN0C,EAAqB,YAAc,wBC5C5B,MAAMrC,EAGT,OAAO,OAAOyC,EAAM,CAAA,KACtBC,EAAA,UACAC,CACF,CAAC,EAED3C,EAAiB,YAAc,mBAC/B0C,EAAK,YAAc,wBACnBC,EAAU,YAAc"}
@@ -1,190 +1,173 @@
1
- import { jsx as m, jsxs as V } from "react/jsx-runtime";
2
- import { ToggleGroup as N } from "@base-ui/react/toggle-group";
3
- import { useMergeRefs as R } from "@spark-ui/hooks/use-merge-refs";
4
- import { createContext as j, useContext as E, useRef as k, useState as x, Children as B, isValidElement as P, useEffect as T } from "react";
5
- import { cva as f } from "class-variance-authority";
6
- import { Toggle as $ } from "@base-ui/react/toggle";
7
- const q = f([
1
+ import { jsx as f, jsxs as j } from "react/jsx-runtime";
2
+ import { RadioGroup as E } from "@base-ui/react/radio-group";
3
+ import { useFormFieldControl as q } from "@spark-ui/components/form-field";
4
+ import { useMergeRefs as z } from "@spark-ui/hooks/use-merge-refs";
5
+ import { createContext as B, useContext as F, useRef as P, useState as b, Children as $, isValidElement as G, useEffect as M } from "react";
6
+ import { cva as p } from "class-variance-authority";
7
+ import { Radio as O } from "@base-ui/react/radio";
8
+ const W = p([
9
+ "default:self-start",
8
10
  "group inline-grid grid-flow-col auto-cols-fr",
9
11
  "relative items-stretch min-w-max",
10
- "rounded-xl",
11
- "bg-surface border-md border-outline",
12
- "p-sz-2"
13
- ]), F = f(
14
- [
15
- "relative z-raised min-h-sz-44 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus focus-visible:ring-inset",
16
- "flex flex-none items-center justify-center flex-col",
17
- "px-lg",
18
- "rounded-xl",
19
- "cursor-pointer select-none",
20
- "font-medium",
21
- "transition-colors duration-150",
22
- "outline-none",
23
- "focus-visible:u-outline",
24
- "disabled:cursor-not-allowed disabled:opacity-dim-3",
25
- "not-disabled:hover:text-on-surface",
26
- "aria-pressed:text-on-support-container",
27
- "aria-pressed:font-bold"
28
- ],
29
- {
30
- variants: {
31
- /**
32
- * Change the size of the segmented control
33
- * @default md
34
- */
35
- size: {
36
- sm: ["h-sz-32 min-w-sz-32 text-caption"],
37
- md: ["h-sz-36 min-w-sz-36 text-body-2"],
38
- lg: ["h-sz-40 min-w-sz-40 text-body-1"]
39
- }
40
- },
41
- defaultVariants: {
42
- size: "md"
43
- }
44
- }
45
- ), G = f([
12
+ "rounded-xl p-sm",
13
+ "bg-surface border-sm border-outline"
14
+ ]), A = p([
15
+ "relative z-raised min-h-sz-44 focus-visible:outline-none",
16
+ "flex flex-none items-center justify-center flex-col",
17
+ "default:px-lg default:py-md",
18
+ "rounded-[20px]",
19
+ "cursor-pointer select-none",
20
+ "font-medium",
21
+ "transition-colors duration-150",
22
+ "outline-none",
23
+ "focus-visible:u-outline",
24
+ "data-disabled:cursor-not-allowed data-disabled:opacity-dim-3",
25
+ "data-checked:text-on-support-container",
26
+ "data-checked:font-bold"
27
+ ]), D = p([
46
28
  "absolute z-base",
47
- "rounded-xl",
29
+ "rounded-[20px]",
48
30
  "bg-support-container border-md border-support",
31
+ "group-has-focus-visible:border-focus",
49
32
  "transition-[left,top,width,height] duration-200 ease-in-out",
50
33
  "pointer-events-none"
51
- ]), b = j(
34
+ ]), v = B(
52
35
  {}
53
- ), v = () => {
54
- const e = E(b);
36
+ ), H = () => {
37
+ const e = F(v);
55
38
  if (!e)
56
39
  throw Error("useSegmentedControlContext must be used within a SegmentedControlContext Provider");
57
40
  return e;
58
- }, M = (e) => {
59
- let o = null;
60
- return B.forEach(e, (t) => {
61
- o === null && P(t) && typeof t.props.value == "string" && (o = t.props.value);
62
- }), o;
63
- }, S = ({
41
+ }, J = (e) => {
42
+ let t = null;
43
+ return $.forEach(e, (o) => {
44
+ t === null && G(o) && typeof o.props.value == "string" && (t = o.props.value);
45
+ }), t;
46
+ }, x = ({
64
47
  value: e,
65
- defaultValue: o,
66
- onValueChange: t,
67
- size: r = "md",
68
- className: i,
69
- children: n,
70
- ref: l,
71
- ...p
48
+ defaultValue: t,
49
+ onValueChange: o,
50
+ className: r,
51
+ children: i,
52
+ ref: n,
53
+ ...c
72
54
  }) => {
73
- const a = k(null), [c, u] = x(
74
- () => o ?? M(n)
75
- ), s = e !== void 0, d = s ? e ?? null : c, y = (I) => {
76
- const C = I[0] ?? null;
77
- s || u(C), t?.(C);
78
- }, w = R(a, l), z = d != null ? [d] : [];
79
- return /* @__PURE__ */ m(
80
- b.Provider,
55
+ const u = P(null), l = z(u, n), d = J(i), s = e !== void 0, [a, m] = b(
56
+ () => t ?? d
57
+ ), S = s ? e ?? null : a, y = (k) => {
58
+ const C = k;
59
+ s || m(C), o?.(C);
60
+ }, { labelId: R, description: I, isRequired: w, isInvalid: N, name: V } = q();
61
+ return /* @__PURE__ */ f(
62
+ v.Provider,
81
63
  {
82
64
  value: {
83
- pressedValue: d,
84
- containerRef: a,
85
- size: r ?? "md"
65
+ checkedValue: S,
66
+ containerRef: u
86
67
  },
87
- children: /* @__PURE__ */ m(
88
- N,
68
+ children: /* @__PURE__ */ f(
69
+ E,
89
70
  {
90
- ref: w,
91
- multiple: !1,
92
- value: z,
71
+ ref: l,
72
+ value: s ? e : void 0,
73
+ defaultValue: s ? void 0 : t ?? d ?? void 0,
93
74
  onValueChange: y,
94
75
  "data-spark-component": "segmented-control",
95
- className: q({ className: i }),
96
- ...p,
97
- children: n
76
+ className: W({ className: r }),
77
+ "aria-labelledby": R,
78
+ "aria-describedby": I,
79
+ "aria-required": w || void 0,
80
+ "aria-invalid": N || void 0,
81
+ name: V,
82
+ ...c,
83
+ children: i
98
84
  }
99
85
  )
100
86
  }
101
87
  );
102
88
  };
103
- S.displayName = "SegmentedControl";
89
+ x.displayName = "SegmentedControl";
104
90
  const g = ({
105
91
  className: e,
106
- ref: o,
107
- ...t
92
+ ref: t,
93
+ ...o
108
94
  }) => {
109
- const { pressedValue: r, containerRef: i } = v(), [n, l] = x(null);
110
- if (T(() => {
111
- const a = i.current;
112
- if (!a)
95
+ const { checkedValue: r, containerRef: i } = H(), [n, c] = b(null);
96
+ if (M(() => {
97
+ const l = i.current;
98
+ if (!l)
113
99
  return;
114
- const c = r ? a.querySelector(`[data-value="${r}"]`) : null;
115
- if (!c) {
116
- l(null);
100
+ const d = r ? l.querySelector(`[data-value="${r}"]`) : null;
101
+ if (!d) {
102
+ c(null);
117
103
  return;
118
104
  }
119
- const u = a.getBoundingClientRect(), s = c.getBoundingClientRect(), d = 2;
120
- l({
121
- left: s.left - u.left - d,
122
- top: s.top - u.top - d,
123
- width: s.width,
124
- height: s.height
105
+ const s = l.getBoundingClientRect(), a = d.getBoundingClientRect(), m = 1;
106
+ c({
107
+ left: a.left - s.left - m,
108
+ top: a.top - s.top - m,
109
+ width: a.width,
110
+ height: a.height
125
111
  });
126
112
  }, [r, i]), !n) return null;
127
- const p = {
113
+ const u = {
128
114
  left: n.left,
129
115
  top: n.top,
130
116
  width: n.width,
131
117
  height: n.height
132
118
  };
133
- return /* @__PURE__ */ m(
119
+ return /* @__PURE__ */ f(
134
120
  "span",
135
121
  {
136
- ref: o,
122
+ ref: t,
137
123
  "data-spark-component": "segmented-control-indicator",
138
124
  "aria-hidden": !0,
139
- className: G({ className: e }),
140
- style: p,
141
- ...t
125
+ className: D({ className: e }),
126
+ style: u,
127
+ ...o
142
128
  }
143
129
  );
144
130
  };
145
131
  g.displayName = "SegmentedControl.Indicator";
146
132
  const h = ({
147
133
  value: e,
148
- disabled: o = !1,
149
- children: t,
134
+ disabled: t = !1,
135
+ children: o,
150
136
  className: r,
151
137
  ref: i,
152
138
  ...n
153
- }) => {
154
- const { size: l } = v();
155
- return /* @__PURE__ */ V(
156
- $,
157
- {
158
- ref: i,
159
- "data-spark-component": "segmented-control-item",
160
- "data-value": e,
161
- value: e,
162
- disabled: o,
163
- className: F({ size: l, className: r }),
164
- ...n,
165
- children: [
166
- t,
167
- /* @__PURE__ */ m(
168
- "span",
169
- {
170
- "aria-hidden": "true",
171
- className: "bg-success pointer-events-none h-0 overflow-hidden font-bold content-[attr(data-text)/'']",
172
- children: t
173
- }
174
- )
175
- ]
176
- }
177
- );
178
- };
139
+ }) => /* @__PURE__ */ j(
140
+ O.Root,
141
+ {
142
+ ref: i,
143
+ "data-spark-component": "segmented-control-item",
144
+ "data-value": e,
145
+ value: e,
146
+ disabled: t,
147
+ className: A({ className: r }),
148
+ ...n,
149
+ children: [
150
+ o,
151
+ /* @__PURE__ */ f(
152
+ "span",
153
+ {
154
+ "aria-hidden": "true",
155
+ className: "bg-success pointer-events-none h-0 overflow-hidden font-bold content-[attr(data-text)/'']",
156
+ children: o
157
+ }
158
+ )
159
+ ]
160
+ }
161
+ );
179
162
  h.displayName = "SegmentedControl.Item";
180
- const O = Object.assign(S, {
163
+ const K = Object.assign(x, {
181
164
  Item: h,
182
165
  Indicator: g
183
166
  });
184
- O.displayName = "SegmentedControl";
167
+ K.displayName = "SegmentedControl";
185
168
  h.displayName = "SegmentedControl.Item";
186
169
  g.displayName = "SegmentedControl.Indicator";
187
170
  export {
188
- O as SegmentedControl
171
+ K as SegmentedControl
189
172
  };
190
173
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../../src/segmented-control/SegmentedControl.styles.ts","../../src/segmented-control/SegmentedControlContext.tsx","../../src/segmented-control/SegmentedControl.tsx","../../src/segmented-control/SegmentedControlIndicator.tsx","../../src/segmented-control/SegmentedControlItem.tsx","../../src/segmented-control/index.ts"],"sourcesContent":["import { cva, VariantProps } from 'class-variance-authority'\n\nexport const rootStyles = cva([\n 'group inline-grid grid-flow-col auto-cols-fr',\n 'relative items-stretch min-w-max',\n 'rounded-xl',\n 'bg-surface border-md border-outline',\n 'p-sz-2',\n])\n\nexport const itemStyles = cva(\n [\n 'relative z-raised min-h-sz-44 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus focus-visible:ring-inset',\n 'flex flex-none items-center justify-center flex-col',\n 'px-lg',\n 'rounded-xl',\n 'cursor-pointer select-none',\n 'font-medium',\n 'transition-colors duration-150',\n 'outline-none',\n 'focus-visible:u-outline',\n 'disabled:cursor-not-allowed disabled:opacity-dim-3',\n 'not-disabled:hover:text-on-surface',\n 'aria-pressed:text-on-support-container',\n 'aria-pressed:font-bold',\n ],\n {\n variants: {\n /**\n * Change the size of the segmented control\n * @default md\n */\n size: {\n sm: ['h-sz-32 min-w-sz-32 text-caption'],\n md: ['h-sz-36 min-w-sz-36 text-body-2'],\n lg: ['h-sz-40 min-w-sz-40 text-body-1'],\n },\n },\n defaultVariants: {\n size: 'md',\n },\n }\n)\n\nexport const indicatorStyles = cva([\n 'absolute z-base',\n 'rounded-xl',\n 'bg-support-container border-md border-support',\n 'transition-[left,top,width,height] duration-200 ease-in-out',\n 'pointer-events-none',\n])\n\nexport type SegmentedControlStylesProps = VariantProps<typeof itemStyles>\n","import { createContext, RefObject, useContext } from 'react'\n\nimport type { SegmentedControlStylesProps } from './SegmentedControl.styles'\n\nexport interface SegmentedControlContextInterface\n extends Required<Pick<SegmentedControlStylesProps, 'size'>> {\n pressedValue: string | null\n containerRef: RefObject<HTMLDivElement | null>\n}\n\nexport const SegmentedControlContext = createContext<SegmentedControlContextInterface>(\n {} as SegmentedControlContextInterface\n)\n\nexport const useSegmentedControlContext = () => {\n const context = useContext(SegmentedControlContext)\n\n if (!context) {\n throw Error('useSegmentedControlContext must be used within a SegmentedControlContext Provider')\n }\n\n return context\n}\n","import { ToggleGroup } from '@base-ui/react/toggle-group'\nimport { useMergeRefs } from '@spark-ui/hooks/use-merge-refs'\nimport { Children, type ComponentProps, isValidElement, Ref, useRef, useState } from 'react'\n\nimport type { SegmentedControlStylesProps } from './SegmentedControl.styles'\nimport { rootStyles } from './SegmentedControl.styles'\nimport { SegmentedControlContext } from './SegmentedControlContext'\n\nexport interface SegmentedControlProps\n extends Omit<\n ComponentProps<typeof ToggleGroup>,\n 'multiple' | 'value' | 'defaultValue' | 'onValueChange'\n >,\n SegmentedControlStylesProps {\n /**\n * The controlled selected value.\n */\n value?: string\n /**\n * The uncontrolled default selected value.\n */\n defaultValue?: string\n /**\n * Callback fired when the selected value changes.\n */\n onValueChange?: (value: string | null) => void\n ref?: Ref<HTMLDivElement>\n}\n\nconst getFirstItemValue = (children: React.ReactNode): string | null => {\n let firstValue: string | null = null\n\n Children.forEach(children, child => {\n if (firstValue !== null) return\n if (isValidElement(child) && typeof (child.props as { value?: string }).value === 'string') {\n firstValue = (child.props as { value: string }).value\n }\n })\n\n return firstValue\n}\n\nexport const SegmentedControl = ({\n value,\n defaultValue,\n onValueChange,\n size = 'md',\n className,\n children,\n ref,\n ...rest\n}: SegmentedControlProps) => {\n const containerRef = useRef<HTMLDivElement | null>(null)\n const [internalValue, setInternalValue] = useState<string | null>(\n () => defaultValue ?? getFirstItemValue(children)\n )\n\n const isControlled = value !== undefined\n const pressedValue = isControlled ? (value ?? null) : internalValue\n\n const handleValueChange = (newValues: unknown[]) => {\n const next = (newValues[0] as string) ?? null\n\n if (!isControlled) {\n setInternalValue(next)\n }\n\n onValueChange?.(next)\n }\n\n const mergedRef = useMergeRefs(containerRef, ref)\n const groupValue = pressedValue != null ? [pressedValue] : []\n\n return (\n <SegmentedControlContext.Provider\n value={{\n pressedValue,\n containerRef,\n size: size ?? 'md',\n }}\n >\n <ToggleGroup\n ref={mergedRef}\n multiple={false}\n value={groupValue}\n onValueChange={handleValueChange}\n data-spark-component=\"segmented-control\"\n className={rootStyles({ className })}\n {...rest}\n >\n {children}\n </ToggleGroup>\n </SegmentedControlContext.Provider>\n )\n}\n\nSegmentedControl.displayName = 'SegmentedControl'\n","import { type ComponentProps, type CSSProperties, Ref, useEffect, useState } from 'react'\n\nimport { indicatorStyles } from './SegmentedControl.styles'\nimport { useSegmentedControlContext } from './SegmentedControlContext'\n\ninterface IndicatorRect {\n left: number\n top: number\n width: number\n height: number\n}\n\nexport interface SegmentedControlIndicatorProps extends ComponentProps<'span'> {\n ref?: Ref<HTMLSpanElement>\n}\n\nexport const SegmentedControlIndicator = ({\n className,\n ref,\n ...rest\n}: SegmentedControlIndicatorProps) => {\n const { pressedValue, containerRef } = useSegmentedControlContext()\n const [rect, setRect] = useState<IndicatorRect | null>(null)\n\n useEffect(() => {\n const container = containerRef.current\n\n if (!container) {\n return\n }\n\n const selectedItem = pressedValue\n ? container.querySelector<HTMLElement>(`[data-value=\"${pressedValue}\"]`)\n : null\n\n if (!selectedItem) {\n setRect(null)\n\n return\n }\n\n const containerRect = container.getBoundingClientRect()\n const itemRect = selectedItem.getBoundingClientRect()\n\n const borderWidth = 2\n\n setRect({\n left: itemRect.left - containerRect.left - borderWidth,\n top: itemRect.top - containerRect.top - borderWidth,\n width: itemRect.width,\n height: itemRect.height,\n })\n }, [pressedValue, containerRef])\n\n if (!rect) return null\n\n const style: CSSProperties = {\n left: rect.left,\n top: rect.top,\n width: rect.width,\n height: rect.height,\n }\n\n return (\n <span\n ref={ref}\n data-spark-component=\"segmented-control-indicator\"\n aria-hidden\n className={indicatorStyles({ className })}\n style={style}\n {...rest}\n />\n )\n}\n\nSegmentedControlIndicator.displayName = 'SegmentedControl.Indicator'\n","import { Toggle } from '@base-ui/react/toggle'\nimport { type ComponentProps, Ref } from 'react'\n\nimport { itemStyles } from './SegmentedControl.styles'\nimport { useSegmentedControlContext } from './SegmentedControlContext'\n\nexport interface SegmentedControlItemProps extends Omit<ComponentProps<typeof Toggle>, 'value'> {\n /**\n * A unique value that identifies this item within the segmented control.\n */\n value: string\n /**\n * When true, prevents the user from interacting with this item.\n * @default false\n */\n disabled?: boolean\n ref?: Ref<HTMLButtonElement>\n}\n\nexport const SegmentedControlItem = ({\n value,\n disabled = false,\n children,\n className,\n ref,\n ...rest\n}: SegmentedControlItemProps) => {\n const { size } = useSegmentedControlContext()\n\n return (\n <Toggle\n ref={ref}\n data-spark-component=\"segmented-control-item\"\n data-value={value}\n value={value}\n disabled={disabled}\n className={itemStyles({ size, className })}\n {...rest}\n >\n {children}\n <span\n aria-hidden=\"true\"\n className=\"bg-success pointer-events-none h-0 overflow-hidden font-bold content-[attr(data-text)/'']\"\n >\n {children}\n </span>\n </Toggle>\n )\n}\n\nSegmentedControlItem.displayName = 'SegmentedControl.Item'\n","import { SegmentedControl as Root } from './SegmentedControl'\nimport { SegmentedControlIndicator as Indicator } from './SegmentedControlIndicator'\nimport { SegmentedControlItem as Item } from './SegmentedControlItem'\n\nexport const SegmentedControl: typeof Root & {\n Item: typeof Item\n Indicator: typeof Indicator\n} = Object.assign(Root, {\n Item,\n Indicator,\n})\n\nSegmentedControl.displayName = 'SegmentedControl'\nItem.displayName = 'SegmentedControl.Item'\nIndicator.displayName = 'SegmentedControl.Indicator'\n\nexport type { SegmentedControlProps } from './SegmentedControl'\nexport type { SegmentedControlItemProps } from './SegmentedControlItem'\nexport type { SegmentedControlIndicatorProps } from './SegmentedControlIndicator'\n"],"names":["rootStyles","cva","itemStyles","indicatorStyles","SegmentedControlContext","createContext","useSegmentedControlContext","context","useContext","getFirstItemValue","children","firstValue","Children","child","isValidElement","SegmentedControl","value","defaultValue","onValueChange","size","className","ref","rest","containerRef","useRef","internalValue","setInternalValue","useState","isControlled","pressedValue","handleValueChange","newValues","next","mergedRef","useMergeRefs","groupValue","jsx","ToggleGroup","SegmentedControlIndicator","rect","setRect","useEffect","container","selectedItem","containerRect","itemRect","borderWidth","style","SegmentedControlItem","disabled","jsxs","Toggle","Root","Item","Indicator"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","sources":["../../src/segmented-control/SegmentedControl.styles.ts","../../src/segmented-control/SegmentedControlContext.tsx","../../src/segmented-control/SegmentedControl.tsx","../../src/segmented-control/SegmentedControlIndicator.tsx","../../src/segmented-control/SegmentedControlItem.tsx","../../src/segmented-control/index.ts"],"sourcesContent":["import { cva, VariantProps } from 'class-variance-authority'\n\nexport const rootStyles = cva([\n 'default:self-start',\n 'group inline-grid grid-flow-col auto-cols-fr',\n 'relative items-stretch min-w-max',\n 'rounded-xl p-sm',\n 'bg-surface border-sm border-outline',\n])\n\nexport const itemStyles = cva([\n 'relative z-raised min-h-sz-44 focus-visible:outline-none',\n 'flex flex-none items-center justify-center flex-col',\n 'default:px-lg default:py-md',\n 'rounded-[20px]',\n 'cursor-pointer select-none',\n 'font-medium',\n 'transition-colors duration-150',\n 'outline-none',\n 'focus-visible:u-outline',\n 'data-disabled:cursor-not-allowed data-disabled:opacity-dim-3',\n 'data-checked:text-on-support-container',\n 'data-checked:font-bold',\n])\n\nexport const indicatorStyles = cva([\n 'absolute z-base',\n 'rounded-[20px]',\n 'bg-support-container border-md border-support',\n 'group-has-focus-visible:border-focus',\n 'transition-[left,top,width,height] duration-200 ease-in-out',\n 'pointer-events-none',\n])\n\nexport type SegmentedControlStylesProps = VariantProps<typeof itemStyles>\n","import { createContext, RefObject, useContext } from 'react'\n\nexport interface SegmentedControlContextInterface {\n checkedValue: string | null\n containerRef: RefObject<HTMLDivElement | null>\n}\n\nexport const SegmentedControlContext = createContext<SegmentedControlContextInterface>(\n {} as SegmentedControlContextInterface\n)\n\nexport const useSegmentedControlContext = () => {\n const context = useContext(SegmentedControlContext)\n\n if (!context) {\n throw Error('useSegmentedControlContext must be used within a SegmentedControlContext Provider')\n }\n\n return context\n}\n","import { RadioGroup } from '@base-ui/react/radio-group'\nimport { useFormFieldControl } from '@spark-ui/components/form-field'\nimport { useMergeRefs } from '@spark-ui/hooks/use-merge-refs'\nimport { Children, type ComponentProps, isValidElement, Ref, useRef, useState } from 'react'\n\nimport type { SegmentedControlStylesProps } from './SegmentedControl.styles'\nimport { rootStyles } from './SegmentedControl.styles'\nimport { SegmentedControlContext } from './SegmentedControlContext'\n\nexport interface SegmentedControlProps\n extends Omit<ComponentProps<typeof RadioGroup>, 'value' | 'defaultValue' | 'onValueChange'>,\n SegmentedControlStylesProps {\n /**\n * The controlled selected value.\n */\n value?: string\n /**\n * The uncontrolled default selected value.\n */\n defaultValue?: string\n /**\n * Callback fired when the selected value changes.\n */\n onValueChange?: (value: string) => void\n ref?: Ref<HTMLDivElement>\n}\n\nconst getFirstItemValue = (children: React.ReactNode): string | null => {\n let firstValue: string | null = null\n\n Children.forEach(children, child => {\n if (firstValue !== null) return\n if (isValidElement(child) && typeof (child.props as { value?: string }).value === 'string') {\n firstValue = (child.props as { value: string }).value\n }\n })\n\n return firstValue\n}\n\nexport const SegmentedControl = ({\n value,\n defaultValue,\n onValueChange,\n className,\n children,\n ref,\n ...rest\n}: SegmentedControlProps) => {\n const containerRef = useRef<HTMLDivElement | null>(null)\n const mergedRef = useMergeRefs(containerRef, ref)\n\n const firstValue = getFirstItemValue(children)\n\n const isControlled = value !== undefined\n const [internalValue, setInternalValue] = useState<string | null>(\n () => defaultValue ?? firstValue\n )\n const checkedValue = isControlled ? (value ?? null) : internalValue\n\n const handleValueChange = (newValue: unknown) => {\n const next = newValue as string\n\n if (!isControlled) {\n setInternalValue(next)\n }\n\n onValueChange?.(next)\n }\n\n const { labelId, description, isRequired, isInvalid, name } = useFormFieldControl()\n\n return (\n <SegmentedControlContext.Provider\n value={{\n checkedValue,\n containerRef,\n }}\n >\n <RadioGroup\n ref={mergedRef}\n value={isControlled ? value : undefined}\n defaultValue={!isControlled ? (defaultValue ?? firstValue ?? undefined) : undefined}\n onValueChange={handleValueChange}\n data-spark-component=\"segmented-control\"\n className={rootStyles({ className })}\n aria-labelledby={labelId}\n aria-describedby={description}\n aria-required={isRequired || undefined}\n aria-invalid={isInvalid || undefined}\n name={name}\n {...rest}\n >\n {children}\n </RadioGroup>\n </SegmentedControlContext.Provider>\n )\n}\n\nSegmentedControl.displayName = 'SegmentedControl'\n","import { type ComponentProps, type CSSProperties, Ref, useEffect, useState } from 'react'\n\nimport { indicatorStyles } from './SegmentedControl.styles'\nimport { useSegmentedControlContext } from './SegmentedControlContext'\n\ninterface IndicatorRect {\n left: number\n top: number\n width: number\n height: number\n}\n\nexport interface SegmentedControlIndicatorProps extends ComponentProps<'span'> {\n ref?: Ref<HTMLSpanElement>\n}\n\nexport const SegmentedControlIndicator = ({\n className,\n ref,\n ...rest\n}: SegmentedControlIndicatorProps) => {\n const { checkedValue, containerRef } = useSegmentedControlContext()\n const [rect, setRect] = useState<IndicatorRect | null>(null)\n\n useEffect(() => {\n const container = containerRef.current\n\n if (!container) {\n return\n }\n\n const selectedItem = checkedValue\n ? container.querySelector<HTMLElement>(`[data-value=\"${checkedValue}\"]`)\n : null\n\n if (!selectedItem) {\n setRect(null)\n\n return\n }\n\n const containerRect = container.getBoundingClientRect()\n const itemRect = selectedItem.getBoundingClientRect()\n\n const rootBorderWidth = 1\n\n setRect({\n left: itemRect.left - containerRect.left - rootBorderWidth,\n top: itemRect.top - containerRect.top - rootBorderWidth,\n width: itemRect.width,\n height: itemRect.height,\n })\n }, [checkedValue, containerRef])\n\n if (!rect) return null\n\n const style: CSSProperties = {\n left: rect.left,\n top: rect.top,\n width: rect.width,\n height: rect.height,\n }\n\n return (\n <span\n ref={ref}\n data-spark-component=\"segmented-control-indicator\"\n aria-hidden\n className={indicatorStyles({ className })}\n style={style}\n {...rest}\n />\n )\n}\n\nSegmentedControlIndicator.displayName = 'SegmentedControl.Indicator'\n","import { Radio } from '@base-ui/react/radio'\nimport { type ComponentProps, Ref } from 'react'\n\nimport { itemStyles } from './SegmentedControl.styles'\n\nexport interface SegmentedControlItemProps\n extends Omit<ComponentProps<typeof Radio.Root>, 'value'> {\n /**\n * A unique value that identifies this item within the segmented control.\n */\n value: string\n /**\n * When true, prevents the user from interacting with this item.\n * @default false\n */\n disabled?: boolean\n ref?: Ref<HTMLElement>\n}\n\nexport const SegmentedControlItem = ({\n value,\n disabled = false,\n children,\n className,\n ref,\n ...rest\n}: SegmentedControlItemProps) => {\n return (\n <Radio.Root\n ref={ref}\n data-spark-component=\"segmented-control-item\"\n data-value={value}\n value={value}\n disabled={disabled}\n className={itemStyles({ className })}\n {...rest}\n >\n {children}\n <span\n aria-hidden=\"true\"\n className=\"bg-success pointer-events-none h-0 overflow-hidden font-bold content-[attr(data-text)/'']\"\n >\n {children}\n </span>\n </Radio.Root>\n )\n}\n\nSegmentedControlItem.displayName = 'SegmentedControl.Item'\n","import { SegmentedControl as Root } from './SegmentedControl'\nimport { SegmentedControlIndicator as Indicator } from './SegmentedControlIndicator'\nimport { SegmentedControlItem as Item } from './SegmentedControlItem'\n\nexport const SegmentedControl: typeof Root & {\n Item: typeof Item\n Indicator: typeof Indicator\n} = Object.assign(Root, {\n Item,\n Indicator,\n})\n\nSegmentedControl.displayName = 'SegmentedControl'\nItem.displayName = 'SegmentedControl.Item'\nIndicator.displayName = 'SegmentedControl.Indicator'\n\nexport type { SegmentedControlProps } from './SegmentedControl'\nexport type { SegmentedControlItemProps } from './SegmentedControlItem'\nexport type { SegmentedControlIndicatorProps } from './SegmentedControlIndicator'\n"],"names":["rootStyles","cva","itemStyles","indicatorStyles","SegmentedControlContext","createContext","useSegmentedControlContext","context","useContext","getFirstItemValue","children","firstValue","Children","child","isValidElement","SegmentedControl","value","defaultValue","onValueChange","className","ref","rest","containerRef","useRef","mergedRef","useMergeRefs","isControlled","internalValue","setInternalValue","useState","checkedValue","handleValueChange","newValue","next","labelId","description","isRequired","isInvalid","name","useFormFieldControl","jsx","RadioGroup","SegmentedControlIndicator","rect","setRect","useEffect","container","selectedItem","containerRect","itemRect","rootBorderWidth","style","SegmentedControlItem","disabled","jsxs","Radio","Root","Item","Indicator"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spark-ui/components",
3
- "version": "17.1.0",
3
+ "version": "17.1.1",
4
4
  "license": "MIT",
5
5
  "description": "Spark (Leboncoin design system) components.",
6
6
  "exports": {
@@ -54,9 +54,9 @@
54
54
  "@react-aria/toast": "^3.0.0-beta.18",
55
55
  "@react-stately/numberfield": "3.9.11",
56
56
  "@react-stately/toast": "^3.0.0-beta.7",
57
- "@spark-ui/hooks": "^17.1.0",
58
- "@spark-ui/icons": "^17.1.0",
59
- "@spark-ui/internal-utils": "^17.1.0",
57
+ "@spark-ui/hooks": "^17.1.1",
58
+ "@spark-ui/icons": "^17.1.1",
59
+ "@spark-ui/internal-utils": "^17.1.1",
60
60
  "@zag-js/pagination": "1.30.0",
61
61
  "@zag-js/react": "1.30.0",
62
62
  "class-variance-authority": "0.7.1",