zds-pickers 4.0.5 → 4.0.6

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 (74) hide show
  1. package/.editorconfig +19 -0
  2. package/.github/workflows/codeql-analysis.yml +67 -0
  3. package/.nvmrc +1 -0
  4. package/.prettierignore +0 -0
  5. package/.prettierrc +13 -0
  6. package/.storybook/main.ts +42 -0
  7. package/.storybook/manager.ts +12 -0
  8. package/.storybook/preview.tsx +26 -0
  9. package/.vscode/extensions.json +32 -0
  10. package/.vscode/javascript.code-snippets +229 -0
  11. package/.vscode/settings.json +358 -0
  12. package/biome.jsonc +158 -0
  13. package/dist/index.es.js +3 -1
  14. package/dist/types/index.d.ts +266 -2
  15. package/dist/types/pickers/CCPicker.d.ts +2 -1
  16. package/dist/types/pickers/ChannelMappingPicker.d.ts +2 -1
  17. package/dist/types/pickers/ChannelPicker.d.ts +5 -3
  18. package/dist/types/pickers/LatchPicker.d.ts +5 -3
  19. package/dist/types/pickers/MappingPicker.d.ts +2 -1
  20. package/dist/types/pickers/NotePicker.d.ts +2 -1
  21. package/dist/types/pickers/PolarityPicker.d.ts +6 -4
  22. package/dist/types/pickers/ResponseCurve.d.ts +14 -5
  23. package/dist/types/pickers/ResponseCurvePicker.d.ts +6 -4
  24. package/dist/types/pickers/StatusPicker.d.ts +2 -1
  25. package/dist/types/pickers/ValuePicker.d.ts +2 -1
  26. package/lib/@types/nebiru-react-rotary-knob.d.ts +20 -0
  27. package/lib/@types/react-svgmt.d.ts +74 -0
  28. package/lib/@types/zds-mappings.d.ts +55 -0
  29. package/lib/@types/zds-react-piano.d.ts +17 -0
  30. package/lib/hooks/useComponentSize.ts +52 -0
  31. package/lib/hooks/useStateWithDynamicDefault.ts +13 -0
  32. package/lib/main.ts +34 -0
  33. package/lib/midi/ccValues.ts +139 -0
  34. package/lib/midi/export.ts +54 -0
  35. package/lib/other/DefaultTooltip.ts +14 -0
  36. package/lib/other/OctavePlayer.tsx +141 -0
  37. package/lib/other/SVGText.tsx +221 -0
  38. package/lib/other/SoundFontProvider.tsx +130 -0
  39. package/lib/pickers/CCPicker.tsx +28 -0
  40. package/lib/pickers/ChannelMappingPicker.tsx +135 -0
  41. package/lib/pickers/ChannelPicker.tsx +76 -0
  42. package/lib/pickers/Knob.tsx +93 -0
  43. package/lib/pickers/KnobPicker.tsx +93 -0
  44. package/lib/pickers/LatchPicker.tsx +33 -0
  45. package/lib/pickers/MappingPicker.tsx +68 -0
  46. package/lib/pickers/NotePicker.tsx +95 -0
  47. package/lib/pickers/PianoPicker.tsx +77 -0
  48. package/lib/pickers/PolarityPicker.tsx +39 -0
  49. package/lib/pickers/ResponseCurve.tsx +304 -0
  50. package/lib/pickers/ResponseCurvePicker.tsx +74 -0
  51. package/lib/pickers/Select.tsx +248 -0
  52. package/lib/pickers/StatusPicker.tsx +28 -0
  53. package/lib/pickers/ValuePicker.tsx +67 -0
  54. package/lib/pickers/knobSkin10.tsx +94 -0
  55. package/lib/rotaryKnob/InternalInput.tsx +43 -0
  56. package/lib/rotaryKnob/Types.ts +6 -0
  57. package/lib/rotaryKnob/helpers/DrawCircle.tsx +41 -0
  58. package/lib/rotaryKnob/helpers/DrawLine.tsx +32 -0
  59. package/lib/rotaryKnob/helpers/HelpersOverlay.tsx +43 -0
  60. package/lib/rotaryKnob/helpers/KnobVisualHelpers.tsx +138 -0
  61. package/lib/rotaryKnob/index.tsx +417 -0
  62. package/lib/rotaryKnob/knobdefaultskin.ts +56 -0
  63. package/lib/rotaryKnob/utils.ts +112 -0
  64. package/lib/temp/acoustic_grand_piano-mp3.js +94 -0
  65. package/lib/utils.ts +41 -0
  66. package/package.json +2 -6
  67. package/stories/assets/sampleStyles.css +349 -0
  68. package/stories/assets/utils.js +7 -0
  69. package/stories/picker.stories.tsx +313 -0
  70. package/tsconfig.app.json +26 -0
  71. package/tsconfig.json +34 -0
  72. package/tsconfig.node.json +24 -0
  73. package/vite.config.ts +45 -0
  74. package/dist/index.d.ts +0 -244
@@ -0,0 +1,248 @@
1
+ import {
2
+ Children,
3
+ type JSX,
4
+ forwardRef,
5
+ isValidElement,
6
+ useCallback,
7
+ useMemo,
8
+ } from 'react'
9
+ import ReactSelect, {
10
+ type GroupBase,
11
+ type IndicatorsContainerProps,
12
+ components as originalComponents,
13
+ type PlaceholderProps,
14
+ type SelectInstance,
15
+ type SingleValue,
16
+ type StylesConfig,
17
+ type ValueContainerProps,
18
+ } from 'react-select'
19
+ import { omit } from '../utils'
20
+
21
+ const { IndicatorsContainer, Placeholder, ValueContainer } = originalComponents
22
+
23
+ type Option<T> = {
24
+ label: React.ReactNode
25
+ value: T
26
+ }
27
+
28
+ interface CustomIndicatorsContainerProps<T>
29
+ extends Omit<IndicatorsContainerProps<Option<T>, false>, 'selectProps'> {
30
+ children: React.ReactNode
31
+ selectProps: IndicatorsContainerProps<Option<T>, false>['selectProps'] & {
32
+ actionButton?: React.ReactNode
33
+ inputValue?: string
34
+ placeholder?: React.ReactNode
35
+ }
36
+ }
37
+
38
+ const CustomIndicatorsContainer = <T,>({
39
+ children,
40
+ ...rest
41
+ }: CustomIndicatorsContainerProps<T>) => {
42
+ const actionButton = rest.selectProps?.actionButton
43
+
44
+ return (
45
+ <IndicatorsContainer {...rest}>
46
+ <div
47
+ onMouseDown={e => {
48
+ e.stopPropagation()
49
+ e.preventDefault()
50
+ }}
51
+ style={{ display: 'flex' }}>
52
+ {actionButton}
53
+ {children}
54
+ </div>
55
+ </IndicatorsContainer>
56
+ )
57
+ }
58
+
59
+ type CustomValueContainerProps<T> = (
60
+ | ValueContainerProps<Option<T>, false>
61
+ | PlaceholderProps<Option<T>, false>
62
+ ) & {
63
+ children: React.ReactNode
64
+ hasValue?: boolean
65
+ isFocused?: boolean
66
+ }
67
+
68
+ const CustomValueContainer = <T,>({
69
+ children,
70
+ ...props
71
+ }: CustomValueContainerProps<T>) => (
72
+ <ValueContainer {...props}>
73
+ <Placeholder
74
+ {...props}
75
+ innerProps={props.innerProps || {}}
76
+ className={props.hasValue || props.selectProps.inputValue ? 'shrunk' : ''}
77
+ isFocused={props.isFocused ?? false}>
78
+ {props.selectProps.placeholder}
79
+ </Placeholder>
80
+ {Children.map(children, child =>
81
+ isValidElement(child) && child.type !== Placeholder ? child : null,
82
+ )}
83
+ </ValueContainer>
84
+ )
85
+
86
+ type SelectProps<T> = {
87
+ className?: string
88
+ components?: object
89
+ disabled?: boolean
90
+ filterOptions?: (candidate: Option<T>, inputValue: string) => boolean
91
+ formatOptionLabel?: (
92
+ option: Option<unknown>,
93
+ { context }: { context: 'menu' | 'value' },
94
+ ) => React.ReactNode
95
+ isSearchable?: boolean
96
+ label?: string
97
+ onChange: (value: Option<T>['value']) => void
98
+ options: Option<T>[] | { entries: Option<T>[] }[]
99
+ preserveMenuWidth?: boolean
100
+ shrinkLabel?: boolean
101
+ value: Option<T>['value']
102
+ }
103
+
104
+ const Select = forwardRef(
105
+ <T,>(
106
+ props: SelectProps<T>,
107
+ ref: React.ForwardedRef<
108
+ SelectInstance<Option<T>, false, GroupBase<Option<T>>>
109
+ >,
110
+ ) => {
111
+ const {
112
+ components,
113
+ disabled,
114
+ label,
115
+ onChange,
116
+ options = [],
117
+ preserveMenuWidth,
118
+ shrinkLabel,
119
+ value,
120
+ ...rest
121
+ } = props
122
+
123
+ const handleChange = useCallback(
124
+ (option: SingleValue<Option<unknown>>) => {
125
+ if (option) {
126
+ onChange((option as Option<T>).value)
127
+ }
128
+ },
129
+ [onChange],
130
+ )
131
+
132
+ const flatOptionsList = options.reduce<Option<T>[]>((acc, entry) => {
133
+ if ('entries' in entry) {
134
+ return acc.concat(entry.entries)
135
+ }
136
+ return acc.concat(entry)
137
+ }, [])
138
+
139
+ const selectedOption =
140
+ flatOptionsList.find(option => value === option.value) || undefined
141
+
142
+ const styles: unknown = useMemo(() => {
143
+ const base = preserveMenuWidth
144
+ ? {
145
+ menu: (base: Record<string, unknown>) => omit('width')(base),
146
+ menuList: (base: object) => ({
147
+ ...base,
148
+ overflowX: 'hidden',
149
+ }),
150
+ option: (base: object) => ({
151
+ ...base,
152
+ whiteSpace: 'nowrap',
153
+ paddingRight: 10,
154
+ }),
155
+ }
156
+ : {}
157
+
158
+ return shrinkLabel
159
+ ? {
160
+ ...base,
161
+ container: (provided: object /* , state */) => ({
162
+ ...provided,
163
+ marginTop: 10,
164
+ }),
165
+ placeholder: (
166
+ _provided: object,
167
+ state: PlaceholderProps<Option<T>, false>,
168
+ ) => ({
169
+ position: 'absolute',
170
+ left: state.hasValue || state.selectProps.inputValue ? -2 : '4%',
171
+ top: state.hasValue || state.selectProps.inputValue ? -12 : '50%',
172
+ transition: 'top 0.1s, font-size 0.1s, color 0.1s',
173
+ fontSize: (state.hasValue || state.selectProps.inputValue) && 13,
174
+ }),
175
+ valueContainer: (provided: object /* , state */) => ({
176
+ ...provided,
177
+ overflow: 'visible',
178
+ }),
179
+ }
180
+ : {
181
+ ...base,
182
+ }
183
+ }, [preserveMenuWidth, shrinkLabel])
184
+
185
+ return shrinkLabel ? (
186
+ <div className="zds-pickers__container">
187
+ <ReactSelect
188
+ {...rest}
189
+ classNamePrefix="zds-pickers"
190
+ components={{
191
+ IndicatorsContainer: CustomIndicatorsContainer,
192
+ ValueContainer: CustomValueContainer,
193
+ ...components,
194
+ }}
195
+ isDisabled={disabled}
196
+ onChange={handleChange}
197
+ options={flatOptionsList}
198
+ placeholder={label}
199
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
200
+ ref={ref as React.Ref<any>}
201
+ styles={
202
+ styles as StylesConfig<
203
+ Option<unknown>,
204
+ false,
205
+ GroupBase<Option<unknown>>
206
+ >
207
+ }
208
+ value={selectedOption}
209
+ />
210
+ </div>
211
+ ) : (
212
+ <div className="zds-pickers__container">
213
+ {Boolean(label) && <span className="zds-pickers__label">{label}</span>}
214
+ <ReactSelect
215
+ {...rest}
216
+ classNamePrefix="zds-pickers"
217
+ components={{
218
+ IndicatorsContainer: CustomIndicatorsContainer,
219
+ ...components,
220
+ }}
221
+ isDisabled={disabled}
222
+ onChange={handleChange}
223
+ options={flatOptionsList}
224
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
225
+ ref={ref as React.Ref<any>}
226
+ styles={
227
+ styles as StylesConfig<
228
+ Option<unknown>,
229
+ false,
230
+ GroupBase<Option<unknown>>
231
+ >
232
+ }
233
+ value={selectedOption}
234
+ />
235
+ </div>
236
+ )
237
+ },
238
+ ) as <T>(
239
+ props: SelectProps<T> & {
240
+ ref?: React.ForwardedRef<
241
+ SelectInstance<Option<T>, false, GroupBase<Option<T>>>
242
+ >
243
+ },
244
+ ) => JSX.Element
245
+
246
+ export default Select
247
+
248
+ export type { Option, SelectProps }
@@ -0,0 +1,28 @@
1
+ import type { Status } from 'lib/midi/export'
2
+ import { forwardRef } from 'react'
3
+ import type { GroupBase, SelectInstance } from 'react-select'
4
+ import Select from './Select'
5
+ import type { Option, SelectProps } from './Select'
6
+
7
+ type StatusPickerProps = SelectProps<Status> & { statuses: Option<Status>[] }
8
+
9
+ type StatusPickerRef = SelectInstance<
10
+ Option<Status>,
11
+ false,
12
+ GroupBase<Option<Status>>
13
+ >
14
+
15
+ const StatusPicker = forwardRef<
16
+ SelectInstance<Option<Status>, false, GroupBase<Option<Status>>>,
17
+ StatusPickerProps
18
+ >(({ statuses, ...rest }, ref) => (
19
+ <Select<Status>
20
+ {...rest}
21
+ options={statuses}
22
+ ref={ref}
23
+ />
24
+ ))
25
+
26
+ export default StatusPicker
27
+
28
+ export type { StatusPickerProps, StatusPickerRef }
@@ -0,0 +1,67 @@
1
+ import { forwardRef, useCallback, useMemo } from 'react'
2
+ import type { GroupBase, SelectInstance } from 'react-select'
3
+ import useStateWithDynamicDefault from '../hooks/useStateWithDynamicDefault'
4
+ import { arraySequence, assertRange } from '../utils'
5
+ import Select from './Select'
6
+ import type { Option, SelectProps } from './Select'
7
+
8
+ type ValuePickerProps = SelectProps<number> & {
9
+ highToLow?: boolean
10
+ max?: number
11
+ min?: number
12
+ }
13
+
14
+ type ValuePickerRef = SelectInstance<
15
+ Option<number>,
16
+ false,
17
+ GroupBase<Option<number>>
18
+ >
19
+
20
+ const ValuePicker = forwardRef<
21
+ SelectInstance<Option<number>, false, GroupBase<Option<number>>>,
22
+ ValuePickerProps
23
+ >((props, ref) => {
24
+ const {
25
+ disabled,
26
+ highToLow,
27
+ max = 127,
28
+ min = 0,
29
+ onChange,
30
+ value: initialValue = 0,
31
+ ...rest
32
+ } = props
33
+ const options = useMemo(() => {
34
+ const result = arraySequence(max - min + 1)
35
+ .map(i => min + i)
36
+ .map(value => ({ value, label: value }))
37
+ return (highToLow
38
+ ? result.reverse()
39
+ : result) as unknown as Option<number>[]
40
+ }, [highToLow, max, min])
41
+
42
+ const [value, setValue] = useStateWithDynamicDefault(initialValue)
43
+
44
+ const handleChange = useCallback(
45
+ (v: number | string) => {
46
+ onChange(assertRange(v, max, min))
47
+
48
+ setValue(Number.parseInt(String(v), 10))
49
+ },
50
+ [max, min, onChange, setValue],
51
+ )
52
+
53
+ return (
54
+ <Select
55
+ {...rest}
56
+ disabled={disabled}
57
+ onChange={handleChange}
58
+ options={options}
59
+ ref={ref}
60
+ value={value}
61
+ />
62
+ )
63
+ })
64
+
65
+ export default ValuePicker
66
+
67
+ export type { ValuePickerProps, ValuePickerRef }
@@ -0,0 +1,94 @@
1
+ const knobSkin10 = {
2
+ knobX: 71.44,
3
+ knobY: 71.44,
4
+ svg: `
5
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="207px" height="207px" viewBox="0 0 207 207" version="1.1">
6
+ <!-- Generator: Sketch 47.1 (45422) - http://www.bohemiancoding.com/sketch -->
7
+ <desc>Created with Sketch.</desc>
8
+ <defs>
9
+ <linearGradient x1="50%" y1="50%" x2="50%" y2="100%" id="27c61b0f-392f-962d-de12-cb9da898274b">
10
+ <stop stop-color="#444040" stop-opacity="0.51098279" offset="0%"/>
11
+ <stop stop-color="#131111" stop-opacity="0.893200861" offset="100%"/>
12
+ </linearGradient>
13
+ <circle id="e966567b-3869-4bcd-76b6-2cf084e45390" cx="100.497487" cy="100.497487" r="99.4974874"/>
14
+ <filter x="-3.3%" y="-3.3%" width="106.5%" height="106.5%" filterUnits="objectBoundingBox" id="e2e6829f-0086-96b2-e92a-6f3809b8ac61">
15
+ <feMorphology radius="0.5" operator="dilate" in="SourceAlpha" result="shadowSpreadOuter1"/>
16
+ <feOffset dx="0" dy="0" in="shadowSpreadOuter1" result="shadowOffsetOuter1"/>
17
+ <feGaussianBlur stdDeviation="2" in="shadowOffsetOuter1" result="shadowBlurOuter1"/>
18
+ <feComposite in="shadowBlurOuter1" in2="SourceAlpha" operator="out" result="shadowBlurOuter1"/>
19
+ <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" type="matrix" in="shadowBlurOuter1"/>
20
+ </filter>
21
+ <linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="0facd5c9-8e04-e83f-4842-8ba16f949942">
22
+ <stop stop-color="#FFFFFF" stop-opacity="0.5" offset="0%"/>
23
+ <stop stop-color="#000000" stop-opacity="0.5" offset="100%"/>
24
+ </linearGradient>
25
+ <circle id="c54189ed-7ea3-956c-f040-f0207548b268" cx="100.432161" cy="100.432161" r="86.4321608"/>
26
+ <filter x="-4.0%" y="-3.5%" width="108.1%" height="108.1%" filterUnits="objectBoundingBox" id="dedf2e7e-f008-c315-f682-e424d670f210">
27
+ <feMorphology radius="0.5" operator="dilate" in="SourceAlpha" result="shadowSpreadOuter1"/>
28
+ <feOffset dx="0" dy="1" in="shadowSpreadOuter1" result="shadowOffsetOuter1"/>
29
+ <feGaussianBlur stdDeviation="2" in="shadowOffsetOuter1" result="shadowBlurOuter1"/>
30
+ <feComposite in="shadowBlurOuter1" in2="SourceAlpha" operator="out" result="shadowBlurOuter1"/>
31
+ <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" type="matrix" in="shadowBlurOuter1"/>
32
+ </filter>
33
+
34
+ <filter x="-5.3%" y="-11.3%" width="110.7%" height="122.6%" filterUnits="objectBoundingBox" id="12f618f7-e258-b597-3ed6-242484ddad8f">
35
+ <feOffset dx="0" dy="0" in="SourceAlpha" result="shadowOffsetOuter1"/>
36
+ <feGaussianBlur stdDeviation="2" in="shadowOffsetOuter1" result="shadowBlurOuter1"/>
37
+ <feColorMatrix values="0 0 0 0 0.915577168 0 0 0 0 0.797591325 0 0 0 0 0.601479722 0 0 0 1 0" type="matrix" in="shadowBlurOuter1"/>
38
+ </filter>
39
+ <pattern id="3cc0e5b8-1f0a-886b-f635-8fcb19212870" width="8.04411765" height="8.04411765" x="21.9558824" y="21.9558824" patternUnits="userSpaceOnUse">
40
+ <use xlink:href="#2b8719c1-286b-ebf8-a488-ac66a6598fc5" transform="scale(0.167585784,0.167585784)"/>
41
+ </pattern>
42
+ <image id="2b8719c1-286b-ebf8-a488-ac66a6598fc5" width="48" height="48" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAEGWlDQ1BrQ0dDb2xvclNwYWNlR2VuZXJpY1JHQgAAOI2NVV1oHFUUPrtzZyMkzlNsNIV0qD8NJQ2TVjShtLp/3d02bpZJNtoi6GT27s6Yyc44M7v9oU9FUHwx6psUxL+3gCAo9Q/bPrQvlQol2tQgKD60+INQ6Ium65k7M5lpurHeZe58853vnnvuuWfvBei5qliWkRQBFpquLRcy4nOHj4g9K5CEh6AXBqFXUR0rXalMAjZPC3e1W99Dwntf2dXd/p+tt0YdFSBxH2Kz5qgLiI8B8KdVy3YBevqRHz/qWh72Yui3MUDEL3q44WPXw3M+fo1pZuQs4tOIBVVTaoiXEI/MxfhGDPsxsNZfoE1q66ro5aJim3XdoLFw72H+n23BaIXzbcOnz5mfPoTvYVz7KzUl5+FRxEuqkp9G/Ajia219thzg25abkRE/BpDc3pqvphHvRFys2weqvp+krbWKIX7nhDbzLOItiM8358pTwdirqpPFnMF2xLc1WvLyOwTAibpbmvHHcvttU57y5+XqNZrLe3lE/Pq8eUj2fXKfOe3pfOjzhJYtB/yll5SDFcSDiH+hRkH25+L+sdxKEAMZahrlSX8ukqMOWy/jXW2m6M9LDBc31B9LFuv6gVKg/0Szi3KAr1kGq1GMjU/aLbnq6/lRxc4XfJ98hTargX++DbMJBSiYMIe9Ck1YAxFkKEAG3xbYaKmDDgYyFK0UGYpfoWYXG+fAPPI6tJnNwb7ClP7IyF+D+bjOtCpkhz6CFrIa/I6sFtNl8auFXGMTP34sNwI/JhkgEtmDz14ySfaRcTIBInmKPE32kxyyE2Tv+thKbEVePDfW/byMM1Kmm0XdObS7oGD/MypMXFPXrCwOtoYjyyn7BV29/MZfsVzpLDdRtuIZnbpXzvlf+ev8MvYr/Gqk4H/kV/G3csdazLuyTMPsbFhzd1UabQbjFvDRmcWJxR3zcfHkVw9GfpbJmeev9F08WW8uDkaslwX6avlWGU6NRKz0g/SHtCy9J30o/ca9zX3Kfc19zn3BXQKRO8ud477hLnAfc1/G9mrzGlrfexZ5GLdn6ZZrrEohI2wVHhZywjbhUWEy8icMCGNCUdiBlq3r+xafL549HQ5jH+an+1y+LlYBifuxAvRN/lVVVOlwlCkdVm9NOL5BE4wkQ2SMlDZU97hX86EilU/lUmkQUztTE6mx1EEPh7OmdqBtAvv8HdWpbrJS6tJj3n0CWdM6busNzRV3S9KTYhqvNiqWmuroiKgYhshMjmhTh9ptWhsF7970j/SbMrsPE1suR5z7DMC+P/Hs+y7ijrQAlhyAgccjbhjPygfeBTjzhNqy28EdkUh8C+DU9+z2v/oyeH791OncxHOs5y2AtTc7nb/f73TWPkD/qwBnjX8BoJ98VQNcC+8AAAFFSURBVGgF7djbDYMwDAXQBjEMYqyqY1WMxTppLiJIQIA8ariWkp8IPuweO60am67r7MstY8wwjuPH7dMz3uUua63p+/7r9rePIRW/9QmQzCV9ub0YgSIgzhxvQkjFb1EZBAdEKolkfJTqtnb7bv/zOJm58moRE0AzYgFoRawAGhE7gDZEEKAJcQjQgjgFaEBcAtgRUQBmRDSAFZEEYEQkA9gQWQAmRDaABVEEYEAUAx5H4EaGOyw+SMl66mbXzNOD4k6gCPNUY/CFwF1YOn5zRxJJRINqaUbUuZA/79sd3wm3xIdbdS60rXzo2XVCbO60/HxKJgFKKv4CkEziuyKBWAE0InYAbYggQBPiEKAFcQrQgLgEsCOiAMyIaAArIgnAiEgGsCGyAEyIbAALogjAgCgGPI7AX9w6F3JtqHMhnMWLFSrSD9jOnakVHpZYAAAAAElFTkSuQmCC"/>
43
+ </defs>
44
+ <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
45
+ <g id="s10" transform="translate(3.000000, 3.000000)">
46
+ <g id="container">
47
+ <g id="Oval-2">
48
+ <use fill="black" fill-opacity="1" filter="url(#e2e6829f-0086-96b2-e92a-6f3809b8ac61)" xlink:href="#e966567b-3869-4bcd-76b6-2cf084e45390"/>
49
+ <use stroke="#979797" stroke-width="1" fill="url(#27c61b0f-392f-962d-de12-cb9da898274b)" fill-rule="evenodd" xlink:href="#e966567b-3869-4bcd-76b6-2cf084e45390"/>
50
+ </g>
51
+ <g id="Oval-2">
52
+ <use fill="black" fill-opacity="1" filter="url(#dedf2e7e-f008-c315-f682-e424d670f210)" xlink:href="#c54189ed-7ea3-956c-f040-f0207548b268"/>
53
+ <use fill="" fill-rule="evenodd" xlink:href="#c54189ed-7ea3-956c-f040-f0207548b268"/>
54
+ <use stroke="#4A4A4A" stroke-width="1" fill="url(#0facd5c9-8e04-e83f-4842-8ba16f949942)" fill-rule="evenodd" xlink:href="#c54189ed-7ea3-956c-f040-f0207548b268"/>
55
+ </g>
56
+ <g id="knob" transform="translate(28.574244, 28.574244)">
57
+ <circle id="Oval-5" fill="#322E2E" cx="71.4356094" cy="71.4356094" r="71.4356094"/>
58
+ <path d="M72.4209282,3.63066376 L88.6786876,16.869789 C81.585496,18.1548295 76.1662428,18.7973498 72.4209282,18.7973498 C68.6756135,18.7973498 63.2563604,18.1548295 56.1631688,16.869789 L72.4209282,3.63066376 Z" id="Rectangle" fill="#E6D7D7" transform="translate(72.420928, 11.214007) scale(1, -1) translate(-72.420928, -11.214007) "/>
59
+ </g>
60
+ <g id="label">
61
+ <g id="labeltext" fill-opacity="1" fill="#E6D7D7">
62
+ <text id="534f4e02-5541-3607-0966-af0b025d80e0" font-family="Helvetica" font-size="44" font-weight="normal" fill="#E6D7D7" class="text-7" filter="url(#12f618f7-e258-b597-3ed6-242484ddad8f)">
63
+ <tspan x="45.3246625" y="117.884225">10.10</tspan>
64
+ </text>
65
+ <text id="92ebe866-c281-70c7-7b0e-a373cee013a9" font-family="Helvetica" font-size="44" font-weight="normal" fill="#E6D7D7" class="text-7">
66
+ <tspan x="45.3246625" y="117.884225">10.10</tspan>
67
+ </text>
68
+ </g>
69
+ <circle id="Oval-6" stroke="#979797" fill-opacity="0.730000019" fill="url(#3cc0e5b8-1f0a-886b-f635-8fcb19212870)" transform="translate(100.351759, 100.351759) rotate(-45.000000) translate(-100.351759, -100.351759) " cx="100.351759" cy="100.351759" r="70.3517588"/>
70
+ </g>
71
+ </g>
72
+ </g>
73
+ </g>
74
+ </svg>
75
+ `,
76
+ updateAttributes: [
77
+ {
78
+ element: '#labeltext text tspan',
79
+ content: (_props: React.CSSProperties, value: number) => value.toFixed(0),
80
+ attrs: [
81
+ {
82
+ name: 'text-anchor',
83
+ value: (/* props, value */) => 'middle',
84
+ },
85
+ {
86
+ name: 'x',
87
+ value: (/* props, value */) => '100',
88
+ },
89
+ ],
90
+ },
91
+ ],
92
+ }
93
+
94
+ export default knobSkin10
@@ -0,0 +1,43 @@
1
+ import React from 'react'
2
+
3
+ type InternalInputProps = {
4
+ disabled?: boolean
5
+ min: number
6
+ max: number
7
+ value: number
8
+ step?: number
9
+ inputRef: React.RefObject<HTMLInputElement>
10
+ onChange: (val: number) => void
11
+ style?: React.CSSProperties
12
+ }
13
+
14
+ class InternalInput extends React.Component<InternalInputProps> {
15
+ static defaultProps = {
16
+ step: 1,
17
+ }
18
+ render() {
19
+ const props = this.props
20
+ const hideStyle = {}
21
+
22
+ function onValChange(event: React.ChangeEvent<HTMLInputElement>) {
23
+ props.onChange(Number(event.target.value))
24
+ }
25
+
26
+ const { value, min, max, step, onChange, inputRef, ...rest } = props
27
+ return (
28
+ <input
29
+ ref={inputRef}
30
+ value={value}
31
+ step={step}
32
+ onChange={onValChange}
33
+ style={hideStyle}
34
+ type="range"
35
+ min={min}
36
+ max={max}
37
+ {...rest}
38
+ />
39
+ )
40
+ }
41
+ }
42
+
43
+ export default InternalInput
@@ -0,0 +1,6 @@
1
+ type Point = {
2
+ x: number
3
+ y: number
4
+ }
5
+
6
+ export type { Point }
@@ -0,0 +1,41 @@
1
+ import React from 'react'
2
+
3
+ /**
4
+ * Draws a circle with radius = r
5
+ * position must be handled by parent
6
+ */
7
+
8
+ type DrawCircleProps = React.SVGProps<SVGCircleElement> & {
9
+ r: number
10
+ borderColor?: string
11
+ fillColor?: string
12
+ borderWidth?: number
13
+ fillOpacity: number
14
+ cx: number
15
+ cy: number
16
+ }
17
+
18
+ class DrawCircle extends React.Component<DrawCircleProps> {
19
+ render() {
20
+ const {
21
+ r,
22
+ borderColor = 'black',
23
+ fillColor = 'transparent',
24
+ borderWidth = 2,
25
+ fillOpacity = 1,
26
+ ...rest
27
+ } = this.props
28
+
29
+ return (
30
+ <circle
31
+ stroke={borderColor}
32
+ fill={fillColor}
33
+ fillOpacity={fillOpacity}
34
+ r={r}
35
+ {...rest}
36
+ />
37
+ )
38
+ }
39
+ }
40
+
41
+ export default DrawCircle
@@ -0,0 +1,32 @@
1
+ import React from 'react'
2
+ import type { Point } from '../Types'
3
+
4
+ /**
5
+ * Draws a line from p1 to p2
6
+ */
7
+
8
+ type DrawLineProps = React.SVGProps<SVGLineElement> & {
9
+ width?: number
10
+ color?: string
11
+ p1: Point
12
+ p2: Point
13
+ }
14
+
15
+ class DrawLine extends React.Component<DrawLineProps> {
16
+ render() {
17
+ const { width = 2, color = 'black', p1, p2, ...rest } = this.props
18
+ return (
19
+ <line
20
+ {...rest}
21
+ stroke={color}
22
+ strokeWidth={width}
23
+ x1={p1.x}
24
+ y1={p1.y}
25
+ x2={p2.x}
26
+ y2={p2.y}
27
+ />
28
+ )
29
+ }
30
+ }
31
+
32
+ export default DrawLine
@@ -0,0 +1,43 @@
1
+ import React from 'react'
2
+ import ReactDOM from 'react-dom'
3
+
4
+ type HelpersOverlayProps = React.PropsWithChildren & {
5
+ overlayStyle?: React.CSSProperties
6
+ }
7
+
8
+ /**
9
+ * Draws the overlay and the children
10
+ */
11
+ class HelpersOverlay extends React.Component<HelpersOverlayProps> {
12
+ render() {
13
+ const { children, ...rest } = this.props
14
+
15
+ const styles = {
16
+ overlay: Object.assign(
17
+ {
18
+ width: '100%',
19
+ height: '100vh',
20
+ top: 0,
21
+ left: 0,
22
+ zIndex: 2147483647,
23
+ margin: '0',
24
+ padding: '0',
25
+ boxSizing: 'border-box',
26
+ position: 'fixed',
27
+ },
28
+ this.props.overlayStyle,
29
+ ),
30
+ }
31
+
32
+ return ReactDOM.createPortal(
33
+ <div
34
+ style={styles.overlay}
35
+ {...rest}>
36
+ {children}
37
+ </div>,
38
+ document.body,
39
+ )
40
+ }
41
+ }
42
+
43
+ export default HelpersOverlay