@tamagui/slider 3.0.0-beta.924.1 → 3.0.1

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/dist/cjs/Slider.cjs +25 -36
  2. package/dist/cjs/Slider.native.cjs +27 -37
  3. package/dist/cjs/Slider.native.js +27 -37
  4. package/dist/cjs/Slider.native.js.map +1 -1
  5. package/dist/cjs/SliderImpl.cjs +9 -35
  6. package/dist/cjs/SliderImpl.native.cjs +10 -51
  7. package/dist/cjs/SliderImpl.native.js +10 -51
  8. package/dist/cjs/SliderImpl.native.js.map +1 -1
  9. package/dist/cjs/SliderResponder.cjs +53 -0
  10. package/dist/cjs/SliderResponder.native.cjs +54 -0
  11. package/dist/cjs/SliderResponder.native.js +56 -0
  12. package/dist/cjs/SliderResponder.native.js.map +1 -0
  13. package/dist/esm/Slider.mjs +26 -37
  14. package/dist/esm/Slider.mjs.map +1 -1
  15. package/dist/esm/Slider.native.js +28 -38
  16. package/dist/esm/Slider.native.js.map +1 -1
  17. package/dist/esm/SliderImpl.mjs +10 -36
  18. package/dist/esm/SliderImpl.mjs.map +1 -1
  19. package/dist/esm/SliderImpl.native.js +11 -52
  20. package/dist/esm/SliderImpl.native.js.map +1 -1
  21. package/dist/esm/SliderResponder.mjs +28 -0
  22. package/dist/esm/SliderResponder.mjs.map +1 -0
  23. package/dist/esm/SliderResponder.native.js +33 -0
  24. package/dist/esm/SliderResponder.native.js.map +1 -0
  25. package/dist/jsx/Slider.mjs +26 -37
  26. package/dist/jsx/Slider.mjs.map +1 -1
  27. package/dist/jsx/Slider.native.cjs +27 -37
  28. package/dist/jsx/Slider.native.js +27 -37
  29. package/dist/jsx/Slider.native.js.map +1 -1
  30. package/dist/jsx/SliderImpl.mjs +10 -36
  31. package/dist/jsx/SliderImpl.mjs.map +1 -1
  32. package/dist/jsx/SliderImpl.native.cjs +10 -51
  33. package/dist/jsx/SliderImpl.native.js +10 -51
  34. package/dist/jsx/SliderImpl.native.js.map +1 -1
  35. package/dist/jsx/SliderResponder.mjs +28 -0
  36. package/dist/jsx/SliderResponder.mjs.map +1 -0
  37. package/dist/jsx/SliderResponder.native.cjs +54 -0
  38. package/dist/jsx/SliderResponder.native.js +56 -0
  39. package/dist/jsx/SliderResponder.native.js.map +1 -0
  40. package/package.json +18 -14
  41. package/src/Slider.tsx +67 -44
  42. package/src/SliderImpl.tsx +10 -32
  43. package/src/SliderResponder.native.tsx +30 -0
  44. package/src/SliderResponder.tsx +43 -0
  45. package/src/constants.tsx +2 -2
  46. package/src/types.ts +11 -6
  47. package/types/Slider.d.ts +42 -196
  48. package/types/Slider.d.ts.map +1 -1
  49. package/types/SliderImpl.d.ts +12 -6
  50. package/types/SliderImpl.d.ts.map +1 -1
  51. package/types/SliderResponder.d.ts +10 -0
  52. package/types/SliderResponder.d.ts.map +1 -0
  53. package/types/SliderResponder.native.d.ts +3 -0
  54. package/types/SliderResponder.native.d.ts.map +1 -0
  55. package/types/constants.d.ts +3 -4
  56. package/types/constants.d.ts.map +1 -1
  57. package/types/types.d.ts +10 -6
  58. package/types/types.d.ts.map +1 -1
@@ -0,0 +1,28 @@
1
+ import { View } from "@tamagui/core";
2
+ import { useResponderEvents } from "@tamagui/react-native-use-responder-events";
3
+ import * as React from "react";
4
+ import { jsx } from "react/jsx-runtime";
5
+
6
+ const SliderResponder = ({ onResponderGrant, onResponderMove, onResponderRelease, children }) => {
7
+ const ref = React.useRef(null);
8
+ useResponderEvents(ref, {
9
+ onMoveShouldSetResponderCapture: () => true,
10
+ onMoveShouldSetResponder: () => true,
11
+ onStartShouldSetResponder: () => true,
12
+ onResponderTerminationRequest: () => false,
13
+ onResponderGrant,
14
+ onResponderMove,
15
+ onResponderRelease
16
+ });
17
+ return /* @__PURE__ */ jsx(View, {
18
+ ref,
19
+ position: "absolute",
20
+ inset: 0,
21
+ justifyContent: "center",
22
+ alignItems: "center",
23
+ children
24
+ });
25
+ };
26
+
27
+ export { SliderResponder };
28
+ //# sourceMappingURL=SliderResponder.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SliderResponder.js","names":[],"sources":["jsx/SliderResponder.js"],"sourcesContent":["import { View } from \"@tamagui/core\";\nimport { useResponderEvents } from \"@tamagui/react-native-use-responder-events\";\nimport * as React from \"react\";\nimport { jsx } from \"react/jsx-runtime\";\nconst SliderResponder = ({\n onResponderGrant,\n onResponderMove,\n onResponderRelease,\n children\n}) => {\n const ref = React.useRef(null);\n useResponderEvents(ref, {\n onMoveShouldSetResponderCapture: () => true,\n onMoveShouldSetResponder: () => true,\n onStartShouldSetResponder: () => true,\n onResponderTerminationRequest: () => false,\n onResponderGrant,\n onResponderMove,\n onResponderRelease\n });\n return /* @__PURE__ */ jsx(\n View,\n {\n ref,\n position: \"absolute\",\n inset: 0,\n justifyContent: \"center\",\n alignItems: \"center\",\n children\n }\n );\n};\nexport {\n SliderResponder\n};\n//# sourceMappingURL=SliderResponder.js.map\n"],"mappings":";;;;;;AAIA,MAAM,mBAAmB,EACvB,kBACA,iBACA,oBACA,eACI;CACJ,MAAM,MAAM,MAAM,OAAO,IAAI;CAC7B,mBAAmB,KAAK;EACtB,uCAAuC;EACvC,gCAAgC;EAChC,iCAAiC;EACjC,qCAAqC;EACrC;EACA;EACA;CACF,CAAC;CACD,OAAuB,oBACrB,MACA;EACE;EACA,UAAU;EACV,OAAO;EACP,gBAAgB;EAChB,YAAY;EACZ;CACF,CACF;AACF"}
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all) __defProp(target, name, {
9
+ get: all[name],
10
+ enumerable: true
11
+ });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
16
+ get: () => from[key],
17
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
18
+ });
19
+ }
20
+ return to;
21
+ };
22
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
23
+ var SliderResponder_native_exports = {};
24
+ __export(SliderResponder_native_exports, { SliderResponder: () => SliderResponder });
25
+ module.exports = __toCommonJS(SliderResponder_native_exports);
26
+ var import_jsx_runtime = require("react/jsx-runtime");
27
+ var import_react_native = require("react-native");
28
+ var SliderResponder = function(param) {
29
+ var { onResponderGrant, onResponderMove, onResponderRelease, children } = param;
30
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.View, {
31
+ onMoveShouldSetResponderCapture: function() {
32
+ return true;
33
+ },
34
+ onMoveShouldSetResponder: function() {
35
+ return true;
36
+ },
37
+ onStartShouldSetResponder: function() {
38
+ return true;
39
+ },
40
+ onResponderTerminationRequest: function() {
41
+ return false;
42
+ },
43
+ onResponderGrant,
44
+ onResponderMove,
45
+ onResponderRelease,
46
+ style: {
47
+ inset: 0,
48
+ position: "absolute",
49
+ justifyContent: "center",
50
+ alignItems: "center"
51
+ },
52
+ children
53
+ });
54
+ };
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all) __defProp(target, name, {
9
+ get: all[name],
10
+ enumerable: true
11
+ });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
16
+ get: () => from[key],
17
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
18
+ });
19
+ }
20
+ return to;
21
+ };
22
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
23
+ var SliderResponder_native_exports = {};
24
+ __export(SliderResponder_native_exports, { SliderResponder: () => SliderResponder });
25
+ module.exports = __toCommonJS(SliderResponder_native_exports);
26
+ var import_jsx_runtime = require("react/jsx-runtime");
27
+ var import_react_native = require("react-native");
28
+ var SliderResponder = function(param) {
29
+ var { onResponderGrant, onResponderMove, onResponderRelease, children } = param;
30
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.View, {
31
+ onMoveShouldSetResponderCapture: function() {
32
+ return true;
33
+ },
34
+ onMoveShouldSetResponder: function() {
35
+ return true;
36
+ },
37
+ onStartShouldSetResponder: function() {
38
+ return true;
39
+ },
40
+ onResponderTerminationRequest: function() {
41
+ return false;
42
+ },
43
+ onResponderGrant,
44
+ onResponderMove,
45
+ onResponderRelease,
46
+ style: {
47
+ inset: 0,
48
+ position: "absolute",
49
+ justifyContent: "center",
50
+ alignItems: "center"
51
+ },
52
+ children
53
+ });
54
+ };
55
+
56
+ //# sourceMappingURL=SliderResponder.native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SliderResponder.native.js","names":[],"sources":["jsx/SliderResponder.native.js"],"sourcesContent":["\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\nvar SliderResponder_native_exports = {};\n__export(SliderResponder_native_exports, {\n SliderResponder: () => SliderResponder\n});\nmodule.exports = __toCommonJS(SliderResponder_native_exports);\nvar import_jsx_runtime = require(\"react/jsx-runtime\");\nvar import_react_native = require(\"react-native\");\nvar SliderResponder = function(param) {\n var { onResponderGrant, onResponderMove, onResponderRelease, children } = param;\n return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.View, {\n onMoveShouldSetResponderCapture: function() {\n return true;\n },\n onMoveShouldSetResponder: function() {\n return true;\n },\n onStartShouldSetResponder: function() {\n return true;\n },\n onResponderTerminationRequest: function() {\n return false;\n },\n onResponderGrant,\n onResponderMove,\n onResponderRelease,\n style: {\n inset: 0,\n position: \"absolute\",\n justifyContent: \"center\",\n alignItems: \"center\"\n },\n children\n });\n};\n//# sourceMappingURL=SliderResponder.native.js.map\n"],"mappings":";;;AACA,IAAI,YAAY,OAAO;AACvB,IAAI,mBAAmB,OAAO;AAC9B,IAAI,oBAAoB,OAAO;AAC/B,IAAI,eAAe,OAAO,UAAU;AACpC,IAAI,YAAY,QAAQ,QAAQ;CAC9B,KAAK,IAAI,QAAQ,KACf,UAAU,QAAQ,MAAM;EAAE,KAAK,IAAI;EAAO,YAAY;CAAK,CAAC;AAChE;AACA,IAAI,eAAe,IAAI,MAAM,QAAQ,SAAS;CAC5C,IAAI,QAAQ,OAAO,SAAS,YAAY,OAAO,SAAS,YAAY;EAClE,KAAK,IAAI,OAAO,kBAAkB,IAAI,GACpC,IAAI,CAAC,aAAa,KAAK,IAAI,GAAG,KAAK,QAAQ,QACzC,UAAU,IAAI,KAAK;GAAE,WAAW,KAAK;GAAM,YAAY,EAAE,OAAO,iBAAiB,MAAM,GAAG,MAAM,KAAK;EAAW,CAAC;CACvH;CACA,OAAO;AACT;AACA,IAAI,gBAAgB,QAAQ,YAAY,UAAU,CAAC,GAAG,cAAc,EAAE,OAAO,KAAK,CAAC,GAAG,GAAG;AACzF,IAAI,iCAAiC,CAAC;AACtC,SAAS,gCAAgC,EACvC,uBAAuB,gBACzB,CAAC;AACD,OAAO,UAAU,aAAa,8BAA8B;AAC5D,IAAI,qBAAqB,QAAQ,mBAAmB;AACpD,IAAI,sBAAsB,QAAQ,cAAc;AAChD,IAAI,kBAAkB,SAAS,OAAO;CACpC,IAAI,EAAE,kBAAkB,iBAAiB,oBAAoB,aAAa;CAC1E,OAAuB,iBAAC,GAAG,mBAAmB,IAAG,CAAE,oBAAoB,MAAM;EAC3E,iCAAiC,WAAW;GAC1C,OAAO;EACT;EACA,0BAA0B,WAAW;GACnC,OAAO;EACT;EACA,2BAA2B,WAAW;GACpC,OAAO;EACT;EACA,+BAA+B,WAAW;GACxC,OAAO;EACT;EACA;EACA;EACA;EACA,OAAO;GACL,OAAO;GACP,UAAU;GACV,gBAAgB;GAChB,YAAY;EACd;EACA;CACF,CAAC;AACH"}
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@tamagui/slider",
3
- "version": "3.0.0-beta.924.1",
3
+ "version": "3.0.1",
4
+ "license": "MIT",
4
5
  "source": "src/index.ts",
5
6
  "files": [
6
7
  "src",
@@ -34,21 +35,23 @@
34
35
  "clean:build": "tamagui-build clean:build"
35
36
  },
36
37
  "dependencies": {
37
- "@tamagui/compose-refs": "3.0.0-beta.924.1",
38
- "@tamagui/constants": "3.0.0-beta.924.1",
39
- "@tamagui/core": "3.0.0-beta.924.1",
40
- "@tamagui/create-context": "3.0.0-beta.924.1",
41
- "@tamagui/get-token": "3.0.0-beta.924.1",
42
- "@tamagui/helpers": "3.0.0-beta.924.1",
43
- "@tamagui/stacks": "3.0.0-beta.924.1",
44
- "@tamagui/use-controllable-state": "3.0.0-beta.924.1",
45
- "@tamagui/use-debounce": "3.0.0-beta.924.1",
46
- "@tamagui/use-direction": "3.0.0-beta.924.1"
38
+ "@tamagui/compose-refs": "3.0.1",
39
+ "@tamagui/constants": "3.0.1",
40
+ "@tamagui/core": "3.0.1",
41
+ "@tamagui/create-context": "3.0.1",
42
+ "@tamagui/get-token": "3.0.1",
43
+ "@tamagui/helpers": "3.0.1",
44
+ "@tamagui/react-native-types": "3.0.1",
45
+ "@tamagui/react-native-use-responder-events": "3.0.1",
46
+ "@tamagui/stacks": "3.0.1",
47
+ "@tamagui/use-controllable-state": "3.0.1",
48
+ "@tamagui/use-debounce": "3.0.1",
49
+ "@tamagui/use-direction": "3.0.1"
47
50
  },
48
51
  "devDependencies": {
49
- "@tamagui/build": "3.0.0-beta.924.1",
52
+ "@tamagui/build": "3.0.1",
50
53
  "react": "19.2.3",
51
- "react-native": "0.86.2"
54
+ "react-native": "0.87.1"
52
55
  },
53
56
  "peerDependencies": {
54
57
  "react": ">=19",
@@ -59,5 +62,6 @@
59
62
  "type": "git",
60
63
  "url": "git+https://github.com/tamagui/tamagui.git",
61
64
  "directory": "code/ui/slider"
62
- }
65
+ },
66
+ "releaseSourceCommit": "c156b7cc55e5a6cc5883ebc8189720850ac32dbd"
63
67
  }
package/src/Slider.tsx CHANGED
@@ -2,18 +2,13 @@
2
2
 
3
3
  import { composeRefs, useComposedRefs } from '@tamagui/compose-refs'
4
4
  import { isIos, isWeb } from '@tamagui/constants'
5
- import type {
6
- GestureReponderEvent,
7
- GetProps,
8
- SizeTokens,
9
- TamaguiElement,
10
- } from '@tamagui/core'
5
+ import type { GestureReponderEvent, GetProps, TamaguiElement } from '@tamagui/core'
11
6
  import {
12
7
  createStyledHOC,
13
8
  createRefComponent,
14
- getTokens,
9
+ getConfig,
15
10
  getVariableValue,
16
- resolveSizeToken,
11
+ resolveTextMetrics,
17
12
  styled,
18
13
  useConfiguration,
19
14
  useCreateShallowSetState,
@@ -23,7 +18,7 @@ import { YStack } from '@tamagui/stacks'
23
18
  import { useControllableState } from '@tamagui/use-controllable-state'
24
19
  import { useDirection } from '@tamagui/use-direction'
25
20
  import * as React from 'react'
26
- import type { View } from 'react-native'
21
+ import type { ViewInstance as View } from '@tamagui/react-native-types'
27
22
 
28
23
  import {
29
24
  ARROW_KEYS,
@@ -88,6 +83,27 @@ function removeActiveSliderMeasureListener(listener: Function) {
88
83
  }
89
84
  }
90
85
 
86
+ // on web a responder event's pageX/pageY come straight off the DOM event and are
87
+ // document-relative, while `measure` reports the track through getBoundingClientRect
88
+ // and is viewport-relative. subtracting the cached offset therefore mixes origins and
89
+ // the thumb lags the cursor by exactly the page scroll (#4146). locationX/locationY
90
+ // are `client - track.getBoundingClientRect()`, read fresh on every event, so they
91
+ // need no offset at all - which is why onSlideStart was already correct. that also
92
+ // closes the window where the cached offset is stale: nothing re-measures on scroll,
93
+ // only on resize, an IntersectionObserver threshold crossing, and a 1s interval.
94
+ // native measures the track and the touch against the screen, so it keeps the offset.
95
+ const getTrackPosition = (
96
+ event: GestureReponderEvent,
97
+ offset: number,
98
+ orientation: 'horizontal' | 'vertical'
99
+ ) => {
100
+ const { locationX, locationY, pageX, pageY } = event.nativeEvent
101
+ if (isWeb) {
102
+ return orientation === 'horizontal' ? locationX : locationY
103
+ }
104
+ return (orientation === 'horizontal' ? pageX : pageY) - offset
105
+ }
106
+
91
107
  /* -------------------------------------------------------------------------------------------------
92
108
  * SliderHorizontal
93
109
  * -----------------------------------------------------------------------------------------------*/
@@ -152,13 +168,17 @@ const SliderHorizontal = createRefComponent<View, SliderHorizontalProps>(
152
168
  }
153
169
  }}
154
170
  onSlideMove={(event) => {
155
- const value = getValueFromPointer(event.nativeEvent.pageX - state.offset)
171
+ const value = getValueFromPointer(
172
+ getTrackPosition(event, state.offset, 'horizontal')
173
+ )
156
174
  if (value) {
157
175
  onSlideMove?.(value, event)
158
176
  }
159
177
  }}
160
178
  onSlideEnd={(event) => {
161
- const value = getValueFromPointer(event.nativeEvent.pageX - state.offset)
179
+ const value = getValueFromPointer(
180
+ getTrackPosition(event, state.offset, 'horizontal')
181
+ )
162
182
  if (value) {
163
183
  onSlideEnd?.(event, value)
164
184
  }
@@ -292,13 +312,17 @@ const SliderVertical = createRefComponent<View, SliderVerticalProps>(
292
312
  }
293
313
  }}
294
314
  onSlideMove={(event) => {
295
- const value = getValueFromPointer(event.nativeEvent.pageY - state.offset)
315
+ const value = getValueFromPointer(
316
+ getTrackPosition(event, state.offset, 'vertical')
317
+ )
296
318
  if (value) {
297
319
  onSlideMove?.(value, event)
298
320
  }
299
321
  }}
300
322
  onSlideEnd={(event) => {
301
- const value = getValueFromPointer(event.nativeEvent.pageY - state.offset)
323
+ const value = getValueFromPointer(
324
+ getTrackPosition(event, state.offset, 'vertical')
325
+ )
302
326
  onSlideEnd?.(event, value)
303
327
  }}
304
328
  onStepKeyDown={(event) => {
@@ -339,7 +363,6 @@ const SliderTrack = createStyledHOC(
339
363
  data-disabled={context.disabled ? '' : undefined}
340
364
  data-orientation={context.orientation}
341
365
  orientation={context.orientation}
342
- size={context.size ?? undefined}
343
366
  {...trackProps}
344
367
  ref={forwardedRef}
345
368
  />
@@ -383,8 +406,6 @@ const SliderActive = createStyledHOC(
383
406
  orientation={context.orientation}
384
407
  data-orientation={context.orientation}
385
408
  data-disabled={context.disabled ? '' : undefined}
386
- size={context.size ?? undefined}
387
- animateOnly={['left', 'top', 'right', 'bottom']}
388
409
  {...rangeProps}
389
410
  ref={composedRefs}
390
411
  {...{
@@ -408,31 +429,38 @@ const SliderActive = createStyledHOC(
408
429
  * SliderThumb
409
430
  * -----------------------------------------------------------------------------------------------*/
410
431
 
411
- // TODO make this customizable through tamagui
412
- // so we can accurately use it for estimatedSize below
413
- const getThumbSize = styled.dynamic<SizeTokens | number | true>((val) => {
414
- const tokens = getTokens()
415
- const sizeToken = resolveSizeToken(val ?? true, 'size')
416
- const resolved = typeof sizeToken === 'number' ? sizeToken : tokens.size[sizeToken]
417
- const size = typeof val === 'number' ? val : getVariableValue(resolved) * 0.86
418
- return {
419
- width: size,
420
- height: size,
421
- minWidth: size,
422
- minHeight: size,
432
+ // the thumb's px before its first layout: a number as given, a font size key
433
+ // measured as that font's line height, otherwise 20. skins pass px through the
434
+ // root's `size`; the thumb re-measures itself on layout either way.
435
+ const thumbSize = (val: string | number | boolean | null | undefined) => {
436
+ if (typeof val === 'number') return val
437
+ if (typeof val === 'string') {
438
+ const conf = getConfig()
439
+ const font = conf.fontsParsed[conf.defaultFontToken]
440
+ const fontSize = font?.size[val]
441
+ if (fontSize != null) {
442
+ const metrics: Record<string, unknown> = {
443
+ fontSize: Number.parseFloat(String(getVariableValue(fontSize))),
444
+ }
445
+ const lineHeight = font?.lineHeight?.[val]
446
+ resolveTextMetrics(
447
+ metrics,
448
+ typeof lineHeight === 'number' ? `${lineHeight}px` : lineHeight
449
+ )
450
+ return (metrics.lineHeight ?? metrics.fontSize) as number
451
+ }
423
452
  }
424
- })
453
+ return 20
454
+ }
425
455
 
426
- // Unstyled thumb frame: positioning + the size mechanism (hit-target
427
- // dimensions) + the circular shape modifier (opt-in, off by default). Border,
428
- // background, and hover/press/focus color styling live in the tamagui skin.
456
+ // Unstyled thumb frame: positioning + the circular shape modifier (opt-in, off
457
+ // by default). Hit-target dimensions, border, background, and hover/press/focus
458
+ // color styling live in the tamagui skin.
429
459
  export const SliderThumbFrame = styled(YStack, {
430
460
  displayName: 'SliderThumb',
431
461
  position: 'absolute',
432
462
 
433
463
  variants: {
434
- size: getThumbSize,
435
-
436
464
  circular: {
437
465
  true: {
438
466
  borderRadius: 100_000,
@@ -455,6 +483,8 @@ export const SliderThumbFrame = styled(YStack, {
455
483
 
456
484
  export interface SliderThumbExtraProps {
457
485
  index?: number
486
+ /** thumb px before its first layout: a number, or a font size key */
487
+ size?: string | number | boolean
458
488
  }
459
489
 
460
490
  export type SliderThumbProps = GetProps<typeof SliderThumbFrame> & SliderThumbExtraProps
@@ -473,14 +503,9 @@ const SliderThumb = createStyledHOC(
473
503
  const percent =
474
504
  value === undefined ? 0 : convertValueToPercentage(value, context.min, context.max)
475
505
  const label = getLabel(index, context.values.length)
476
- const sizeIn = (sizeProp ?? context.size ?? true) as SizeTokens | number | true
477
- const [size, setSize] = React.useState(() => {
478
- // for SSR
479
- const estimatedSize = getVariableValue(
480
- getThumbSize(sizeIn, {} as any)?.width
481
- ) as number
482
- return estimatedSize
483
- })
506
+ const sizeIn = (sizeProp ?? context.size ?? true) as string | number | boolean
507
+ // for SSR
508
+ const [size, setSize] = React.useState(() => thumbSize(sizeIn))
484
509
 
485
510
  const thumbInBoundsOffset = size
486
511
  ? getThumbInBoundsOffset(size, percent, orientation.direction)
@@ -528,12 +553,10 @@ const SliderThumb = createStyledHOC(
528
553
  data-orientation={context.orientation}
529
554
  data-disabled={context.disabled ? '' : undefined}
530
555
  tabIndex={context.disabled ? undefined : 0}
531
- animateOnly={['transform', 'left', 'top', 'right', 'bottom']}
532
556
  {...positionalStyles}
533
557
  {...{
534
558
  [orientation.startEdge]: `${percent}%`,
535
559
  }}
536
- size={sizeIn}
537
560
  circular={circular}
538
561
  {...thumbProps}
539
562
  onLayout={(e) => {
@@ -5,46 +5,32 @@ import { createRefComponent } from '@tamagui/core'
5
5
 
6
6
  import { isWeb } from '@tamagui/constants'
7
7
  import type { TamaguiElement } from '@tamagui/core'
8
- import { getVariableValue, styled } from '@tamagui/core'
9
- import { getSize } from '@tamagui/get-token'
8
+ import { styled } from '@tamagui/core'
10
9
  import { YStack } from '@tamagui/stacks'
11
10
  import * as React from 'react'
12
- import { View } from 'react-native'
13
11
 
14
12
  import { ARROW_KEYS, PAGE_KEYS, SLIDER_NAME, useSliderContext } from './constants'
13
+ import { SliderResponder } from './SliderResponder'
15
14
  import type { ScopedProps, SliderImplProps } from './types'
16
15
 
16
+ // Unstyled track container: positioning only. Track thickness lives in the
17
+ // tamagui skin (code/ui/tamagui/src/components/Slider.tsx).
17
18
  const SliderFrameBase = styled(YStack, {
18
19
  position: 'relative',
20
+ justifyContent: 'center',
21
+ alignItems: 'center',
19
22
 
20
23
  variants: {
21
24
  orientation: {
22
25
  horizontal: {},
23
26
  vertical: {},
24
27
  },
25
-
26
- size: styled.dynamic<SliderImplProps['size']>(),
27
28
  } as const,
28
29
  })
29
30
 
30
- export const SliderFrame = SliderFrameBase.resolve((props) => {
31
- if (!props.size) return
32
- const size = Math.round(getVariableValue(getSize(props.size as any)) / 6)
33
- if (props.orientation === 'horizontal') {
34
- return {
35
- height: size,
36
- borderRadius: size,
37
- justifyContent: 'center',
38
- }
39
- }
40
- return {
41
- width: size,
42
- borderRadius: size,
43
- alignItems: 'center',
44
- }
45
- })
31
+ export const SliderFrame = SliderFrameBase
46
32
 
47
- export const SliderImpl = createRefComponent<View, SliderImplProps>(
33
+ export const SliderImpl = createRefComponent<TamaguiElement, SliderImplProps>(
48
34
  (props: ScopedProps<SliderImplProps>, forwardedRef) => {
49
35
  const {
50
36
  __scopeSlider,
@@ -104,10 +90,7 @@ export const SliderImpl = createRefComponent<View, SliderImplProps>(
104
90
  )
105
91
 
106
92
  return (
107
- // wrap with plain RN View for responder events - tamagui views no longer handle responder events on web
108
-
109
93
  <SliderFrame
110
- size="4"
111
94
  ref={forwardedRef as any}
112
95
  {...sliderProps}
113
96
  data-orientation={sliderProps.orientation}
@@ -129,18 +112,13 @@ export const SliderImpl = createRefComponent<View, SliderImplProps>(
129
112
  },
130
113
  })}
131
114
  >
132
- <View
133
- onMoveShouldSetResponderCapture={() => true}
134
- onMoveShouldSetResponder={() => true}
135
- onStartShouldSetResponder={() => true}
136
- onResponderTerminationRequest={() => false}
115
+ <SliderResponder
137
116
  onResponderGrant={handleResponderGrant}
138
117
  onResponderMove={handleResponderMove}
139
118
  onResponderRelease={handleResponderRelease}
140
- style={{ inset: 0, position: 'absolute' }}
141
119
  >
142
120
  {children}
143
- </View>
121
+ </SliderResponder>
144
122
  </SliderFrame>
145
123
  )
146
124
  }
@@ -0,0 +1,30 @@
1
+ import { View } from 'react-native'
2
+
3
+ import type { SliderResponderProps } from './types'
4
+
5
+ export const SliderResponder = ({
6
+ onResponderGrant,
7
+ onResponderMove,
8
+ onResponderRelease,
9
+ children,
10
+ }: SliderResponderProps) => {
11
+ return (
12
+ <View
13
+ onMoveShouldSetResponderCapture={() => true}
14
+ onMoveShouldSetResponder={() => true}
15
+ onStartShouldSetResponder={() => true}
16
+ onResponderTerminationRequest={() => false}
17
+ onResponderGrant={onResponderGrant}
18
+ onResponderMove={onResponderMove}
19
+ onResponderRelease={onResponderRelease}
20
+ style={{
21
+ inset: 0,
22
+ position: 'absolute',
23
+ justifyContent: 'center',
24
+ alignItems: 'center',
25
+ }}
26
+ >
27
+ {children}
28
+ </View>
29
+ )
30
+ }
@@ -0,0 +1,43 @@
1
+ import type { TamaguiElement } from '@tamagui/core'
2
+ import { View } from '@tamagui/core'
3
+ import { useResponderEvents } from '@tamagui/react-native-use-responder-events'
4
+ import * as React from 'react'
5
+
6
+ import type { SliderResponderProps } from './types'
7
+
8
+ /**
9
+ * The slider is dragged through the responder system, and tamagui views stopped
10
+ * carrying responder props on web. This is the same responder system
11
+ * react-native-web runs, used directly, so dragging behaves as it did when this
12
+ * was a react-native `View`.
13
+ */
14
+ export const SliderResponder = ({
15
+ onResponderGrant,
16
+ onResponderMove,
17
+ onResponderRelease,
18
+ children,
19
+ }: SliderResponderProps) => {
20
+ const ref = React.useRef<TamaguiElement>(null)
21
+
22
+ useResponderEvents(ref, {
23
+ onMoveShouldSetResponderCapture: () => true,
24
+ onMoveShouldSetResponder: () => true,
25
+ onStartShouldSetResponder: () => true,
26
+ onResponderTerminationRequest: () => false,
27
+ onResponderGrant,
28
+ onResponderMove,
29
+ onResponderRelease,
30
+ })
31
+
32
+ return (
33
+ <View
34
+ ref={ref}
35
+ position="absolute"
36
+ inset={0}
37
+ justifyContent="center"
38
+ alignItems="center"
39
+ >
40
+ {children}
41
+ </View>
42
+ )
43
+ }
package/src/constants.tsx CHANGED
@@ -1,4 +1,4 @@
1
- import { createStyledContext, type SizeTokens } from '@tamagui/core'
1
+ import { createStyledContext } from '@tamagui/core'
2
2
 
3
3
  import type { Direction, SliderContextValue } from './types'
4
4
 
@@ -31,7 +31,7 @@ export const {
31
31
  startEdge: 'bottom' | 'left' | 'right'
32
32
  endEdge: 'top' | 'right' | 'left'
33
33
  sizeProp: 'width' | 'height'
34
- size: number | SizeTokens
34
+ size: number
35
35
  direction: number
36
36
  }>({
37
37
  startEdge: 'left',
package/src/types.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { GestureReponderEvent, SizeTokens, TamaguiElement } from '@tamagui/core'
1
+ import type { GestureReponderEvent, TamaguiElement } from '@tamagui/core'
2
2
  import type { Scope } from '@tamagui/create-context'
3
3
  import type { YStackProps } from '@tamagui/stacks'
4
4
 
@@ -25,9 +25,7 @@ type SliderImplPrivateProps = {
25
25
  onStepKeyDown(event: React.KeyboardEvent): void
26
26
  }
27
27
 
28
- export type SliderTrackProps = YStackProps & {
29
- size?: SizeTokens | true
30
- }
28
+ export type SliderTrackProps = YStackProps
31
29
 
32
30
  export interface SliderImplProps extends SliderTrackProps, SliderImplPrivateProps {
33
31
  dir?: Direction
@@ -66,7 +64,7 @@ export interface SliderProps
66
64
  extends
67
65
  Omit<SliderHorizontalProps, keyof SliderOrientationPrivateProps | 'defaultValue'>,
68
66
  SliderEventProps {
69
- size?: SizeTokens | true
67
+ size?: string | number | boolean
70
68
  name?: string
71
69
  disabled?: boolean
72
70
  orientation?: React.AriaAttributes['aria-orientation']
@@ -81,7 +79,7 @@ export interface SliderProps
81
79
  }
82
80
 
83
81
  export type SliderContextValue = {
84
- size?: SizeTokens | number | true | null
82
+ size?: string | number | boolean | null
85
83
  disabled?: boolean
86
84
  min: number
87
85
  max: number
@@ -90,3 +88,10 @@ export type SliderContextValue = {
90
88
  thumbs: Map<TamaguiElement, number>
91
89
  orientation: SliderProps['orientation']
92
90
  }
91
+
92
+ export type SliderResponderProps = {
93
+ onResponderGrant: (event: any) => void
94
+ onResponderMove: (event: any) => void
95
+ onResponderRelease: (event: any) => void
96
+ children?: React.ReactNode
97
+ }