@hanzogui/checkbox 2.0.0

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 (58) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cjs/Checkbox.cjs +111 -0
  3. package/dist/cjs/Checkbox.native.js +117 -0
  4. package/dist/cjs/Checkbox.native.js.map +1 -0
  5. package/dist/cjs/CheckboxStyledContext.cjs +33 -0
  6. package/dist/cjs/CheckboxStyledContext.native.js +36 -0
  7. package/dist/cjs/CheckboxStyledContext.native.js.map +1 -0
  8. package/dist/cjs/createCheckbox.cjs +184 -0
  9. package/dist/cjs/createCheckbox.native.js +209 -0
  10. package/dist/cjs/createCheckbox.native.js.map +1 -0
  11. package/dist/cjs/index.cjs +35 -0
  12. package/dist/cjs/index.native.js +38 -0
  13. package/dist/cjs/index.native.js.map +1 -0
  14. package/dist/esm/Checkbox.mjs +87 -0
  15. package/dist/esm/Checkbox.mjs.map +1 -0
  16. package/dist/esm/Checkbox.native.js +90 -0
  17. package/dist/esm/Checkbox.native.js.map +1 -0
  18. package/dist/esm/CheckboxStyledContext.mjs +10 -0
  19. package/dist/esm/CheckboxStyledContext.mjs.map +1 -0
  20. package/dist/esm/CheckboxStyledContext.native.js +10 -0
  21. package/dist/esm/CheckboxStyledContext.native.js.map +1 -0
  22. package/dist/esm/createCheckbox.mjs +148 -0
  23. package/dist/esm/createCheckbox.mjs.map +1 -0
  24. package/dist/esm/createCheckbox.native.js +171 -0
  25. package/dist/esm/createCheckbox.native.js.map +1 -0
  26. package/dist/esm/index.js +11 -0
  27. package/dist/esm/index.js.map +1 -0
  28. package/dist/esm/index.mjs +11 -0
  29. package/dist/esm/index.mjs.map +1 -0
  30. package/dist/esm/index.native.js +11 -0
  31. package/dist/esm/index.native.js.map +1 -0
  32. package/dist/jsx/Checkbox.mjs +87 -0
  33. package/dist/jsx/Checkbox.mjs.map +1 -0
  34. package/dist/jsx/Checkbox.native.js +117 -0
  35. package/dist/jsx/Checkbox.native.js.map +1 -0
  36. package/dist/jsx/CheckboxStyledContext.mjs +10 -0
  37. package/dist/jsx/CheckboxStyledContext.mjs.map +1 -0
  38. package/dist/jsx/CheckboxStyledContext.native.js +36 -0
  39. package/dist/jsx/CheckboxStyledContext.native.js.map +1 -0
  40. package/dist/jsx/createCheckbox.mjs +148 -0
  41. package/dist/jsx/createCheckbox.mjs.map +1 -0
  42. package/dist/jsx/createCheckbox.native.js +209 -0
  43. package/dist/jsx/createCheckbox.native.js.map +1 -0
  44. package/dist/jsx/index.js +11 -0
  45. package/dist/jsx/index.js.map +1 -0
  46. package/dist/jsx/index.mjs +11 -0
  47. package/dist/jsx/index.mjs.map +1 -0
  48. package/dist/jsx/index.native.js +38 -0
  49. package/dist/jsx/index.native.js.map +1 -0
  50. package/package.json +63 -0
  51. package/src/Checkbox.tsx +122 -0
  52. package/src/CheckboxStyledContext.tsx +16 -0
  53. package/src/createCheckbox.tsx +280 -0
  54. package/src/index.ts +12 -0
  55. package/types/Checkbox.d.ts +39 -0
  56. package/types/CheckboxStyledContext.d.ts +9 -0
  57. package/types/createCheckbox.d.ts +196 -0
  58. package/types/index.d.ts +324 -0
@@ -0,0 +1,122 @@
1
+ // fork of radix
2
+ // https://github.com/radix-ui/primitives/tree/main/packages/react/checkbox/src/Checkbox.tsx
3
+
4
+ import { getVariableValue, styled } from '@hanzogui/core'
5
+ import { getSize } from '@hanzogui/get-token'
6
+ import { YStack } from '@hanzogui/stacks'
7
+
8
+ import { CheckboxStyledContext } from './CheckboxStyledContext'
9
+
10
+ /* -------------------------------------------------------------------------------------------------
11
+ * CheckboxIndicator
12
+ * -----------------------------------------------------------------------------------------------*/
13
+ const INDICATOR_NAME = 'CheckboxIndicator'
14
+
15
+ export const CheckboxIndicatorFrame = styled(
16
+ YStack,
17
+ {
18
+ // use Checkbox for easier themes
19
+ name: INDICATOR_NAME,
20
+ context: CheckboxStyledContext,
21
+ variants: {
22
+ unstyled: {
23
+ false: {},
24
+ },
25
+ } as const,
26
+ defaultVariants: {
27
+ unstyled: process.env.HANZO_GUI_HEADLESS === '1',
28
+ },
29
+ },
30
+ {
31
+ accept: {
32
+ activeStyle: 'style',
33
+ } as const,
34
+ }
35
+ )
36
+
37
+ /* -------------------------------------------------------------------------------------------------
38
+ * Checkbox
39
+ * -----------------------------------------------------------------------------------------------*/
40
+
41
+ const CHECKBOX_NAME = 'Checkbox'
42
+
43
+ export const CheckboxFrame = styled(
44
+ YStack,
45
+ {
46
+ name: CHECKBOX_NAME,
47
+ render: 'button',
48
+
49
+ context: CheckboxStyledContext,
50
+ variants: {
51
+ unstyled: {
52
+ false: {
53
+ size: '$true',
54
+ backgroundColor: '$background',
55
+ alignItems: 'center',
56
+ justifyContent: 'center',
57
+ borderWidth: 1,
58
+ borderColor: '$borderColor',
59
+
60
+ hoverStyle: {
61
+ borderColor: '$borderColorHover',
62
+ },
63
+
64
+ pressStyle: {
65
+ backgroundColor: '$backgroundPress',
66
+ borderColor: '$borderColorPress',
67
+ },
68
+
69
+ focusStyle: {
70
+ borderColor: '$borderColorFocus',
71
+ },
72
+
73
+ focusVisibleStyle: {
74
+ outlineStyle: 'solid',
75
+ outlineWidth: 2,
76
+ outlineColor: '$outlineColor',
77
+ },
78
+ },
79
+ },
80
+
81
+ disabled: {
82
+ true: {
83
+ pointerEvents: 'none',
84
+ userSelect: 'none',
85
+ cursor: 'not-allowed',
86
+
87
+ hoverStyle: {
88
+ borderColor: '$borderColor',
89
+ backgroundColor: '$background',
90
+ },
91
+
92
+ pressStyle: {
93
+ borderColor: '$borderColor',
94
+ backgroundColor: '$background',
95
+ },
96
+
97
+ focusStyle: {
98
+ outlineWidth: 0,
99
+ },
100
+ },
101
+ },
102
+
103
+ size: {
104
+ '...size': (val) => {
105
+ const radiusToken = getVariableValue(getSize(val)) / 8
106
+ return {
107
+ borderRadius: radiusToken,
108
+ }
109
+ },
110
+ },
111
+ } as const,
112
+
113
+ defaultVariants: {
114
+ unstyled: process.env.HANZO_GUI_HEADLESS === '1',
115
+ },
116
+ },
117
+ {
118
+ accept: {
119
+ activeStyle: 'style',
120
+ } as const,
121
+ }
122
+ )
@@ -0,0 +1,16 @@
1
+ import type { SizeTokens } from '@hanzogui/core'
2
+ import { createStyledContext } from '@hanzogui/core'
3
+
4
+ export const CheckboxStyledContext = createStyledContext<{
5
+ size: SizeTokens
6
+ scaleIcon: number
7
+ unstyled?: boolean
8
+ active?: boolean
9
+ disabled?: boolean
10
+ }>({
11
+ size: '$true' as SizeTokens,
12
+ scaleIcon: 1,
13
+ unstyled: process.env.HANZO_GUI_HEADLESS === '1',
14
+ active: false,
15
+ disabled: false,
16
+ })
@@ -0,0 +1,280 @@
1
+ import type {
2
+ CheckedState,
3
+ CheckboxExtraProps as HeadlessCheckboxExtraProps,
4
+ } from '@hanzogui/checkbox-headless'
5
+ import { isIndeterminate, useCheckbox } from '@hanzogui/checkbox-headless'
6
+ import type { GetProps, NativeValue, SizeTokens, ViewProps } from '@hanzogui/core'
7
+ import {
8
+ getVariableValue,
9
+ isWeb,
10
+ shouldRenderNativePlatform,
11
+ useProps,
12
+ useTheme,
13
+ withStaticProperties,
14
+ } from '@hanzogui/core'
15
+ import { registerFocusable } from '@hanzogui/focusable'
16
+ import { getFontSize } from '@hanzogui/font-size'
17
+ import { getSize } from '@hanzogui/get-token'
18
+ import { useGetThemedIcon } from '@hanzogui/helpers'
19
+ import { useControllableState } from '@hanzogui/use-controllable-state'
20
+ import React, { useMemo } from 'react'
21
+
22
+ import { CheckboxFrame, CheckboxIndicatorFrame } from './Checkbox'
23
+ import { CheckboxStyledContext } from './CheckboxStyledContext'
24
+
25
+ type CheckboxExpectingVariantProps = {
26
+ size?: SizeTokens
27
+ unstyled?: boolean
28
+ }
29
+
30
+ type CheckboxExtraProps = HeadlessCheckboxExtraProps & {
31
+ scaleIcon?: number
32
+ scaleSize?: number
33
+ sizeAdjust?: number
34
+ native?: NativeValue<'web'>
35
+ }
36
+ type CheckboxBaseProps = ViewProps
37
+
38
+ type DefaultCheckboxFrame = typeof CheckboxFrame
39
+ type DefaultIndicatorFrame = typeof CheckboxIndicatorFrame
40
+
41
+ type CheckboxFrameActiveStyleProps = {
42
+ activeStyle?: GetProps<DefaultCheckboxFrame>
43
+ activeTheme?: string | null
44
+ }
45
+
46
+ type CheckboxIndicatorActiveStyleProps = {
47
+ activeStyle?: GetProps<DefaultIndicatorFrame>
48
+ }
49
+
50
+ export type CheckboxProps = CheckboxBaseProps &
51
+ CheckboxExtraProps &
52
+ CheckboxExpectingVariantProps &
53
+ CheckboxFrameActiveStyleProps
54
+
55
+ // loose types for createCheckbox generics - actual components have stricter types
56
+ type CheckboxComponent = (props: any) => React.ReactNode
57
+ type CheckboxIndicatorComponent = (props: any) => React.ReactNode
58
+
59
+ type CheckboxIndicatorBaseProps = ViewProps
60
+ type CheckboxIndicatorExtraProps = {
61
+ /**
62
+ * Used to force mounting when more control is needed. Useful when
63
+ * controlling animation with React animation libraries.
64
+ */
65
+ forceMount?: boolean
66
+ /**
67
+ * Used to disable passing styles down to children.
68
+ */
69
+ disablePassStyles?: boolean
70
+ }
71
+
72
+ export type CheckboxIndicatorProps = CheckboxIndicatorBaseProps &
73
+ CheckboxIndicatorExtraProps &
74
+ CheckboxIndicatorActiveStyleProps
75
+
76
+ export const CheckboxContext = React.createContext<{
77
+ checked: CheckedState
78
+ disabled?: boolean
79
+ }>({
80
+ checked: false,
81
+ disabled: false,
82
+ })
83
+
84
+ const ensureContext = (x: any) => {
85
+ if (!x.context) {
86
+ x.context = CheckboxContext
87
+ }
88
+ }
89
+
90
+ export function createCheckbox<
91
+ F extends CheckboxComponent,
92
+ T extends CheckboxIndicatorComponent,
93
+ >(createProps: { Frame?: F; Indicator?: T }) {
94
+ const { Frame = CheckboxFrame, Indicator = CheckboxIndicatorFrame } =
95
+ createProps as any as {
96
+ Frame: typeof CheckboxFrame
97
+ Indicator: typeof CheckboxIndicatorFrame
98
+ }
99
+
100
+ ensureContext(Frame)
101
+ ensureContext(Indicator)
102
+
103
+ const FrameComponent = Frame.styleable<CheckboxProps>(
104
+ function Checkbox(_props, forwardedRef) {
105
+ const {
106
+ scaleSize = 0.45,
107
+ sizeAdjust = 0,
108
+ scaleIcon,
109
+ checked: checkedProp,
110
+ defaultChecked,
111
+ onCheckedChange,
112
+ native,
113
+ unstyled = false,
114
+ activeStyle,
115
+ activeTheme,
116
+ ...props
117
+ } = _props
118
+ const propsActive = useProps(props)
119
+
120
+ const styledContext = React.useContext(CheckboxStyledContext.context)
121
+ let adjustedSize = 0
122
+ let size = 0
123
+ if (!unstyled) {
124
+ adjustedSize = getVariableValue(
125
+ getSize(propsActive.size ?? styledContext?.size ?? '$true', {
126
+ shift: sizeAdjust,
127
+ })
128
+ ) as number
129
+ size = scaleSize ? Math.round(adjustedSize * scaleSize) : adjustedSize
130
+ }
131
+
132
+ const [checked = false, setChecked] = useControllableState({
133
+ prop: checkedProp,
134
+ defaultProp: defaultChecked!,
135
+ onChange: onCheckedChange,
136
+ })
137
+
138
+ const { checkboxProps, checkboxRef, bubbleInput } = useCheckbox(
139
+ // @ts-ignore
140
+ propsActive,
141
+ [checked, setChecked],
142
+ forwardedRef
143
+ )
144
+
145
+ if (process.env.HANZO_GUI_TARGET === 'native') {
146
+ React.useEffect(() => {
147
+ if (!props.id) return
148
+ if (props.disabled) return
149
+
150
+ return registerFocusable(props.id, {
151
+ focusAndSelect: () => {
152
+ setChecked?.((value) => !value)
153
+ },
154
+ focus: () => {},
155
+ })
156
+ }, [props.id, props.disabled])
157
+ }
158
+
159
+ const renderNative = shouldRenderNativePlatform(native)
160
+ if (renderNative === 'web') {
161
+ return (
162
+ <input
163
+ type="checkbox"
164
+ defaultChecked={isIndeterminate(checked) ? false : checked}
165
+ tabIndex={-1}
166
+ ref={checkboxRef as any}
167
+ disabled={checkboxProps.disabled}
168
+ style={{
169
+ appearance: 'auto',
170
+ accentColor: 'var(--color6)',
171
+ ...(checkboxProps.style as any),
172
+ }}
173
+ />
174
+ )
175
+ }
176
+
177
+ const memoizedContext = useMemo(
178
+ () => ({
179
+ checked,
180
+ disabled: checkboxProps.disabled,
181
+ }),
182
+ [checked, checkboxProps.disabled]
183
+ )
184
+
185
+ const isActive = !!checked
186
+ const disabled = checkboxProps.disabled
187
+
188
+ return (
189
+ <CheckboxContext.Provider value={memoizedContext}>
190
+ <CheckboxStyledContext.Provider
191
+ size={propsActive.size ?? styledContext?.size ?? '$true'}
192
+ scaleIcon={scaleIcon ?? styledContext?.scaleIcon ?? 1}
193
+ unstyled={unstyled}
194
+ active={isActive}
195
+ disabled={disabled}
196
+ >
197
+ <Frame
198
+ render="button"
199
+ ref={checkboxRef}
200
+ unstyled={unstyled}
201
+ theme={activeTheme ?? null}
202
+ {...(isWeb && { type: 'button' })}
203
+ {...(!unstyled && {
204
+ width: size,
205
+ height: size,
206
+ size,
207
+ })}
208
+ checked={checked}
209
+ disabled={disabled}
210
+ {...(checkboxProps as CheckboxProps)}
211
+ {...props}
212
+ {...(isActive && {
213
+ ...(!unstyled &&
214
+ !activeStyle && {
215
+ backgroundColor: '$backgroundActive',
216
+ }),
217
+ ...activeStyle,
218
+ })}
219
+ >
220
+ {propsActive.children}
221
+ </Frame>
222
+ {bubbleInput}
223
+ </CheckboxStyledContext.Provider>
224
+ </CheckboxContext.Provider>
225
+ )
226
+ }
227
+ )
228
+
229
+ const IndicatorComponent = Indicator.styleable<CheckboxIndicatorProps>(
230
+ (props, forwardedRef) => {
231
+ const {
232
+ children: childrenProp,
233
+ forceMount,
234
+ disablePassStyles,
235
+ unstyled = false,
236
+ activeStyle,
237
+ ...indicatorProps
238
+ } = props
239
+ const styledContext = CheckboxStyledContext.useStyledContext()
240
+ const { active } = styledContext
241
+ let children = childrenProp
242
+
243
+ if (!unstyled) {
244
+ const iconSize =
245
+ (typeof styledContext.size === 'number'
246
+ ? styledContext.size * 0.65
247
+ : getFontSize(styledContext.size as any)) * styledContext.scaleIcon
248
+ const theme = useTheme()
249
+ const getThemedIcon = useGetThemedIcon({ size: iconSize, color: theme.color })
250
+
251
+ const childrens = React.Children.toArray(childrenProp)
252
+ children = childrens.map((child) => {
253
+ if (disablePassStyles || !React.isValidElement(child)) {
254
+ return child
255
+ }
256
+ return getThemedIcon(child)
257
+ })
258
+ }
259
+
260
+ const context = React.useContext(CheckboxContext)
261
+ if (forceMount || isIndeterminate(context.checked) || context.checked === true)
262
+ return (
263
+ <Indicator
264
+ pointerEvents="none"
265
+ {...indicatorProps}
266
+ {...(active && activeStyle)}
267
+ ref={forwardedRef}
268
+ >
269
+ {children}
270
+ </Indicator>
271
+ )
272
+
273
+ return null
274
+ }
275
+ )
276
+
277
+ return withStaticProperties(FrameComponent, {
278
+ Indicator: IndicatorComponent,
279
+ })
280
+ }
package/src/index.ts ADDED
@@ -0,0 +1,12 @@
1
+ import { CheckboxFrame, CheckboxIndicatorFrame } from './Checkbox'
2
+ import { createCheckbox } from './createCheckbox'
3
+
4
+ export * from './createCheckbox'
5
+ export * from './Checkbox'
6
+ export * from './CheckboxStyledContext'
7
+ export type { CheckedState } from '@hanzogui/checkbox-headless'
8
+
9
+ export const Checkbox = createCheckbox({
10
+ Frame: CheckboxFrame,
11
+ Indicator: CheckboxIndicatorFrame,
12
+ })
@@ -0,0 +1,39 @@
1
+ export declare const CheckboxIndicatorFrame: import("@gui/core").GuiComponent<import("@gui/core").TamaDefer, import("@gui/core").GuiElement, import("@gui/core").RNGuiViewNonStyleProps, import("@gui/core").StackStyleBase & {
2
+ readonly activeStyle?: Partial<import("@gui/core").InferStyleProps<import("@gui/core").GuiComponent<import("@gui/core").TamaDefer, import("@gui/core").GuiElement, import("@gui/core").RNGuiViewNonStyleProps, import("@gui/core").StackStyleBase, {
3
+ elevation?: number | import("@gui/core").SizeTokens | undefined;
4
+ fullscreen?: boolean | undefined;
5
+ }, import("@gui/core").StaticConfigPublic>, {
6
+ accept: {
7
+ readonly activeStyle: "style";
8
+ };
9
+ }>> | undefined;
10
+ }, {
11
+ unstyled?: boolean | undefined;
12
+ elevation?: number | import("@gui/core").SizeTokens | undefined;
13
+ fullscreen?: boolean | undefined;
14
+ }, import("@gui/core").StaticConfigPublic & {
15
+ accept: {
16
+ readonly activeStyle: "style";
17
+ };
18
+ }>;
19
+ export declare const CheckboxFrame: import("@gui/core").GuiComponent<import("@gui/core").TamaDefer, import("@gui/core").GuiElement, import("@gui/core").RNGuiViewNonStyleProps, import("@gui/core").StackStyleBase & {
20
+ readonly activeStyle?: Partial<import("@gui/core").InferStyleProps<import("@gui/core").GuiComponent<import("@gui/core").TamaDefer, import("@gui/core").GuiElement, import("@gui/core").RNGuiViewNonStyleProps, import("@gui/core").StackStyleBase, {
21
+ elevation?: number | import("@gui/core").SizeTokens | undefined;
22
+ fullscreen?: boolean | undefined;
23
+ }, import("@gui/core").StaticConfigPublic>, {
24
+ accept: {
25
+ readonly activeStyle: "style";
26
+ };
27
+ }>> | undefined;
28
+ }, {
29
+ size?: import("@gui/core").SizeTokens | undefined;
30
+ disabled?: boolean | undefined;
31
+ unstyled?: boolean | undefined;
32
+ elevation?: number | import("@gui/core").SizeTokens | undefined;
33
+ fullscreen?: boolean | undefined;
34
+ }, import("@gui/core").StaticConfigPublic & {
35
+ accept: {
36
+ readonly activeStyle: "style";
37
+ };
38
+ }>;
39
+ //# sourceMappingURL=Checkbox.d.ts.map
@@ -0,0 +1,9 @@
1
+ import type { SizeTokens } from '@gui/core';
2
+ export declare const CheckboxStyledContext: import("@gui/core").StyledContext<{
3
+ size: SizeTokens;
4
+ scaleIcon: number;
5
+ unstyled?: boolean;
6
+ active?: boolean;
7
+ disabled?: boolean;
8
+ }>;
9
+ //# sourceMappingURL=CheckboxStyledContext.d.ts.map