@tamagui/slider 1.0.1-beta.94 → 1.0.1-beta.97
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/dist/cjs/Slider.js +43 -39
- package/dist/cjs/Slider.js.map +2 -2
- package/dist/cjs/SliderImpl.js +2 -4
- package/dist/cjs/SliderImpl.js.map +2 -2
- package/dist/cjs/constants.js +0 -0
- package/dist/cjs/constants.js.map +0 -0
- package/dist/cjs/helpers.js +0 -0
- package/dist/cjs/helpers.js.map +2 -2
- package/dist/cjs/index.js +0 -0
- package/dist/cjs/index.js.map +0 -0
- package/dist/cjs/types.js +0 -0
- package/dist/cjs/types.js.map +1 -1
- package/dist/esm/Slider.js +51 -41
- package/dist/esm/Slider.js.map +2 -2
- package/dist/esm/SliderImpl.js +2 -4
- package/dist/esm/SliderImpl.js.map +2 -2
- package/dist/esm/constants.js +0 -0
- package/dist/esm/constants.js.map +0 -0
- package/dist/esm/helpers.js +0 -0
- package/dist/esm/helpers.js.map +2 -2
- package/dist/esm/index.js +0 -0
- package/dist/esm/index.js.map +0 -0
- package/dist/esm/types.js +0 -0
- package/dist/esm/types.js.map +0 -0
- package/dist/jsx/Slider.js +47 -37
- package/dist/jsx/Slider.js.map +2 -2
- package/dist/jsx/SliderImpl.js +3 -4
- package/dist/jsx/SliderImpl.js.map +2 -2
- package/dist/jsx/constants.js +0 -0
- package/dist/jsx/constants.js.map +0 -0
- package/dist/jsx/helpers.js +0 -0
- package/dist/jsx/helpers.js.map +2 -2
- package/dist/jsx/index.js +0 -0
- package/dist/jsx/index.js.map +0 -0
- package/dist/jsx/types.js +0 -0
- package/dist/jsx/types.js.map +0 -0
- package/package.json +8 -8
- package/src/Slider.tsx +69 -66
- package/src/SliderImpl.tsx +6 -6
- package/src/helpers.tsx +0 -2
- package/src/types.ts +0 -3
- package/types/Slider.d.ts +177 -38
- package/types/Slider.d.ts.map +1 -1
- package/types/SliderImpl.d.ts +3 -2
- package/types/SliderImpl.d.ts.map +1 -1
- package/types/constants.d.ts +0 -1
- package/types/constants.d.ts.map +1 -1
- package/types/helpers.d.ts +0 -0
- package/types/helpers.d.ts.map +1 -1
- package/types/index.d.ts +0 -0
- package/types/index.d.ts.map +0 -0
- package/types/types.d.ts +0 -2
- package/types/types.d.ts.map +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/SliderImpl.tsx"],
|
|
4
|
-
"sourcesContent": ["/* -------------------------------------------------------------------------------------------------\n * SliderImpl\n * -----------------------------------------------------------------------------------------------*/\n\nimport { composeEventHandlers, getSize, getVariableValue, isWeb, styled } from '@tamagui/core'\nimport { YStack } from '@tamagui/stacks'\nimport * as React from 'react'\n\nimport { ARROW_KEYS, PAGE_KEYS, SLIDER_NAME, useSliderContext } from './constants'\nimport { ScopedProps,
|
|
5
|
-
"mappings": "AAIA;AACA;AACA;
|
|
4
|
+
"sourcesContent": ["/* -------------------------------------------------------------------------------------------------\n * SliderImpl\n * -----------------------------------------------------------------------------------------------*/\n\nimport { composeEventHandlers, getSize, getVariableValue, isWeb, styled } from '@tamagui/core'\nimport { YStack } from '@tamagui/stacks'\nimport * as React from 'react'\nimport { View } from 'react-native'\n\nimport { ARROW_KEYS, PAGE_KEYS, SLIDER_NAME, useSliderContext } from './constants'\nimport { ScopedProps, SliderImplProps } from './types'\n\nexport const DirectionalYStack = styled(YStack, {\n variants: {\n orientation: {\n horizontal: {},\n vertical: {},\n },\n },\n})\n\nexport const SliderFrame = styled(DirectionalYStack, {\n position: 'relative',\n\n variants: {\n size: (val, extras) => {\n const orientation = extras.props.orientation\n const size = Math.round(getVariableValue(getSize(val)) / 6)\n if (orientation === 'horizontal') {\n return {\n height: size,\n borderRadius: size,\n justifyContent: 'center',\n }\n }\n return {\n width: size,\n borderRadius: size,\n alignItems: 'center',\n }\n },\n },\n})\n\nexport const SliderImpl = React.forwardRef<View, SliderImplProps>(\n (props: ScopedProps<SliderImplProps>, forwardedRef) => {\n const {\n __scopeSlider,\n onSlideStart,\n onSlideMove,\n onSlideEnd,\n onHomeKeyDown,\n onEndKeyDown,\n onStepKeyDown,\n ...sliderProps\n } = props\n const context = useSliderContext(SLIDER_NAME, __scopeSlider)\n return (\n <SliderFrame\n size=\"$4\"\n {...sliderProps}\n data-orientation={sliderProps.orientation}\n ref={forwardedRef}\n {...(isWeb && {\n onKeyDown: (event) => {\n if (event.key === 'Home') {\n onHomeKeyDown(event)\n // Prevent scrolling to page start\n event.preventDefault()\n } else if (event.key === 'End') {\n onEndKeyDown(event)\n // Prevent scrolling to page end\n event.preventDefault()\n } else if (PAGE_KEYS.concat(ARROW_KEYS).includes(event.key)) {\n onStepKeyDown(event)\n // Prevent scrolling for directional key presses\n event.preventDefault()\n }\n },\n })}\n onMoveShouldSetResponderCapture={() => true}\n onScrollShouldSetResponder={() => true}\n onScrollShouldSetResponderCapture={() => true}\n onMoveShouldSetResponder={() => true}\n onStartShouldSetResponder={() => true}\n // onStartShouldSetResponderCapture={() => true}\n onResponderTerminationRequest={() => {\n return false\n }}\n onResponderGrant={composeEventHandlers(props.onResponderGrant, (event) => {\n const target = event.target as HTMLElement | number\n console.log('target', target, context.thumbs.has(target), context.thumbs)\n const isStartingOnThumb = context.thumbs.has(target)\n // // Prevent browser focus behaviour because we focus a thumb manually when values change.\n // Touch devices have a delay before focusing so won't focus if touch immediately moves\n // away from target (sliding). We want thumb to focus regardless.\n if (isWeb && target instanceof HTMLElement) {\n if (context.thumbs.has(target)) {\n target.focus()\n }\n }\n onSlideStart(event, isStartingOnThumb ? 'thumb' : 'track')\n })}\n onResponderMove={composeEventHandlers(props.onResponderMove, (event) => {\n event.preventDefault()\n event.stopPropagation()\n\n // const target = event.target as HTMLElement\n onSlideMove(event)\n })}\n onResponderRelease={composeEventHandlers(props.onResponderRelease, (event) => {\n // const target = event.target as HTMLElement\n onSlideEnd(event)\n })}\n />\n )\n }\n)\n"],
|
|
5
|
+
"mappings": "AAIA;AACA;AACA;AAGA;AAGO,MAAM,oBAAoB,OAAO,QAAQ;AAAA,EAC9C,UAAU;AAAA,IACR,aAAa;AAAA,MACX,YAAY,CAAC;AAAA,MACb,UAAU,CAAC;AAAA,IACb;AAAA,EACF;AACF,CAAC;AAEM,MAAM,cAAc,OAAO,mBAAmB;AAAA,EACnD,UAAU;AAAA,EAEV,UAAU;AAAA,IACR,MAAM,CAAC,KAAK,WAAW;AACrB,YAAM,cAAc,OAAO,MAAM;AACjC,YAAM,OAAO,KAAK,MAAM,iBAAiB,QAAQ,GAAG,CAAC,IAAI,CAAC;AAC1D,UAAI,gBAAgB,cAAc;AAChC,eAAO;AAAA,UACL,QAAQ;AAAA,UACR,cAAc;AAAA,UACd,gBAAgB;AAAA,QAClB;AAAA,MACF;AACA,aAAO;AAAA,QACL,OAAO;AAAA,QACP,cAAc;AAAA,QACd,YAAY;AAAA,MACd;AAAA,IACF;AAAA,EACF;AACF,CAAC;AAEM,MAAM,aAAa,MAAM,WAC9B,CAAC,OAAqC,iBAAiB;AACrD,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,OACG;AAAA,MACD;AACJ,QAAM,UAAU,iBAAiB,aAAa,aAAa;AAC3D,SACE,CAAC,YACC,KAAK,SACD,aACJ,kBAAkB,YAAY,aAC9B,KAAK,kBACA,SAAS;AAAA,IACZ,WAAW,CAAC,UAAU;AACpB,UAAI,MAAM,QAAQ,QAAQ;AACxB,sBAAc,KAAK;AAEnB,cAAM,eAAe;AAAA,MACvB,WAAW,MAAM,QAAQ,OAAO;AAC9B,qBAAa,KAAK;AAElB,cAAM,eAAe;AAAA,MACvB,WAAW,UAAU,OAAO,UAAU,EAAE,SAAS,MAAM,GAAG,GAAG;AAC3D,sBAAc,KAAK;AAEnB,cAAM,eAAe;AAAA,MACvB;AAAA,IACF;AAAA,EACF,GACA,iCAAiC,MAAM,MACvC,4BAA4B,MAAM,MAClC,mCAAmC,MAAM,MACzC,0BAA0B,MAAM,MAChC,2BAA2B,MAAM,MAEjC,+BAA+B,MAAM;AACnC,WAAO;AAAA,EACT,GACA,kBAAkB,qBAAqB,MAAM,kBAAkB,CAAC,UAAU;AACxE,UAAM,SAAS,MAAM;AACrB,YAAQ,IAAI,UAAU,QAAQ,QAAQ,OAAO,IAAI,MAAM,GAAG,QAAQ,MAAM;AACxE,UAAM,oBAAoB,QAAQ,OAAO,IAAI,MAAM;AAInD,QAAI,SAAS,kBAAkB,aAAa;AAC1C,UAAI,QAAQ,OAAO,IAAI,MAAM,GAAG;AAC9B,eAAO,MAAM;AAAA,MACf;AAAA,IACF;AACA,iBAAa,OAAO,oBAAoB,UAAU,OAAO;AAAA,EAC3D,CAAC,GACD,iBAAiB,qBAAqB,MAAM,iBAAiB,CAAC,UAAU;AACtE,UAAM,eAAe;AACrB,UAAM,gBAAgB;AAGtB,gBAAY,KAAK;AAAA,EACnB,CAAC,GACD,oBAAoB,qBAAqB,MAAM,oBAAoB,CAAC,UAAU;AAE5E,eAAW,KAAK;AAAA,EAClB,CAAC,GACH;AAEJ,CACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/jsx/constants.js
CHANGED
|
File without changes
|
|
File without changes
|
package/dist/jsx/helpers.js
CHANGED
|
File without changes
|
package/dist/jsx/helpers.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/helpers.tsx"],
|
|
4
|
-
"sourcesContent": ["
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["export function getNextSortedValues(prevValues: number[] = [], nextValue: number, atIndex: number) {\n const nextValues = [...prevValues]\n nextValues[atIndex] = nextValue\n return nextValues.sort((a, b) => a - b)\n}\n\nexport function convertValueToPercentage(value: number, min: number, max: number) {\n const maxSteps = max - min\n const percentPerStep = 100 / maxSteps\n return percentPerStep * (value - min)\n}\n\n/**\n * Returns a label for each thumb when there are two or more thumbs\n */\nexport function getLabel(index: number, totalValues: number) {\n if (totalValues > 2) {\n return `Value ${index + 1} of ${totalValues}`\n } else if (totalValues === 2) {\n return ['Minimum', 'Maximum'][index]\n } else {\n return undefined\n }\n}\n\n/**\n * Given a `values` array and a `nextValue`, determine which value in\n * the array is closest to `nextValue` and return its index.\n *\n * @example\n * // returns 1\n * getClosestValueIndex([10, 30], 25);\n */\nexport function getClosestValueIndex(values: number[], nextValue: number) {\n if (values.length === 1) return 0\n const distances = values.map((value) => Math.abs(value - nextValue))\n const closestDistance = Math.min(...distances)\n return distances.indexOf(closestDistance)\n}\n\n/**\n * Offsets the thumb centre point while sliding to ensure it remains\n * within the bounds of the slider when reaching the edges\n */\nexport function getThumbInBoundsOffset(width: number, left: number, direction: number) {\n const halfWidth = width / 2\n const halfPercent = 50\n const offset = linearScale([0, halfPercent], [0, halfWidth])\n return (halfWidth - offset(left) * direction) * direction\n}\n\n/**\n * Gets an array of steps between each value.\n *\n * @example\n * // returns [1, 9]\n * getStepsBetweenValues([10, 11, 20]);\n */\nfunction getStepsBetweenValues(values: number[]) {\n return values.slice(0, -1).map((value, index) => values[index + 1] - value)\n}\n\n/**\n * Verifies the minimum steps between all values is greater than or equal\n * to the expected minimum steps.\n *\n * @example\n * // returns false\n * hasMinStepsBetweenValues([1,2,3], 2);\n *\n * @example\n * // returns true\n * hasMinStepsBetweenValues([1,2,3], 1);\n */\nexport function hasMinStepsBetweenValues(values: number[], minStepsBetweenValues: number) {\n if (minStepsBetweenValues > 0) {\n const stepsBetweenValues = getStepsBetweenValues(values)\n const actualMinStepsBetweenValues = Math.min(...stepsBetweenValues)\n return actualMinStepsBetweenValues >= minStepsBetweenValues\n }\n return true\n}\n\n// https://github.com/tmcw-up-for-adoption/simple-linear-scale/blob/master/index.js\nexport function linearScale(input: readonly [number, number], output: readonly [number, number]) {\n return (value: number) => {\n if (input[0] === input[1] || output[0] === output[1]) return output[0]\n const ratio = (output[1] - output[0]) / (input[1] - input[0])\n return output[0] + ratio * (value - input[0])\n }\n}\n\nexport function getDecimalCount(value: number) {\n return (String(value).split('.')[1] || '').length\n}\n\nexport function roundValue(value: number, decimalCount: number) {\n const rounder = Math.pow(10, decimalCount)\n return Math.round(value * rounder) / rounder\n}\n"],
|
|
5
|
+
"mappings": "AAAO,6BAA6B,aAAuB,CAAC,GAAG,WAAmB,SAAiB;AACjG,QAAM,aAAa,CAAC,GAAG,UAAU;AACjC,aAAW,WAAW;AACtB,SAAO,WAAW,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC;AACxC;AAEO,kCAAkC,OAAe,KAAa,KAAa;AAChF,QAAM,WAAW,MAAM;AACvB,QAAM,iBAAiB,MAAM;AAC7B,SAAO,iBAAkB,SAAQ;AACnC;AAKO,kBAAkB,OAAe,aAAqB;AAC3D,MAAI,cAAc,GAAG;AACnB,WAAO,SAAS,QAAQ,QAAQ;AAAA,EAClC,WAAW,gBAAgB,GAAG;AAC5B,WAAO,CAAC,WAAW,SAAS,EAAE;AAAA,EAChC,OAAO;AACL,WAAO;AAAA,EACT;AACF;AAUO,8BAA8B,QAAkB,WAAmB;AACxE,MAAI,OAAO,WAAW;AAAG,WAAO;AAChC,QAAM,YAAY,OAAO,IAAI,CAAC,UAAU,KAAK,IAAI,QAAQ,SAAS,CAAC;AACnE,QAAM,kBAAkB,KAAK,IAAI,GAAG,SAAS;AAC7C,SAAO,UAAU,QAAQ,eAAe;AAC1C;AAMO,gCAAgC,OAAe,MAAc,WAAmB;AACrF,QAAM,YAAY,QAAQ;AAC1B,QAAM,cAAc;AACpB,QAAM,SAAS,YAAY,CAAC,GAAG,WAAW,GAAG,CAAC,GAAG,SAAS,CAAC;AAC3D,SAAQ,aAAY,OAAO,IAAI,IAAI,aAAa;AAClD;AASA,+BAA+B,QAAkB;AAC/C,SAAO,OAAO,MAAM,GAAG,EAAE,EAAE,IAAI,CAAC,OAAO,UAAU,OAAO,QAAQ,KAAK,KAAK;AAC5E;AAcO,kCAAkC,QAAkB,uBAA+B;AACxF,MAAI,wBAAwB,GAAG;AAC7B,UAAM,qBAAqB,sBAAsB,MAAM;AACvD,UAAM,8BAA8B,KAAK,IAAI,GAAG,kBAAkB;AAClE,WAAO,+BAA+B;AAAA,EACxC;AACA,SAAO;AACT;AAGO,qBAAqB,OAAkC,QAAmC;AAC/F,SAAO,CAAC,UAAkB;AACxB,QAAI,MAAM,OAAO,MAAM,MAAM,OAAO,OAAO,OAAO;AAAI,aAAO,OAAO;AACpE,UAAM,QAAS,QAAO,KAAK,OAAO,MAAO,OAAM,KAAK,MAAM;AAC1D,WAAO,OAAO,KAAK,QAAS,SAAQ,MAAM;AAAA,EAC5C;AACF;AAEO,yBAAyB,OAAe;AAC7C,SAAQ,QAAO,KAAK,EAAE,MAAM,GAAG,EAAE,MAAM,IAAI;AAC7C;AAEO,oBAAoB,OAAe,cAAsB;AAC9D,QAAM,UAAU,KAAK,IAAI,IAAI,YAAY;AACzC,SAAO,KAAK,MAAM,QAAQ,OAAO,IAAI;AACvC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/jsx/index.js
CHANGED
|
File without changes
|
package/dist/jsx/index.js.map
CHANGED
|
File without changes
|
package/dist/jsx/types.js
CHANGED
|
File without changes
|
package/dist/jsx/types.js.map
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tamagui/slider",
|
|
3
|
-
"version": "1.0.1-beta.
|
|
3
|
+
"version": "1.0.1-beta.97",
|
|
4
4
|
"sideEffects": [
|
|
5
5
|
"*.css"
|
|
6
6
|
],
|
|
@@ -21,12 +21,12 @@
|
|
|
21
21
|
"clean:build": "tamagui-build clean:build"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@tamagui/compose-refs": "^1.0.1-beta.
|
|
25
|
-
"@tamagui/core": "^1.0.1-beta.
|
|
26
|
-
"@tamagui/create-context": "^1.0.1-beta.
|
|
27
|
-
"@tamagui/stacks": "^1.0.1-beta.
|
|
28
|
-
"@tamagui/use-controllable-state": "^1.0.1-beta.
|
|
29
|
-
"@tamagui/use-direction": "^1.0.1-beta.
|
|
24
|
+
"@tamagui/compose-refs": "^1.0.1-beta.97",
|
|
25
|
+
"@tamagui/core": "^1.0.1-beta.97",
|
|
26
|
+
"@tamagui/create-context": "^1.0.1-beta.97",
|
|
27
|
+
"@tamagui/stacks": "^1.0.1-beta.97",
|
|
28
|
+
"@tamagui/use-controllable-state": "^1.0.1-beta.97",
|
|
29
|
+
"@tamagui/use-direction": "^1.0.1-beta.97"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
32
|
"react": "*",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"react-native": "*"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@tamagui/build": "^1.0.1-beta.
|
|
37
|
+
"@tamagui/build": "^1.0.1-beta.97",
|
|
38
38
|
"@types/react-native": "^0.67.3",
|
|
39
39
|
"react": "*",
|
|
40
40
|
"react-dom": "*",
|
package/src/Slider.tsx
CHANGED
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
// forked from radix-ui
|
|
2
2
|
|
|
3
|
-
import { useComposedRefs } from '@tamagui/compose-refs'
|
|
4
|
-
import {
|
|
3
|
+
import { composeRefs, useComposedRefs } from '@tamagui/compose-refs'
|
|
4
|
+
import {
|
|
5
|
+
GetProps,
|
|
6
|
+
SizeTokens,
|
|
7
|
+
getSize,
|
|
8
|
+
getVariableValue,
|
|
9
|
+
isWeb,
|
|
10
|
+
styled,
|
|
11
|
+
withStaticProperties,
|
|
12
|
+
} from '@tamagui/core'
|
|
5
13
|
import { clamp, composeEventHandlers } from '@tamagui/helpers'
|
|
6
|
-
import { SizableStackProps, ThemeableStack
|
|
14
|
+
import { SizableStackProps, ThemeableStack } from '@tamagui/stacks'
|
|
7
15
|
import { useControllableState } from '@tamagui/use-controllable-state'
|
|
8
16
|
import { useDirection } from '@tamagui/use-direction'
|
|
9
17
|
import * as React from 'react'
|
|
10
|
-
import {
|
|
18
|
+
import { View } from 'react-native'
|
|
11
19
|
|
|
12
20
|
import {
|
|
13
21
|
ARROW_KEYS,
|
|
@@ -35,7 +43,6 @@ import {
|
|
|
35
43
|
ScopedProps,
|
|
36
44
|
SliderContextValue,
|
|
37
45
|
SliderHorizontalProps,
|
|
38
|
-
SliderImplElement,
|
|
39
46
|
SliderProps,
|
|
40
47
|
SliderTrackProps,
|
|
41
48
|
SliderVerticalProps,
|
|
@@ -45,20 +52,16 @@ import {
|
|
|
45
52
|
* SliderHorizontal
|
|
46
53
|
* -----------------------------------------------------------------------------------------------*/
|
|
47
54
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const SliderHorizontal = React.forwardRef<SliderHorizontalElement, SliderHorizontalProps>(
|
|
55
|
+
const SliderHorizontal = React.forwardRef<View, SliderHorizontalProps>(
|
|
51
56
|
(props: ScopedProps<SliderHorizontalProps>, forwardedRef) => {
|
|
52
57
|
const { min, max, dir, onSlideStart, onSlideMove, onStepKeyDown, ...sliderProps } = props
|
|
53
58
|
const direction = useDirection(dir)
|
|
54
59
|
const isDirectionLTR = direction === 'ltr'
|
|
55
|
-
const
|
|
56
|
-
const [
|
|
60
|
+
const sliderRef = React.useRef<View>(null)
|
|
61
|
+
const [state, setState] = React.useState(() => ({ size: 0, offset: 0 }))
|
|
57
62
|
|
|
58
63
|
function getValueFromPointer(pointerPosition: number) {
|
|
59
|
-
const
|
|
60
|
-
if (!layout) return
|
|
61
|
-
const input: [number, number] = [0, layout.width]
|
|
64
|
+
const input: [number, number] = [0, state.size]
|
|
62
65
|
const output: [number, number] = isDirectionLTR ? [min, max] : [max, min]
|
|
63
66
|
const value = linearScale(input, output)
|
|
64
67
|
return value(pointerPosition)
|
|
@@ -71,17 +74,20 @@ const SliderHorizontal = React.forwardRef<SliderHorizontalElement, SliderHorizon
|
|
|
71
74
|
endEdge={isDirectionLTR ? 'right' : 'left'}
|
|
72
75
|
direction={isDirectionLTR ? 1 : -1}
|
|
73
76
|
sizeProp="width"
|
|
74
|
-
size={size}
|
|
77
|
+
size={state.size}
|
|
75
78
|
>
|
|
76
79
|
<SliderImpl
|
|
77
|
-
ref={forwardedRef}
|
|
80
|
+
ref={composeRefs(forwardedRef, sliderRef)}
|
|
78
81
|
dir={direction}
|
|
79
82
|
{...sliderProps}
|
|
80
83
|
orientation="horizontal"
|
|
81
|
-
onLayout={(
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
84
|
+
onLayout={() => {
|
|
85
|
+
sliderRef.current?.measure((_x, _y, width, _height, pageX, _pageY) => {
|
|
86
|
+
setState({
|
|
87
|
+
size: width,
|
|
88
|
+
offset: pageX,
|
|
89
|
+
})
|
|
90
|
+
})
|
|
85
91
|
}}
|
|
86
92
|
onSlideStart={(event, target) => {
|
|
87
93
|
const value = getValueFromPointer(event.nativeEvent.locationX)
|
|
@@ -90,7 +96,7 @@ const SliderHorizontal = React.forwardRef<SliderHorizontalElement, SliderHorizon
|
|
|
90
96
|
}
|
|
91
97
|
}}
|
|
92
98
|
onSlideMove={(event) => {
|
|
93
|
-
const value = getValueFromPointer(event.nativeEvent.
|
|
99
|
+
const value = getValueFromPointer(event.nativeEvent.pageX - state.offset)
|
|
94
100
|
if (value) {
|
|
95
101
|
onSlideMove?.(value)
|
|
96
102
|
}
|
|
@@ -110,18 +116,14 @@ const SliderHorizontal = React.forwardRef<SliderHorizontalElement, SliderHorizon
|
|
|
110
116
|
* SliderVertical
|
|
111
117
|
* -----------------------------------------------------------------------------------------------*/
|
|
112
118
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
const SliderVertical = React.forwardRef<SliderVerticalElement, SliderVerticalProps>(
|
|
119
|
+
const SliderVertical = React.forwardRef<View, SliderVerticalProps>(
|
|
116
120
|
(props: ScopedProps<SliderVerticalProps>, forwardedRef) => {
|
|
117
121
|
const { min, max, onSlideStart, onSlideMove, onStepKeyDown, ...sliderProps } = props
|
|
118
|
-
const
|
|
119
|
-
const
|
|
122
|
+
const [state, setState] = React.useState(() => ({ size: 0, offset: 0 }))
|
|
123
|
+
const sliderRef = React.useRef<View>(null)
|
|
120
124
|
|
|
121
125
|
function getValueFromPointer(pointerPosition: number) {
|
|
122
|
-
const
|
|
123
|
-
if (!layout) return
|
|
124
|
-
const input: [number, number] = [0, layout.height]
|
|
126
|
+
const input: [number, number] = [0, state.size]
|
|
125
127
|
const output: [number, number] = [max, min]
|
|
126
128
|
const value = linearScale(input, output)
|
|
127
129
|
return value(pointerPosition)
|
|
@@ -133,17 +135,20 @@ const SliderVertical = React.forwardRef<SliderVerticalElement, SliderVerticalPro
|
|
|
133
135
|
startEdge="bottom"
|
|
134
136
|
endEdge="top"
|
|
135
137
|
sizeProp="height"
|
|
136
|
-
size={size}
|
|
138
|
+
size={state.size}
|
|
137
139
|
direction={1}
|
|
138
140
|
>
|
|
139
141
|
<SliderImpl
|
|
140
|
-
ref={forwardedRef}
|
|
142
|
+
ref={composeRefs(forwardedRef, sliderRef)}
|
|
141
143
|
{...sliderProps}
|
|
142
144
|
orientation="vertical"
|
|
143
|
-
onLayout={(
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
145
|
+
onLayout={() => {
|
|
146
|
+
sliderRef.current?.measure((_x, _y, _width, height, _pageX, pageY) => {
|
|
147
|
+
setState({
|
|
148
|
+
size: height,
|
|
149
|
+
offset: pageY,
|
|
150
|
+
})
|
|
151
|
+
})
|
|
147
152
|
}}
|
|
148
153
|
onSlideStart={(event, target) => {
|
|
149
154
|
const value = getValueFromPointer(event.nativeEvent.locationY)
|
|
@@ -152,7 +157,7 @@ const SliderVertical = React.forwardRef<SliderVerticalElement, SliderVerticalPro
|
|
|
152
157
|
}
|
|
153
158
|
}}
|
|
154
159
|
onSlideMove={(event) => {
|
|
155
|
-
const value = getValueFromPointer(event.nativeEvent.
|
|
160
|
+
const value = getValueFromPointer(event.nativeEvent.pageY - state.offset)
|
|
156
161
|
if (value) {
|
|
157
162
|
onSlideMove?.(value)
|
|
158
163
|
}
|
|
@@ -211,21 +216,20 @@ SliderTrack.displayName = TRACK_NAME
|
|
|
211
216
|
|
|
212
217
|
const RANGE_NAME = 'SliderTrackActive'
|
|
213
218
|
|
|
214
|
-
type SliderTrackActiveElement = HTMLElement | View
|
|
215
|
-
interface SliderTrackActiveProps extends YStackProps {}
|
|
216
|
-
|
|
217
219
|
export const SliderTrackActiveFrame = styled(SliderFrame, {
|
|
218
220
|
name: 'SliderTrackActive',
|
|
219
221
|
backgroundColor: '$background',
|
|
220
222
|
position: 'absolute',
|
|
221
223
|
})
|
|
222
224
|
|
|
223
|
-
|
|
225
|
+
type SliderTrackActiveProps = GetProps<typeof SliderTrackActiveFrame>
|
|
226
|
+
|
|
227
|
+
const SliderTrackActive = React.forwardRef<View, SliderTrackActiveProps>(
|
|
224
228
|
(props: ScopedProps<SliderTrackActiveProps>, forwardedRef) => {
|
|
225
229
|
const { __scopeSlider, ...rangeProps } = props
|
|
226
230
|
const context = useSliderContext(RANGE_NAME, __scopeSlider)
|
|
227
231
|
const orientation = useSliderOrientationContext(RANGE_NAME, __scopeSlider)
|
|
228
|
-
const ref = React.useRef<
|
|
232
|
+
const ref = React.useRef<View>(null)
|
|
229
233
|
const composedRefs = useComposedRefs(forwardedRef, ref)
|
|
230
234
|
const valuesCount = context.values.length
|
|
231
235
|
const percentages = context.values.map((value) =>
|
|
@@ -267,6 +271,18 @@ SliderTrackActive.displayName = RANGE_NAME
|
|
|
267
271
|
|
|
268
272
|
const THUMB_NAME = 'SliderThumb'
|
|
269
273
|
|
|
274
|
+
// TODO make this customizable through tamagui
|
|
275
|
+
// so we can accurately use it for estimatedSize below
|
|
276
|
+
const getThumbSize = (val?: SizeTokens | number) => {
|
|
277
|
+
const size = typeof val === 'number' ? val : getSize(val, -1)
|
|
278
|
+
return {
|
|
279
|
+
width: size,
|
|
280
|
+
height: size,
|
|
281
|
+
minWidth: size,
|
|
282
|
+
minHeight: size,
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
270
286
|
export const SliderThumbFrame = styled(ThemeableStack, {
|
|
271
287
|
name: 'SliderThumb',
|
|
272
288
|
position: 'absolute',
|
|
@@ -281,25 +297,16 @@ export const SliderThumbFrame = styled(ThemeableStack, {
|
|
|
281
297
|
|
|
282
298
|
variants: {
|
|
283
299
|
size: {
|
|
284
|
-
'...size':
|
|
285
|
-
const size = typeof val === 'number' ? val : getSize(val, -1)
|
|
286
|
-
return {
|
|
287
|
-
width: size,
|
|
288
|
-
height: size,
|
|
289
|
-
minWidth: size,
|
|
290
|
-
minHeight: size,
|
|
291
|
-
}
|
|
292
|
-
},
|
|
300
|
+
'...size': getThumbSize,
|
|
293
301
|
},
|
|
294
302
|
},
|
|
295
303
|
})
|
|
296
304
|
|
|
297
|
-
type SliderThumbElement = HTMLElement | View
|
|
298
305
|
interface SliderThumbProps extends SizableStackProps {
|
|
299
306
|
index: number
|
|
300
307
|
}
|
|
301
308
|
|
|
302
|
-
const SliderThumb = React.forwardRef<
|
|
309
|
+
const SliderThumb = React.forwardRef<View, SliderThumbProps>(
|
|
303
310
|
(props: ScopedProps<SliderThumbProps>, forwardedRef) => {
|
|
304
311
|
const { __scopeSlider, index, size: sizeProp, ...thumbProps } = props
|
|
305
312
|
const context = useSliderContext(THUMB_NAME, __scopeSlider)
|
|
@@ -312,7 +319,11 @@ const SliderThumb = React.forwardRef<SliderThumbElement, SliderThumbProps>(
|
|
|
312
319
|
const percent =
|
|
313
320
|
value === undefined ? 0 : convertValueToPercentage(value, context.min, context.max)
|
|
314
321
|
const label = getLabel(index, context.values.length)
|
|
315
|
-
const [size, setSize] = React.useState(
|
|
322
|
+
const [size, setSize] = React.useState(() => {
|
|
323
|
+
// for SSR
|
|
324
|
+
const estimatedSize = getVariableValue(getThumbSize(sizeProp).width)
|
|
325
|
+
return estimatedSize
|
|
326
|
+
})
|
|
316
327
|
|
|
317
328
|
const thumbInBoundsOffset = size
|
|
318
329
|
? getThumbInBoundsOffset(size, percent, orientation.direction)
|
|
@@ -340,8 +351,6 @@ const SliderThumb = React.forwardRef<SliderThumbElement, SliderThumbProps>(
|
|
|
340
351
|
aria-orientation={context.orientation}
|
|
341
352
|
data-orientation={context.orientation}
|
|
342
353
|
data-disabled={context.disabled ? '' : undefined}
|
|
343
|
-
// TODO
|
|
344
|
-
// @ts-ignore
|
|
345
354
|
tabIndex={context.disabled ? undefined : 0}
|
|
346
355
|
{...thumbProps}
|
|
347
356
|
{...(context.orientation === 'horizontal'
|
|
@@ -380,11 +389,6 @@ const SliderThumb = React.forwardRef<SliderThumbElement, SliderThumbProps>(
|
|
|
380
389
|
onFocus={composeEventHandlers(props.onFocus, () => {
|
|
381
390
|
context.valueIndexToChangeRef.current = index
|
|
382
391
|
})}
|
|
383
|
-
// temp fix to make slider work nicely on native
|
|
384
|
-
// we just let the events propagate to the track
|
|
385
|
-
{...(!isWeb && {
|
|
386
|
-
pointerEvents: 'none',
|
|
387
|
-
})}
|
|
388
392
|
/>
|
|
389
393
|
)
|
|
390
394
|
}
|
|
@@ -396,10 +400,8 @@ SliderThumb.displayName = THUMB_NAME
|
|
|
396
400
|
* Slider
|
|
397
401
|
* -----------------------------------------------------------------------------------------------*/
|
|
398
402
|
|
|
399
|
-
type SliderElement = SliderHorizontalElement | SliderVerticalElement
|
|
400
|
-
|
|
401
403
|
const Slider = withStaticProperties(
|
|
402
|
-
React.forwardRef<
|
|
404
|
+
React.forwardRef<View, SliderProps>((props: ScopedProps<SliderProps>, forwardedRef) => {
|
|
403
405
|
const {
|
|
404
406
|
name,
|
|
405
407
|
min = 0,
|
|
@@ -414,14 +416,14 @@ const Slider = withStaticProperties(
|
|
|
414
416
|
size: sizeProp,
|
|
415
417
|
...sliderProps
|
|
416
418
|
} = props
|
|
417
|
-
const sliderRef = React.useRef<
|
|
419
|
+
const sliderRef = React.useRef<View>(null)
|
|
418
420
|
const composedRefs = useComposedRefs(sliderRef, forwardedRef)
|
|
419
421
|
const thumbRefs = React.useRef<SliderContextValue['thumbs']>(new Set())
|
|
420
422
|
const valueIndexToChangeRef = React.useRef<number>(0)
|
|
421
423
|
const isHorizontal = orientation === 'horizontal'
|
|
422
424
|
// We set this to true by default so that events bubble to forms without JS (SSR)
|
|
423
|
-
//
|
|
424
|
-
//
|
|
425
|
+
// const isFormControl =
|
|
426
|
+
// sliderRef.current instanceof HTMLElement ? Boolean(sliderRef.current.closest('form')) : true
|
|
425
427
|
|
|
426
428
|
const [values = [], setValues] = useControllableState({
|
|
427
429
|
prop: value,
|
|
@@ -437,6 +439,7 @@ const Slider = withStaticProperties(
|
|
|
437
439
|
|
|
438
440
|
if (isWeb) {
|
|
439
441
|
React.useEffect(() => {
|
|
442
|
+
// @ts-ignore
|
|
440
443
|
const node = sliderRef.current as HTMLElement
|
|
441
444
|
if (!node) return
|
|
442
445
|
const preventDefault = (e) => {
|
|
@@ -538,7 +541,7 @@ Slider.displayName = SLIDER_NAME
|
|
|
538
541
|
|
|
539
542
|
/* -----------------------------------------------------------------------------------------------*/
|
|
540
543
|
|
|
541
|
-
// TODO
|
|
544
|
+
// // TODO
|
|
542
545
|
// const BubbleInput = (props: any) => {
|
|
543
546
|
// const { value, ...inputProps } = props
|
|
544
547
|
// const ref = React.useRef<HTMLInputElement>(null)
|
package/src/SliderImpl.tsx
CHANGED
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
import { composeEventHandlers, getSize, getVariableValue, isWeb, styled } from '@tamagui/core'
|
|
6
6
|
import { YStack } from '@tamagui/stacks'
|
|
7
7
|
import * as React from 'react'
|
|
8
|
+
import { View } from 'react-native'
|
|
8
9
|
|
|
9
10
|
import { ARROW_KEYS, PAGE_KEYS, SLIDER_NAME, useSliderContext } from './constants'
|
|
10
|
-
import { ScopedProps,
|
|
11
|
+
import { ScopedProps, SliderImplProps } from './types'
|
|
11
12
|
|
|
12
13
|
export const DirectionalYStack = styled(YStack, {
|
|
13
14
|
variants: {
|
|
@@ -41,7 +42,7 @@ export const SliderFrame = styled(DirectionalYStack, {
|
|
|
41
42
|
},
|
|
42
43
|
})
|
|
43
44
|
|
|
44
|
-
export const SliderImpl = React.forwardRef<
|
|
45
|
+
export const SliderImpl = React.forwardRef<View, SliderImplProps>(
|
|
45
46
|
(props: ScopedProps<SliderImplProps>, forwardedRef) => {
|
|
46
47
|
const {
|
|
47
48
|
__scopeSlider,
|
|
@@ -82,14 +83,14 @@ export const SliderImpl = React.forwardRef<SliderImplElement, SliderImplProps>(
|
|
|
82
83
|
onScrollShouldSetResponderCapture={() => true}
|
|
83
84
|
onMoveShouldSetResponder={() => true}
|
|
84
85
|
onStartShouldSetResponder={() => true}
|
|
85
|
-
onStartShouldSetResponderCapture={() => true}
|
|
86
|
+
// onStartShouldSetResponderCapture={() => true}
|
|
86
87
|
onResponderTerminationRequest={() => {
|
|
87
|
-
console.log('got??/')
|
|
88
88
|
return false
|
|
89
89
|
}}
|
|
90
90
|
onResponderGrant={composeEventHandlers(props.onResponderGrant, (event) => {
|
|
91
91
|
const target = event.target as HTMLElement | number
|
|
92
|
-
|
|
92
|
+
console.log('target', target, context.thumbs.has(target), context.thumbs)
|
|
93
|
+
const isStartingOnThumb = context.thumbs.has(target)
|
|
93
94
|
// // Prevent browser focus behaviour because we focus a thumb manually when values change.
|
|
94
95
|
// Touch devices have a delay before focusing so won't focus if touch immediately moves
|
|
95
96
|
// away from target (sliding). We want thumb to focus regardless.
|
|
@@ -101,7 +102,6 @@ export const SliderImpl = React.forwardRef<SliderImplElement, SliderImplProps>(
|
|
|
101
102
|
onSlideStart(event, isStartingOnThumb ? 'thumb' : 'track')
|
|
102
103
|
})}
|
|
103
104
|
onResponderMove={composeEventHandlers(props.onResponderMove, (event) => {
|
|
104
|
-
console.log('gogo')
|
|
105
105
|
event.preventDefault()
|
|
106
106
|
event.stopPropagation()
|
|
107
107
|
|
package/src/helpers.tsx
CHANGED
package/src/types.ts
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import type { GestureReponderEvent, SizeTokens } from '@tamagui/core'
|
|
2
2
|
import type { Scope } from '@tamagui/create-context'
|
|
3
3
|
import type { SizableStackProps } from '@tamagui/stacks'
|
|
4
|
-
import type { View } from 'react-native'
|
|
5
4
|
|
|
6
5
|
export type ScopedProps<P> = P & { __scopeSlider?: Scope }
|
|
7
6
|
|
|
8
7
|
export type Direction = 'ltr' | 'rtl'
|
|
9
8
|
|
|
10
|
-
export type SliderImplElement = HTMLElement | View
|
|
11
|
-
|
|
12
9
|
type SliderImplPrivateProps = {
|
|
13
10
|
onSlideStart(event: GestureReponderEvent, target: 'thumb' | 'track'): void
|
|
14
11
|
onSlideMove(event: GestureReponderEvent): void
|