@startupjs-ui/checkbox 0.1.3

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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,20 @@
1
+ # Change Log
2
+
3
+ All notable changes to this project will be documented in this file.
4
+ See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
+
6
+ ## [0.1.3](https://github.com/startupjs/startupjs-ui/compare/v0.1.2...v0.1.3) (2025-12-29)
7
+
8
+ **Note:** Version bump only for package @startupjs-ui/checkbox
9
+
10
+
11
+
12
+
13
+
14
+ ## [0.1.2](https://github.com/startupjs/startupjs-ui/compare/v0.1.1...v0.1.2) (2025-12-29)
15
+
16
+
17
+ ### Features
18
+
19
+ * add mdx and docs packages. Refactor docs to get rid of any @startupjs/ui usage and use startupjs-ui instead ([703c926](https://github.com/startupjs/startupjs-ui/commit/703c92636efb0421ffd11783f692fc892b74018f))
20
+ * **checkbox:** refactor Checkbox component ([563a274](https://github.com/startupjs/startupjs-ui/commit/563a2743e6c4d655d15dadd4035a48dc204a8f05))
package/README.mdx ADDED
@@ -0,0 +1,98 @@
1
+ import { useState } from 'react'
2
+ import { faMinus } from '@fortawesome/free-solid-svg-icons/faMinus'
3
+ import Checkbox, { _PropsJsonSchema as CheckboxPropsJsonSchema } from './index'
4
+ import Div from '@startupjs-ui/div'
5
+ import Br from '@startupjs-ui/br'
6
+ import { Sandbox } from '@startupjs-ui/docs'
7
+
8
+ # Checkbox
9
+
10
+ Checkboxes allow the user to select one or more items from a set.
11
+
12
+ ```jsx
13
+ import { Checkbox } from 'startupjs-ui'
14
+ ```
15
+
16
+ ## Simple example
17
+
18
+ ```jsx example
19
+ const [checked, setChecked] = useState(false)
20
+
21
+ return (
22
+ <Div>
23
+ <Checkbox
24
+ value={checked}
25
+ onChange={setChecked}
26
+ />
27
+ <Br />
28
+ <Checkbox
29
+ variant='switch'
30
+ value={checked}
31
+ onChange={setChecked}
32
+ />
33
+ </Div>
34
+ )
35
+ ```
36
+
37
+ ## Variants
38
+
39
+ There are two display variants of component: `checkbox` and `switch`. **Default**: `checkbox`.
40
+
41
+ ```jsx example
42
+ const [checked, setChecked] = useState(false)
43
+
44
+ return (
45
+ <Checkbox
46
+ variant='switch'
47
+ value={checked}
48
+ onChange={setChecked}
49
+ />
50
+ )
51
+ ```
52
+
53
+ ## Disabled
54
+
55
+ ```jsx example
56
+ return (
57
+ <Checkbox disabled />
58
+ )
59
+ ```
60
+
61
+ ## Readonly
62
+
63
+ ```jsx example
64
+ return (
65
+ <Checkbox readonly />
66
+ )
67
+ ```
68
+
69
+ ## Checkbox with custom icon
70
+
71
+ The `icon` property allows to change the default icon.
72
+
73
+ ```jsx example
74
+ const [checked, setChecked] = useState(false)
75
+
76
+ return (
77
+ <Checkbox
78
+ value={checked}
79
+ icon={faMinus}
80
+ onChange={setChecked}
81
+ />
82
+ )
83
+ ```
84
+
85
+ ## Sandbox
86
+
87
+ <Sandbox
88
+ Component={Checkbox}
89
+ propsJsonSchema={CheckboxPropsJsonSchema}
90
+ extraParams={{
91
+ icon: {
92
+ showIconSelect: true
93
+ }
94
+ }}
95
+ props={{
96
+ onChange: value => alert('New value is ' + value)
97
+ }}
98
+ />
package/checkbox.tsx ADDED
@@ -0,0 +1,77 @@
1
+ import { useState, useRef, type ReactNode } from 'react'
2
+ import { Animated, Easing } from 'react-native'
3
+ import { pug, observer, useDidUpdate } from 'startupjs'
4
+ import { themed } from '@startupjs-ui/core'
5
+ import Div from '@startupjs-ui/div'
6
+ import Icon from '@startupjs-ui/icon'
7
+ import { faCheck } from '@fortawesome/free-solid-svg-icons/faCheck'
8
+ import STYLES from './index.cssx.styl'
9
+
10
+ const { config: { checkbox: { iconSize } } } = STYLES
11
+ const AnimatedView = Animated.View
12
+
13
+ interface CheckboxInputProps {
14
+ value?: boolean
15
+ icon?: any
16
+ _hasError?: boolean
17
+ [key: string]: any
18
+ }
19
+
20
+ function CheckboxInput ({
21
+ value,
22
+ icon,
23
+ _hasError,
24
+ ...props
25
+ }: CheckboxInputProps): ReactNode {
26
+ const animation = useRef(new Animated.Value(value ? 1 : 0)).current
27
+ const [width, setWidth] = useState(0)
28
+ const [animated, setAnimated] = useState(false)
29
+
30
+ useDidUpdate(() => {
31
+ if (value) {
32
+ setAnimated(true)
33
+ Animated.timing(
34
+ animation,
35
+ {
36
+ toValue: 1,
37
+ duration: 120,
38
+ easing: Easing.linear,
39
+ useNativeDriver: true
40
+ }
41
+ ).start(() => {
42
+ setAnimated(false)
43
+ })
44
+ } else {
45
+ animation.setValue(0)
46
+ }
47
+ }, [value])
48
+
49
+ const checkedStyleName = { checked: value }
50
+
51
+ return pug`
52
+ Div.checkbox(
53
+ styleName=[checkedStyleName, { error: _hasError }]
54
+ accessibilityRole='checkbox'
55
+ onLayout=(event) => setWidth(event.nativeEvent.layout.width)
56
+ ...props
57
+ )
58
+ Icon.checkbox-icon(
59
+ styleName=[checkedStyleName]
60
+ icon= icon || faCheck
61
+ size=iconSize
62
+ )
63
+ AnimatedView.checkbox-animation(
64
+ styleName=[{ animated }]
65
+ style={
66
+ transform: [{
67
+ translateX: animation.interpolate({
68
+ inputRange: [0, 1],
69
+ outputRange: [0, width]
70
+ })
71
+ }]
72
+ }
73
+ )
74
+ `
75
+ }
76
+
77
+ export default observer(themed('Checkbox', CheckboxInput))
@@ -0,0 +1,103 @@
1
+ $checkboxBorderColor = var(--color-border-main)
2
+ $checkedIconColor = var(--color-text-on-primary)
3
+ $height = 2u
4
+
5
+ $this = merge({
6
+ checkbox: {
7
+ size: 2u,
8
+ borderWidth: 2px,
9
+ borderColor: $checkboxBorderColor,
10
+ borderRadius: 2px,
11
+ iconSize: 12
12
+ },
13
+ switch: {
14
+ width: 3u,
15
+ height: 2u,
16
+ circleSize: 10px,
17
+ circleBg: var(--Checkbox-switchBulletBg),
18
+ circleBgChecked: var(--Checkbox-switchBulletBg-checked),
19
+ circleLeftPosition: 3px,
20
+ circleRightPosition: 11px
21
+ }
22
+ }, $UI.Checkbox, true)
23
+
24
+ .readonly
25
+ fontFamily('normal', 900)
26
+ font-size 2u
27
+ line-height $height
28
+
29
+ .checkbox
30
+ height: $this.checkbox.size
31
+ width @height
32
+ border-width: $this.checkbox.borderWidth
33
+ border-color: $this.checkbox.borderColor
34
+ justify-content center
35
+ align-items center
36
+ // due to border-radius on emulator
37
+ // you can see white 1px boundary between border and background
38
+ border-radius: $this.checkbox.borderRadius
39
+ overflow hidden
40
+
41
+ // NOTE:
42
+ // We do not change the background color for the error
43
+ // because this behavior is not possible
44
+ // but if it is necessary for some reason
45
+ // then we need to change it for the checkbox-animation class too
46
+ // IMPORTANT: checked modifier should overlaps error modifier
47
+ &.error
48
+ border-color var(--color-border-error)
49
+
50
+ &.checked
51
+ background-color var(--color-bg-primary)
52
+ border-color var(--color-border-primary)
53
+
54
+ .checkbox-icon
55
+ display none
56
+ color $checkedIconColor
57
+
58
+ &.checked
59
+ display flex
60
+
61
+ // NOTE: opacity is workaround because display none and position absolute doesn't work right
62
+ // https://github.com/facebook/react-native/issues/18415
63
+ .checkbox-animation
64
+ opacity 0
65
+ position absolute
66
+ left 0
67
+ top 0
68
+ bottom 0
69
+ right 0
70
+ background-color var(--color-bg-primary)
71
+
72
+ &.animated
73
+ opacity 1
74
+
75
+ .switch
76
+ width: $this.switch.width
77
+ height $this.switch.height
78
+ radius(circle)
79
+ justify-content center
80
+ background-color var(--Checkbox-switchBg)
81
+ // padding 0 3px
82
+
83
+ // IMPORTANT: checked modifier should overlap error modifier
84
+ &.error
85
+ background-color var(--color-bg-error)
86
+
87
+ &.checked
88
+ background-color var(--color-bg-primary)
89
+
90
+ .switch-circle
91
+ width: $this.switch.circleSize
92
+ height @width
93
+ background-color: $this.switch.circleBg
94
+ radius(circle)
95
+
96
+ if $this.switch.circleShadowLevel
97
+ shadow($this.switch.circleShadowLevel)
98
+
99
+ &.checked
100
+ background-color: $this.switch.circleBgChecked
101
+
102
+ :export
103
+ config: $this
package/index.d.ts ADDED
@@ -0,0 +1,35 @@
1
+ /* eslint-disable */
2
+ // DO NOT MODIFY THIS FILE - IT IS AUTOMATICALLY GENERATED ON COMMITS.
3
+
4
+ import { type StyleProp, type ViewStyle } from 'react-native';
5
+ import './index.cssx.styl';
6
+ export declare const _PropsJsonSchema: {};
7
+ export interface CheckboxProps {
8
+ /** Custom styles for the wrapper */
9
+ style?: StyleProp<ViewStyle>;
10
+ /** Custom styles for the input element */
11
+ inputStyle?: StyleProp<ViewStyle>;
12
+ /** Visual variant @default 'checkbox' */
13
+ variant?: 'checkbox' | 'switch';
14
+ /** Checked state @default false */
15
+ value?: boolean;
16
+ /** Custom icon for the checkbox variant */
17
+ icon?: any;
18
+ /** Disable interactions @default false */
19
+ disabled?: boolean;
20
+ /** Render a non-interactive value @default false */
21
+ readonly?: boolean;
22
+ /** Change handler */
23
+ onChange?: (value: boolean) => void;
24
+ /** Focus handler (ignored on wrapper) */
25
+ onFocus?: (...args: any[]) => void;
26
+ /** Blur handler (ignored on wrapper) */
27
+ onBlur?: (...args: any[]) => void;
28
+ /** Style override for the switch thumb */
29
+ switchCircleStyle?: StyleProp<ViewStyle>;
30
+ /** Error flag @private */
31
+ _hasError?: boolean;
32
+ [key: string]: any;
33
+ }
34
+ declare const _default: import("react").ComponentType<CheckboxProps>;
35
+ export default _default;
package/index.tsx ADDED
@@ -0,0 +1,87 @@
1
+ import { type ReactNode } from 'react'
2
+ import { type StyleProp, type ViewStyle } from 'react-native'
3
+ import { pug, observer } from 'startupjs'
4
+ import { themed } from '@startupjs-ui/core'
5
+ import Div from '@startupjs-ui/div'
6
+ import Span from '@startupjs-ui/span'
7
+ import CheckboxInput from './checkbox'
8
+ import SwitchInput from './switch'
9
+ import './index.cssx.styl'
10
+
11
+ const INPUT_COMPONENTS = {
12
+ checkbox: CheckboxInput,
13
+ switch: SwitchInput
14
+ } as const
15
+
16
+ const READONLY_ICONS = {
17
+ TRUE: '✓',
18
+ FALSE: '✗'
19
+ }
20
+
21
+ export const _PropsJsonSchema = {/* CheckboxProps */}
22
+
23
+ export interface CheckboxProps {
24
+ /** Custom styles for the wrapper */
25
+ style?: StyleProp<ViewStyle>
26
+ /** Custom styles for the input element */
27
+ inputStyle?: StyleProp<ViewStyle>
28
+ /** Visual variant @default 'checkbox' */
29
+ variant?: 'checkbox' | 'switch'
30
+ /** Checked state @default false */
31
+ value?: boolean
32
+ /** Custom icon for the checkbox variant */
33
+ icon?: any
34
+ /** Disable interactions @default false */
35
+ disabled?: boolean
36
+ /** Render a non-interactive value @default false */
37
+ readonly?: boolean
38
+ /** Change handler */
39
+ onChange?: (value: boolean) => void
40
+ /** Focus handler (ignored on wrapper) */
41
+ onFocus?: (...args: any[]) => void
42
+ /** Blur handler (ignored on wrapper) */
43
+ onBlur?: (...args: any[]) => void
44
+ /** Style override for the switch thumb */
45
+ switchCircleStyle?: StyleProp<ViewStyle>
46
+ /** Error flag @private */
47
+ _hasError?: boolean
48
+ [key: string]: any
49
+ }
50
+
51
+ function Checkbox ({
52
+ style,
53
+ inputStyle,
54
+ variant = 'checkbox',
55
+ readonly = false,
56
+ value = false,
57
+ disabled = false,
58
+ onChange,
59
+ onFocus, // skip due to pointless triggering when clicked on the View
60
+ onBlur, // skip due to pointless triggering when clicked on the View
61
+ ...props
62
+ }: CheckboxProps): ReactNode {
63
+ const InputComponent = INPUT_COMPONENTS[variant]
64
+
65
+ function onPress () {
66
+ onChange && onChange(!value)
67
+ }
68
+
69
+ return pug`
70
+ Div(style=style)
71
+ if readonly
72
+ Span.readonly=value ? READONLY_ICONS.TRUE : READONLY_ICONS.FALSE
73
+ else
74
+ InputComponent(
75
+ style=inputStyle
76
+ value=value
77
+ onPress=onPress
78
+ disabled=disabled
79
+ accessibilityRole='checkbox'
80
+ ...props
81
+ )
82
+ `
83
+ }
84
+
85
+ export default observer(
86
+ themed('Checkbox', Checkbox)
87
+ )
package/package.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "@startupjs-ui/checkbox",
3
+ "version": "0.1.3",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "main": "index.tsx",
8
+ "types": "index.d.ts",
9
+ "type": "module",
10
+ "dependencies": {
11
+ "@startupjs-ui/core": "^0.1.3",
12
+ "@startupjs-ui/div": "^0.1.3",
13
+ "@startupjs-ui/icon": "^0.1.3",
14
+ "@startupjs-ui/span": "^0.1.3"
15
+ },
16
+ "peerDependencies": {
17
+ "react": "*",
18
+ "react-native": "*",
19
+ "startupjs": "*"
20
+ },
21
+ "gitHead": "fd964ebc3892d3dd0a6c85438c0af619cc50c3f0"
22
+ }
package/switch.tsx ADDED
@@ -0,0 +1,74 @@
1
+ import { useRef, type ReactNode } from 'react'
2
+ import { Animated, Easing } from 'react-native'
3
+ import { pug, observer, useDidUpdate } from 'startupjs'
4
+ import Div from '@startupjs-ui/div'
5
+ import { themed } from '@startupjs-ui/core'
6
+ import STYLES from './index.cssx.styl'
7
+
8
+ const {
9
+ config: {
10
+ switch: {
11
+ circleLeftPosition,
12
+ circleRightPosition
13
+ }
14
+ }
15
+ } = STYLES
16
+ const AnimatedView = Animated.View
17
+
18
+ interface SwitchInputProps {
19
+ value?: boolean
20
+ _hasError?: boolean
21
+ [key: string]: any
22
+ }
23
+
24
+ function SwitchInput ({
25
+ value,
26
+ _hasError,
27
+ ...props
28
+ }: SwitchInputProps): ReactNode {
29
+ const animation = useRef(new Animated.Value(value ? 1 : 0)).current
30
+
31
+ useDidUpdate(() => {
32
+ if (value) {
33
+ Animated.timing(
34
+ animation,
35
+ {
36
+ toValue: 1,
37
+ duration: 120,
38
+ easing: Easing.linear,
39
+ useNativeDriver: true
40
+ }
41
+ ).start()
42
+ } else {
43
+ Animated.timing(
44
+ animation,
45
+ {
46
+ toValue: 0,
47
+ duration: 120,
48
+ easing: Easing.linear,
49
+ useNativeDriver: true
50
+ }
51
+ ).start()
52
+ }
53
+ }, [value])
54
+
55
+ return pug`
56
+ Div.switch(
57
+ styleName=[{ checked: value, error: _hasError }]
58
+ ...props
59
+ )
60
+ AnimatedView.switch-circle(
61
+ part='switchCircle'
62
+ style={
63
+ transform: [{
64
+ translateX: animation.interpolate({
65
+ inputRange: [0, 1],
66
+ outputRange: [circleLeftPosition, circleRightPosition]
67
+ })
68
+ }]
69
+ }
70
+ styleName={ checked: value }
71
+ )
72
+ `
73
+ }
74
+ export default observer(themed('Checkbox', SwitchInput))