se-design 1.0.68-devnav → 1.0.69-dev

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 +1 @@
1
- {"version":3,"file":"index5.js","sources":["../src/components/Icon/index.tsx"],"sourcesContent":["// TODO: `applyAttributesToElement` recursion drops `size` for nested elements (pre-existing).\nimport React, { FC } from 'react';\nimport { ReactSVG } from 'react-svg';\nimport { getA11yNameAttributes, useAccessiblePress } from '../../utils/a11y';\n\n// Dynamically import icons using Vite's asset handling\nconst ICON_MAP: Record<string, string> = (import.meta as any).glob('/src/assets/icons/*.svg', {\n eager: true,\n query: '?url',\n import: 'default'\n});\n\nexport type RotationTypes = '0' | '45' | '90' | '135' | '180' | '225' | '270' | '315';\n\nexport type IconProps = {\n name: string;\n className?: string;\n onClick?: () => void;\n /**\n * Accessible name when Icon is interactive (onClick is provided).\n * If omitted, we fall back to `name` and warn in development.\n */\n ariaLabel?: string;\n /**\n * ID(s) of visible element(s) that label this Icon when interactive.\n * Preferred over ariaLabel when a visible label exists (keeps SR and visual text in sync).\n */\n ariaLabelledBy?: string;\n /**\n * ID(s) of element(s) that describe this Icon when interactive (additional context).\n */\n ariaDescribedBy?: string;\n /**\n * Toggle state when Icon is used as a button (e.g., show/hide sidebar).\n * Only applies when `onClick` is provided (interactive icon).\n */\n ariaPressed?: boolean;\n /**\n * Expansion state when Icon controls a collapsible region/panel.\n * Only applies when `onClick` is provided (interactive icon).\n */\n ariaExpanded?: boolean;\n /**\n * ID of the element controlled by this Icon (for aria-controls).\n * Only applies when `onClick` is provided (interactive icon).\n */\n ariaControls?: string;\n fill?: string;\n stroke?: string;\n rotation?: RotationTypes;\n size?: number;\n shouldStopPropagation?: boolean;\n automationId?: string;\n};\n\nconst applyAttributesToElement = (element: Element, fill?: string, stroke?: string, size?: number) => {\n // Only modify existing attributes\n if (fill && element.hasAttribute('fill')) {\n const currentFill = element.getAttribute('fill');\n // Only update if the current fill is not \"none\"\n if (currentFill !== 'none') {\n element.setAttribute('fill', fill);\n }\n }\n\n if (stroke && element.hasAttribute('stroke')) {\n element.setAttribute('stroke', stroke);\n }\n\n if (size && element.hasAttribute('width')) {\n element.setAttribute('width', size.toString());\n }\n\n if (size && element.hasAttribute('height')) {\n element.setAttribute('height', size.toString());\n }\n\n // Recursively apply to all child elements\n Array.from(element.children).forEach((child) => {\n applyAttributesToElement(child, fill, stroke);\n });\n};\n\nexport const Icon: FC<IconProps> = (props) => {\n const {\n name = '',\n className = '',\n onClick,\n ariaLabel,\n ariaLabelledBy,\n ariaDescribedBy,\n ariaPressed,\n ariaExpanded,\n ariaControls,\n fill,\n stroke,\n rotation = '0',\n size,\n shouldStopPropagation = false\n } = props;\n const iconRotationClasses = {\n '0': 'rotate-0',\n '45': 'rotate-45',\n '90': 'rotate-90',\n '135': 'rotate-[135deg]',\n '180': 'rotate-180',\n '225': 'rotate-[225deg]',\n '270': '-rotate-90',\n '315': '-rotate-45'\n };\n const src = ICON_MAP[`/src/assets/icons/${name}.svg`];\n\n if (!src) {\n console.error(`Icon \"${name}\" not found in ICON_MAP.`);\n return null;\n }\n\n const isInteractive = typeof onClick === 'function';\n const computedAriaLabel = ariaLabel || name;\n\n if (isInteractive && !ariaLabel && (import.meta as { env?: { DEV?: boolean } }).env?.DEV) {\n // eslint-disable-next-line no-console\n console.warn(\n `[se-design/Icon] Missing ariaLabel for clickable icon \"${name}\". ` +\n `Falling back to aria-label=\"${computedAriaLabel}\".`\n );\n }\n\n const { pressProps, role, tabIndex } = useAccessiblePress({\n isNative: false,\n onClick: isInteractive ? () => onClick?.() : undefined,\n stopPropagation: shouldStopPropagation\n });\n\n // Compute accessible name/description props with correct precedence (aligns with Button/Link).\n const accessibleNameProps = getA11yNameAttributes({\n ariaLabel: computedAriaLabel,\n ariaLabelledBy,\n ariaDescribedBy\n });\n\n const interactiveProps = isInteractive\n ? {\n ...pressProps,\n role,\n tabIndex,\n ...accessibleNameProps,\n 'aria-pressed': ariaPressed,\n 'aria-expanded': ariaExpanded,\n 'aria-controls': ariaControls || undefined\n }\n : undefined;\n\n return (\n <div\n className={`se-design-svg-wrapper transition-transform duration-250 ease-linear rounded-[3px] ${\n isInteractive ? 'cursor-pointer focus-outline' : ''\n } ${className} ${iconRotationClasses[rotation]}`}\n aria-hidden={!isInteractive ? 'true' : undefined}\n {...interactiveProps}\n data-automation-id={props?.automationId}\n >\n <ReactSVG\n src={src}\n wrapper=\"span\"\n beforeInjection={(svg) => {\n svg.setAttribute('aria-hidden', 'true');\n svg.setAttribute('role', 'none');\n applyAttributesToElement(svg, fill, stroke, size);\n }}\n />\n </div>\n );\n};\n"],"names":["ICON_MAP","import","applyAttributesToElement","element","fill","stroke","size","hasAttribute","getAttribute","setAttribute","toString","Array","from","children","forEach","child","Icon","props","name","className","onClick","ariaLabel","ariaLabelledBy","ariaDescribedBy","ariaPressed","ariaExpanded","ariaControls","rotation","shouldStopPropagation","iconRotationClasses","src","console","error","isInteractive","computedAriaLabel","pressProps","role","tabIndex","useAccessiblePress","isNative","undefined","stopPropagation","accessibleNameProps","getA11yNameAttributes","interactiveProps","React","createElement","_extends","automationId","ReactSVG","wrapper","beforeInjection","svg"],"mappings":"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"}
1
+ {"version":3,"file":"index5.js","sources":["../src/components/Icon/index.tsx"],"sourcesContent":["// TODO: `applyAttributesToElement` recursion drops `size` for nested elements (pre-existing).\nimport React from 'react';\nimport { ReactSVG } from 'react-svg';\nimport { getA11yNameAttributes, useAccessiblePress } from '../../utils/a11y';\n\n// Dynamically import icons using Vite's asset handling\nconst ICON_MAP: Record<string, string> = (import.meta as any).glob('/src/assets/icons/*.svg', {\n eager: true,\n query: '?url',\n import: 'default'\n});\n\nexport type RotationTypes = '0' | '45' | '90' | '135' | '180' | '225' | '270' | '315';\n\nexport type IconProps = {\n name: string;\n className?: string;\n onClick?: () => void;\n /**\n * Accessible name when Icon is interactive (onClick is provided).\n * If omitted, we fall back to `name` and warn in development.\n */\n ariaLabel?: string;\n /**\n * ID(s) of visible element(s) that label this Icon when interactive.\n * Preferred over ariaLabel when a visible label exists (keeps SR and visual text in sync).\n */\n ariaLabelledBy?: string;\n /**\n * ID(s) of element(s) that describe this Icon when interactive (additional context).\n */\n ariaDescribedBy?: string;\n /**\n * Toggle state when Icon is used as a button (e.g., show/hide sidebar).\n * Only applies when `onClick` is provided (interactive icon).\n */\n ariaPressed?: boolean;\n /**\n * Expansion state when Icon controls a collapsible region/panel.\n * Only applies when `onClick` is provided (interactive icon).\n */\n ariaExpanded?: boolean;\n /**\n * ID of the element controlled by this Icon (for aria-controls).\n * Only applies when `onClick` is provided (interactive icon).\n */\n ariaControls?: string;\n fill?: string;\n stroke?: string;\n rotation?: RotationTypes;\n size?: number;\n shouldStopPropagation?: boolean;\n automationId?: string;\n id?: string;\n tabIndex?: number;\n disabled?: boolean;\n onFocus?: React.FocusEventHandler<HTMLDivElement>;\n onKeyDown?: React.KeyboardEventHandler<HTMLDivElement>;\n};\n\nconst applyAttributesToElement = (element: Element, fill?: string, stroke?: string, size?: number) => {\n // Only modify existing attributes\n if (fill && element.hasAttribute('fill')) {\n const currentFill = element.getAttribute('fill');\n // Only update if the current fill is not \"none\"\n if (currentFill !== 'none') {\n element.setAttribute('fill', fill);\n }\n }\n\n if (stroke && element.hasAttribute('stroke')) {\n element.setAttribute('stroke', stroke);\n }\n\n if (size && element.hasAttribute('width')) {\n element.setAttribute('width', size.toString());\n }\n\n if (size && element.hasAttribute('height')) {\n element.setAttribute('height', size.toString());\n }\n\n // Recursively apply to all child elements\n Array.from(element.children).forEach((child) => {\n applyAttributesToElement(child, fill, stroke);\n });\n};\n\nexport const Icon = React.forwardRef<HTMLDivElement, IconProps>((props, ref) => {\n const {\n name = '',\n className = '',\n onClick,\n ariaLabel,\n ariaLabelledBy,\n ariaDescribedBy,\n ariaPressed,\n ariaExpanded,\n ariaControls,\n fill,\n stroke,\n rotation = '0',\n size,\n shouldStopPropagation = false,\n tabIndex: tabIndexProp = 0,\n id,\n disabled = false,\n automationId,\n onFocus,\n onKeyDown\n } = props;\n const iconRotationClasses = {\n '0': 'rotate-0',\n '45': 'rotate-45',\n '90': 'rotate-90',\n '135': 'rotate-[135deg]',\n '180': 'rotate-180',\n '225': 'rotate-[225deg]',\n '270': '-rotate-90',\n '315': '-rotate-45'\n };\n const src = ICON_MAP[`/src/assets/icons/${name}.svg`];\n\n if (!src) {\n console.error(`Icon \"${name}\" not found in ICON_MAP.`);\n return null;\n }\n\n const isInteractive = typeof onClick === 'function';\n const computedAriaLabel = ariaLabel || name;\n\n if (isInteractive && !ariaLabel && (import.meta as { env?: { DEV?: boolean } }).env?.DEV) {\n // eslint-disable-next-line no-console\n console.warn(\n `[se-design/Icon] Missing ariaLabel for clickable icon \"${name}\". ` +\n `Falling back to aria-label=\"${computedAriaLabel}\".`\n );\n }\n\n const { pressProps, role, tabIndex, isDisabled } = useAccessiblePress({\n isNative: false,\n onClick: isInteractive ? () => onClick?.() : undefined,\n disabled: isInteractive ? disabled : false,\n stopPropagation: shouldStopPropagation,\n tabIndex: tabIndexProp\n });\n\n // Compute accessible name/description props with correct precedence (aligns with Button/Link).\n const accessibleNameProps = getA11yNameAttributes({\n ariaLabel: computedAriaLabel,\n ariaLabelledBy,\n ariaDescribedBy\n });\n\n const interactiveProps = isInteractive\n ? {\n ...pressProps,\n role,\n tabIndex,\n ...accessibleNameProps,\n 'aria-pressed': ariaPressed,\n 'aria-expanded': ariaExpanded,\n 'aria-controls': ariaControls || undefined,\n onKeyDown: (e: React.KeyboardEvent<HTMLDivElement>) => { pressProps.onKeyDown?.(e); onKeyDown?.(e); }\n }\n : undefined;\n\n return (\n <div\n ref={ref}\n className={`se-design-svg-wrapper transition-transform duration-250 ease-linear rounded-[3px] ${\n isInteractive ? `${isDisabled ? 'opacity-50 cursor-default' : 'cursor-pointer focus-outline'}` : ''\n } ${className} ${iconRotationClasses[rotation]}`}\n id={id}\n aria-hidden={!isInteractive ? 'true' : undefined}\n {...interactiveProps}\n onFocus={onFocus}\n data-automation-id={automationId}\n >\n <ReactSVG\n src={src}\n wrapper=\"span\"\n beforeInjection={(svg) => {\n svg.setAttribute('aria-hidden', 'true');\n svg.setAttribute('role', 'none');\n applyAttributesToElement(svg, fill, stroke, size);\n }}\n />\n </div>\n );\n});\n\nIcon.displayName = 'Icon';\n"],"names":["ICON_MAP","import","applyAttributesToElement","element","fill","stroke","size","hasAttribute","getAttribute","setAttribute","toString","Array","from","children","forEach","child","Icon","React","forwardRef","props","ref","name","className","onClick","ariaLabel","ariaLabelledBy","ariaDescribedBy","ariaPressed","ariaExpanded","ariaControls","rotation","shouldStopPropagation","tabIndex","tabIndexProp","id","disabled","automationId","onFocus","onKeyDown","iconRotationClasses","src","console","error","isInteractive","computedAriaLabel","pressProps","role","isDisabled","useAccessiblePress","isNative","undefined","stopPropagation","accessibleNameProps","getA11yNameAttributes","interactiveProps","e","createElement","_extends","ReactSVG","wrapper","beforeInjection","svg","displayName"],"mappings":"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"}
package/dist/index68.js CHANGED
@@ -1,26 +1,26 @@
1
- import * as a from "react";
1
+ import * as c from "react";
2
2
  function R({
3
3
  itemIds: n,
4
4
  tabIndex: i = 0,
5
- defaultFocusedId: s,
5
+ defaultFocusedId: l,
6
6
  orientation: o = "horizontal",
7
7
  cols: u,
8
8
  loop: h = !0,
9
- onFocusChange: k
9
+ onFocusChange: x
10
10
  }) {
11
- const [c, x] = a.useState(s || n[0] || ""), g = a.useRef({});
12
- a.useEffect(() => {
13
- if (n.length > 0 && !n.includes(c)) {
14
- const e = s || n[0] || "";
15
- x(e);
11
+ const [a, g] = c.useState(l || n[0] || ""), b = c.useRef({});
12
+ c.useEffect(() => {
13
+ if (n.length > 0 && !n.includes(a)) {
14
+ const e = l || n[0] || "";
15
+ g(e);
16
16
  }
17
- }, [n, c, s]);
18
- const w = a.useCallback((e) => {
19
- x(e), k?.(e);
20
- }, [k]), b = a.useCallback((e, t = 1) => {
17
+ }, [n, a, l]);
18
+ const k = c.useCallback((e) => {
19
+ g(e), x?.(e);
20
+ }, [x]), v = c.useCallback((e, t = 1) => {
21
21
  if (n.length === 0) return;
22
- const l = n.indexOf(c), f = Math.max(0, l);
23
- let r = f;
22
+ const f = n.indexOf(a), s = Math.max(0, f);
23
+ let r = s;
24
24
  switch (e) {
25
25
  case "first":
26
26
  r = 0;
@@ -29,25 +29,26 @@ function R({
29
29
  r = n.length - 1;
30
30
  break;
31
31
  case "prev":
32
- h ? r = (f - t + n.length) % n.length : r = Math.max(0, f - t);
32
+ h ? r = (s - t + n.length) % n.length : r = Math.max(0, s - t);
33
33
  break;
34
34
  case "next":
35
- h ? r = (f + t) % n.length : r = Math.min(n.length - 1, f + t);
35
+ h ? r = (s + t) % n.length : r = Math.min(n.length - 1, s + t);
36
36
  break;
37
37
  }
38
- const v = n[r];
39
- v && g.current[v]?.focus();
40
- }, [n, c, h]), y = a.useCallback((e) => ({
38
+ const w = n[r];
39
+ w && b.current[w]?.focus();
40
+ }, [n, a, h]), y = c.useCallback((e) => ({
41
41
  ref: (t) => {
42
- g.current[e] = t;
42
+ b.current[e] = t;
43
43
  },
44
- tabIndex: c === e ? i : -1
45
- }), [c, i]), p = a.useCallback((e) => {
46
- let t = null, l = 1;
47
- e.key === "Home" ? t = "first" : e.key === "End" ? t = "last" : (o !== "vertical" && (e.key === "ArrowLeft" ? t = "prev" : e.key === "ArrowRight" && (t = "next")), !t && o !== "horizontal" && (e.key === "ArrowUp" ? t = "prev" : e.key === "ArrowDown" && (t = "next"), t && u && (l = u))), t && (e.preventDefault(), e.stopPropagation(), b(t, l));
48
- }, [o, u, b]);
44
+ tabIndex: a === e ? i : -1,
45
+ onFocus: () => k(e)
46
+ }), [a, i, k]), p = c.useCallback((e) => {
47
+ let t = null, f = 1;
48
+ e.key === "Home" ? t = "first" : e.key === "End" ? t = "last" : (o !== "vertical" && (e.key === "ArrowLeft" ? t = "prev" : e.key === "ArrowRight" && (t = "next")), !t && o !== "horizontal" && (e.key === "ArrowUp" ? t = "prev" : e.key === "ArrowDown" && (t = "next"), t && u && (f = u))), t && (e.preventDefault(), e.stopPropagation(), v(t, f));
49
+ }, [o, u, v]);
49
50
  return {
50
- setFocusedId: w,
51
+ setFocusedId: k,
51
52
  handleKeyDown: p,
52
53
  getRovingItemProps: y
53
54
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index68.js","sources":["../src/utils/a11y/useRovingFocus.ts"],"sourcesContent":["import * as React from 'react';\n\nexport type RovingDirection = 'prev' | 'next' | 'first' | 'last';\n\nexport interface UseRovingFocusOptions {\n /**\n * Array of item IDs in order\n */\n itemIds: string[];\n\n /**\n * The tabIndex to apply to the currently focused item in the roving group.\n * Defaults to 0 \n */\n tabIndex?: number;\n\n /**\n * Initial focused item ID. Defaults to first item.\n */\n defaultFocusedId?: string;\n\n /**\n * Orientation for arrow key mapping.\n * - horizontal: ArrowLeft/ArrowRight\n * - vertical: ArrowUp/ArrowDown\n * - grid: all four arrow keys (Left/Right move by 1, Up/Down move by `cols`)\n */\n orientation?: 'horizontal' | 'vertical' | 'grid';\n\n /**\n * Number of columns in the grid. Required when orientation is 'grid'.\n * ArrowUp/ArrowDown navigate by this many items in the flat itemIds array.\n */\n cols?: number;\n\n /**\n * Whether navigation wraps around at ends. Defaults to true.\n */\n loop?: boolean;\n\n /**\n * Callback when focus changes\n */\n onFocusChange?: (id: string) => void;\n}\n\nexport interface RovingItemProps {\n ref: (el: HTMLElement | null) => void;\n tabIndex: number;\n}\n\nexport interface UseRovingFocusReturn {\n /**\n * Set focused item ID manually\n */\n setFocusedId: (id: string) => void;\n\n /**\n * Keyboard handler for arrow/Home/End navigation.\n * Attach to each item's onKeyDown.\n */\n handleKeyDown: (e: React.KeyboardEvent) => void;\n\n /**\n * Get props for an item in the roving focus group (ref + tabIndex)\n */\n getRovingItemProps: (id: string) => RovingItemProps;\n}\n\n/**\n * Hook for managing roving focus pattern (roving tabindex).\n * Reusable for composite widgets: tabs, toolbars, menus, listboxes, radio groups, grids.\n *\n * @example\n * // 1D (toolbar/tabs):\n * const { getRovingItemProps, handleKeyDown } = useRovingFocus({\n * itemIds: ['tab1', 'tab2', 'tab3'],\n * orientation: 'horizontal'\n * });\n *\n * // 2D (grid — flat itemIds, cols for row-jump math):\n * const { getRovingItemProps, handleKeyDown } = useRovingFocus({\n * itemIds: ['r0c0', 'r0c1', 'r0c2', 'r1c0', 'r1c1', 'r1c2'],\n * orientation: 'grid',\n * cols: 3\n * });\n *\n * // In render:\n * <button {...getRovingItemProps('tab1')} onKeyDown={handleKeyDown}>Tab 1</button>\n */\nexport function useRovingFocus({\n itemIds,\n tabIndex = 0,\n defaultFocusedId,\n orientation = 'horizontal',\n cols,\n loop = true,\n onFocusChange\n}: UseRovingFocusOptions): UseRovingFocusReturn {\n const [focusedId, setFocusedIdState] = React.useState<string>(\n defaultFocusedId || itemIds[0] || ''\n );\n\n const itemRefs = React.useRef<Record<string, HTMLElement | null>>({});\n\n // Sync focusedId if itemIds change and current focusedId is no longer valid\n React.useEffect(() => {\n if (itemIds.length > 0 && !itemIds.includes(focusedId)) {\n const newFocusedId = defaultFocusedId || itemIds[0] || '';\n setFocusedIdState(newFocusedId);\n }\n }, [itemIds, focusedId, defaultFocusedId]);\n\n const setFocusedId = React.useCallback(\n (id: string) => {\n setFocusedIdState(id);\n onFocusChange?.(id);\n },\n [onFocusChange]\n );\n\n const moveFocus = React.useCallback(\n (direction: RovingDirection, step: number = 1) => {\n if (itemIds.length === 0) return;\n\n const currentIdx = itemIds.indexOf(focusedId);\n const safeIdx = Math.max(0, currentIdx);\n let nextIdx = safeIdx;\n\n switch (direction) {\n case 'first':\n nextIdx = 0;\n break;\n case 'last':\n nextIdx = itemIds.length - 1;\n break;\n case 'prev':\n if (loop) {\n nextIdx = (safeIdx - step + itemIds.length) % itemIds.length;\n } else {\n nextIdx = Math.max(0, safeIdx - step);\n }\n break;\n case 'next':\n if (loop) {\n nextIdx = (safeIdx + step) % itemIds.length;\n } else {\n nextIdx = Math.min(itemIds.length - 1, safeIdx + step);\n }\n break;\n }\n\n const nextId = itemIds[nextIdx];\n if (!nextId) return;\n\n itemRefs.current[nextId]?.focus();\n },\n [itemIds, focusedId, loop]\n );\n\n const getRovingItemProps = React.useCallback(\n (id: string): RovingItemProps => ({\n ref: (el: HTMLElement | null) => {\n itemRefs.current[id] = el;\n },\n tabIndex: focusedId === id ? tabIndex : -1\n }),\n [focusedId, tabIndex]\n );\n\n // Keyboard handler for arrow/Home/End navigation\n const handleKeyDown = React.useCallback(\n (e: React.KeyboardEvent) => {\n let direction: RovingDirection | null = null;\n let step = 1;\n\n if (e.key === 'Home') {\n direction = 'first';\n } else if (e.key === 'End') {\n direction = 'last';\n } else {\n // Horizontal axis (Left/Right) — active for 'horizontal' and 'grid'\n if (orientation !== 'vertical') {\n if (e.key === 'ArrowLeft') direction = 'prev';\n else if (e.key === 'ArrowRight') direction = 'next';\n }\n // Vertical axis (Up/Down) — active for 'vertical' and 'grid'\n if (!direction && orientation !== 'horizontal') {\n if (e.key === 'ArrowUp') direction = 'prev';\n else if (e.key === 'ArrowDown') direction = 'next';\n if (direction && cols) step = cols;\n }\n }\n\n if (direction) {\n e.preventDefault();\n e.stopPropagation();\n moveFocus(direction, step);\n }\n },\n [orientation, cols, moveFocus]\n );\n\n return {\n setFocusedId,\n handleKeyDown,\n getRovingItemProps\n };\n}\n"],"names":["React","useRovingFocus","itemIds","tabIndex","defaultFocusedId","orientation","cols","loop","onFocusChange","focusedId","setFocusedIdState","useState","itemRefs","useRef","useEffect","length","includes","newFocusedId","setFocusedId","useCallback","id","moveFocus","direction","step","currentIdx","indexOf","safeIdx","Math","max","nextIdx","min","nextId","current","focus","getRovingItemProps","ref","el","handleKeyDown","e","key","preventDefault","stopPropagation"],"mappings":"AA0FO,YAAAA,OAAA;AAAA,SAASC,EAAe;AAAA,EAC7BC,SAAAA;AAAAA,EACAC,UAAAA,IAAW;AAAA,EACXC,kBAAAA;AAAAA,EACAC,aAAAA,IAAc;AAAA,EACdC,MAAAA;AAAAA,EACAC,MAAAA,IAAO;AAAA,EACPC,eAAAA;AACqB,GAAyB;AAC9C,QAAM,CAACC,GAAWC,CAAiB,IAAIV,EAAMW,SAC3CP,KAAoBF,EAAQ,CAAC,KAAK,EACpC,GAEMU,IAAWZ,EAAMa,OAA2C,EAAE;AAGpEb,EAAAA,EAAMc,UAAU,MAAM;AACpB,QAAIZ,EAAQa,SAAS,KAAK,CAACb,EAAQc,SAASP,CAAS,GAAG;AACtD,YAAMQ,IAAeb,KAAoBF,EAAQ,CAAC,KAAK;AACvDQ,MAAAA,EAAkBO,CAAY;AAAA,IAChC;AAAA,EACF,GAAG,CAACf,GAASO,GAAWL,CAAgB,CAAC;AAEzC,QAAMc,IAAelB,EAAMmB,YACzB,CAACC,MAAe;AACdV,IAAAA,EAAkBU,CAAE,GACpBZ,IAAgBY,CAAE;AAAA,EACpB,GACA,CAACZ,CAAa,CAChB,GAEMa,IAAYrB,EAAMmB,YACtB,CAACG,GAA4BC,IAAe,MAAM;AAChD,QAAIrB,EAAQa,WAAW,EAAG;AAE1B,UAAMS,IAAatB,EAAQuB,QAAQhB,CAAS,GACtCiB,IAAUC,KAAKC,IAAI,GAAGJ,CAAU;AACtC,QAAIK,IAAUH;AAEd,YAAQJ,GAAAA;AAAAA,MACN,KAAK;AACHO,QAAAA,IAAU;AACV;AAAA,MACF,KAAK;AACHA,QAAAA,IAAU3B,EAAQa,SAAS;AAC3B;AAAA,MACF,KAAK;AACH,QAAIR,IACFsB,KAAWH,IAAUH,IAAOrB,EAAQa,UAAUb,EAAQa,SAEtDc,IAAUF,KAAKC,IAAI,GAAGF,IAAUH,CAAI;AAEtC;AAAA,MACF,KAAK;AACH,QAAIhB,IACFsB,KAAWH,IAAUH,KAAQrB,EAAQa,SAErCc,IAAUF,KAAKG,IAAI5B,EAAQa,SAAS,GAAGW,IAAUH,CAAI;AAEvD;AAAA,IAAA;AAGJ,UAAMQ,IAAS7B,EAAQ2B,CAAO;AAC9B,IAAKE,KAELnB,EAASoB,QAAQD,CAAM,GAAGE,MAAAA;AAAAA,EAC5B,GACA,CAAC/B,GAASO,GAAWF,CAAI,CAC3B,GAEM2B,IAAqBlC,EAAMmB,YAC/B,CAACC,OAAiC;AAAA,IAChCe,KAAKA,CAACC,MAA2B;AAC/BxB,MAAAA,EAASoB,QAAQZ,CAAE,IAAIgB;AAAAA,IACzB;AAAA,IACAjC,UAAUM,MAAcW,IAAKjB,IAAW;AAAA,EAAA,IAE1C,CAACM,GAAWN,CAAQ,CACtB,GAGMkC,IAAgBrC,EAAMmB,YAC1B,CAACmB,MAA2B;AAC1B,QAAIhB,IAAoC,MACpCC,IAAO;AAEX,IAAIe,EAAEC,QAAQ,SACZjB,IAAY,UACHgB,EAAEC,QAAQ,QACnBjB,IAAY,UAGRjB,MAAgB,eACdiC,EAAEC,QAAQ,cAAajB,IAAY,SAC9BgB,EAAEC,QAAQ,iBAAcjB,IAAY,UAG3C,CAACA,KAAajB,MAAgB,iBAC5BiC,EAAEC,QAAQ,YAAWjB,IAAY,SAC5BgB,EAAEC,QAAQ,gBAAajB,IAAY,SACxCA,KAAahB,MAAMiB,IAAOjB,MAI9BgB,MACFgB,EAAEE,eAAAA,GACFF,EAAEG,gBAAAA,GACFpB,EAAUC,GAAWC,CAAI;AAAA,EAE7B,GACA,CAAClB,GAAaC,GAAMe,CAAS,CAC/B;AAEA,SAAO;AAAA,IACLH,cAAAA;AAAAA,IACAmB,eAAAA;AAAAA,IACAH,oBAAAA;AAAAA,EAAAA;AAEJ;"}
1
+ {"version":3,"file":"index68.js","sources":["../src/utils/a11y/useRovingFocus.ts"],"sourcesContent":["import * as React from 'react';\n\nexport type RovingDirection = 'prev' | 'next' | 'first' | 'last';\n\nexport interface UseRovingFocusOptions {\n /**\n * Array of item IDs in order\n */\n itemIds: string[];\n\n /**\n * The tabIndex to apply to the currently focused item in the roving group.\n * Defaults to 0 \n */\n tabIndex?: number;\n\n /**\n * Initial focused item ID. Defaults to first item.\n */\n defaultFocusedId?: string;\n\n /**\n * Orientation for arrow key mapping.\n * - horizontal: ArrowLeft/ArrowRight\n * - vertical: ArrowUp/ArrowDown\n * - grid: all four arrow keys (Left/Right move by 1, Up/Down move by `cols`)\n */\n orientation?: 'horizontal' | 'vertical' | 'grid';\n\n /**\n * Number of columns in the grid. Required when orientation is 'grid'.\n * ArrowUp/ArrowDown navigate by this many items in the flat itemIds array.\n */\n cols?: number;\n\n /**\n * Whether navigation wraps around at ends. Defaults to true.\n */\n loop?: boolean;\n\n /**\n * Callback when focus changes\n */\n onFocusChange?: (id: string) => void;\n}\n\nexport interface RovingItemProps {\n ref: (el: HTMLElement | null) => void;\n tabIndex: number;\n onFocus: () => void;\n}\n\nexport interface UseRovingFocusReturn {\n /**\n * Set focused item ID manually\n */\n setFocusedId: (id: string) => void;\n\n /**\n * Keyboard handler for arrow/Home/End navigation.\n * Attach to each item's onKeyDown.\n */\n handleKeyDown: (e: React.KeyboardEvent) => void;\n\n /**\n * Get props for an item in the roving focus group (ref + tabIndex)\n */\n getRovingItemProps: (id: string) => RovingItemProps;\n}\n\n/**\n * Hook for managing roving focus pattern (roving tabindex).\n * Reusable for composite widgets: tabs, toolbars, menus, listboxes, radio groups, grids.\n *\n * @example\n * // 1D (toolbar/tabs):\n * const { getRovingItemProps, handleKeyDown } = useRovingFocus({\n * itemIds: ['tab1', 'tab2', 'tab3'],\n * orientation: 'horizontal'\n * });\n *\n * // 2D (grid — flat itemIds, cols for row-jump math):\n * const { getRovingItemProps, handleKeyDown } = useRovingFocus({\n * itemIds: ['r0c0', 'r0c1', 'r0c2', 'r1c0', 'r1c1', 'r1c2'],\n * orientation: 'grid',\n * cols: 3\n * });\n *\n * // In render:\n * <button {...getRovingItemProps('tab1')} onKeyDown={handleKeyDown}>Tab 1</button>\n */\nexport function useRovingFocus({\n itemIds,\n tabIndex = 0,\n defaultFocusedId,\n orientation = 'horizontal',\n cols,\n loop = true,\n onFocusChange\n}: UseRovingFocusOptions): UseRovingFocusReturn {\n const [focusedId, setFocusedIdState] = React.useState<string>(\n defaultFocusedId || itemIds[0] || ''\n );\n\n const itemRefs = React.useRef<Record<string, HTMLElement | null>>({});\n\n // Sync focusedId if itemIds change and current focusedId is no longer valid\n React.useEffect(() => {\n if (itemIds.length > 0 && !itemIds.includes(focusedId)) {\n const newFocusedId = defaultFocusedId || itemIds[0] || '';\n setFocusedIdState(newFocusedId);\n }\n }, [itemIds, focusedId, defaultFocusedId]);\n\n const setFocusedId = React.useCallback(\n (id: string) => {\n setFocusedIdState(id);\n onFocusChange?.(id);\n },\n [onFocusChange]\n );\n\n const moveFocus = React.useCallback(\n (direction: RovingDirection, step: number = 1) => {\n if (itemIds.length === 0) return;\n\n const currentIdx = itemIds.indexOf(focusedId);\n const safeIdx = Math.max(0, currentIdx);\n let nextIdx = safeIdx;\n\n switch (direction) {\n case 'first':\n nextIdx = 0;\n break;\n case 'last':\n nextIdx = itemIds.length - 1;\n break;\n case 'prev':\n if (loop) {\n nextIdx = (safeIdx - step + itemIds.length) % itemIds.length;\n } else {\n nextIdx = Math.max(0, safeIdx - step);\n }\n break;\n case 'next':\n if (loop) {\n nextIdx = (safeIdx + step) % itemIds.length;\n } else {\n nextIdx = Math.min(itemIds.length - 1, safeIdx + step);\n }\n break;\n }\n\n const nextId = itemIds[nextIdx];\n if (!nextId) return;\n\n itemRefs.current[nextId]?.focus();\n },\n [itemIds, focusedId, loop]\n );\n\n const getRovingItemProps = React.useCallback(\n (id: string): RovingItemProps => ({\n ref: (el: HTMLElement | null) => {\n itemRefs.current[id] = el;\n },\n tabIndex: focusedId === id ? tabIndex : -1,\n onFocus: () => setFocusedId(id)\n }),\n [focusedId, tabIndex, setFocusedId]\n );\n\n // Keyboard handler for arrow/Home/End navigation\n const handleKeyDown = React.useCallback(\n (e: React.KeyboardEvent) => {\n let direction: RovingDirection | null = null;\n let step = 1;\n\n if (e.key === 'Home') {\n direction = 'first';\n } else if (e.key === 'End') {\n direction = 'last';\n } else {\n // Horizontal axis (Left/Right) — active for 'horizontal' and 'grid'\n if (orientation !== 'vertical') {\n if (e.key === 'ArrowLeft') direction = 'prev';\n else if (e.key === 'ArrowRight') direction = 'next';\n }\n // Vertical axis (Up/Down) — active for 'vertical' and 'grid'\n if (!direction && orientation !== 'horizontal') {\n if (e.key === 'ArrowUp') direction = 'prev';\n else if (e.key === 'ArrowDown') direction = 'next';\n if (direction && cols) step = cols;\n }\n }\n\n if (direction) {\n e.preventDefault();\n e.stopPropagation();\n moveFocus(direction, step);\n }\n },\n [orientation, cols, moveFocus]\n );\n\n return {\n setFocusedId,\n handleKeyDown,\n getRovingItemProps\n };\n}\n"],"names":["React","useRovingFocus","itemIds","tabIndex","defaultFocusedId","orientation","cols","loop","onFocusChange","focusedId","setFocusedIdState","useState","itemRefs","useRef","useEffect","length","includes","newFocusedId","setFocusedId","useCallback","id","moveFocus","direction","step","currentIdx","indexOf","safeIdx","Math","max","nextIdx","min","nextId","current","focus","getRovingItemProps","ref","el","onFocus","handleKeyDown","e","key","preventDefault","stopPropagation"],"mappings":"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"}
package/dist/index8.js CHANGED
@@ -1,57 +1,57 @@
1
- import n from "react";
1
+ import o from "react";
2
2
  import { useStableId as k } from "./index188.js";
3
3
  import { getA11yNameAttributes as A } from "./index70.js";
4
- import { useAccessiblePress as I } from "./index66.js";
5
- import { mergeIds as O } from "./index189.js";
4
+ import { useAccessiblePress as O } from "./index66.js";
5
+ import { mergeIds as C } from "./index189.js";
6
6
  function l() {
7
7
  return l = Object.assign ? Object.assign.bind() : function(t) {
8
- for (var o = 1; o < arguments.length; o++) {
9
- var e = arguments[o];
8
+ for (var a = 1; a < arguments.length; a++) {
9
+ var e = arguments[a];
10
10
  for (var r in e) ({}).hasOwnProperty.call(e, r) && (t[r] = e[r]);
11
11
  }
12
12
  return t;
13
13
  }, l.apply(null, arguments);
14
14
  }
15
- const L = ({
15
+ const P = /* @__PURE__ */ o.forwardRef(({
16
16
  checked: t = !1,
17
- onToggle: o = () => {
17
+ onToggle: a = () => {
18
18
  },
19
19
  disabled: e = !1,
20
20
  label: r,
21
21
  labelPosition: c = "left",
22
- labelClickable: a = !0,
22
+ labelClickable: n = !0,
23
23
  automationId: s = "toggle",
24
24
  ariaLabelledBy: i,
25
25
  ariaDescribedBy: b,
26
26
  ariaLabel: g,
27
27
  tabIndex: v = 0
28
- }) => {
28
+ }, h) => {
29
29
  const u = k(void 0, "toggle-label"), d = () => {
30
- e || o(!t);
30
+ e || a(!t);
31
31
  }, {
32
- pressProps: h,
33
- tabIndex: y,
32
+ pressProps: y,
33
+ tabIndex: x,
34
34
  role: $
35
- } = I({
35
+ } = O({
36
36
  disabled: e,
37
37
  onClick: d,
38
- stopPropagation: a,
38
+ stopPropagation: n,
39
39
  isNative: !1,
40
40
  role: "switch",
41
41
  tabIndex: v
42
- }), x = A({
43
- ariaLabelledBy: r && !g ? O(u, i) : i,
42
+ }), w = A({
43
+ ariaLabelledBy: r && !g ? C(u, i) : i,
44
44
  ariaLabel: g,
45
45
  ariaDescribedBy: b
46
- }), m = (p, E = !1) => p ? /* @__PURE__ */ n.createElement("label", {
46
+ }), m = (p, I = !1) => p ? /* @__PURE__ */ o.createElement("label", {
47
47
  id: u,
48
- className: `select-none ${N[E ? "disabled" : "enabled"]}`,
48
+ className: `select-none ${E[I ? "disabled" : "enabled"]}`,
49
49
  "data-automation-id": `${s}-label`
50
- }, p) : null, w = {
50
+ }, p) : null, N = {
51
51
  enabled: "cursor-pointer",
52
52
  disabled: "cursor-not-allowed"
53
- }, N = {
54
- enabled: `text-[var(--color-gray-700)] ${a ? "cursor-pointer" : ""}`,
53
+ }, E = {
54
+ enabled: `text-[var(--color-gray-700)] ${n ? "cursor-pointer" : ""}`,
55
55
  disabled: "text-[var(--color-gray-600)] cursor-not-allowed"
56
56
  }, f = {
57
57
  checked: ` ${e ? "bg-[var(--color-green-100)]" : "bg-[var(--color-green-400)] hover:bg-[var(--color-green-500)]"}`,
@@ -59,32 +59,35 @@ const L = ({
59
59
  enabled: " cursor-pointer",
60
60
  disabled: " cursor-not-allowed"
61
61
  };
62
- return /* @__PURE__ */ n.createElement("div", {
63
- className: `se-design-toggle flex items-center gap-1 ${w[e ? "disabled" : "enabled"]}`,
64
- onClick: a ? d : void 0,
62
+ return /* @__PURE__ */ o.createElement("div", {
63
+ className: `se-design-toggle flex items-center gap-1 ${N[e ? "disabled" : "enabled"]}`,
64
+ onClick: n ? d : void 0,
65
65
  "data-automation-id": `${s}-container`
66
- }, r && c === "left" && m(r, e), /* @__PURE__ */ n.createElement("div", l({
66
+ }, r && c === "left" && m(r, e), /* @__PURE__ */ o.createElement("div", l({
67
+ ref: h,
67
68
  role: $,
68
- tabIndex: y,
69
+ tabIndex: x,
69
70
  "aria-checked": t
70
- }, x, h, {
71
+ }, w, y, {
71
72
  className: `toggle-btn focus-outline block w-8 h-4 p-0.5 rounded-full transition ease-in-out
72
73
  ${f[t ? "checked" : "unchecked"]}
73
74
  ${f[e ? "disabled" : "enabled"]}
74
75
  `,
75
76
  "data-automation-id": `${s}-button`
76
- }), /* @__PURE__ */ n.createElement("input", {
77
+ }), /* @__PURE__ */ o.createElement("input", {
77
78
  className: "opacity-0 hidden",
78
79
  type: "checkbox",
79
80
  checked: t,
80
81
  readOnly: !0,
81
- disabled: e
82
- }), /* @__PURE__ */ n.createElement("span", {
82
+ disabled: e,
83
+ tabIndex: -1
84
+ }), /* @__PURE__ */ o.createElement("span", {
83
85
  className: `block w-3 h-3 rounded-full bg-[var(--color-white)]
84
86
  transform transition-transform ${t ? "translate-x-4" : ""}`
85
87
  })), r && c === "right" && m(r, e));
86
- };
88
+ });
89
+ P.displayName = "Toggle";
87
90
  export {
88
- L as Toggle
91
+ P as Toggle
89
92
  };
90
93
  //# sourceMappingURL=index8.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index8.js","sources":["../src/components/Toggle/index.tsx"],"sourcesContent":["import React from 'react';\nimport { useStableId } from '../../utils/useStableId';\nimport { useAccessiblePress, getA11yNameAttributes } from '../../utils/a11y';\nimport { mergeIds } from '../../utils/mergeIds';\n\nexport interface ToggleProps {\n /**\n * Callback when the toggle is toggled. The parent is responsible for updating the checked state.\n */\n onToggle?: (checked: boolean) => void;\n /**\n * The controlled state of the toggle.\n */\n checked: boolean;\n /**\n * Optional disabled state\n */\n disabled?: boolean;\n /**\n * Optional label\n */\n label?: string;\n /**\n * Position of the label\n */\n labelPosition?: 'left' | 'right';\n /**\n * Optional className\n */\n labelClickable?: boolean;\n /**\n * Automation ID for testing\n */\n automationId?: string;\n /**\n * ID(s) of element(s) that label this toggle (for screen reader association).\n * Typically used when toggle is part of a larger labelled context.\n */\n ariaLabelledBy?: string;\n /**\n * ID(s) of element(s) that describe this toggle (provides additional context).\n * Often used for help text or instructions.\n */\n ariaDescribedBy?: string;\n /**\n * Explicit accessible name for the toggle.\n * Used as fallback when ariaLabelledBy is not provided and no internal label exists.\n */\n ariaLabel?: string;\n /**\n * Custom tab index for the toggle.\n * Use -1 to remove from tab order, 0 (default) for natural tab order.\n */\n tabIndex?: number;\n}\n\nexport const Toggle: React.FC<ToggleProps> = ({\n checked = false,\n onToggle = () => {},\n disabled = false,\n label,\n labelPosition = 'left',\n labelClickable = true,\n automationId = 'toggle',\n ariaLabelledBy,\n ariaDescribedBy,\n ariaLabel,\n tabIndex: tabIndexProp = 0\n}) => {\n const internalLabelId = useStableId(undefined, 'toggle-label');\n\n const handleToggle = () => {\n if (disabled) return;\n onToggle(!checked);\n };\n\n // pressProps contains: onPointerDown, onMouseDown, onTouchStart, onClick, onKeyDown, aria-disabled, aria-busy\n // When labelClickable=true, container has onClick handler, so we need stopPropagation to prevent\n // container's onClick from firing when button is clicked (avoiding double-toggle).\n // When labelClickable=false, container has no onClick, so stopPropagation isn't needed but harmless.\n const { pressProps, tabIndex, role } = useAccessiblePress({\n disabled,\n onClick: handleToggle,\n stopPropagation: labelClickable,\n isNative: false,\n role: 'switch',\n tabIndex: tabIndexProp\n });\n\n // a11yNameAttributes contains: aria-labelledby (if provided), aria-label (fallback), aria-describedby (if provided)\n // When ariaLabel is provided, it takes precedence over label (matches AutoCompleteInput/PhoneInput pattern)\n const a11yNameAttributes = getA11yNameAttributes({\n ariaLabelledBy: label && !ariaLabel ? mergeIds(internalLabelId, ariaLabelledBy) : ariaLabelledBy,\n ariaLabel,\n ariaDescribedBy\n });\n\n const renderLabel = (label: string, disabled: boolean = false) => {\n if (label) {\n return (\n <label\n id={internalLabelId}\n className={`select-none ${labelClass[disabled ? 'disabled' : 'enabled']}`}\n data-automation-id={`${automationId}-label`}\n >\n {label}\n </label>\n );\n }\n return null;\n };\n\n const containerClass = {\n enabled: 'cursor-pointer',\n disabled: 'cursor-not-allowed'\n };\n const labelClass = {\n enabled: `text-[var(--color-gray-700)] ${labelClickable ? 'cursor-pointer' : ''}`,\n disabled: 'text-[var(--color-gray-600)] cursor-not-allowed'\n };\n const toggleClass = {\n checked: ` ${\n disabled ? 'bg-[var(--color-green-100)]' : 'bg-[var(--color-green-400)] hover:bg-[var(--color-green-500)]'\n }`,\n unchecked: ` ${\n disabled ? 'bg-[var(--color-gray-400)]' : 'bg-[var(--color-gray-600)] hover:bg-[var(--color-gray-650)]'\n }`,\n enabled: ' cursor-pointer',\n disabled: ' cursor-not-allowed'\n };\n\n return (\n <div\n className={`se-design-toggle flex items-center gap-1 ${containerClass[disabled ? 'disabled' : 'enabled']}`}\n onClick={labelClickable ? handleToggle : undefined}\n data-automation-id={`${automationId}-container`}\n >\n {label && labelPosition === 'left' && renderLabel(label, disabled)}\n <div\n role={role}\n tabIndex={tabIndex}\n aria-checked={checked}\n {...a11yNameAttributes}\n {...pressProps}\n className={`toggle-btn focus-outline block w-8 h-4 p-0.5 rounded-full transition ease-in-out\n ${toggleClass[checked ? 'checked' : 'unchecked']}\n ${toggleClass[disabled ? 'disabled' : 'enabled']}\n `}\n data-automation-id={`${automationId}-button`}\n >\n <input className=\"opacity-0 hidden\" type=\"checkbox\" checked={checked} readOnly disabled={disabled} />\n <span\n className={`block w-3 h-3 rounded-full bg-[var(--color-white)]\n transform transition-transform ${checked ? 'translate-x-4' : ''}`}\n ></span>\n </div>\n {label && labelPosition === 'right' && renderLabel(label, disabled)}\n </div>\n );\n};\n"],"names":["Toggle","checked","onToggle","disabled","label","labelPosition","labelClickable","automationId","ariaLabelledBy","ariaDescribedBy","ariaLabel","tabIndex","tabIndexProp","internalLabelId","useStableId","undefined","handleToggle","pressProps","role","useAccessiblePress","onClick","stopPropagation","isNative","a11yNameAttributes","getA11yNameAttributes","mergeIds","renderLabel","React","createElement","id","className","labelClass","containerClass","enabled","toggleClass","unchecked","_extends","type","readOnly"],"mappings":";;;;;;;;;;;;;;AAwDO,MAAMA,IAAgCA,CAAC;AAAA,EAC5CC,SAAAA,IAAU;AAAA,EACVC,UAAAA,IAAWA,MAAM;AAAA,EAAC;AAAA,EAClBC,UAAAA,IAAW;AAAA,EACXC,OAAAA;AAAAA,EACAC,eAAAA,IAAgB;AAAA,EAChBC,gBAAAA,IAAiB;AAAA,EACjBC,cAAAA,IAAe;AAAA,EACfC,gBAAAA;AAAAA,EACAC,iBAAAA;AAAAA,EACAC,WAAAA;AAAAA,EACAC,UAAUC,IAAe;AAC3B,MAAM;AACJ,QAAMC,IAAkBC,EAAYC,QAAW,cAAc,GAEvDC,IAAeA,MAAM;AACzB,IAAIb,KACJD,EAAS,CAACD,CAAO;AAAA,EACnB,GAMM;AAAA,IAAEgB,YAAAA;AAAAA,IAAYN,UAAAA;AAAAA,IAAUO,MAAAA;AAAAA,EAAAA,IAASC,EAAmB;AAAA,IACxDhB,UAAAA;AAAAA,IACAiB,SAASJ;AAAAA,IACTK,iBAAiBf;AAAAA,IACjBgB,UAAU;AAAA,IACVJ,MAAM;AAAA,IACNP,UAAUC;AAAAA,EAAAA,CACX,GAIKW,IAAqBC,EAAsB;AAAA,IAC/ChB,gBAAgBJ,KAAS,CAACM,IAAYe,EAASZ,GAAiBL,CAAc,IAAIA;AAAAA,IAClFE,WAAAA;AAAAA,IACAD,iBAAAA;AAAAA,EAAAA,CACD,GAEKiB,IAAcA,CAACtB,GAAeD,IAAoB,OAClDC,IAEAuB,gBAAAA,EAAAC,cAAA,SAAA;AAAA,IACEC,IAAIhB;AAAAA,IACJiB,WAAW,eAAeC,EAAW5B,IAAW,aAAa,SAAS,CAAC;AAAA,IACvE,sBAAoB,GAAGI,CAAY;AAAA,EAAA,GAElCH,CACI,IAGJ,MAGH4B,IAAiB;AAAA,IACrBC,SAAS;AAAA,IACT9B,UAAU;AAAA,EAAA,GAEN4B,IAAa;AAAA,IACjBE,SAAS,gCAAgC3B,IAAiB,mBAAmB,EAAE;AAAA,IAC/EH,UAAU;AAAA,EAAA,GAEN+B,IAAc;AAAA,IAClBjC,SAAS,IACPE,IAAW,gCAAgC,+DAA+D;AAAA,IAE5GgC,WAAW,IACThC,IAAW,+BAA+B,6DAA6D;AAAA,IAEzG8B,SAAS;AAAA,IACT9B,UAAU;AAAA,EAAA;AAGZ,SACEwB,gBAAAA,EAAAC,cAAA,OAAA;AAAA,IACEE,WAAW,4CAA4CE,EAAe7B,IAAW,aAAa,SAAS,CAAC;AAAA,IACxGiB,SAASd,IAAiBU,IAAeD;AAAAA,IACzC,sBAAoB,GAAGR,CAAY;AAAA,EAAA,GAElCH,KAASC,MAAkB,UAAUqB,EAAYtB,GAAOD,CAAQ,GACjEwB,gBAAAA,EAAAC,qBAAAQ,EAAA;AAAA,IACElB,MAAAA;AAAAA,IACAP,UAAAA;AAAAA,IACA,gBAAcV;AAAAA,EAAAA,GACVsB,GACAN,GAAU;AAAA,IACda,WAAW;AAAA,UACTI,EAAYjC,IAAU,YAAY,WAAW,CAAC;AAAA,UAC9CiC,EAAY/B,IAAW,aAAa,SAAS,CAAC;AAAA;AAAA,IAEhD,sBAAoB,GAAGI,CAAY;AAAA,EAAA,CAAU,GAE7CoB,gBAAAA,EAAAC,cAAA,SAAA;AAAA,IAAOE,WAAU;AAAA,IAAmBO,MAAK;AAAA,IAAWpC,SAAAA;AAAAA,IAAkBqC,UAAQ;AAAA,IAACnC,UAAAA;AAAAA,EAAAA,CAAqB,GACpGwB,gBAAAA,EAAAC,cAAA,QAAA;AAAA,IACEE,WAAW;AAAA,6CACwB7B,IAAU,kBAAkB,EAAE;AAAA,EAAA,CAC5D,CACJ,GACJG,KAASC,MAAkB,WAAWqB,EAAYtB,GAAOD,CAAQ,CAC/D;AAET;"}
1
+ {"version":3,"file":"index8.js","sources":["../src/components/Toggle/index.tsx"],"sourcesContent":["import React from 'react';\nimport { useStableId } from '../../utils/useStableId';\nimport { useAccessiblePress, getA11yNameAttributes } from '../../utils/a11y';\nimport { mergeIds } from '../../utils/mergeIds';\n\nexport interface ToggleProps {\n /**\n * Callback when the toggle is toggled. The parent is responsible for updating the checked state.\n */\n onToggle?: (checked: boolean) => void;\n /**\n * The controlled state of the toggle.\n */\n checked: boolean;\n /**\n * Optional disabled state\n */\n disabled?: boolean;\n /**\n * Optional label\n */\n label?: string;\n /**\n * Position of the label\n */\n labelPosition?: 'left' | 'right';\n /**\n * Optional className\n */\n labelClickable?: boolean;\n /**\n * Automation ID for testing\n */\n automationId?: string;\n /**\n * ID(s) of element(s) that label this toggle (for screen reader association).\n * Typically used when toggle is part of a larger labelled context.\n */\n ariaLabelledBy?: string;\n /**\n * ID(s) of element(s) that describe this toggle (provides additional context).\n * Often used for help text or instructions.\n */\n ariaDescribedBy?: string;\n /**\n * Explicit accessible name for the toggle.\n * Used as fallback when ariaLabelledBy is not provided and no internal label exists.\n */\n ariaLabel?: string;\n /**\n * Custom tab index for the toggle.\n * Use -1 to remove from tab order, 0 (default) for natural tab order.\n */\n tabIndex?: number;\n}\n\nexport const Toggle = React.forwardRef<HTMLDivElement, ToggleProps>(({\n checked = false,\n onToggle = () => {},\n disabled = false,\n label,\n labelPosition = 'left',\n labelClickable = true,\n automationId = 'toggle',\n ariaLabelledBy,\n ariaDescribedBy,\n ariaLabel,\n tabIndex: tabIndexProp = 0\n}, ref) => {\n const internalLabelId = useStableId(undefined, 'toggle-label');\n\n const handleToggle = () => {\n if (disabled) return;\n onToggle(!checked);\n };\n\n // pressProps contains: onPointerDown, onMouseDown, onTouchStart, onClick, onKeyDown, aria-disabled, aria-busy\n // When labelClickable=true, container has onClick handler, so we need stopPropagation to prevent\n // container's onClick from firing when button is clicked (avoiding double-toggle).\n // When labelClickable=false, container has no onClick, so stopPropagation isn't needed but harmless.\n const { pressProps, tabIndex, role } = useAccessiblePress({\n disabled,\n onClick: handleToggle,\n stopPropagation: labelClickable,\n isNative: false,\n role: 'switch',\n tabIndex: tabIndexProp\n });\n\n // a11yNameAttributes contains: aria-labelledby (if provided), aria-label (fallback), aria-describedby (if provided)\n // When ariaLabel is provided, it takes precedence over label (matches AutoCompleteInput/PhoneInput pattern)\n const a11yNameAttributes = getA11yNameAttributes({\n ariaLabelledBy: label && !ariaLabel ? mergeIds(internalLabelId, ariaLabelledBy) : ariaLabelledBy,\n ariaLabel,\n ariaDescribedBy\n });\n\n const renderLabel = (label: string, disabled: boolean = false) => {\n if (label) {\n return (\n <label\n id={internalLabelId}\n className={`select-none ${labelClass[disabled ? 'disabled' : 'enabled']}`}\n data-automation-id={`${automationId}-label`}\n >\n {label}\n </label>\n );\n }\n return null;\n };\n\n const containerClass = {\n enabled: 'cursor-pointer',\n disabled: 'cursor-not-allowed'\n };\n const labelClass = {\n enabled: `text-[var(--color-gray-700)] ${labelClickable ? 'cursor-pointer' : ''}`,\n disabled: 'text-[var(--color-gray-600)] cursor-not-allowed'\n };\n const toggleClass = {\n checked: ` ${\n disabled ? 'bg-[var(--color-green-100)]' : 'bg-[var(--color-green-400)] hover:bg-[var(--color-green-500)]'\n }`,\n unchecked: ` ${\n disabled ? 'bg-[var(--color-gray-400)]' : 'bg-[var(--color-gray-600)] hover:bg-[var(--color-gray-650)]'\n }`,\n enabled: ' cursor-pointer',\n disabled: ' cursor-not-allowed'\n };\n\n return (\n <div\n className={`se-design-toggle flex items-center gap-1 ${containerClass[disabled ? 'disabled' : 'enabled']}`}\n onClick={labelClickable ? handleToggle : undefined}\n data-automation-id={`${automationId}-container`}\n >\n {label && labelPosition === 'left' && renderLabel(label, disabled)}\n <div\n ref={ref}\n role={role}\n tabIndex={tabIndex}\n aria-checked={checked}\n {...a11yNameAttributes}\n {...pressProps}\n className={`toggle-btn focus-outline block w-8 h-4 p-0.5 rounded-full transition ease-in-out\n ${toggleClass[checked ? 'checked' : 'unchecked']}\n ${toggleClass[disabled ? 'disabled' : 'enabled']}\n `}\n data-automation-id={`${automationId}-button`}\n >\n <input className=\"opacity-0 hidden\" type=\"checkbox\" checked={checked} readOnly disabled={disabled} tabIndex={-1} />\n <span\n className={`block w-3 h-3 rounded-full bg-[var(--color-white)]\n transform transition-transform ${checked ? 'translate-x-4' : ''}`}\n ></span>\n </div>\n {label && labelPosition === 'right' && renderLabel(label, disabled)}\n </div>\n );\n});\n\nToggle.displayName = 'Toggle';\n"],"names":["Toggle","React","forwardRef","checked","onToggle","disabled","label","labelPosition","labelClickable","automationId","ariaLabelledBy","ariaDescribedBy","ariaLabel","tabIndex","tabIndexProp","ref","internalLabelId","useStableId","undefined","handleToggle","pressProps","role","useAccessiblePress","onClick","stopPropagation","isNative","a11yNameAttributes","getA11yNameAttributes","mergeIds","renderLabel","createElement","id","className","labelClass","containerClass","enabled","toggleClass","unchecked","_extends","type","readOnly","displayName"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "se-design",
3
- "version": "1.0.68-devnav",
3
+ "version": "1.0.69-dev",
4
4
  "type": "module",
5
5
  "module": "dist/index.js",
6
6
  "exports": {