@newtonedev/components 0.1.9 → 0.1.11

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@newtonedev/components",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
4
4
  "description": "React + React Native Web component library for Newtone",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -38,6 +38,7 @@ export function ColorScaleSlider({
38
38
  const trackPageX = React.useRef(0);
39
39
  const isDragging = React.useRef(false);
40
40
  const thumbAnim = React.useRef(new Animated.Value(0)).current;
41
+ const [layoutWidth, setLayoutWidth] = React.useState(0);
41
42
 
42
43
  // Mutable refs to avoid stale closures in PanResponder
43
44
  const onValueChangeRef = React.useRef(onValueChange);
@@ -104,7 +105,7 @@ export function ColorScaleSlider({
104
105
  ? Math.min(maxNV, Math.max(minNV, value))
105
106
  : (maxNV + minNV) / 2;
106
107
  const ratio = range > 0 ? (maxNV - clampedValue) / range : 0.5;
107
- const usableWidth = Math.max(0, trackWidth.current - THUMB_SIZE);
108
+ const usableWidth = Math.max(0, layoutWidth - THUMB_SIZE);
108
109
  const thumbLeft = ratio * usableWidth;
109
110
 
110
111
  // Sync animated thumb position: animate on prop-driven changes, instant during drag
@@ -131,10 +132,9 @@ export function ColorScaleSlider({
131
132
  ref={trackRef}
132
133
  style={styles.trackContainer}
133
134
  onLayout={(e) => {
134
- trackWidth.current = e.nativeEvent.layout.width;
135
- // Set thumb position immediately on layout (no animation)
136
- const newUsableWidth = Math.max(0, e.nativeEvent.layout.width - THUMB_SIZE);
137
- thumbAnim.setValue(ratio * newUsableWidth);
135
+ const w = e.nativeEvent.layout.width;
136
+ trackWidth.current = w;
137
+ setLayoutWidth(w);
138
138
  trackRef.current?.measure((_x, _y, _w, _h, pageX) => {
139
139
  if (pageX != null) trackPageX.current = pageX;
140
140
  });
@@ -44,6 +44,7 @@ export function HueSlider({
44
44
  const trackRef = React.useRef<View>(null);
45
45
  const trackWidth = React.useRef(0);
46
46
  const trackPageX = React.useRef(0);
47
+ const [layoutWidth, setLayoutWidth] = React.useState(0);
47
48
 
48
49
  // Mutable refs to avoid stale closures in PanResponder
49
50
  const onValueChangeRef = React.useRef(onValueChange);
@@ -80,7 +81,7 @@ export function HueSlider({
80
81
  // For wrapping ranges (max > 359), convert stored value to slider range
81
82
  const sliderValue = max > 359 && value < min ? value + 360 : value;
82
83
  const ratio = max > min ? (sliderValue - min) / (max - min) : 0;
83
- const usableWidth = Math.max(0, trackWidth.current - THUMB_SIZE);
84
+ const usableWidth = Math.max(0, layoutWidth - THUMB_SIZE);
84
85
  const thumbLeft = ratio * usableWidth;
85
86
 
86
87
  const handleValueTextSubmit = React.useCallback(
@@ -123,7 +124,9 @@ export function HueSlider({
123
124
  ref={trackRef}
124
125
  style={styles.trackContainer}
125
126
  onLayout={(e) => {
126
- trackWidth.current = e.nativeEvent.layout.width;
127
+ const w = e.nativeEvent.layout.width;
128
+ trackWidth.current = w;
129
+ setLayoutWidth(w);
127
130
  trackRef.current?.measure((_x, _y, _w, _h, pageX) => {
128
131
  if (pageX != null) trackPageX.current = pageX;
129
132
  });
@@ -26,6 +26,7 @@ export function Slider({
26
26
  const trackRef = React.useRef<View>(null);
27
27
  const trackWidth = React.useRef(0);
28
28
  const trackPageX = React.useRef(0);
29
+ const [layoutWidth, setLayoutWidth] = React.useState(0);
29
30
 
30
31
  // Mutable refs to avoid stale closures in PanResponder
31
32
  const onValueChangeRef = React.useRef(onValueChange);
@@ -62,7 +63,7 @@ export function Slider({
62
63
  ).current;
63
64
 
64
65
  const ratio = max > min ? (value - min) / (max - min) : 0;
65
- const usableWidth = Math.max(0, trackWidth.current - THUMB_SIZE);
66
+ const usableWidth = Math.max(0, layoutWidth - THUMB_SIZE);
66
67
  const thumbLeft = ratio * usableWidth;
67
68
  const fillWidth = thumbLeft + THUMB_SIZE / 2;
68
69
 
@@ -106,7 +107,9 @@ export function Slider({
106
107
  ref={trackRef}
107
108
  style={styles.trackContainer}
108
109
  onLayout={(e) => {
109
- trackWidth.current = e.nativeEvent.layout.width;
110
+ const w = e.nativeEvent.layout.width;
111
+ trackWidth.current = w;
112
+ setLayoutWidth(w);
110
113
  trackRef.current?.measure((_x, _y, _w, _h, pageX) => {
111
114
  if (pageX != null) trackPageX.current = pageX;
112
115
  });
@@ -5,10 +5,19 @@
5
5
  const REF_STRING =
6
6
  'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 ';
7
7
 
8
+ /** Race a promise against a timeout. Resolves with fallback if the promise doesn't settle in time. */
9
+ function withTimeout<T>(promise: Promise<T>, ms: number, fallback: T): Promise<T> {
10
+ return Promise.race([
11
+ promise,
12
+ new Promise<T>((resolve) => setTimeout(() => resolve(fallback), ms)),
13
+ ]);
14
+ }
15
+
8
16
  /**
9
17
  * Measure the average character width ratio for a font using the Canvas API.
10
18
  *
11
- * Waits for the font to load via `document.fonts.load()` before measuring.
19
+ * Waits for the font to load via `document.fonts.load()` before measuring,
20
+ * with a 3-second timeout to prevent hangs when fonts fail to load silently.
12
21
  * Falls back to 0.55 if the browser context is unavailable, the font fails
13
22
  * to load, or canvas is not supported.
14
23
  *
@@ -29,7 +38,11 @@ export async function measureAvgCharWidth(
29
38
  ): Promise<number> {
30
39
  if (typeof document === 'undefined') return 0.55;
31
40
  try {
32
- await document.fonts.load(`${fontWeight} ${fontSize}px "${fontFamily}"`);
41
+ await withTimeout(
42
+ document.fonts.load(`${fontWeight} ${fontSize}px "${fontFamily}"`),
43
+ 3000,
44
+ [] as FontFace[],
45
+ );
33
46
  const canvas = document.createElement('canvas');
34
47
  const ctx = canvas.getContext('2d');
35
48
  if (!ctx) return 0.55;