@startupjs-ui/range-input 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,21 @@
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/range-input
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
+ * **docs:** support static web bundling (each route as a separate html page) ([5e4738c](https://github.com/startupjs/startupjs-ui/commit/5e4738c50157ae37e14d8dc36cb43d6a45a008ad))
21
+ * **range-input:** refactor RangeInput component ([e1c4a74](https://github.com/startupjs/startupjs-ui/commit/e1c4a742fcc0e416b7129364b40ba3f2aef59971))
@@ -0,0 +1,31 @@
1
+ .root
2
+ position relative
3
+
4
+ .label
5
+ position absolute
6
+ top 2px
7
+ width 12u
8
+ align-items center
9
+
10
+ // todo: implement common tooltip style
11
+ .text
12
+ background-color var(--Range-labelBg)
13
+ padding 0.5u 1u
14
+ font-style normal
15
+ font(caption)
16
+ color var(--Range-labelText)
17
+ shadow(3)
18
+ radius()
19
+
20
+ .arrow
21
+ width 0
22
+ height 0
23
+ background-color transparent
24
+ border-style solid
25
+ border-left-width 4px
26
+ border-right-width 4px
27
+ border-bottom-width 4px
28
+ border-left-color transparent
29
+ border-right-color transparent
30
+ border-bottom-color var(--Range-labelBg)
31
+ transform rotate(180deg)
@@ -0,0 +1,41 @@
1
+ import { type ReactNode } from 'react'
2
+ import { type LabelProps as MultiSliderLabelProps } from '@ptomasroos/react-native-multi-slider'
3
+ import { pug } from 'startupjs'
4
+ import Div from '@startupjs-ui/div'
5
+ import Span from '@startupjs-ui/span'
6
+ import STYLES from './index.cssx.styl'
7
+
8
+ function Label ({
9
+ oneMarkerValue,
10
+ twoMarkerValue,
11
+ oneMarkerLeftPosition,
12
+ twoMarkerLeftPosition,
13
+ oneMarkerPressed,
14
+ twoMarkerPressed
15
+ }: MultiSliderLabelProps): ReactNode {
16
+ // Number.isFinite - This condition has been taken from original vendor component.
17
+ // Be aware when you change this.
18
+ const showOne = oneMarkerPressed && Number.isFinite(oneMarkerLeftPosition) &&
19
+ Number.isFinite(oneMarkerValue)
20
+ const showTwo = twoMarkerPressed && Number.isFinite(twoMarkerLeftPosition) &&
21
+ Number.isFinite(twoMarkerValue)
22
+
23
+ return pug`
24
+ Div.root
25
+ if showOne
26
+ = renderLabel(oneMarkerLeftPosition, oneMarkerValue)
27
+ if showTwo
28
+ = renderLabel(twoMarkerLeftPosition, twoMarkerValue)
29
+ `
30
+ }
31
+
32
+ function renderLabel (position: number, value: string | number): ReactNode {
33
+ return pug`
34
+ Div.label(style={ left: position - STYLES.label.width / 2 })
35
+ // todo: implement common tooltip style
36
+ Span.text= value
37
+ Span.arrow
38
+ `
39
+ }
40
+
41
+ export default Label
package/README.mdx ADDED
@@ -0,0 +1,164 @@
1
+ import { useState } from 'react'
2
+ import RangeInput, { _PropsJsonSchema as RangeInputPropsJsonSchema } from './index'
3
+ import { Sandbox } from '@startupjs-ui/docs'
4
+
5
+ # RangeInput
6
+
7
+ RangeInput lets user make selections from a range of values.
8
+
9
+ ```jsx
10
+ import { RangeInput } from 'startupjs-ui'
11
+ ```
12
+
13
+ ## Simple example
14
+
15
+ ```jsx example
16
+ const [value, setValue] = useState(50)
17
+
18
+ return (
19
+ <RangeInput
20
+ value={value}
21
+ min={0}
22
+ max={100}
23
+ onChange={(val) => setValue(val)}
24
+ />
25
+ )
26
+ ```
27
+
28
+ ## Two markers
29
+
30
+ By default component has one marker. To enable two makers pass `range=true`.
31
+
32
+ ```jsx example
33
+ const [value, setValue] = useState([20, 60])
34
+
35
+ return (
36
+ <RangeInput
37
+ min={0}
38
+ max={100}
39
+ range
40
+ value={value}
41
+ onChange={(val) => setValue(val)}
42
+ />
43
+ )
44
+ ```
45
+
46
+ ## Hide marker label
47
+
48
+ Pass `showLabel=false` to hide marker label.
49
+
50
+ ```jsx example
51
+ const [value, setValue] = useState(40)
52
+
53
+ return (
54
+ <RangeInput
55
+ value={value}
56
+ min={0}
57
+ max={100}
58
+ showLabel={false}
59
+ onChange={(val) => setValue(val)}
60
+ />
61
+ )
62
+ ```
63
+
64
+ ## Step
65
+
66
+ Step with which the marker can step through values. It cannot be negative. We recommend `max - min` to be evenly divisible by the step.
67
+
68
+ ```jsx example
69
+ const [value, setValue] = useState(30)
70
+
71
+ return (
72
+ <RangeInput
73
+ value={value}
74
+ min={0}
75
+ max={100}
76
+ step={10}
77
+ onChange={(val) => setValue(val)}
78
+ />
79
+ )
80
+ ```
81
+
82
+ ## Show labels and markers for step
83
+
84
+ Pass `showSteps=true` to display labels and markers for step.
85
+
86
+ ```jsx example
87
+ const [value, setValue] = useState(4)
88
+
89
+ return (
90
+ <RangeInput
91
+ value={value}
92
+ min={0}
93
+ max={5}
94
+ showSteps
95
+ onChange={(val) => setValue(val)}
96
+ />
97
+ )
98
+ ```
99
+
100
+ When you pass `showSteps=true` to hide the labels or markers you need to pass `showStepLabels=false` or `showStepMarkers=false`.
101
+
102
+ **Hide labels**
103
+
104
+ ```jsx example
105
+ const [value, setValue] = useState(4)
106
+
107
+ return (
108
+ <RangeInput
109
+ value={value}
110
+ min={0}
111
+ max={5}
112
+ showSteps
113
+ showStepLabels={false}
114
+ onChange={(val) => setValue(val)}
115
+ />
116
+ )
117
+ ```
118
+
119
+ **Hide markers**
120
+
121
+ ```jsx example
122
+ const [value, setValue] = useState(4)
123
+
124
+ return (
125
+ <RangeInput
126
+ value={value}
127
+ min={0}
128
+ max={5}
129
+ showLabel={false}
130
+ showSteps
131
+ showStepMarkers={false}
132
+ onChange={(val) => setValue(val)}
133
+ />
134
+ )
135
+ ```
136
+
137
+ ## Width
138
+
139
+ Use `width` property to specify custom width of input.
140
+
141
+ ```jsx example
142
+ const [value, setValue] = useState(30)
143
+
144
+ return (
145
+ <RangeInput
146
+ value={value}
147
+ min={0}
148
+ max={100}
149
+ width={400}
150
+ onChange={(val) => setValue(val)}
151
+ />
152
+ )
153
+ ```
154
+
155
+ ## Sandbox
156
+
157
+ <Sandbox
158
+ Component={RangeInput}
159
+ propsJsonSchema={RangeInputPropsJsonSchema}
160
+ props={{
161
+ value: 50,
162
+ onChange: value => alert('New value is ' + JSON.stringify(value))
163
+ }}
164
+ />
@@ -0,0 +1,34 @@
1
+ $this = merge({
2
+ trackColor: var(--color-bg-main-subtle),
3
+ selectedColor: var(--color-bg-primary),
4
+ stepMarker: var(--color-text-on-color)
5
+ }, $UI.RangeInput, true)
6
+
7
+ .root
8
+ &:part(container)
9
+ height 10u
10
+
11
+ &:part(track)
12
+ height 1u
13
+ background-color $this.trackColor
14
+ border-radius 4px
15
+
16
+ &:part(selected)
17
+ background-color $this.selectedColor
18
+
19
+ &:part(marker)
20
+ top 4px
21
+ width 16px
22
+ height @width
23
+ border-radius 10px
24
+ shadow(1)
25
+
26
+ &:part(stepLabel)
27
+ font-style normal
28
+ font(caption)
29
+ color var(--color-text-main)
30
+
31
+ &:part(stepMarker)
32
+ border-radius 0
33
+ width 2px
34
+ background-color $this.stepMarker
package/index.d.ts ADDED
@@ -0,0 +1,52 @@
1
+ /* eslint-disable */
2
+ // DO NOT MODIFY THIS FILE - IT IS AUTOMATICALLY GENERATED ON COMMITS.
3
+
4
+ import { type MultiSliderProps } from '@ptomasroos/react-native-multi-slider';
5
+ import './index.cssx.styl';
6
+ declare const _default: import("react").ComponentType<RangeInputProps>;
7
+ export default _default;
8
+ export declare const _PropsJsonSchema: {};
9
+ export interface RangeInputProps {
10
+ /** Custom marker label component @default Label */
11
+ customLabel?: MultiSliderProps['customLabel'];
12
+ /** Show pressed marker label @default true */
13
+ showLabel?: boolean;
14
+ /** Minimum value @default 0 */
15
+ min?: number;
16
+ /** Maximum value @default 100 */
17
+ max?: number;
18
+ /** Enable two markers mode @default false */
19
+ range?: boolean;
20
+ /** Show steps on the track @default false */
21
+ showSteps?: boolean;
22
+ /** Show step labels when showSteps is enabled @default true */
23
+ showStepLabels?: boolean;
24
+ /** Show step markers when showSteps is enabled @default true */
25
+ showStepMarkers?: boolean;
26
+ /** Step size @default 1 */
27
+ step?: number;
28
+ /** Current value (number for single marker, array for two markers) */
29
+ value?: number | number[] | null;
30
+ /** Slider width in pixels @default 280 */
31
+ width?: number;
32
+ /** Style overrides for the container part */
33
+ containerStyle?: any;
34
+ /** Style overrides for the selected track part */
35
+ selectedStyle?: any;
36
+ /** Style overrides for the step label part */
37
+ stepLabelStyle?: any;
38
+ /** Style overrides for the step marker part */
39
+ stepMarkerStyle?: any;
40
+ /** Style overrides for the step part */
41
+ stepStyle?: any;
42
+ /** Style overrides for the track part */
43
+ trackStyle?: any;
44
+ /** Style overrides for the marker part */
45
+ markerStyle?: any;
46
+ /** Change handler */
47
+ onChange?: (value: number | number[]) => void | Promise<void>;
48
+ /** Handler triggered when sliding starts */
49
+ onChangeStart?: MultiSliderProps['onValuesChangeStart'];
50
+ /** Handler triggered when sliding ends */
51
+ onChangeFinish?: MultiSliderProps['onValuesChangeFinish'];
52
+ }
package/index.tsx ADDED
@@ -0,0 +1,117 @@
1
+ import { useMemo, type ReactNode } from 'react'
2
+ import MultiSlider, { type MultiSliderProps } from '@ptomasroos/react-native-multi-slider'
3
+ import { pug, observer } from 'startupjs'
4
+ import { themed } from '@startupjs-ui/core'
5
+ import Label from './Label'
6
+ import './index.cssx.styl'
7
+
8
+ export default observer(themed('RangeInput', RangeInput))
9
+
10
+ export const _PropsJsonSchema = {/* RangeInputProps */}
11
+
12
+ export interface RangeInputProps {
13
+ /** Custom marker label component @default Label */
14
+ customLabel?: MultiSliderProps['customLabel']
15
+ /** Show pressed marker label @default true */
16
+ showLabel?: boolean
17
+ /** Minimum value @default 0 */
18
+ min?: number
19
+ /** Maximum value @default 100 */
20
+ max?: number
21
+ /** Enable two markers mode @default false */
22
+ range?: boolean
23
+ /** Show steps on the track @default false */
24
+ showSteps?: boolean
25
+ /** Show step labels when showSteps is enabled @default true */
26
+ showStepLabels?: boolean
27
+ /** Show step markers when showSteps is enabled @default true */
28
+ showStepMarkers?: boolean
29
+ /** Step size @default 1 */
30
+ step?: number
31
+ /** Current value (number for single marker, array for two markers) */
32
+ value?: number | number[] | null
33
+ /** Slider width in pixels @default 280 */
34
+ width?: number
35
+ /** Style overrides for the container part */
36
+ containerStyle?: any
37
+ /** Style overrides for the selected track part */
38
+ selectedStyle?: any
39
+ /** Style overrides for the step label part */
40
+ stepLabelStyle?: any
41
+ /** Style overrides for the step marker part */
42
+ stepMarkerStyle?: any
43
+ /** Style overrides for the step part */
44
+ stepStyle?: any
45
+ /** Style overrides for the track part */
46
+ trackStyle?: any
47
+ /** Style overrides for the marker part */
48
+ markerStyle?: any
49
+ /** Change handler */
50
+ onChange?: (value: number | number[]) => void | Promise<void>
51
+ /** Handler triggered when sliding starts */
52
+ onChangeStart?: MultiSliderProps['onValuesChangeStart']
53
+ /** Handler triggered when sliding ends */
54
+ onChangeFinish?: MultiSliderProps['onValuesChangeFinish']
55
+ }
56
+
57
+ function RangeInput ({
58
+ customLabel = Label,
59
+ showLabel = true,
60
+ min = 0,
61
+ max = 100,
62
+ range = false,
63
+ showSteps = false,
64
+ showStepLabels = true,
65
+ showStepMarkers = true,
66
+ step = 1,
67
+ value,
68
+ width = 280,
69
+ onChange,
70
+ onChangeFinish,
71
+ onChangeStart,
72
+ ...props
73
+ }: RangeInputProps): ReactNode {
74
+ useMemo(() => {
75
+ if (typeof value === 'undefined' || value === null) {
76
+ // to initialize a model with default value if it is missing
77
+ // eslint-disable-next-line @typescript-eslint/no-throw-literal
78
+ throw new Promise<void>(resolve => {
79
+ void (async () => {
80
+ // TODO: maybe throw an Error instead of console.warn?
81
+ if (!onChange) console.warn('[@startupjs-ui/range-input] `onChange` is required when `value` is undefined')
82
+ await onChange?.(range ? [min, max] : min)
83
+ resolve()
84
+ })()
85
+ })
86
+ }
87
+ }, []) // eslint-disable-line react-hooks/exhaustive-deps
88
+
89
+ // vendor component requires an array in any case
90
+ const values = Array.isArray(value) ? value : [value as any]
91
+
92
+ function onValuesChange (nextValues: number[]) {
93
+ onChange && onChange(range ? nextValues : nextValues[0])
94
+ }
95
+
96
+ return pug`
97
+ MultiSlider.root(
98
+ ...props
99
+ part='root'
100
+ customLabel=customLabel
101
+ enableLabel=showLabel
102
+ enabledTwo=range
103
+ min=min
104
+ max=max
105
+ showSteps=showSteps
106
+ showStepLabels=showStepLabels
107
+ showStepMarkers=showStepMarkers
108
+ sliderLength=width
109
+ snapped
110
+ step=step
111
+ values=values
112
+ onValuesChange=onValuesChange
113
+ onValuesChangeFinish=onChangeFinish
114
+ onValuesChangeStart=onChangeStart
115
+ )
116
+ `
117
+ }
package/package.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "@startupjs-ui/range-input",
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
+ "@ptomasroos/react-native-multi-slider": "github:ptomasroos/react-native-multi-slider#368a0e8a67a595a84f411ea394b471a43ad8e7a4",
12
+ "@startupjs-ui/core": "^0.1.3",
13
+ "@startupjs-ui/div": "^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
+ }