@tamagui/radio-headless 1.0.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 (82) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cjs/BubbleInput.cjs +82 -0
  3. package/dist/cjs/BubbleInput.js +65 -0
  4. package/dist/cjs/BubbleInput.js.map +6 -0
  5. package/dist/cjs/BubbleInput.native.js +86 -0
  6. package/dist/cjs/BubbleInput.native.js.map +1 -0
  7. package/dist/cjs/index.cjs +19 -0
  8. package/dist/cjs/index.js +16 -0
  9. package/dist/cjs/index.js.map +6 -0
  10. package/dist/cjs/index.native.js +22 -0
  11. package/dist/cjs/index.native.js.map +1 -0
  12. package/dist/cjs/useRadioGroup.cjs +191 -0
  13. package/dist/cjs/useRadioGroup.js +160 -0
  14. package/dist/cjs/useRadioGroup.js.map +6 -0
  15. package/dist/cjs/useRadioGroup.native.js +206 -0
  16. package/dist/cjs/useRadioGroup.native.js.map +1 -0
  17. package/dist/cjs/utils.cjs +28 -0
  18. package/dist/cjs/utils.js +23 -0
  19. package/dist/cjs/utils.js.map +6 -0
  20. package/dist/cjs/utils.native.js +31 -0
  21. package/dist/cjs/utils.native.js.map +1 -0
  22. package/dist/esm/BubbleInput.js +43 -0
  23. package/dist/esm/BubbleInput.js.map +6 -0
  24. package/dist/esm/BubbleInput.mjs +48 -0
  25. package/dist/esm/BubbleInput.mjs.map +1 -0
  26. package/dist/esm/BubbleInput.native.js +49 -0
  27. package/dist/esm/BubbleInput.native.js.map +1 -0
  28. package/dist/esm/index.js +3 -0
  29. package/dist/esm/index.js.map +6 -0
  30. package/dist/esm/index.mjs +3 -0
  31. package/dist/esm/index.mjs.map +1 -0
  32. package/dist/esm/index.native.js +3 -0
  33. package/dist/esm/index.native.js.map +1 -0
  34. package/dist/esm/useRadioGroup.js +153 -0
  35. package/dist/esm/useRadioGroup.js.map +6 -0
  36. package/dist/esm/useRadioGroup.mjs +165 -0
  37. package/dist/esm/useRadioGroup.mjs.map +1 -0
  38. package/dist/esm/useRadioGroup.native.js +178 -0
  39. package/dist/esm/useRadioGroup.native.js.map +1 -0
  40. package/dist/esm/utils.js +7 -0
  41. package/dist/esm/utils.js.map +6 -0
  42. package/dist/esm/utils.mjs +5 -0
  43. package/dist/esm/utils.mjs.map +1 -0
  44. package/dist/esm/utils.native.js +5 -0
  45. package/dist/esm/utils.native.js.map +1 -0
  46. package/dist/jsx/BubbleInput.js +43 -0
  47. package/dist/jsx/BubbleInput.js.map +6 -0
  48. package/dist/jsx/BubbleInput.mjs +48 -0
  49. package/dist/jsx/BubbleInput.mjs.map +1 -0
  50. package/dist/jsx/BubbleInput.native.js +86 -0
  51. package/dist/jsx/BubbleInput.native.js.map +1 -0
  52. package/dist/jsx/index.js +3 -0
  53. package/dist/jsx/index.js.map +6 -0
  54. package/dist/jsx/index.mjs +3 -0
  55. package/dist/jsx/index.mjs.map +1 -0
  56. package/dist/jsx/index.native.js +22 -0
  57. package/dist/jsx/index.native.js.map +1 -0
  58. package/dist/jsx/useRadioGroup.js +153 -0
  59. package/dist/jsx/useRadioGroup.js.map +6 -0
  60. package/dist/jsx/useRadioGroup.mjs +165 -0
  61. package/dist/jsx/useRadioGroup.mjs.map +1 -0
  62. package/dist/jsx/useRadioGroup.native.js +206 -0
  63. package/dist/jsx/useRadioGroup.native.js.map +1 -0
  64. package/dist/jsx/utils.js +7 -0
  65. package/dist/jsx/utils.js.map +6 -0
  66. package/dist/jsx/utils.mjs +5 -0
  67. package/dist/jsx/utils.mjs.map +1 -0
  68. package/dist/jsx/utils.native.js +31 -0
  69. package/dist/jsx/utils.native.js.map +1 -0
  70. package/package.json +61 -0
  71. package/src/BubbleInput.tsx +59 -0
  72. package/src/index.ts +2 -0
  73. package/src/useRadioGroup.tsx +260 -0
  74. package/src/utils.tsx +3 -0
  75. package/types/BubbleInput.d.ts +11 -0
  76. package/types/BubbleInput.d.ts.map +1 -0
  77. package/types/index.d.ts +3 -0
  78. package/types/index.d.ts.map +1 -0
  79. package/types/useRadioGroup.d.ts +100 -0
  80. package/types/useRadioGroup.d.ts.map +1 -0
  81. package/types/utils.d.ts +2 -0
  82. package/types/utils.d.ts.map +1 -0
@@ -0,0 +1,206 @@
1
+ "use strict";
2
+
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all) __defProp(target, name, {
9
+ get: all[name],
10
+ enumerable: !0
11
+ });
12
+ },
13
+ __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from == "object" || typeof from == "function") for (let key of __getOwnPropNames(from)) !__hasOwnProp.call(to, key) && key !== except && __defProp(to, key, {
15
+ get: () => from[key],
16
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
17
+ });
18
+ return to;
19
+ };
20
+ var __toCommonJS = mod => __copyProps(__defProp({}, "__esModule", {
21
+ value: !0
22
+ }), mod);
23
+ var useRadioGroup_exports = {};
24
+ __export(useRadioGroup_exports, {
25
+ useRadioGroup: () => useRadioGroup,
26
+ useRadioGroupItem: () => useRadioGroupItem,
27
+ useRadioGroupItemIndicator: () => useRadioGroupItemIndicator
28
+ });
29
+ module.exports = __toCommonJS(useRadioGroup_exports);
30
+ var import_jsx_runtime = require("react/jsx-runtime"),
31
+ import_compose_refs = require("@tamagui/compose-refs"),
32
+ import_constants = require("@tamagui/constants"),
33
+ import_focusable = require("@tamagui/focusable"),
34
+ import_helpers = require("@tamagui/helpers"),
35
+ import_label = require("@tamagui/label"),
36
+ import_use_controllable_state = require("@tamagui/use-controllable-state"),
37
+ import_react = require("react"),
38
+ import_BubbleInput = require("./BubbleInput.native.js"),
39
+ import_utils = require("./utils.native.js");
40
+ function useRadioGroup(params) {
41
+ var {
42
+ value: valueProp,
43
+ onValueChange,
44
+ defaultValue,
45
+ required,
46
+ disabled,
47
+ name,
48
+ native,
49
+ accentColor,
50
+ orientation,
51
+ ref
52
+ } = params,
53
+ [value, setValue] = (0, import_use_controllable_state.useControllableState)({
54
+ prop: valueProp,
55
+ defaultProp: defaultValue,
56
+ onChange: onValueChange
57
+ });
58
+ return {
59
+ providerValue: {
60
+ value,
61
+ onChange: setValue,
62
+ required,
63
+ disabled,
64
+ name,
65
+ native,
66
+ accentColor
67
+ },
68
+ frameAttrs: {
69
+ role: "radiogroup",
70
+ "aria-orientation": orientation,
71
+ "data-disabled": disabled ? "" : void 0
72
+ },
73
+ rovingFocusGroupAttrs: {
74
+ orientation,
75
+ loop: !0
76
+ }
77
+ };
78
+ }
79
+ var ARROW_KEYS = ["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"],
80
+ useRadioGroupItem = function (params) {
81
+ var {
82
+ radioGroupContext,
83
+ value,
84
+ labelledBy: ariaLabelledby,
85
+ disabled: itemDisabled,
86
+ ref: refProp,
87
+ id,
88
+ onPress,
89
+ onKeyDown,
90
+ onFocus
91
+ } = params,
92
+ {
93
+ value: groupValue,
94
+ disabled,
95
+ required,
96
+ onChange,
97
+ name,
98
+ native,
99
+ accentColor
100
+ } = (0, import_react.useContext)(radioGroupContext),
101
+ [button, setButton] = (0, import_react.useState)(null),
102
+ hasConsumerStoppedPropagationRef = (0, import_react.useRef)(!1),
103
+ ref = (0, import_react.useRef)(null),
104
+ composedRefs = (0, import_compose_refs.useComposedRefs)(refProp, function (node) {
105
+ return setButton(node);
106
+ }, ref),
107
+ isArrowKeyPressedRef = (0, import_react.useRef)(!1),
108
+ isFormControl = import_constants.isWeb ? button ? !!button.closest("form") : !0 : !1,
109
+ checked = groupValue === value,
110
+ labelId = (0, import_label.useLabelContext)(button),
111
+ labelledBy = ariaLabelledby || labelId;
112
+ (0, import_react.useEffect)(function () {
113
+ if (import_constants.isWeb) {
114
+ var handleKeyDown = function (event) {
115
+ ARROW_KEYS.includes(event.key) && (isArrowKeyPressedRef.current = !0);
116
+ },
117
+ handleKeyUp = function () {
118
+ isArrowKeyPressedRef.current = !1;
119
+ };
120
+ return document.addEventListener("keydown", handleKeyDown), document.addEventListener("keyup", handleKeyUp), function () {
121
+ document.removeEventListener("keydown", handleKeyDown), document.removeEventListener("keyup", handleKeyUp);
122
+ };
123
+ }
124
+ }, []), (0, import_react.useEffect)(function () {
125
+ if (id && !disabled) return (0, import_focusable.registerFocusable)(id, {
126
+ focusAndSelect: function () {
127
+ onChange?.(value);
128
+ },
129
+ focus: function () {}
130
+ });
131
+ }, [id, value, disabled]);
132
+ var isDisabled = disabled || itemDisabled;
133
+ return {
134
+ providerValue: {
135
+ checked
136
+ },
137
+ checked,
138
+ isFormControl,
139
+ bubbleInput: /* @__PURE__ */(0, import_jsx_runtime.jsx)(import_BubbleInput.BubbleInput, {
140
+ isHidden: !native,
141
+ control: button,
142
+ bubbles: !hasConsumerStoppedPropagationRef.current,
143
+ name,
144
+ value,
145
+ checked,
146
+ required,
147
+ disabled: isDisabled,
148
+ ...(import_constants.isWeb && native && {
149
+ accentColor,
150
+ id
151
+ })
152
+ }),
153
+ native,
154
+ frameAttrs: {
155
+ "data-state": (0, import_utils.getState)(checked),
156
+ "data-disabled": isDisabled ? "" : void 0,
157
+ role: "radio",
158
+ "aria-labelledby": labelledBy,
159
+ "aria-checked": checked,
160
+ "aria-required": required,
161
+ disabled: isDisabled,
162
+ ref: composedRefs,
163
+ ...(import_constants.isWeb && {
164
+ type: "button",
165
+ value
166
+ }),
167
+ id,
168
+ onPress: (0, import_helpers.composeEventHandlers)(onPress, function (event) {
169
+ checked || onChange?.(value), isFormControl && (hasConsumerStoppedPropagationRef.current = event.isPropagationStopped(), hasConsumerStoppedPropagationRef.current || event.stopPropagation());
170
+ }),
171
+ ...(import_constants.isWeb && {
172
+ onKeyDown: (0, import_helpers.composeEventHandlers)(onKeyDown, function (event) {
173
+ (event.key === "Enter" || event.key === " ") && (checked || onChange?.(value));
174
+ }),
175
+ onFocus: (0, import_helpers.composeEventHandlers)(onFocus, function () {
176
+ if (isArrowKeyPressedRef.current) {
177
+ var _ref_current;
178
+ (_ref_current = ref.current) === null || _ref_current === void 0 || _ref_current.click();
179
+ }
180
+ })
181
+ })
182
+ },
183
+ rovingFocusGroupAttrs: {
184
+ asChild: "except-style",
185
+ focusable: !isDisabled,
186
+ active: checked
187
+ }
188
+ };
189
+ };
190
+ function useRadioGroupItemIndicator(params) {
191
+ var {
192
+ radioGroupItemContext,
193
+ disabled,
194
+ ...rest
195
+ } = params,
196
+ {
197
+ checked
198
+ } = (0, import_react.useContext)(radioGroupItemContext);
199
+ return {
200
+ checked,
201
+ "data-state": (0, import_utils.getState)(checked),
202
+ "data-disabled": disabled ? "" : void 0,
203
+ ...rest
204
+ };
205
+ }
206
+ //# sourceMappingURL=useRadioGroup.native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["__defProp","Object","defineProperty","__getOwnPropDesc","getOwnPropertyDescriptor","__getOwnPropNames","getOwnPropertyNames","__hasOwnProp","prototype","hasOwnProperty","__export","target","all","name","get","enumerable","__copyProps","to","from","except","desc","key","call","__toCommonJS","mod","value","useRadioGroup_exports","useRadioGroup","useRadioGroupItem","useRadioGroupItemIndicator","module","exports","import_jsx_runtime","require","import_compose_refs","import_constants","import_focusable","import_helpers","import_label","import_use_controllable_state","import_react","import_BubbleInput","import_utils","params","valueProp","onValueChange","defaultValue","required","disabled","native","accentColor","orientation","ref","setValue","useControllableState","prop","defaultProp","onChange","providerValue","frameAttrs","role","rovingFocusGroupAttrs","loop","ARROW_KEYS","radioGroupContext","labelledBy","ariaLabelledby","itemDisabled","refProp","id","onPress","onKeyDown","onFocus","groupValue","useContext","button","setButton","useState","hasConsumerStoppedPropagationRef","useRef","composedRefs","useComposedRefs","node","isArrowKeyPressedRef","isFormControl","isWeb","closest","checked","labelId","useLabelContext","useEffect","handleKeyDown","event","includes","current","handleKeyUp","document","addEventListener","removeEventListener","registerFocusable","focusAndSelect","focus","isDisabled","bubbleInput","jsx","BubbleInput","isHidden","control","bubbles","getState","type","composeEventHandlers","isPropagationStopped","stopPropagation","_ref_current","click","asChild","focusable","active","radioGroupItemContext","rest"],"sources":["../../src/useRadioGroup.tsx"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,7 @@
1
+ function getState(checked) {
2
+ return checked ? "checked" : "unchecked";
3
+ }
4
+ export {
5
+ getState
6
+ };
7
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/utils.tsx"],
4
+ "mappings": "AAAO,SAAS,SAAS,SAAkB;AACzC,SAAO,UAAU,YAAY;AAC/B;",
5
+ "names": []
6
+ }
@@ -0,0 +1,5 @@
1
+ function getState(checked) {
2
+ return checked ? "checked" : "unchecked";
3
+ }
4
+ export { getState };
5
+ //# sourceMappingURL=utils.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["getState","checked"],"sources":["../../src/utils.tsx"],"sourcesContent":[null],"mappings":"AAAO,SAASA,SAASC,OAAA,EAAkB;EACzC,OAAOA,OAAA,GAAU,YAAY;AAC/B","ignoreList":[]}
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all) __defProp(target, name, {
9
+ get: all[name],
10
+ enumerable: !0
11
+ });
12
+ },
13
+ __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from == "object" || typeof from == "function") for (let key of __getOwnPropNames(from)) !__hasOwnProp.call(to, key) && key !== except && __defProp(to, key, {
15
+ get: () => from[key],
16
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
17
+ });
18
+ return to;
19
+ };
20
+ var __toCommonJS = mod => __copyProps(__defProp({}, "__esModule", {
21
+ value: !0
22
+ }), mod);
23
+ var utils_exports = {};
24
+ __export(utils_exports, {
25
+ getState: () => getState
26
+ });
27
+ module.exports = __toCommonJS(utils_exports);
28
+ function getState(checked) {
29
+ return checked ? "checked" : "unchecked";
30
+ }
31
+ //# sourceMappingURL=utils.native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["__defProp","Object","defineProperty","__getOwnPropDesc","getOwnPropertyDescriptor"],"sources":["../../src/utils.tsx"],"sourcesContent":[null],"mappings":"AAAO,YAAS;;AACd,IAAAA,SAAO,GAAAC,MAAU,CAAAC,cAAY;AAC/B,IAAAC,gBAAA,GAAAF,MAAA,CAAAG,wBAAA","ignoreList":[]}
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@tamagui/radio-headless",
3
+ "version": "1.0.1",
4
+ "gitHead": "a49cc7ea6b93ba384e77a4880ae48ac4a5635c14",
5
+ "source": "src/index.ts",
6
+ "files": [
7
+ "src",
8
+ "types",
9
+ "dist"
10
+ ],
11
+ "type": "module",
12
+ "sideEffects": [
13
+ "*.css"
14
+ ],
15
+ "main": "dist/cjs",
16
+ "module": "dist/esm",
17
+ "types": "./types/index.d.ts",
18
+ "exports": {
19
+ "./package.json": "./package.json",
20
+ ".": {
21
+ "types": "./types/index.d.ts",
22
+ "react-native": "./dist/esm/index.native.js",
23
+ "browser": "./dist/esm/index.mjs",
24
+ "module": "./dist/esm/index.mjs",
25
+ "import": "./dist/esm/index.mjs",
26
+ "require": "./dist/cjs/index.cjs",
27
+ "default": "./dist/esm/index.mjs"
28
+ }
29
+ },
30
+ "publishConfig": {
31
+ "access": "public"
32
+ },
33
+ "scripts": {
34
+ "build": "tamagui-build",
35
+ "watch": "tamagui-build --watch",
36
+ "clean": "tamagui-build clean",
37
+ "clean:build": "tamagui-build clean:build"
38
+ },
39
+ "dependencies": {
40
+ "@tamagui/compose-refs": "1.0.1",
41
+ "@tamagui/constants": "1.0.1",
42
+ "@tamagui/create-context": "1.0.1",
43
+ "@tamagui/focusable": "1.0.1",
44
+ "@tamagui/helpers": "1.0.1",
45
+ "@tamagui/label": "1.0.1",
46
+ "@tamagui/use-controllable-state": "1.0.1",
47
+ "@tamagui/use-previous": "1.0.1",
48
+ "@tamagui/web": "1.0.1"
49
+ },
50
+ "devDependencies": {
51
+ "@tamagui/build": "1.0.1",
52
+ "react": ">=19",
53
+ "react-native": "0.81.5"
54
+ },
55
+ "peerDependencies": {
56
+ "react": ">=19",
57
+ "react-native": "*"
58
+ },
59
+ "module:jsx": "dist/jsx",
60
+ "removeSideEffects": "true"
61
+ }
@@ -0,0 +1,59 @@
1
+ import React from 'react'
2
+ import { usePrevious } from '@tamagui/use-previous'
3
+
4
+ interface BubbleInputProps extends Omit<React.HTMLProps<HTMLInputElement>, 'checked'> {
5
+ checked: boolean
6
+ control: HTMLElement | null
7
+ bubbles: boolean
8
+ isHidden?: boolean
9
+ accentColor?: string
10
+ }
11
+
12
+ export const BubbleInput = (props: BubbleInputProps) => {
13
+ const { checked, bubbles = true, control, isHidden, accentColor, ...inputProps } = props
14
+ const ref = React.useRef<HTMLInputElement>(null)
15
+ const prevChecked = usePrevious(checked)
16
+
17
+ // Bubble checked change to parents (e.g form change event)
18
+ React.useEffect(() => {
19
+ const input = ref.current!
20
+ const inputProto = window.HTMLInputElement.prototype
21
+ const descriptor = Object.getOwnPropertyDescriptor(
22
+ inputProto,
23
+ 'checked'
24
+ ) as PropertyDescriptor
25
+ const setChecked = descriptor.set
26
+ if (prevChecked !== checked && setChecked) {
27
+ const event = new Event('click', { bubbles })
28
+ setChecked.call(input, checked)
29
+ input.dispatchEvent(event)
30
+ }
31
+ }, [prevChecked, checked, bubbles])
32
+
33
+ return (
34
+ <input
35
+ type="radio"
36
+ defaultChecked={checked}
37
+ {...inputProps}
38
+ tabIndex={-1}
39
+ ref={ref}
40
+ aria-hidden={isHidden}
41
+ style={{
42
+ ...(isHidden
43
+ ? {
44
+ // ...controlSize,
45
+ position: 'absolute',
46
+ pointerEvents: 'none',
47
+ opacity: 0,
48
+ margin: 0,
49
+ }
50
+ : {
51
+ appearance: 'auto',
52
+ accentColor,
53
+ }),
54
+
55
+ ...props.style,
56
+ }}
57
+ />
58
+ )
59
+ }
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from './useRadioGroup'
2
+ export * from './utils'
@@ -0,0 +1,260 @@
1
+ import { useComposedRefs } from '@tamagui/compose-refs'
2
+ import { isWeb } from '@tamagui/constants'
3
+ import { registerFocusable } from '@tamagui/focusable'
4
+ import { composeEventHandlers } from '@tamagui/helpers'
5
+ import { useLabelContext } from '@tamagui/label'
6
+ import { useControllableState } from '@tamagui/use-controllable-state'
7
+ import type { ViewProps } from '@tamagui/web'
8
+ import type { ReactElement } from 'react'
9
+ import { useContext, useEffect, useRef, useState } from 'react'
10
+ import type { GestureResponderEvent } from 'react-native'
11
+ import { BubbleInput } from './BubbleInput'
12
+ import { getState } from './utils'
13
+
14
+ interface UseRadioGroupParams {
15
+ value?: string
16
+ defaultValue?: string
17
+ onValueChange?: (value: string) => void
18
+ required?: boolean
19
+ disabled?: boolean
20
+ name?: string
21
+ native?: boolean
22
+ accentColor?: string
23
+ orientation: 'horizontal' | 'vertical'
24
+ ref?: React.Ref<ReactElement>
25
+ }
26
+ export function useRadioGroup(params: UseRadioGroupParams) {
27
+ const {
28
+ value: valueProp,
29
+ onValueChange,
30
+ defaultValue,
31
+ required,
32
+ disabled,
33
+ name,
34
+ native,
35
+ accentColor,
36
+ orientation,
37
+ ref,
38
+ } = params
39
+ const [value, setValue] = useControllableState({
40
+ prop: valueProp,
41
+ defaultProp: defaultValue!,
42
+ onChange: onValueChange,
43
+ })
44
+
45
+ return {
46
+ providerValue: {
47
+ value,
48
+ onChange: setValue,
49
+ required,
50
+ disabled,
51
+ name,
52
+ native,
53
+ accentColor,
54
+ },
55
+ frameAttrs: {
56
+ role: 'radiogroup' as any,
57
+ 'aria-orientation': orientation,
58
+ 'data-disabled': disabled ? '' : undefined,
59
+ },
60
+ rovingFocusGroupAttrs: {
61
+ orientation,
62
+ loop: true,
63
+ },
64
+ }
65
+ }
66
+
67
+ interface UseRadioItemParams {
68
+ radioGroupContext: React.Context<RadioGroupContextValue>
69
+ value: string
70
+ id?: string
71
+ labelledBy?: string
72
+ disabled?: boolean
73
+ ref?: any
74
+ onPress?: ViewProps['onPress']
75
+ onKeyDown?: ViewProps['onKeyDown']
76
+ onFocus?: ViewProps['onFocus']
77
+ }
78
+
79
+ export type RadioGroupContextValue = {
80
+ value?: string
81
+ disabled?: boolean
82
+ required?: boolean
83
+ onChange?: (value: string) => void
84
+ name?: string
85
+ native?: boolean
86
+ accentColor?: string
87
+ }
88
+
89
+ const ARROW_KEYS = ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight']
90
+
91
+ export const useRadioGroupItem = (params: UseRadioItemParams) => {
92
+ const {
93
+ radioGroupContext,
94
+ value,
95
+ labelledBy: ariaLabelledby,
96
+ disabled: itemDisabled,
97
+ ref: refProp,
98
+ id,
99
+ onPress,
100
+ onKeyDown,
101
+ onFocus,
102
+ } = params
103
+ const {
104
+ value: groupValue,
105
+ disabled,
106
+ required,
107
+ onChange,
108
+ name,
109
+ native,
110
+ accentColor,
111
+ } = useContext(radioGroupContext)
112
+
113
+ const [button, setButton] = useState<HTMLButtonElement | null>(null)
114
+ const hasConsumerStoppedPropagationRef = useRef(false)
115
+ const ref = useRef<any>(null)
116
+ const composedRefs = useComposedRefs(refProp, (node) => setButton(node), ref)
117
+ const isArrowKeyPressedRef = useRef(false)
118
+
119
+ const isFormControl = isWeb ? (button ? Boolean(button.closest('form')) : true) : false
120
+
121
+ const checked = groupValue === value
122
+
123
+ const labelId = useLabelContext(button)
124
+ const labelledBy = ariaLabelledby || labelId
125
+
126
+ useEffect(() => {
127
+ if (isWeb) {
128
+ const handleKeyDown = (event: KeyboardEvent) => {
129
+ if (ARROW_KEYS.includes(event.key)) {
130
+ isArrowKeyPressedRef.current = true
131
+ }
132
+ }
133
+ const handleKeyUp = () => {
134
+ isArrowKeyPressedRef.current = false
135
+ }
136
+ document.addEventListener('keydown', handleKeyDown)
137
+ document.addEventListener('keyup', handleKeyUp)
138
+ return () => {
139
+ document.removeEventListener('keydown', handleKeyDown)
140
+ document.removeEventListener('keyup', handleKeyUp)
141
+ }
142
+ }
143
+ }, [])
144
+
145
+ if (process.env.TAMAGUI_TARGET === 'native') {
146
+ useEffect(() => {
147
+ if (!id) return
148
+ if (disabled) return
149
+
150
+ return registerFocusable(id, {
151
+ focusAndSelect: () => {
152
+ onChange?.(value)
153
+ },
154
+ focus: () => {},
155
+ })
156
+ }, [id, value, disabled])
157
+ }
158
+
159
+ const isDisabled = disabled || itemDisabled
160
+
161
+ return {
162
+ providerValue: {
163
+ checked,
164
+ },
165
+ checked,
166
+ isFormControl,
167
+ bubbleInput: (
168
+ <BubbleInput
169
+ isHidden={!native}
170
+ control={button}
171
+ bubbles={!hasConsumerStoppedPropagationRef.current}
172
+ name={name}
173
+ value={value}
174
+ checked={checked}
175
+ required={required}
176
+ disabled={isDisabled}
177
+ {...(isWeb &&
178
+ native && {
179
+ accentColor,
180
+ id,
181
+ })}
182
+ />
183
+ ),
184
+ native,
185
+ frameAttrs: {
186
+ 'data-state': getState(checked),
187
+ 'data-disabled': isDisabled ? '' : undefined,
188
+ role: 'radio' as any,
189
+ 'aria-labelledby': labelledBy,
190
+ 'aria-checked': checked,
191
+ 'aria-required': required,
192
+ disabled: isDisabled,
193
+ ref: composedRefs,
194
+ ...(isWeb && {
195
+ type: 'button',
196
+ value: value,
197
+ }),
198
+ id,
199
+ onPress: composeEventHandlers(onPress, (event: GestureResponderEvent) => {
200
+ if (!checked) {
201
+ onChange?.(value)
202
+ }
203
+
204
+ if (isFormControl) {
205
+ hasConsumerStoppedPropagationRef.current = event.isPropagationStopped()
206
+ // if radio is in a form, stop propagation from the button so that we only propagate
207
+ // one click event (from the input). We propagate changes from an input so that native
208
+ // form validation works and form events reflect radio updates.
209
+ if (!hasConsumerStoppedPropagationRef.current) event.stopPropagation()
210
+ }
211
+ }),
212
+ ...(isWeb && {
213
+ onKeyDown: composeEventHandlers(onKeyDown, (event) => {
214
+ // Allow Enter and Space to select the radio item
215
+ if (event.key === 'Enter' || event.key === ' ') {
216
+ if (!checked) {
217
+ onChange?.(value)
218
+ }
219
+ }
220
+ }),
221
+ onFocus: composeEventHandlers(onFocus, () => {
222
+ /**
223
+ * Our `RovingFocusGroup` will focus the radio when navigating with arrow keys
224
+ * and we need to "check" it in that case. We click it to "check" it (instead
225
+ * of updating `context.value`) so that the radio change event fires.
226
+ */
227
+ if (isArrowKeyPressedRef.current) {
228
+ ;(ref.current as HTMLButtonElement)?.click()
229
+ }
230
+ }),
231
+ }),
232
+ },
233
+ rovingFocusGroupAttrs: {
234
+ asChild: 'except-style' as const,
235
+ focusable: !isDisabled,
236
+ active: checked,
237
+ },
238
+ }
239
+ }
240
+
241
+ export type RadioGroupItemContextValue = {
242
+ checked: boolean
243
+ disabled?: boolean
244
+ }
245
+
246
+ type UseRadioGroupItemIndicatorParams = {
247
+ radioGroupItemContext: React.Context<RadioGroupItemContextValue>
248
+ disabled?: boolean
249
+ }
250
+ export function useRadioGroupItemIndicator(params: UseRadioGroupItemIndicatorParams) {
251
+ const { radioGroupItemContext, disabled, ...rest } = params
252
+ const { checked } = useContext(radioGroupItemContext)
253
+
254
+ return {
255
+ checked,
256
+ 'data-state': getState(checked),
257
+ 'data-disabled': disabled ? '' : undefined,
258
+ ...rest,
259
+ }
260
+ }
package/src/utils.tsx ADDED
@@ -0,0 +1,3 @@
1
+ export function getState(checked: boolean) {
2
+ return checked ? 'checked' : 'unchecked'
3
+ }
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ interface BubbleInputProps extends Omit<React.HTMLProps<HTMLInputElement>, 'checked'> {
3
+ checked: boolean;
4
+ control: HTMLElement | null;
5
+ bubbles: boolean;
6
+ isHidden?: boolean;
7
+ accentColor?: string;
8
+ }
9
+ export declare const BubbleInput: (props: BubbleInputProps) => import("react/jsx-runtime").JSX.Element;
10
+ export {};
11
+ //# sourceMappingURL=BubbleInput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BubbleInput.d.ts","sourceRoot":"","sources":["../src/BubbleInput.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,UAAU,gBAAiB,SAAQ,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,gBAAgB,CAAC,EAAE,SAAS,CAAC;IACnF,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,EAAE,WAAW,GAAG,IAAI,CAAA;IAC3B,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,eAAO,MAAM,WAAW,GAAI,OAAO,gBAAgB,4CA+ClD,CAAA"}