@frontify/fondue 12.0.0-beta.358 → 12.0.0-beta.359

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,30 +1,30 @@
1
1
  import { jsx as r, jsxs as S } from "react/jsx-runtime";
2
- import { useMemoizedId as F } from "../../hooks/useMemoizedId.es.js";
3
- import { useFocusRing as M } from "@react-aria/focus";
4
- import { setInteractionModality as P } from "@react-aria/interactions";
5
- import { useRadio as $, useRadioGroup as E } from "@react-aria/radio";
2
+ import { useMemoizedId as M } from "../../hooks/useMemoizedId.es.js";
3
+ import { useFocusRing as P } from "@react-aria/focus";
4
+ import { setInteractionModality as $ } from "@react-aria/interactions";
5
+ import { useRadio as k, useRadioGroup as E } from "@react-aria/radio";
6
6
  import { VisuallyHidden as T } from "@react-aria/visually-hidden";
7
7
  import { useRadioGroupState as W } from "@react-stately/radio";
8
8
  import { FOCUS_STYLE as D } from "../../utilities/focusStyle.es.js";
9
- import { merge as b } from "../../utilities/merge.es.js";
9
+ import { merge as x } from "../../utilities/merge.es.js";
10
10
  import { motion as H } from "framer-motion";
11
11
  import { forwardRef as O, useRef as C, useMemo as X } from "react";
12
- const x = (u) => u.icon !== void 0, I = O((u, m) => {
13
- const { id: p, item: t, disabled: l, radioGroupState: o, size: f } = u, n = C(null), a = t.id === o.selectedValue, { inputProps: g } = $(
12
+ const b = (u) => u.icon !== void 0, I = O((u, m) => {
13
+ const { id: p, item: t, disabled: l, radioGroupState: o, size: f } = u, n = C(null), a = t.id === o.selectedValue, { inputProps: g } = k(
14
14
  {
15
15
  value: t.id,
16
- "aria-label": x(t) ? t.ariaLabel : t.value.toString(),
16
+ "aria-label": b(t) ? t.ariaLabel : t.value.toString(),
17
17
  isDisabled: l,
18
18
  id: a ? p : void 0
19
19
  },
20
20
  o,
21
21
  n
22
- ), { isFocusVisible: d, focusProps: h } = M(), c = () => {
22
+ ), { isFocusVisible: d, focusProps: h } = P(), c = () => {
23
23
  var w;
24
- l || (o.setSelectedValue(t.id), (w = n.current) == null || w.focus(), P("pointer"));
24
+ l || (o.setSelectedValue(t.id), (w = n.current) == null || w.focus(), $("pointer"));
25
25
  }, v = () => {
26
26
  switch (!0) {
27
- case x(t):
27
+ case b(t):
28
28
  return "fondue-segmented-controls-item-icon";
29
29
  case typeof t.value == "string":
30
30
  return "fondue-segmented-controls-item-text";
@@ -36,7 +36,7 @@ const x = (u) => u.icon !== void 0, I = O((u, m) => {
36
36
  "div",
37
37
  {
38
38
  ref: m,
39
- className: b([
39
+ className: x([
40
40
  "tw-relative",
41
41
  "after:tw-content-[''] after:tw-border-r after:tw-border-solid after:tw-border-line-strong after:tw-absolute after:tw-right-0 after:tw-h-full last:after:tw-hidden",
42
42
  d && D
@@ -47,10 +47,10 @@ const x = (u) => u.icon !== void 0, I = O((u, m) => {
47
47
  role: "none",
48
48
  onClick: c,
49
49
  "data-test-id": v(),
50
- className: b([
50
+ className: x([
51
51
  "tw-relative tw-w-full tw-py-2 tw-inline-flex tw-justify-center tw-items-center tw-font-sans tw-font-normal tw-h-full tw-text-center",
52
52
  f === "small" ? "tw-px-2" : "tw-px-4",
53
- a && !l ? "tw-text-text tw-bg-base tw-ease-in tw-duration-300" : "tw-text-text-weak tw-ease-out tw-duration-100",
53
+ a && !l ? "tw-text-text tw-bg-base tw-ease-in tw-duration-300" : "tw-bg-box-disabled tw-text-box-disabled-inverse tw-ease-out tw-duration-100",
54
54
  l ? "tw-text-box-disabled-inverse hover:tw-cursor-not-allowed" : "hover:tw-text-text hover:tw-cursor-pointer"
55
55
  ]),
56
56
  children: [
@@ -64,8 +64,8 @@ const x = (u) => u.icon !== void 0, I = O((u, m) => {
64
64
  }
65
65
  ) }),
66
66
  /* @__PURE__ */ S("span", { className: "tw-overflow-hidden tw-text-ellipsis tw-whitespace-nowrap tw-flex", children: [
67
- x(t) && /* @__PURE__ */ r("span", { className: "tw-leading-3", "aria-label": t.ariaLabel, children: t.icon }),
68
- t.value && /* @__PURE__ */ r("span", { className: x(t) ? "tw-ml-2" : "", children: t.value.toString() })
67
+ b(t) && /* @__PURE__ */ r("span", { className: "tw-leading-3", "aria-label": t.ariaLabel, children: t.icon }),
68
+ t.value && /* @__PURE__ */ r("span", { className: b(t) ? "tw-ml-2" : "", children: t.value.toString() })
69
69
  ] })
70
70
  ]
71
71
  }
@@ -85,7 +85,7 @@ const z = ({
85
85
  hugWidth: f = !1,
86
86
  size: n
87
87
  }) => {
88
- const a = F(u), g = { onChange: t, value: p, label: l, isDisabled: o }, d = W(g), { radioGroupProps: h } = E(g, d), c = C([]), v = X(() => m.map((e, s) => /* @__PURE__ */ r(
88
+ const a = M(u), g = { onChange: t, value: p, label: l, isDisabled: o }, d = W(g), { radioGroupProps: h } = E(g, d), c = C([]), v = X(() => m.map((e, s) => /* @__PURE__ */ r(
89
89
  I,
90
90
  {
91
91
  id: a,
@@ -106,19 +106,19 @@ const z = ({
106
106
  var N;
107
107
  const e = w === c.current.length - 1, s = y ? 1 : 2, i = e ? s + 1 : s;
108
108
  return `${(((N = c.current[w]) == null ? void 0 : N.clientWidth) ?? 0) + i}px`;
109
- }, j = G(), k = L();
109
+ }, j = G(), F = L();
110
110
  return /* @__PURE__ */ S("div", { className: "tw-flex", children: [
111
111
  /* @__PURE__ */ r(
112
112
  H.div,
113
113
  {
114
114
  "aria-hidden": "true",
115
- animate: { x: j, width: k },
115
+ animate: { x: j, width: F },
116
116
  initial: !1,
117
117
  transition: { type: "tween", duration: 0.3 },
118
118
  hidden: !p,
119
- className: b([
119
+ className: x([
120
120
  "tw-absolute tw-h-9 tw-border tw-rounded tw-pointer-events-none tw-z-10",
121
- o ? "tw-border-line-x-strong tw-bg-box-disabled" : "tw-border-line-xx-strong"
121
+ o ? "tw-border-line-x-strong hover:tw-cursor-not-allowed" : "tw-border-line-xx-strong"
122
122
  ])
123
123
  }
124
124
  ),
@@ -127,7 +127,7 @@ const z = ({
127
127
  {
128
128
  ...h,
129
129
  "data-test-id": "fondue-segmented-controls",
130
- className: b([
130
+ className: x([
131
131
  "tw-relative tw-h-9 tw-p-0 tw-border tw-border-solid tw-border-line-strong tw-m-0 tw-bg-base-alt tw-rounded tw-font-sans tw-text-s tw-select-none",
132
132
  R,
133
133
  V
@@ -1 +1 @@
1
- {"version":3,"file":"SegmentedControls.es.js","sources":["../../../src/components/SegmentedControls/SegmentedControls.tsx"],"sourcesContent":["/* (c) Copyright Frontify Ltd., all rights reserved. */\n\nimport { IconProps } from '@foundation/Icon/IconProps';\nimport { useMemoizedId } from '@hooks/useMemoizedId';\nimport { useFocusRing } from '@react-aria/focus';\nimport { setInteractionModality } from '@react-aria/interactions';\nimport { useRadio, useRadioGroup } from '@react-aria/radio';\nimport { VisuallyHidden } from '@react-aria/visually-hidden';\nimport { RadioGroupState, useRadioGroupState } from '@react-stately/radio';\nimport { FOCUS_STYLE } from '@utilities/focusStyle';\nimport { merge } from '@utilities/merge';\nimport { motion } from 'framer-motion';\nimport { ReactElement, forwardRef, useMemo, useRef } from 'react';\n\nexport type IconItem = {\n id: string;\n icon: ReactElement<IconProps>;\n value?: string;\n ariaLabel: string;\n};\n\nexport type TextOrNumberItem = {\n id: string;\n value: string | number;\n};\n\nexport type SegmentSize = 'small' | 'medium';\n\nexport type SegmentedControlsProps = {\n id?: string;\n items: (TextOrNumberItem | IconItem)[];\n activeItemId?: string;\n onChange: (id: string) => void;\n ariaLabel?: string;\n disabled?: boolean;\n hugWidth?: boolean;\n size?: SegmentSize;\n};\n\nconst isIconItem = (item: TextOrNumberItem | IconItem): item is IconItem => (item as IconItem).icon !== undefined;\n\ninterface SegmentedControlsItemProps {\n id: string;\n item: TextOrNumberItem | IconItem;\n disabled: boolean;\n radioGroupState: RadioGroupState;\n size?: SegmentSize;\n}\n\nconst SegmentedControlsItem = forwardRef<HTMLDivElement, SegmentedControlsItemProps>((props, ref) => {\n const { id, item, disabled, radioGroupState, size } = props;\n const inputRef = useRef<HTMLInputElement | null>(null);\n const isActive = item.id === radioGroupState.selectedValue;\n const { inputProps } = useRadio(\n {\n value: item.id,\n 'aria-label': isIconItem(item) ? item.ariaLabel : item.value.toString(),\n isDisabled: disabled,\n id: isActive ? id : undefined,\n },\n radioGroupState,\n inputRef,\n );\n const { isFocusVisible, focusProps } = useFocusRing();\n\n const handleMockLabelClick = () => {\n if (!disabled) {\n radioGroupState.setSelectedValue(item.id);\n inputRef.current?.focus();\n setInteractionModality('pointer');\n }\n };\n\n const getSegmentedControlsItemTestId = () => {\n switch (true) {\n case isIconItem(item):\n return 'fondue-segmented-controls-item-icon';\n case typeof item.value === 'string':\n return 'fondue-segmented-controls-item-text';\n default:\n return 'fondue-segmented-controls-item-number';\n }\n };\n\n return (\n <div\n key={item.id}\n ref={ref}\n className={merge([\n 'tw-relative',\n \"after:tw-content-[''] after:tw-border-r after:tw-border-solid after:tw-border-line-strong after:tw-absolute after:tw-right-0 after:tw-h-full last:after:tw-hidden\",\n isFocusVisible && FOCUS_STYLE,\n ])}\n >\n <div\n // TODO: Change element back to label when bug #2380 from @react-aria is fixed\n // https://github.com/adobe/react-spectrum/issues/2380\n role=\"none\"\n onClick={handleMockLabelClick}\n data-test-id={getSegmentedControlsItemTestId()}\n className={merge([\n 'tw-relative tw-w-full tw-py-2 tw-inline-flex tw-justify-center tw-items-center tw-font-sans tw-font-normal tw-h-full tw-text-center',\n size === 'small' ? 'tw-px-2' : 'tw-px-4',\n isActive && !disabled\n ? 'tw-text-text tw-bg-base tw-ease-in tw-duration-300'\n : 'tw-text-text-weak tw-ease-out tw-duration-100',\n !disabled\n ? 'hover:tw-text-text hover:tw-cursor-pointer'\n : 'tw-text-box-disabled-inverse hover:tw-cursor-not-allowed',\n ])}\n >\n <VisuallyHidden>\n <input\n {...inputProps}\n {...focusProps}\n data-test-id=\"fondue-segmented-controls-input\"\n ref={inputRef}\n />\n </VisuallyHidden>\n <span className=\"tw-overflow-hidden tw-text-ellipsis tw-whitespace-nowrap tw-flex\">\n {isIconItem(item) && (\n <span className=\"tw-leading-3\" aria-label={item.ariaLabel}>\n {item.icon}\n </span>\n )}\n {item.value && <span className={isIconItem(item) ? 'tw-ml-2' : ''}>{item.value.toString()}</span>}\n </span>\n </div>\n </div>\n );\n});\n\nSegmentedControlsItem.displayName = 'SegmentedControlsItem';\n\nexport const SegmentedControls = ({\n id: propId,\n items,\n activeItemId,\n onChange,\n ariaLabel = 'SegmentedControls',\n disabled = false,\n hugWidth = false,\n size,\n}: SegmentedControlsProps): ReactElement => {\n const id = useMemoizedId(propId);\n const groupProps = { onChange, value: activeItemId, label: ariaLabel, isDisabled: disabled };\n const radioGroupState = useRadioGroupState(groupProps);\n const { radioGroupProps } = useRadioGroup(groupProps, radioGroupState);\n const itemsRef = useRef<(HTMLDivElement | null)[]>([]);\n const itemElements = useMemo(() => {\n return items.map((item, index) => (\n <SegmentedControlsItem\n id={id}\n item={item}\n disabled={disabled}\n radioGroupState={radioGroupState}\n ref={(el) => (itemsRef.current[index] = el)}\n key={`fondue-segmented-controls-${id}-item-${item.id}`}\n size={size}\n />\n ));\n }, [items, id, disabled, radioGroupState, size]);\n const selectedIndex = items.findIndex((item) => item.id === radioGroupState.selectedValue);\n const width = hugWidth ? '' : 'tw-w-full';\n const alignment = hugWidth ? 'tw-flex' : 'tw-grid tw-grid-flow-col tw-auto-cols-fr tw-justify-evenly';\n\n const isSmallOrHugWidth = size === 'small' || hugWidth;\n const getSliderX = () => {\n let translateX = isSmallOrHugWidth ? -1 : 0;\n for (let i = 0; i < selectedIndex; i++) {\n translateX += itemsRef.current[i]?.clientWidth ?? 0;\n }\n return `${translateX}px`;\n };\n\n const getSliderWidth = () => {\n const isLastElement = selectedIndex === itemsRef.current.length - 1;\n const baseValue = isSmallOrHugWidth ? 1 : 2;\n const width = isLastElement ? baseValue + 1 : baseValue;\n\n return `${(itemsRef.current[selectedIndex]?.clientWidth ?? 0) + width}px`;\n };\n const sliderTranslation = getSliderX();\n const sliderWidth = getSliderWidth();\n\n return (\n <div className=\"tw-flex\">\n <motion.div\n aria-hidden=\"true\"\n // div border is not included in width so it must be subtracted from translation.\n animate={{ x: sliderTranslation, width: sliderWidth }}\n initial={false}\n transition={{ type: 'tween', duration: 0.3 }}\n hidden={!activeItemId}\n className={merge([\n 'tw-absolute tw-h-9 tw-border tw-rounded tw-pointer-events-none tw-z-10',\n disabled ? 'tw-border-line-x-strong tw-bg-box-disabled' : 'tw-border-line-xx-strong',\n ])}\n />\n <fieldset\n {...radioGroupProps}\n data-test-id=\"fondue-segmented-controls\"\n className={merge([\n 'tw-relative tw-h-9 tw-p-0 tw-border tw-border-solid tw-border-line-strong tw-m-0 tw-bg-base-alt tw-rounded tw-font-sans tw-text-s tw-select-none',\n width,\n alignment,\n ])}\n >\n {itemElements}\n </fieldset>\n </div>\n );\n};\nSegmentedControls.displayName = 'FondueSegmentedControls';\n"],"names":["isIconItem","item","SegmentedControlsItem","forwardRef","props","ref","id","disabled","radioGroupState","size","inputRef","useRef","isActive","inputProps","useRadio","isFocusVisible","focusProps","useFocusRing","handleMockLabelClick","_a","setInteractionModality","getSegmentedControlsItemTestId","jsx","merge","FOCUS_STYLE","jsxs","VisuallyHidden","SegmentedControls","propId","items","activeItemId","onChange","ariaLabel","hugWidth","useMemoizedId","groupProps","useRadioGroupState","radioGroupProps","useRadioGroup","itemsRef","itemElements","useMemo","index","el","selectedIndex","width","alignment","isSmallOrHugWidth","getSliderX","translateX","getSliderWidth","isLastElement","baseValue","sliderTranslation","sliderWidth","motion"],"mappings":"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"}
1
+ {"version":3,"file":"SegmentedControls.es.js","sources":["../../../src/components/SegmentedControls/SegmentedControls.tsx"],"sourcesContent":["/* (c) Copyright Frontify Ltd., all rights reserved. */\n\nimport { IconProps } from '@foundation/Icon/IconProps';\nimport { useMemoizedId } from '@hooks/useMemoizedId';\nimport { useFocusRing } from '@react-aria/focus';\nimport { setInteractionModality } from '@react-aria/interactions';\nimport { useRadio, useRadioGroup } from '@react-aria/radio';\nimport { VisuallyHidden } from '@react-aria/visually-hidden';\nimport { RadioGroupState, useRadioGroupState } from '@react-stately/radio';\nimport { FOCUS_STYLE } from '@utilities/focusStyle';\nimport { merge } from '@utilities/merge';\nimport { motion } from 'framer-motion';\nimport { ReactElement, forwardRef, useMemo, useRef } from 'react';\n\nexport type IconItem = {\n id: string;\n icon: ReactElement<IconProps>;\n value?: string;\n ariaLabel: string;\n};\n\nexport type TextOrNumberItem = {\n id: string;\n value: string | number;\n};\n\nexport type SegmentSize = 'small' | 'medium';\n\nexport type SegmentedControlsProps = {\n id?: string;\n items: (TextOrNumberItem | IconItem)[];\n activeItemId?: string;\n onChange: (id: string) => void;\n ariaLabel?: string;\n disabled?: boolean;\n hugWidth?: boolean;\n size?: SegmentSize;\n};\n\nconst isIconItem = (item: TextOrNumberItem | IconItem): item is IconItem => (item as IconItem).icon !== undefined;\n\ninterface SegmentedControlsItemProps {\n id: string;\n item: TextOrNumberItem | IconItem;\n disabled: boolean;\n radioGroupState: RadioGroupState;\n size?: SegmentSize;\n}\n\nconst SegmentedControlsItem = forwardRef<HTMLDivElement, SegmentedControlsItemProps>((props, ref) => {\n const { id, item, disabled, radioGroupState, size } = props;\n const inputRef = useRef<HTMLInputElement | null>(null);\n const isActive = item.id === radioGroupState.selectedValue;\n const { inputProps } = useRadio(\n {\n value: item.id,\n 'aria-label': isIconItem(item) ? item.ariaLabel : item.value.toString(),\n isDisabled: disabled,\n id: isActive ? id : undefined,\n },\n radioGroupState,\n inputRef,\n );\n const { isFocusVisible, focusProps } = useFocusRing();\n\n const handleMockLabelClick = () => {\n if (!disabled) {\n radioGroupState.setSelectedValue(item.id);\n inputRef.current?.focus();\n setInteractionModality('pointer');\n }\n };\n\n const getSegmentedControlsItemTestId = () => {\n switch (true) {\n case isIconItem(item):\n return 'fondue-segmented-controls-item-icon';\n case typeof item.value === 'string':\n return 'fondue-segmented-controls-item-text';\n default:\n return 'fondue-segmented-controls-item-number';\n }\n };\n\n return (\n <div\n key={item.id}\n ref={ref}\n className={merge([\n 'tw-relative',\n \"after:tw-content-[''] after:tw-border-r after:tw-border-solid after:tw-border-line-strong after:tw-absolute after:tw-right-0 after:tw-h-full last:after:tw-hidden\",\n isFocusVisible && FOCUS_STYLE,\n ])}\n >\n <div\n // TODO: Change element back to label when bug #2380 from @react-aria is fixed\n // https://github.com/adobe/react-spectrum/issues/2380\n role=\"none\"\n onClick={handleMockLabelClick}\n data-test-id={getSegmentedControlsItemTestId()}\n className={merge([\n 'tw-relative tw-w-full tw-py-2 tw-inline-flex tw-justify-center tw-items-center tw-font-sans tw-font-normal tw-h-full tw-text-center',\n size === 'small' ? 'tw-px-2' : 'tw-px-4',\n isActive && !disabled\n ? 'tw-text-text tw-bg-base tw-ease-in tw-duration-300'\n : 'tw-bg-box-disabled tw-text-box-disabled-inverse tw-ease-out tw-duration-100',\n disabled\n ? 'tw-text-box-disabled-inverse hover:tw-cursor-not-allowed'\n : 'hover:tw-text-text hover:tw-cursor-pointer',\n ])}\n >\n <VisuallyHidden>\n <input\n {...inputProps}\n {...focusProps}\n data-test-id=\"fondue-segmented-controls-input\"\n ref={inputRef}\n />\n </VisuallyHidden>\n <span className=\"tw-overflow-hidden tw-text-ellipsis tw-whitespace-nowrap tw-flex\">\n {isIconItem(item) && (\n <span className=\"tw-leading-3\" aria-label={item.ariaLabel}>\n {item.icon}\n </span>\n )}\n {item.value && <span className={isIconItem(item) ? 'tw-ml-2' : ''}>{item.value.toString()}</span>}\n </span>\n </div>\n </div>\n );\n});\n\nSegmentedControlsItem.displayName = 'SegmentedControlsItem';\n\nexport const SegmentedControls = ({\n id: propId,\n items,\n activeItemId,\n onChange,\n ariaLabel = 'SegmentedControls',\n disabled = false,\n hugWidth = false,\n size,\n}: SegmentedControlsProps): ReactElement => {\n const id = useMemoizedId(propId);\n const groupProps = { onChange, value: activeItemId, label: ariaLabel, isDisabled: disabled };\n const radioGroupState = useRadioGroupState(groupProps);\n const { radioGroupProps } = useRadioGroup(groupProps, radioGroupState);\n const itemsRef = useRef<(HTMLDivElement | null)[]>([]);\n const itemElements = useMemo(() => {\n return items.map((item, index) => (\n <SegmentedControlsItem\n id={id}\n item={item}\n disabled={disabled}\n radioGroupState={radioGroupState}\n ref={(el) => (itemsRef.current[index] = el)}\n key={`fondue-segmented-controls-${id}-item-${item.id}`}\n size={size}\n />\n ));\n }, [items, id, disabled, radioGroupState, size]);\n const selectedIndex = items.findIndex((item) => item.id === radioGroupState.selectedValue);\n const width = hugWidth ? '' : 'tw-w-full';\n const alignment = hugWidth ? 'tw-flex' : 'tw-grid tw-grid-flow-col tw-auto-cols-fr tw-justify-evenly';\n\n const isSmallOrHugWidth = size === 'small' || hugWidth;\n const getSliderX = () => {\n let translateX = isSmallOrHugWidth ? -1 : 0;\n for (let i = 0; i < selectedIndex; i++) {\n translateX += itemsRef.current[i]?.clientWidth ?? 0;\n }\n return `${translateX}px`;\n };\n\n const getSliderWidth = () => {\n const isLastElement = selectedIndex === itemsRef.current.length - 1;\n const baseValue = isSmallOrHugWidth ? 1 : 2;\n const width = isLastElement ? baseValue + 1 : baseValue;\n\n return `${(itemsRef.current[selectedIndex]?.clientWidth ?? 0) + width}px`;\n };\n const sliderTranslation = getSliderX();\n const sliderWidth = getSliderWidth();\n\n return (\n <div className=\"tw-flex\">\n <motion.div\n aria-hidden=\"true\"\n // div border is not included in width so it must be subtracted from translation.\n animate={{ x: sliderTranslation, width: sliderWidth }}\n initial={false}\n transition={{ type: 'tween', duration: 0.3 }}\n hidden={!activeItemId}\n className={merge([\n 'tw-absolute tw-h-9 tw-border tw-rounded tw-pointer-events-none tw-z-10',\n disabled ? 'tw-border-line-x-strong hover:tw-cursor-not-allowed' : 'tw-border-line-xx-strong',\n ])}\n />\n <fieldset\n {...radioGroupProps}\n data-test-id=\"fondue-segmented-controls\"\n className={merge([\n 'tw-relative tw-h-9 tw-p-0 tw-border tw-border-solid tw-border-line-strong tw-m-0 tw-bg-base-alt tw-rounded tw-font-sans tw-text-s tw-select-none',\n width,\n alignment,\n ])}\n >\n {itemElements}\n </fieldset>\n </div>\n );\n};\nSegmentedControls.displayName = 'FondueSegmentedControls';\n"],"names":["isIconItem","item","SegmentedControlsItem","forwardRef","props","ref","id","disabled","radioGroupState","size","inputRef","useRef","isActive","inputProps","useRadio","isFocusVisible","focusProps","useFocusRing","handleMockLabelClick","_a","setInteractionModality","getSegmentedControlsItemTestId","jsx","merge","FOCUS_STYLE","jsxs","VisuallyHidden","SegmentedControls","propId","items","activeItemId","onChange","ariaLabel","hugWidth","useMemoizedId","groupProps","useRadioGroupState","radioGroupProps","useRadioGroup","itemsRef","itemElements","useMemo","index","el","selectedIndex","width","alignment","isSmallOrHugWidth","getSliderX","translateX","getSliderWidth","isLastElement","baseValue","sliderTranslation","sliderWidth","motion"],"mappings":";;;;;;;;;;;AAuCA,MAAMA,IAAa,CAACC,MAAyDA,EAAkB,SAAS,QAUlGC,IAAwBC,EAAuD,CAACC,GAAOC,MAAQ;AACjG,QAAM,EAAE,IAAAC,GAAI,MAAAL,GAAM,UAAAM,GAAU,iBAAAC,GAAiB,MAAAC,EAAS,IAAAL,GAChDM,IAAWC,EAAgC,IAAI,GAC/CC,IAAWX,EAAK,OAAOO,EAAgB,eACvC,EAAE,YAAAK,MAAeC;AAAA,IACnB;AAAA,MACI,OAAOb,EAAK;AAAA,MACZ,cAAcD,EAAWC,CAAI,IAAIA,EAAK,YAAYA,EAAK,MAAM,SAAS;AAAA,MACtE,YAAYM;AAAA,MACZ,IAAIK,IAAWN,IAAK;AAAA,IACxB;AAAA,IACAE;AAAA,IACAE;AAAA,EAAA,GAEE,EAAE,gBAAAK,GAAgB,YAAAC,EAAW,IAAIC,EAAa,GAE9CC,IAAuB,MAAM;;AAC/B,IAAKX,MACeC,EAAA,iBAAiBP,EAAK,EAAE,IACxCkB,IAAAT,EAAS,YAAT,QAAAS,EAAkB,SAClBC,EAAuB,SAAS;AAAA,EACpC,GAGEC,IAAiC,MAAM;AACzC,YAAQ,IAAM;AAAA,MACV,KAAKrB,EAAWC,CAAI;AACT,eAAA;AAAA,MACX,KAAK,OAAOA,EAAK,SAAU;AAChB,eAAA;AAAA,MACX;AACW,eAAA;AAAA,IACf;AAAA,EAAA;AAIA,SAAA,gBAAAqB;AAAA,IAAC;AAAA,IAAA;AAAA,MAEG,KAAAjB;AAAA,MACA,WAAWkB,EAAM;AAAA,QACb;AAAA,QACA;AAAA,QACAR,KAAkBS;AAAA,MAAA,CACrB;AAAA,MAED,UAAA,gBAAAC;AAAA,QAAC;AAAA,QAAA;AAAA,UAGG,MAAK;AAAA,UACL,SAASP;AAAA,UACT,gBAAcG,EAA+B;AAAA,UAC7C,WAAWE,EAAM;AAAA,YACb;AAAA,YACAd,MAAS,UAAU,YAAY;AAAA,YAC/BG,KAAY,CAACL,IACP,uDACA;AAAA,YACNA,IACM,6DACA;AAAA,UAAA,CACT;AAAA,UAED,UAAA;AAAA,YAAA,gBAAAe,EAACI,GACG,EAAA,UAAA,gBAAAJ;AAAA,cAAC;AAAA,cAAA;AAAA,gBACI,GAAGT;AAAA,gBACH,GAAGG;AAAA,gBACJ,gBAAa;AAAA,gBACb,KAAKN;AAAA,cAAA;AAAA,YAAA,GAEb;AAAA,YACA,gBAAAe,EAAC,QAAK,EAAA,WAAU,oEACX,UAAA;AAAA,cAAWzB,EAAAC,CAAI,KACZ,gBAAAqB,EAAC,QAAK,EAAA,WAAU,gBAAe,cAAYrB,EAAK,WAC3C,UAAAA,EAAK,KACV,CAAA;AAAA,cAEHA,EAAK,SAAU,gBAAAqB,EAAA,QAAA,EAAK,WAAWtB,EAAWC,CAAI,IAAI,YAAY,IAAK,UAAKA,EAAA,MAAM,YAAW;AAAA,YAAA,GAC9F;AAAA,UAAA;AAAA,QAAA;AAAA,MACJ;AAAA,IAAA;AAAA,IAzCKA,EAAK;AAAA,EAAA;AA4CtB,CAAC;AAEDC,EAAsB,cAAc;AAE7B,MAAMyB,IAAoB,CAAC;AAAA,EAC9B,IAAIC;AAAA,EACJ,OAAAC;AAAA,EACA,cAAAC;AAAA,EACA,UAAAC;AAAA,EACA,WAAAC,IAAY;AAAA,EACZ,UAAAzB,IAAW;AAAA,EACX,UAAA0B,IAAW;AAAA,EACX,MAAAxB;AACJ,MAA4C;AAClC,QAAAH,IAAK4B,EAAcN,CAAM,GACzBO,IAAa,EAAE,UAAAJ,GAAU,OAAOD,GAAc,OAAOE,GAAW,YAAYzB,KAC5EC,IAAkB4B,EAAmBD,CAAU,GAC/C,EAAE,iBAAAE,EAAoB,IAAAC,EAAcH,GAAY3B,CAAe,GAC/D+B,IAAW5B,EAAkC,CAAA,CAAE,GAC/C6B,IAAeC,EAAQ,MAClBZ,EAAM,IAAI,CAAC5B,GAAMyC,MACpB,gBAAApB;AAAA,IAACpB;AAAA,IAAA;AAAA,MACG,IAAAI;AAAA,MACA,MAAAL;AAAA,MACA,UAAAM;AAAA,MACA,iBAAAC;AAAA,MACA,KAAK,CAACmC,MAAQJ,EAAS,QAAQG,CAAK,IAAIC;AAAA,MAExC,MAAAlC;AAAA,IAAA;AAAA,IADK,6BAA6BH,CAAE,SAASL,EAAK,EAAE;AAAA,EAAA,CAG3D,GACF,CAAC4B,GAAOvB,GAAIC,GAAUC,GAAiBC,CAAI,CAAC,GACzCmC,IAAgBf,EAAM,UAAU,CAAC5B,MAASA,EAAK,OAAOO,EAAgB,aAAa,GACnFqC,IAAQZ,IAAW,KAAK,aACxBa,IAAYb,IAAW,YAAY,8DAEnCc,IAAoBtC,MAAS,WAAWwB,GACxCe,IAAa,MAAM;;AACjB,QAAAC,IAAaF,IAAoB,KAAK;AAC1C,aAAS,IAAI,GAAG,IAAIH,GAAe;AAC/B,MAAAK,OAAc9B,IAAAoB,EAAS,QAAQ,CAAC,MAAlB,gBAAApB,EAAqB,gBAAe;AAEtD,WAAO,GAAG8B,CAAU;AAAA,EAAA,GAGlBC,IAAiB,MAAM;;AACzB,UAAMC,IAAgBP,MAAkBL,EAAS,QAAQ,SAAS,GAC5Da,IAAYL,IAAoB,IAAI,GACpCF,IAAQM,IAAgBC,IAAY,IAAIA;AAE9C,WAAO,MAAIjC,IAAAoB,EAAS,QAAQK,CAAa,MAA9B,gBAAAzB,EAAiC,gBAAe,KAAK0B,CAAK;AAAA,EAAA,GAEnEQ,IAAoBL,KACpBM,IAAcJ;AAGhB,SAAA,gBAAAzB,EAAC,OAAI,EAAA,WAAU,WACX,UAAA;AAAA,IAAA,gBAAAH;AAAA,MAACiC,EAAO;AAAA,MAAP;AAAA,QACG,eAAY;AAAA,QAEZ,SAAS,EAAE,GAAGF,GAAmB,OAAOC,EAAY;AAAA,QACpD,SAAS;AAAA,QACT,YAAY,EAAE,MAAM,SAAS,UAAU,IAAI;AAAA,QAC3C,QAAQ,CAACxB;AAAA,QACT,WAAWP,EAAM;AAAA,UACb;AAAA,UACAhB,IAAW,wDAAwD;AAAA,QAAA,CACtE;AAAA,MAAA;AAAA,IACL;AAAA,IACA,gBAAAe;AAAA,MAAC;AAAA,MAAA;AAAA,QACI,GAAGe;AAAA,QACJ,gBAAa;AAAA,QACb,WAAWd,EAAM;AAAA,UACb;AAAA,UACAsB;AAAA,UACAC;AAAA,QAAA,CACH;AAAA,QAEA,UAAAN;AAAA,MAAA;AAAA,IACL;AAAA,EACJ,EAAA,CAAA;AAER;AACAb,EAAkB,cAAc;"}