@medway-ui/native 1.7.2 → 1.8.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.
Files changed (57) hide show
  1. package/README.md +4 -1
  2. package/lib/commonjs/components/Badge.js +159 -36
  3. package/lib/commonjs/components/Badge.js.map +1 -1
  4. package/lib/commonjs/components/Choice.js +35 -37
  5. package/lib/commonjs/components/Choice.js.map +1 -1
  6. package/lib/commonjs/components/SegmentControl.js +197 -0
  7. package/lib/commonjs/components/SegmentControl.js.map +1 -0
  8. package/lib/commonjs/components/Switch.js +176 -66
  9. package/lib/commonjs/components/Switch.js.map +1 -1
  10. package/lib/commonjs/editor/editorHtml.generated.js +1 -1
  11. package/lib/commonjs/editor/editorHtml.generated.js.map +1 -1
  12. package/lib/commonjs/hooks/useThemeColor.js +42 -42
  13. package/lib/commonjs/hooks/useThemeColor.js.map +1 -1
  14. package/lib/commonjs/index.js +31 -0
  15. package/lib/commonjs/index.js.map +1 -1
  16. package/lib/commonjs/lib/raised-surface.js +24 -0
  17. package/lib/commonjs/lib/raised-surface.js.map +1 -0
  18. package/lib/module/components/Badge.js +159 -36
  19. package/lib/module/components/Badge.js.map +1 -1
  20. package/lib/module/components/Choice.js +35 -37
  21. package/lib/module/components/Choice.js.map +1 -1
  22. package/lib/module/components/SegmentControl.js +189 -0
  23. package/lib/module/components/SegmentControl.js.map +1 -0
  24. package/lib/module/components/Switch.js +181 -69
  25. package/lib/module/components/Switch.js.map +1 -1
  26. package/lib/module/editor/editorHtml.generated.js +1 -1
  27. package/lib/module/editor/editorHtml.generated.js.map +1 -1
  28. package/lib/module/hooks/useThemeColor.js +42 -42
  29. package/lib/module/hooks/useThemeColor.js.map +1 -1
  30. package/lib/module/index.js +2 -0
  31. package/lib/module/index.js.map +1 -1
  32. package/lib/module/lib/raised-surface.js +22 -0
  33. package/lib/module/lib/raised-surface.js.map +1 -0
  34. package/lib/typescript/components/Badge.d.ts +14 -4
  35. package/lib/typescript/components/Badge.d.ts.map +1 -1
  36. package/lib/typescript/components/Chip.d.ts +2 -2
  37. package/lib/typescript/components/Choice.d.ts.map +1 -1
  38. package/lib/typescript/components/SegmentControl.d.ts +37 -0
  39. package/lib/typescript/components/SegmentControl.d.ts.map +1 -0
  40. package/lib/typescript/components/Switch.d.ts +5 -5
  41. package/lib/typescript/components/Switch.d.ts.map +1 -1
  42. package/lib/typescript/components/Tag.d.ts +2 -2
  43. package/lib/typescript/editor/editorHtml.generated.d.ts.map +1 -1
  44. package/lib/typescript/index.d.ts +3 -1
  45. package/lib/typescript/index.d.ts.map +1 -1
  46. package/lib/typescript/lib/raised-surface.d.ts +3 -0
  47. package/lib/typescript/lib/raised-surface.d.ts.map +1 -0
  48. package/package.json +1 -1
  49. package/setup/tokens.native.css +49 -22
  50. package/src/components/Badge.tsx +207 -61
  51. package/src/components/Choice.tsx +66 -45
  52. package/src/components/SegmentControl.tsx +265 -0
  53. package/src/components/Switch.tsx +303 -115
  54. package/src/editor/editorHtml.generated.ts +1 -1
  55. package/src/hooks/useThemeColor.ts +42 -42
  56. package/src/index.ts +21 -1
  57. package/src/lib/raised-surface.tsx +21 -0
@@ -4,23 +4,33 @@ import { Pressable, View } from "react-native";
4
4
  import * as MedwayIcons from "@medway-ui/icons/native";
5
5
  import { Text } from "@/components/Text";
6
6
  import { ThemedIcon } from "@/components/ThemedIcon";
7
- import { useThemeColor } from "@/hooks/useThemeColor";
7
+ import { RaisedSurface } from "@/lib/raised-surface";
8
8
  import { cn } from "@/lib/utils";
9
9
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
10
+ // The design's padding minus the 2px ring (`p-0.5`) around the inner card. The vertical hit slop
11
+ // takes the 32, 40 and 48pt chips to the package's 44pt touch target (`MIN_TOUCH_TARGET`).
10
12
  const SIZE_MAP = {
11
13
  sm: {
12
- container: "gap-2 px-3 py-2",
13
- text: "text-xs",
14
- icon: 16
14
+ container: "gap-2 px-2.5 py-1.5",
15
+ text: "text-xs leading-xs",
16
+ icon: 16,
17
+ hitSlop: {
18
+ top: 6,
19
+ bottom: 6
20
+ }
15
21
  },
16
22
  md: {
17
- container: "gap-2.5 px-3.5 py-2.5",
18
- text: "text-sm",
19
- icon: 20
23
+ container: "gap-2.5 px-3 py-2",
24
+ text: "text-sm leading-sm",
25
+ icon: 20,
26
+ hitSlop: {
27
+ top: 2,
28
+ bottom: 2
29
+ }
20
30
  },
21
31
  lg: {
22
- container: "gap-3 px-4 py-3",
23
- text: "text-base",
32
+ container: "gap-3 px-3.5 py-2.5",
33
+ text: "text-md leading-md",
24
34
  icon: 24
25
35
  }
26
36
  };
@@ -50,15 +60,6 @@ const THEME_CHECK_COLOR_TOKEN = {
50
60
  ped: "ped-foreground",
51
61
  prev: "prev-foreground"
52
62
  };
53
- const SHADOW_STYLE = {
54
- shadowOffset: {
55
- width: 0,
56
- height: 2
57
- },
58
- shadowOpacity: 0.08,
59
- shadowRadius: 4,
60
- elevation: 2
61
- };
62
63
  function Choice({
63
64
  label,
64
65
  selected = false,
@@ -70,39 +71,36 @@ function Choice({
70
71
  className
71
72
  }) {
72
73
  const sz = SIZE_MAP[size] ?? SIZE_MAP.md;
73
- const shadowColor = useThemeColor("gray-700");
74
- const outerBg = disabled ? "bg-gray-background-soft-muted" : selected ? THEME_SELECTED_OUTER_BG[theme] : "bg-gray-background-soft";
75
- const textClass = disabled ? "font-medium text-gray-foreground-muted" : selected ? "font-semibold text-primary-foreground" : "font-medium text-gray-foreground";
74
+ const isRaised = selected && !disabled;
75
+ const outerBg = disabled ? "bg-gray-background-soft-muted" : selected ? THEME_SELECTED_OUTER_BG[theme] : "bg-gray-background-soft active:bg-gray-background-soft-emphasis";
76
76
  return /*#__PURE__*/_jsx(Pressable, {
77
77
  onPress: disabled ? undefined : onPress,
78
78
  disabled: disabled,
79
- accessibilityRole: "button",
79
+ hitSlop: sz.hitSlop,
80
+ accessibilityRole: "togglebutton",
81
+ accessibilityLabel: label,
80
82
  accessibilityState: {
81
- selected,
83
+ checked: selected,
82
84
  disabled
83
85
  },
84
- className: cn("rounded-md", outerBg, className),
85
- style: {
86
- padding: 2
87
- },
88
- children: /*#__PURE__*/_jsxs(View, {
89
- className: cn("flex-row items-center justify-center rounded-md", sz.container, selected ? "bg-surface-card" : "bg-transparent"),
90
- style: selected ? {
91
- ...SHADOW_STYLE,
92
- shadowColor
93
- } : undefined,
94
- children: [icon ? /*#__PURE__*/_jsx(View, {
86
+ className: cn("rounded-md p-0.5", outerBg, className),
87
+ children: ({
88
+ pressed
89
+ }) => /*#__PURE__*/_jsxs(View, {
90
+ className: cn("flex-row items-center justify-center", sz.container),
91
+ children: [isRaised ? /*#__PURE__*/_jsx(RaisedSurface, {}) : null, icon ? /*#__PURE__*/_jsx(View, {
95
92
  className: "shrink-0",
96
93
  children: icon
97
94
  }) : null, /*#__PURE__*/_jsx(Text, {
98
- className: cn("text-center", sz.text, textClass),
95
+ numberOfLines: 1,
96
+ className: cn("shrink text-center", sz.text, disabled ? "font-medium text-gray-foreground-muted" : selected ? "font-semibold text-primary-foreground" : pressed ? "font-medium text-gray-foreground-emphasis" : "font-medium text-gray-foreground"),
99
97
  children: label
100
98
  }), selected ? /*#__PURE__*/_jsx(View, {
101
99
  className: "shrink-0",
102
100
  children: /*#__PURE__*/_jsx(ThemedIcon, {
103
- icon: MedwayIcons.Check,
101
+ icon: MedwayIcons.CheckMedium,
104
102
  size: sz.icon,
105
- colorToken: THEME_CHECK_COLOR_TOKEN[theme]
103
+ colorToken: disabled ? "gray-foreground-muted" : THEME_CHECK_COLOR_TOKEN[theme]
106
104
  })
107
105
  }) : null]
108
106
  })
@@ -1 +1 @@
1
- {"version":3,"names":["Pressable","View","MedwayIcons","Text","ThemedIcon","useThemeColor","cn","jsx","_jsx","jsxs","_jsxs","SIZE_MAP","sm","container","text","icon","md","lg","THEME_SELECTED_OUTER_BG","gray","primary","secondary","green","red","yellow","cm","go","cir","ped","prev","THEME_CHECK_COLOR_TOKEN","SHADOW_STYLE","shadowOffset","width","height","shadowOpacity","shadowRadius","elevation","Choice","label","selected","disabled","size","theme","onPress","className","sz","shadowColor","outerBg","textClass","undefined","accessibilityRole","accessibilityState","style","padding","children","Check","colorToken"],"sourceRoot":"../../../src","sources":["components/Choice.tsx"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["Pressable","View","MedwayIcons","Text","ThemedIcon","RaisedSurface","cn","jsx","_jsx","jsxs","_jsxs","SIZE_MAP","sm","container","text","icon","hitSlop","top","bottom","md","lg","THEME_SELECTED_OUTER_BG","gray","primary","secondary","green","red","yellow","cm","go","cir","ped","prev","THEME_CHECK_COLOR_TOKEN","Choice","label","selected","disabled","size","theme","onPress","className","sz","isRaised","outerBg","undefined","accessibilityRole","accessibilityLabel","accessibilityState","checked","children","pressed","numberOfLines","CheckMedium","colorToken"],"sourceRoot":"../../../src","sources":["components/Choice.tsx"],"mappings":";;AACA,SAASA,SAAS,EAAEC,IAAI,QAAqB,cAAc;AAC3D,OAAO,KAAKC,WAAW,MAAM,yBAAyB;AAEtD,SAASC,IAAI,QAAQ,mBAAmB;AACxC,SAASC,UAAU,QAAQ,yBAAyB;AACpD,SAASC,aAAa,QAAQ,sBAAsB;AACpD,SAASC,EAAE,QAAQ,aAAa;AAAC,SAAAC,GAAA,IAAAC,IAAA,EAAAC,IAAA,IAAAC,KAAA;AA4BjC;AACA;AACA,MAAMC,QAGL,GAAG;EACFC,EAAE,EAAE;IACFC,SAAS,EAAE,qBAAqB;IAChCC,IAAI,EAAE,oBAAoB;IAC1BC,IAAI,EAAE,EAAE;IACRC,OAAO,EAAE;MAAEC,GAAG,EAAE,CAAC;MAAEC,MAAM,EAAE;IAAE;EAC/B,CAAC;EACDC,EAAE,EAAE;IACFN,SAAS,EAAE,mBAAmB;IAC9BC,IAAI,EAAE,oBAAoB;IAC1BC,IAAI,EAAE,EAAE;IACRC,OAAO,EAAE;MAAEC,GAAG,EAAE,CAAC;MAAEC,MAAM,EAAE;IAAE;EAC/B,CAAC;EACDE,EAAE,EAAE;IACFP,SAAS,EAAE,qBAAqB;IAChCC,IAAI,EAAE,oBAAoB;IAC1BC,IAAI,EAAE;EACR;AACF,CAAC;AAED,MAAMM,uBAAoD,GAAG;EAC3DC,IAAI,EAAE,yBAAyB;EAC/BC,OAAO,EAAE,4BAA4B;EACrCC,SAAS,EAAE,8BAA8B;EACzCC,KAAK,EAAE,0BAA0B;EACjCC,GAAG,EAAE,wBAAwB;EAC7BC,MAAM,EAAE,2BAA2B;EACnCC,EAAE,EAAE,uBAAuB;EAC3BC,EAAE,EAAE,uBAAuB;EAC3BC,GAAG,EAAE,iCAAiC;EACtCC,GAAG,EAAE,iCAAiC;EACtCC,IAAI,EAAE;AACR,CAAC;AAED,MAAMC,uBAAoD,GAAG;EAC3DX,IAAI,EAAE,sBAAsB;EAC5BC,OAAO,EAAE,oBAAoB;EAC7BC,SAAS,EAAE,sBAAsB;EACjCC,KAAK,EAAE,kBAAkB;EACzBC,GAAG,EAAE,gBAAgB;EACrBC,MAAM,EAAE,mBAAmB;EAC3BC,EAAE,EAAE,eAAe;EACnBC,EAAE,EAAE,eAAe;EACnBC,GAAG,EAAE,gBAAgB;EACrBC,GAAG,EAAE,gBAAgB;EACrBC,IAAI,EAAE;AACR,CAAC;AAED,SAASE,MAAMA,CAAC;EACdC,KAAK;EACLC,QAAQ,GAAG,KAAK;EAChBC,QAAQ,GAAG,KAAK;EAChBC,IAAI,GAAG,IAAI;EACXC,KAAK,GAAG,MAAM;EACdxB,IAAI;EACJyB,OAAO;EACPC;AACW,CAAC,EAAE;EACd,MAAMC,EAAE,GAAG/B,QAAQ,CAAC2B,IAAI,CAAC,IAAI3B,QAAQ,CAACQ,EAAE;EACxC,MAAMwB,QAAQ,GAAGP,QAAQ,IAAI,CAACC,QAAQ;EAEtC,MAAMO,OAAO,GAAGP,QAAQ,GACpB,+BAA+B,GAC/BD,QAAQ,GACNf,uBAAuB,CAACkB,KAAK,CAAC,GAC9B,iEAAiE;EAEvE,oBACE/B,IAAA,CAACR,SAAS;IACRwC,OAAO,EAAEH,QAAQ,GAAGQ,SAAS,GAAGL,OAAQ;IACxCH,QAAQ,EAAEA,QAAS;IACnBrB,OAAO,EAAE0B,EAAE,CAAC1B,OAAQ;IACpB8B,iBAAiB,EAAC,cAAc;IAChCC,kBAAkB,EAAEZ,KAAM;IAC1Ba,kBAAkB,EAAE;MAAEC,OAAO,EAAEb,QAAQ;MAAEC;IAAS,CAAE;IACpDI,SAAS,EAAEnC,EAAE,CAAC,kBAAkB,EAAEsC,OAAO,EAAEH,SAAS,CAAE;IAAAS,QAAA,EAErDA,CAAC;MAAEC;IAAQ,CAAC,kBACXzC,KAAA,CAACT,IAAI;MACHwC,SAAS,EAAEnC,EAAE,CAAC,sCAAsC,EAAEoC,EAAE,CAAC7B,SAAS,CAAE;MAAAqC,QAAA,GAEnEP,QAAQ,gBAAGnC,IAAA,CAACH,aAAa,IAAE,CAAC,GAAG,IAAI,EACnCU,IAAI,gBAAGP,IAAA,CAACP,IAAI;QAACwC,SAAS,EAAC,UAAU;QAAAS,QAAA,EAAEnC;MAAI,CAAO,CAAC,GAAG,IAAI,eACvDP,IAAA,CAACL,IAAI;QACHiD,aAAa,EAAE,CAAE;QACjBX,SAAS,EAAEnC,EAAE,CACX,oBAAoB,EACpBoC,EAAE,CAAC5B,IAAI,EACPuB,QAAQ,GACJ,wCAAwC,GACxCD,QAAQ,GACN,uCAAuC,GACvCe,OAAO,GACL,2CAA2C,GAC3C,kCACV,CAAE;QAAAD,QAAA,EAEDf;MAAK,CACF,CAAC,EACNC,QAAQ,gBACP5B,IAAA,CAACP,IAAI;QAACwC,SAAS,EAAC,UAAU;QAAAS,QAAA,eACxB1C,IAAA,CAACJ,UAAU;UACTW,IAAI,EAAEb,WAAW,CAACmD,WAAY;UAC9Bf,IAAI,EAAEI,EAAE,CAAC3B,IAAK;UACduC,UAAU,EACRjB,QAAQ,GACJ,uBAAuB,GACvBJ,uBAAuB,CAACM,KAAK;QAClC,CACF;MAAC,CACE,CAAC,GACL,IAAI;IAAA,CACJ;EACP,CACQ,CAAC;AAEhB;AAEA,SAASL,MAAM","ignoreList":[]}
@@ -0,0 +1,189 @@
1
+ "use strict";
2
+
3
+ import { Children, createContext, useContext, useMemo, useState } from "react";
4
+ import { Pressable, View } from "react-native";
5
+ import * as TabsPrimitive from "@rn-primitives/tabs";
6
+ import { cva } from "class-variance-authority";
7
+ import { Badge } from "@/components/Badge";
8
+ import { Text } from "@/components/Text";
9
+ import { RaisedSurface } from "@/lib/raised-surface";
10
+ import { cn } from "@/lib/utils";
11
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
12
+ const SegmentControlContext = /*#__PURE__*/createContext({
13
+ size: "md"
14
+ });
15
+
16
+ // `min-h` instead of the web's `max-h`: a larger system font grows the segment instead of clipping it.
17
+ const segmentControlTriggerVariants = cva("shrink flex-row items-center justify-center", {
18
+ variants: {
19
+ size: {
20
+ sm: "min-h-7 gap-2 px-3 py-1.5",
21
+ md: "min-h-9 gap-2.5 px-3.5 py-2",
22
+ lg: "min-h-11 gap-3 px-4 py-2.5"
23
+ }
24
+ },
25
+ defaultVariants: {
26
+ size: "md"
27
+ }
28
+ });
29
+
30
+ // Up to the package's 44pt touch target (`MIN_TOUCH_TARGET`), vertically only: segments sit 2px apart.
31
+ const TRIGGER_HIT_SLOP = {
32
+ sm: {
33
+ top: 8,
34
+ bottom: 8
35
+ },
36
+ md: {
37
+ top: 4,
38
+ bottom: 4
39
+ },
40
+ lg: undefined
41
+ };
42
+ const segmentControlTextVariants = cva("text-center", {
43
+ variants: {
44
+ size: {
45
+ sm: "text-xs leading-xs",
46
+ md: "text-sm leading-sm",
47
+ lg: "text-md leading-md"
48
+ }
49
+ },
50
+ defaultVariants: {
51
+ size: "md"
52
+ }
53
+ });
54
+ function SegmentControl({
55
+ value: valueProp,
56
+ defaultValue = "",
57
+ onValueChange,
58
+ size = "md",
59
+ className,
60
+ children,
61
+ ...props
62
+ }) {
63
+ const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);
64
+ const value = valueProp ?? uncontrolledValue;
65
+ const context = useMemo(() => ({
66
+ size
67
+ }), [size]);
68
+ const handleValueChange = next => {
69
+ if (next === value) return;
70
+ if (valueProp === undefined) setUncontrolledValue(next);
71
+ onValueChange?.(next);
72
+ };
73
+ return /*#__PURE__*/_jsx(SegmentControlContext.Provider, {
74
+ value: context,
75
+ children: /*#__PURE__*/_jsx(TabsPrimitive.Root, {
76
+ asChild: true,
77
+ value: value,
78
+ onValueChange: handleValueChange,
79
+ ...props,
80
+ children: /*#__PURE__*/_jsx(View, {
81
+ className: cn("gap-2", className),
82
+ children: children
83
+ })
84
+ })
85
+ });
86
+ }
87
+ function SegmentControlList({
88
+ className,
89
+ children,
90
+ ...props
91
+ }) {
92
+ return /*#__PURE__*/_jsx(TabsPrimitive.List, {
93
+ asChild: true,
94
+ ...props,
95
+ children: /*#__PURE__*/_jsx(View, {
96
+ className: cn("flex-row items-center gap-0.5 self-start rounded-md bg-gray-background-soft p-0.5", className),
97
+ children: children
98
+ })
99
+ });
100
+ }
101
+ function shouldShowBadge(badge, disabled) {
102
+ return badge != null && badge !== 0 && badge !== "" && badge !== "0" && !disabled;
103
+ }
104
+
105
+ // Strings and numbers, as in `Aulas {count}`, join into one label; anything else renders as is.
106
+ function toLabel(children) {
107
+ const parts = Children.toArray(children);
108
+ return parts.length > 0 && parts.every(part => typeof part === "string" || typeof part === "number") ? parts.join("") : null;
109
+ }
110
+ function SegmentControlTrigger({
111
+ className,
112
+ children,
113
+ icon,
114
+ badge,
115
+ badgeVariant,
116
+ value,
117
+ disabled,
118
+ accessibilityLabel,
119
+ ...props
120
+ }) {
121
+ const {
122
+ size
123
+ } = useContext(SegmentControlContext);
124
+ const {
125
+ value: activeValue
126
+ } = TabsPrimitive.useRootContext();
127
+ const isActive = activeValue === value;
128
+ const isDisabled = !!disabled;
129
+ const showBadge = shouldShowBadge(badge, isDisabled);
130
+ const label = toLabel(children);
131
+ return /*#__PURE__*/_jsx(TabsPrimitive.Trigger, {
132
+ asChild: true,
133
+ value: value,
134
+ disabled: disabled,
135
+ ...props,
136
+ children: /*#__PURE__*/_jsx(Pressable, {
137
+ accessibilityLabel: accessibilityLabel ?? (label != null ? showBadge ? `${label}, ${badge}` : label : undefined),
138
+ hitSlop: TRIGGER_HIT_SLOP[size],
139
+ className: cn(segmentControlTriggerVariants({
140
+ size
141
+ }), className),
142
+ children: ({
143
+ pressed
144
+ }) => /*#__PURE__*/_jsxs(_Fragment, {
145
+ children: [isActive ? /*#__PURE__*/_jsx(RaisedSurface, {}) : null, icon ? /*#__PURE__*/_jsx(View, {
146
+ className: "shrink-0",
147
+ children: icon
148
+ }) : null, label != null ? /*#__PURE__*/_jsxs(View, {
149
+ className: "min-w-0 shrink",
150
+ children: [/*#__PURE__*/_jsx(Text, {
151
+ numberOfLines: 1,
152
+ accessibilityElementsHidden: true,
153
+ importantForAccessibility: "no-hide-descendants",
154
+ className: cn(segmentControlTextVariants({
155
+ size
156
+ }), "font-semibold opacity-0"),
157
+ children: label
158
+ }), /*#__PURE__*/_jsx(Text, {
159
+ numberOfLines: 1,
160
+ className: cn(segmentControlTextVariants({
161
+ size
162
+ }), "absolute inset-0", isActive ? "font-semibold" : "font-medium", isDisabled ? "text-gray-foreground-muted" : isActive ? pressed ? "text-primary-foreground-emphasis" : "text-primary-foreground" : pressed ? "text-gray-foreground-emphasis" : "text-gray-foreground"),
163
+ children: label
164
+ })]
165
+ }) : children, showBadge ? /*#__PURE__*/_jsx(Badge, {
166
+ size: size,
167
+ variant: badgeVariant,
168
+ children: String(badge)
169
+ }) : null]
170
+ })
171
+ })
172
+ });
173
+ }
174
+ function SegmentControlContent({
175
+ className,
176
+ children,
177
+ ...props
178
+ }) {
179
+ return /*#__PURE__*/_jsx(TabsPrimitive.Content, {
180
+ asChild: true,
181
+ ...props,
182
+ children: /*#__PURE__*/_jsx(View, {
183
+ className: cn("flex-1", className),
184
+ children: children
185
+ })
186
+ });
187
+ }
188
+ export { SegmentControl, SegmentControlContent, SegmentControlList, SegmentControlTrigger, segmentControlTriggerVariants };
189
+ //# sourceMappingURL=SegmentControl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["Children","createContext","useContext","useMemo","useState","Pressable","View","TabsPrimitive","cva","Badge","Text","RaisedSurface","cn","jsx","_jsx","jsxs","_jsxs","Fragment","_Fragment","SegmentControlContext","size","segmentControlTriggerVariants","variants","sm","md","lg","defaultVariants","TRIGGER_HIT_SLOP","top","bottom","undefined","segmentControlTextVariants","SegmentControl","value","valueProp","defaultValue","onValueChange","className","children","props","uncontrolledValue","setUncontrolledValue","context","handleValueChange","next","Provider","Root","asChild","SegmentControlList","List","shouldShowBadge","badge","disabled","toLabel","parts","toArray","length","every","part","join","SegmentControlTrigger","icon","badgeVariant","accessibilityLabel","activeValue","useRootContext","isActive","isDisabled","showBadge","label","Trigger","hitSlop","pressed","numberOfLines","accessibilityElementsHidden","importantForAccessibility","variant","String","SegmentControlContent","Content"],"sourceRoot":"../../../src","sources":["components/SegmentControl.tsx"],"mappings":"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","ignoreList":[]}
@@ -1,24 +1,39 @@
1
1
  "use strict";
2
2
 
3
- import { useState, useEffect } from "react";
4
- import { View } from "react-native";
3
+ import { cloneElement, isValidElement, memo, useLayoutEffect, useMemo, useRef, useState } from "react";
4
+ import { StyleSheet } from "react-native";
5
+ import { cssInterop } from "nativewind";
5
6
  import * as SwitchPrimitive from "@rn-primitives/switch";
6
- import Animated, { useSharedValue, useAnimatedStyle, withTiming, Easing } from "react-native-reanimated";
7
+ import Animated, { Easing, interpolateColor, useAnimatedStyle, useSharedValue, withTiming } from "react-native-reanimated";
7
8
  import { cva } from "class-variance-authority";
8
9
  import { cn } from "@/lib/utils";
9
10
  import { getMinTouchHitSlop } from "@/lib/touch-target";
10
- import { useThemeColor } from "@/hooks/useThemeColor";
11
- import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
11
+ import { useThemeColor, withAlpha } from "@/hooks/useThemeColor";
12
+
13
+ // `@rn-primitives/switch` renders a plain Pressable — cssInterop makes `className` work.
14
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
15
+ const StyledSwitchRoot = cssInterop(SwitchPrimitive.Root, {
16
+ className: "style"
17
+ });
18
+ const BORDER_WIDTH = 2;
19
+ /** Gap between thumb and inner edge of the track border (web `translate-x-0.5`). */
20
+ const THUMB_INSET = 2;
21
+ const CENTER = {
22
+ alignItems: "center",
23
+ justifyContent: "center"
24
+ };
12
25
  const THUMB_SIZES = {
13
26
  sm: 8,
14
27
  md: 12,
15
28
  lg: 16
16
29
  };
17
- const THUMB_TRANSLATE = {
18
- sm: 11,
19
- md: 15,
20
- lg: 19
30
+ const ICON_SIZES = {
31
+ sm: 8,
32
+ md: 12,
33
+ lg: 14
21
34
  };
35
+
36
+ /** Same scale as web `h-4 w-6` / `h-5 w-8` / `h-6 w-10` at 16px rem. */
22
37
  const SWITCH_DIMENSIONS = {
23
38
  sm: {
24
39
  width: 24,
@@ -33,15 +48,43 @@ const SWITCH_DIMENSIONS = {
33
48
  height: 24
34
49
  }
35
50
  };
36
- const switchVariants = cva("rounded-full border-2 items-center shrink-0", {
51
+
52
+ /**
53
+ * Thumb is a sibling of the bordered track (not a child of it), so offsets are
54
+ * from the root's outer box. That avoids Yoga content-box quirks where absolute
55
+ * children of a bordered view shift the knob down / past the right edge.
56
+ *
57
+ * off = border + inset
58
+ * on = width - border - inset - thumb
59
+ * on+disabled keeps a 1px tighter right inset, matching web.
60
+ */
61
+ function getThumbTranslateX(trackWidth, thumbSize, checked, disabled) {
62
+ const off = BORDER_WIDTH + THUMB_INSET;
63
+ if (!checked) return off;
64
+ const on = trackWidth - BORDER_WIDTH - THUMB_INSET - thumbSize;
65
+ return disabled ? on - 1 : on;
66
+ }
67
+
68
+ /**
69
+ * Even curve. A strong ease-out spends the last frames crawling, which reads
70
+ * as the thumb catching. Track and thumb colors ride the same curve.
71
+ */
72
+ const THUMB_MOTION = {
73
+ duration: 250,
74
+ easing: Easing.inOut(Easing.cubic)
75
+ };
76
+
77
+ // Px, not `h-6 w-10`: NativeWind resolves rem as 14px on native, which shrinks
78
+ // the track below SWITCH_DIMENSIONS and pushes the thumb down and out the right.
79
+ const switchVariants = cva("shrink-0", {
37
80
  variants: {
38
81
  variant: {
39
82
  regular: ""
40
83
  },
41
84
  size: {
42
- sm: "h-4 w-6",
43
- md: "h-5 w-8",
44
- lg: "h-6 w-10"
85
+ sm: "h-[16px] w-[24px]",
86
+ md: "h-[20px] w-[32px]",
87
+ lg: "h-[24px] w-[40px]"
45
88
  }
46
89
  },
47
90
  defaultVariants: {
@@ -49,91 +92,160 @@ const switchVariants = cva("rounded-full border-2 items-center shrink-0", {
49
92
  size: "md"
50
93
  }
51
94
  });
52
- function Switch({
95
+ function renderThumbIcon(icon, color, size) {
96
+ if (! /*#__PURE__*/isValidElement(icon)) return icon;
97
+ return /*#__PURE__*/cloneElement(icon, {
98
+ color: icon.props.color ?? color,
99
+ width: icon.props.width ?? size,
100
+ height: icon.props.height ?? size
101
+ });
102
+ }
103
+ function SwitchThumbIcons({
104
+ progress,
105
+ checkedIcon,
106
+ uncheckedIcon,
107
+ checkedIconColor,
108
+ uncheckedIconColor,
109
+ iconSize
110
+ }) {
111
+ const checkedIconStyle = useAnimatedStyle(() => ({
112
+ opacity: progress.value
113
+ }));
114
+ const uncheckedIconStyle = useAnimatedStyle(() => ({
115
+ opacity: 1 - progress.value
116
+ }));
117
+ return /*#__PURE__*/_jsxs(_Fragment, {
118
+ children: [/*#__PURE__*/_jsx(Animated.View, {
119
+ style: [StyleSheet.absoluteFill, CENTER, uncheckedIconStyle],
120
+ children: renderThumbIcon(uncheckedIcon, uncheckedIconColor, iconSize)
121
+ }), /*#__PURE__*/_jsx(Animated.View, {
122
+ style: [StyleSheet.absoluteFill, CENTER, checkedIconStyle],
123
+ children: renderThumbIcon(checkedIcon, checkedIconColor, iconSize)
124
+ })]
125
+ });
126
+ }
127
+ const Switch = /*#__PURE__*/memo(function Switch({
53
128
  className,
54
129
  size = "md",
55
- variant,
130
+ variant = "regular",
56
131
  checkedIcon,
57
132
  uncheckedIcon,
58
133
  checked,
59
134
  defaultChecked,
60
135
  onCheckedChange,
61
- disabled,
136
+ disabled = false,
62
137
  style,
63
138
  ...props
64
139
  }) {
65
140
  const resolvedSize = size ?? "md";
66
141
  const dimensions = SWITCH_DIMENSIONS[resolvedSize];
142
+ const thumbSize = THUMB_SIZES[resolvedSize];
143
+ const iconSize = ICON_SIZES[resolvedSize];
67
144
  const [internalChecked, setInternalChecked] = useState(defaultChecked ?? false);
68
145
  const isControlled = checked !== undefined;
69
- const isChecked = isControlled ? checked ?? false : internalChecked;
70
- const trackOn = useThemeColor("primary-background-fill");
71
- const trackOff = useThemeColor("surface-card");
72
- const trackDisabled = useThemeColor("gray-background-soft-muted");
73
- const trackBorder = useThemeColor("gray-stroke-muted");
74
- const thumbOn = useThemeColor("primary-foreground-onfill");
75
- const thumbOff = useThemeColor("gray-foreground-muted");
76
- const thumbDisabled = useThemeColor("gray-background-fill-muted");
77
- const translateX = useSharedValue(isChecked ? THUMB_TRANSLATE[resolvedSize] : 2);
78
- useEffect(() => {
79
- translateX.value = withTiming(isChecked ? THUMB_TRANSLATE[resolvedSize] : 2, {
80
- duration: 180,
81
- easing: Easing.out(Easing.ease)
82
- });
83
- }, [isChecked, resolvedSize, translateX]);
84
- const thumbStyle = useAnimatedStyle(() => ({
85
- transform: [{
86
- translateX: translateX.value
87
- }]
88
- }));
146
+ const isChecked = isControlled ? checked : internalChecked;
89
147
  const hasIcons = Boolean(checkedIcon || uncheckedIcon);
90
- const thumbSize = THUMB_SIZES[resolvedSize];
148
+ const checkedIconColor = useThemeColor(disabled ? "gray-300" : "primary-foreground-onfill");
149
+ const uncheckedIconColor = useThemeColor(disabled ? "gray-300" : "gray-foreground");
150
+ const trackOffColor = useThemeColor(disabled ? "gray-background-soft-muted" : "surface-card");
151
+ const trackOnColor = useThemeColor(disabled ? "gray-background-soft-muted" : "primary-background-fill");
152
+ const borderOffColor = useThemeColor("gray-stroke-muted");
153
+ const borderOnColor = disabled ? borderOffColor : withAlpha(borderOffColor, 0);
154
+ const thumbDisabledColor = useThemeColor("gray-background-fill-muted");
155
+ const thumbOnToken = useThemeColor("primary-foreground-onfill");
156
+ const thumbOffToken = useThemeColor("gray-foreground-muted");
157
+ const thumbOffColor = hasIcons ? "rgba(0, 0, 0, 0)" : disabled ? thumbDisabledColor : thumbOffToken;
158
+ const thumbOnColor = hasIcons ? "rgba(0, 0, 0, 0)" : disabled ? thumbDisabledColor : thumbOnToken;
159
+ const offX = getThumbTranslateX(dimensions.width, thumbSize, false, disabled);
160
+ const onX = getThumbTranslateX(dimensions.width, thumbSize, true, disabled);
161
+ // Root has no border — center against the outer height.
162
+ const thumbTop = (dimensions.height - thumbSize) / 2;
163
+
164
+ // Single UI-thread driver for position, colors and icons. In controlled mode
165
+ // the visual only moves when `checked` changes (same as the web Radix switch).
166
+ const progress = useSharedValue(isChecked ? 1 : 0);
167
+ const targetRef = useRef(isChecked);
168
+ const animateTo = next => {
169
+ if (targetRef.current === next) return;
170
+ targetRef.current = next;
171
+ progress.value = withTiming(next ? 1 : 0, THUMB_MOTION);
172
+ };
173
+ useLayoutEffect(() => {
174
+ animateTo(isChecked);
175
+ }, [isChecked]);
91
176
  const handleCheckedChange = nextChecked => {
92
- if (!isControlled) setInternalChecked(nextChecked);
177
+ if (!isControlled) {
178
+ animateTo(nextChecked);
179
+ setInternalChecked(nextChecked);
180
+ }
93
181
  onCheckedChange?.(nextChecked);
94
182
  };
95
- const trackBackgroundColor = disabled ? trackDisabled : isChecked ? trackOn : trackOff;
96
- const trackBorderColor = disabled || !isChecked ? trackBorder : "transparent";
97
- const thumbBackgroundColor = disabled ? thumbDisabled : hasIcons ? "transparent" : isChecked ? thumbOn : thumbOff;
98
- const rootStyle = {
183
+ const trackMotionStyle = useAnimatedStyle(() => ({
184
+ backgroundColor: interpolateColor(progress.value, [0, 1], [trackOffColor, trackOnColor]),
185
+ borderColor: interpolateColor(progress.value, [0, 1], [borderOffColor, borderOnColor])
186
+ }));
187
+ const thumbMotionStyle = useAnimatedStyle(() => ({
188
+ transform: [{
189
+ translateX: offX + (onX - offX) * progress.value
190
+ }]
191
+ }), [offX, onX]);
192
+ const thumbColorStyle = useAnimatedStyle(() => ({
193
+ backgroundColor: interpolateColor(progress.value, [0, 1], [thumbOffColor, thumbOnColor])
194
+ }));
195
+ const baseRootStyle = useMemo(() => ({
99
196
  width: dimensions.width,
100
197
  height: dimensions.height,
101
198
  minWidth: dimensions.width,
102
199
  minHeight: dimensions.height,
103
200
  borderRadius: dimensions.height / 2,
104
- borderWidth: 2,
105
- alignItems: "flex-start",
106
- justifyContent: "center",
107
- backgroundColor: trackBackgroundColor,
108
- borderColor: trackBorderColor
109
- };
110
- return /*#__PURE__*/_jsx(SwitchPrimitive.Root, {
201
+ borderWidth: 0,
202
+ padding: 0,
203
+ overflow: "visible"
204
+ }), [dimensions.height, dimensions.width]);
205
+ const trackStyle = useMemo(() => ({
206
+ ...StyleSheet.absoluteFill,
207
+ borderRadius: dimensions.height / 2,
208
+ borderWidth: BORDER_WIDTH
209
+ }), [dimensions.height]);
210
+ const thumbStyle = useMemo(() => ({
211
+ position: "absolute",
212
+ top: thumbTop,
213
+ left: 0,
214
+ width: thumbSize,
215
+ height: thumbSize,
216
+ borderRadius: thumbSize / 2,
217
+ alignItems: "center",
218
+ justifyContent: "center"
219
+ }), [thumbSize, thumbTop]);
220
+ const hitSlop = useMemo(() => getMinTouchHitSlop(dimensions.width, dimensions.height), [dimensions.height, dimensions.width]);
221
+ return /*#__PURE__*/_jsxs(StyledSwitchRoot, {
222
+ hitSlop: hitSlop,
223
+ ...props,
111
224
  checked: isChecked,
112
225
  onCheckedChange: handleCheckedChange,
113
226
  disabled: disabled,
114
- hitSlop: getMinTouchHitSlop(dimensions.width, dimensions.height),
115
- style: state => [rootStyle, typeof style === "function" ? style(state) : style],
116
227
  className: cn(switchVariants({
117
- size,
228
+ size: resolvedSize,
118
229
  variant
119
230
  }), className),
120
- ...props,
121
- children: /*#__PURE__*/_jsx(SwitchPrimitive.Thumb, {
122
- asChild: true,
123
- children: /*#__PURE__*/_jsx(Animated.View, {
124
- style: [thumbStyle, {
125
- width: thumbSize,
126
- height: thumbSize,
127
- borderRadius: thumbSize / 2,
128
- backgroundColor: thumbBackgroundColor
129
- }],
130
- children: hasIcons ? /*#__PURE__*/_jsxs(View, {
131
- className: "flex-1 items-center justify-center",
132
- children: [isChecked && checkedIcon, !isChecked && uncheckedIcon]
133
- }) : null
134
- })
135
- })
231
+ style: state => [baseRootStyle, typeof style === "function" ? style(state) : style],
232
+ children: [/*#__PURE__*/_jsx(Animated.View, {
233
+ pointerEvents: "none",
234
+ style: [trackStyle, trackMotionStyle]
235
+ }), /*#__PURE__*/_jsx(Animated.View, {
236
+ pointerEvents: "none",
237
+ collapsable: false,
238
+ style: [thumbStyle, thumbMotionStyle, thumbColorStyle],
239
+ children: hasIcons ? /*#__PURE__*/_jsx(SwitchThumbIcons, {
240
+ progress: progress,
241
+ checkedIcon: checkedIcon,
242
+ uncheckedIcon: uncheckedIcon,
243
+ checkedIconColor: checkedIconColor,
244
+ uncheckedIconColor: uncheckedIconColor,
245
+ iconSize: iconSize
246
+ }) : null
247
+ })]
136
248
  });
137
- }
249
+ });
138
250
  export { Switch, switchVariants };
139
251
  //# sourceMappingURL=Switch.js.map