@proulr/sdui-components 0.1.87 → 0.1.88

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/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  Lib de UI completa do Proulr: identidade Night Stalker OLED + componentes BDC + renderer RN.
4
4
 
5
+ Design system consolidado (tokens, movimento, estados, checklist): [`docs/DESIGN.md`](docs/DESIGN.md).
6
+
5
7
  ## Exports
6
8
 
7
9
  | Export | Consumidor | Uso |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@proulr/sdui-components",
3
- "version": "0.1.87",
3
+ "version": "0.1.88",
4
4
  "type": "module",
5
5
  "main": "./src/renderer/index.ts",
6
6
  "types": "./src/renderer/index.ts",
@@ -39,7 +39,7 @@
39
39
  "access": "public"
40
40
  },
41
41
  "dependencies": {
42
- "@proulr/sdui-contract": "^0.1.16",
42
+ "@proulr/sdui-contract": "^0.1.17",
43
43
  "react-native-qrcode-svg": "^6.3.21"
44
44
  },
45
45
  "peerDependencies": {
@@ -9,19 +9,28 @@ import Animated, {
9
9
  withTiming,
10
10
  } from 'react-native-reanimated';
11
11
  import { m3Colors, m3Shape, spacing } from '../theme/proulr-theme';
12
+ import { useReduceMotion } from './use-reduce-motion';
12
13
 
13
14
  const PULSE_DURATION_MS = 900;
14
15
  const PULSE_MIN_OPACITY = 0.45;
16
+ const PULSE_STATIC_OPACITY = 0.7;
15
17
 
16
18
  /**
17
19
  * Pulso de opacidade compartilhado por cada bloco de skeleton. Respeita o
18
- * "reduzir movimento" do sistema (fica estatico). Como `react-native-reanimated`
19
- * ja e usado nos primitivos do pacote (ex.: RangeSlider), importamos direto.
20
+ * "reduzir movimento" do sistema: o loop infinito é desligado por completo
21
+ * (com `ReduceMotion.System` puro, o `withRepeat` alternaria 0↠1 a cada
22
+ * frame, virando strobe). Como `react-native-reanimated` ja e usado nos
23
+ * primitivos do pacote (ex.: RangeSlider), importamos direto.
20
24
  */
21
25
  function usePulseStyle() {
22
- const progress = useSharedValue(PULSE_MIN_OPACITY);
26
+ const reducedMotion = useReduceMotion();
27
+ const progress = useSharedValue(reducedMotion ? PULSE_STATIC_OPACITY : PULSE_MIN_OPACITY);
23
28
 
24
29
  useEffect(() => {
30
+ if (reducedMotion) {
31
+ progress.value = PULSE_STATIC_OPACITY;
32
+ return;
33
+ }
25
34
  progress.value = withRepeat(
26
35
  withTiming(1, {
27
36
  duration: PULSE_DURATION_MS,
@@ -31,7 +40,7 @@ function usePulseStyle() {
31
40
  -1,
32
41
  true,
33
42
  );
34
- }, [progress]);
43
+ }, [progress, reducedMotion]);
35
44
 
36
45
  return useAnimatedStyle(() => ({ opacity: progress.value }));
37
46
  }
@@ -89,3 +89,4 @@ export { StoryComposeHeader } from './story-compose-header';
89
89
  export { StoryCreateShortcutRow, type StoryCreateShortcutItem } from './story-create-shortcut-row';
90
90
  export { StoryEditorChrome, type StoryEditorTool } from './story-editor-chrome';
91
91
  export { StorySurfacePicker, type StorySurfaceOption } from './story-surface-picker';
92
+ export { useReduceMotion } from './use-reduce-motion';
@@ -0,0 +1,31 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { AccessibilityInfo, Platform } from 'react-native';
3
+
4
+ /** Fonte única do "Reduzir movimento" — web lê `prefers-reduced-motion` via matchMedia, nativo via AccessibilityInfo. */
5
+ export function useReduceMotion(): boolean {
6
+ const [reduced, setReduced] = useState(false);
7
+
8
+ useEffect(() => {
9
+ if (Platform.OS === 'web') {
10
+ if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return;
11
+ const query = window.matchMedia('(prefers-reduced-motion: reduce)');
12
+ setReduced(query.matches);
13
+ const onChange = (event: MediaQueryListEvent) => setReduced(event.matches);
14
+ query.addEventListener('change', onChange);
15
+ return () => query.removeEventListener('change', onChange);
16
+ }
17
+ let active = true;
18
+ AccessibilityInfo.isReduceMotionEnabled().then((value) => {
19
+ if (active) setReduced(value);
20
+ });
21
+ const subscription = AccessibilityInfo.addEventListener('reduceMotionChanged', (value) => {
22
+ if (active) setReduced(value);
23
+ });
24
+ return () => {
25
+ active = false;
26
+ subscription?.remove?.();
27
+ };
28
+ }, []);
29
+
30
+ return reduced;
31
+ }