@dloizides/ui-motion 1.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/motionTokens.ts","../src/motionUtils.ts","../src/constants.ts","../src/hooks/useEnterExit.ts","../src/FadeIn/FadeIn.tsx","../src/Collapse/Collapse.tsx","../src/PressableScale/PressableScale.tsx","../src/Skeleton/Skeleton.tsx"],"names":["anim","useReducedMotion","useRef","Animated","useEffect","useMemo","useState","jsx","useCallback","styles","StyleSheet","Easing","View"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * motionTokens — the RN-ready motion scale, DERIVED from `@dloizides/design-tokens`.\n *\n * design-tokens ships framework-agnostic VALUES (durations in ms + easings as a\n * `css` string plus `[x1,y1,x2,y2]` bezier control points). This module turns the\n * bezier tuples into RN `Easing.bezier(...)` functions ONCE, so every primitive in\n * this package animates on the same curves the web/CSS side uses — one source, two\n * runtimes. Nothing here is app-specific; motion is uniform across portals.\n */\nimport { Easing, type EasingFunction } from 'react-native';\n\nimport {\n DEFAULT_MOTION,\n type Motion,\n type MotionDurations,\n type MotionEasings,\n} from '@dloizides/design-tokens';\n\n/** Re-export the raw token group so consumers can read durations/css strings directly. */\nexport { DEFAULT_MOTION };\nexport type { Motion, MotionDurations, MotionEasings };\n\n/** Durations in ms (numbers). `instant` (0) is the reduced-motion collapse target. */\nexport const motionDurations: MotionDurations = DEFAULT_MOTION.durations;\n\n/** The easing token group in its raw (`css` + `bezier`) form. */\nexport const motionEasingTokens: MotionEasings = DEFAULT_MOTION.easings;\n\n/** The named RN easing curves, one per {@link MotionEasings} key. */\nexport type MotionEasingName = keyof MotionEasings;\n\n/**\n * RN `EasingFunction`s built from the design-token bezier tuples. Built once at\n * module load; the same three functions are reused by every primitive.\n */\nexport const motionEasings: Record<MotionEasingName, EasingFunction> = {\n standard: Easing.bezier(...motionEasingTokens.standard.bezier),\n decelerate: Easing.bezier(...motionEasingTokens.decelerate.bezier),\n accelerate: Easing.bezier(...motionEasingTokens.accelerate.bezier),\n};\n","/**\n * motionUtils — the pure decision logic behind the primitives, extracted so it can\n * be unit-tested WITHOUT driving RN `Animated` (which needs a running animation\n * frame loop). Each primitive imports these and only wires the result into an\n * `Animated.Value`; the interesting branching lives here where a plain assertion\n * can pin it.\n */\nimport { Platform } from 'react-native';\n\nimport { motionDurations } from './motionTokens';\n\n/**\n * The animation duration a primitive should actually use. Collapses to\n * `instant` (0) under reduced-motion — the single source of the \"every animation\n * collapses to instant\" rule the whole package promises. `0` means \"jump to the\n * end state on the next frame\", i.e. no visible motion.\n */\nexport function resolveDuration(duration: number, reduced: boolean): number {\n return reduced ? motionDurations.instant : duration;\n}\n\n/**\n * Whether RN `Animated` should use the native driver. Layout props (height) can\n * NEVER be native-driven, so callers animating height must pass `false` regardless\n * — this helper is for opacity/transform animations, which are native-drivable on\n * native and must fall back to the JS driver on web.\n */\nexport function shouldUseNativeDriver(): boolean {\n return Platform.OS !== 'web';\n}\n\n/**\n * The target height for a {@link Collapse}: the measured content height when open,\n * `0` when closed. `undefined` while the content has not been measured yet — the\n * caller leaves height `auto` for that first layout pass so the content can report\n * its natural size.\n */\nexport function collapseTargetHeight(open: boolean, measured: number | null): number | undefined {\n if (measured === null) return undefined;\n return open ? measured : 0;\n}\n\n/**\n * The scale a {@link PressableScale} should animate to. `1` (no scale) whenever\n * reduced-motion is on OR the control is not pressed; the pressed scale otherwise.\n */\nexport function resolveScale(pressed: boolean, reduced: boolean, pressedScale: number): number {\n if (reduced) return 1;\n return pressed ? pressedScale : 1;\n}\n\n/**\n * The `[from, to]` translateX range for a {@link Skeleton} shimmer sweep across a\n * block of the given pixel width — the highlight travels from just off the left\n * edge to just off the right edge.\n */\nexport function shimmerRange(width: number): readonly [number, number] {\n return [-width, width];\n}\n","/**\n * Default testID strings for the motion primitives. Consumers can override each\n * via the component's `testID` prop; these are the fallbacks so Playwright/RTL\n * selectors have a stable default.\n */\nexport const MOTION_TEST_IDS = {\n fadeIn: 'fade-in',\n collapse: 'collapse',\n pressableScale: 'pressable-scale',\n skeleton: 'skeleton',\n} as const;\n\n/** Default press-in scale for {@link PressableScale}. */\nexport const DEFAULT_PRESSED_SCALE = 0.96;\n\n/** Default enter translate-Y (px) for {@link FadeIn}. */\nexport const DEFAULT_FADE_TRANSLATE_Y = 8;\n\n/** Default shimmer sweep duration (ms) for {@link Skeleton}. */\nexport const DEFAULT_SKELETON_DURATION_MS = 1200;\n","/**\n * useEnterExit — the reusable enter/exit animation promoted from the ToastHost\n * pattern in `@dloizides/ui-feedback` (fade + optional translate/scale via\n * `Animated`, native driver off on web).\n *\n * The problem it solves: an exiting element must stay MOUNTED until its fade-out\n * finishes, otherwise it vanishes instantly. Callers can't easily track that, so\n * the hook owns a `mounted` flag alongside the animated `style` — keep the node in\n * the tree while `mounted` is true, and it will unmount itself once the exit\n * completes.\n *\n * Reduced-motion (via `@dloizides/rn-web-hooks`) collapses the duration to 0, so\n * both enter and exit are instant and `mounted` flips synchronously.\n */\nimport { useEffect, useMemo, useRef, useState } from 'react';\n\nimport { Animated } from 'react-native';\n\nimport { useReducedMotion } from '@dloizides/rn-web-hooks';\n\nimport { motionDurations, motionEasings } from '../motionTokens';\nimport { resolveDuration, shouldUseNativeDriver } from '../motionUtils';\n\nexport interface UseEnterExitOptions {\n /** Whether the element should be visible (entered). */\n visible: boolean;\n /** Enter/exit duration in ms. Defaults to the `base` motion duration (200). */\n duration?: number;\n /**\n * Initial translate-Y offset (px) the element enters from / exits to. `0`\n * (default) disables the translate, leaving a pure fade.\n */\n translateY?: number;\n /**\n * Initial scale the element enters from / exits to. `1` (default) disables the\n * scale, leaving a pure fade.\n */\n fromScale?: number;\n}\n\nexport interface UseEnterExitResult {\n /** Animated style to spread onto an `Animated.View`. */\n style: {\n opacity: Animated.Value;\n transform: Animated.WithAnimatedArray<{ translateY: Animated.AnimatedInterpolation<number> } | { scale: Animated.AnimatedInterpolation<number> }>;\n };\n /** True while the element must remain in the tree (entered OR exiting). */\n mounted: boolean;\n}\n\nexport function useEnterExit(options: UseEnterExitOptions): UseEnterExitResult {\n const { visible, duration = motionDurations.base, translateY = 0, fromScale = 1 } = options;\n\n const reduced = useReducedMotion();\n const progress = useRef(new Animated.Value(visible ? 1 : 0)).current;\n const [mounted, setMounted] = useState(visible);\n\n useEffect(() => {\n const effectiveDuration = resolveDuration(duration, reduced);\n\n if (visible) {\n // Enter: mount immediately, then animate in.\n setMounted(true);\n if (effectiveDuration === 0) {\n progress.setValue(1);\n return undefined;\n }\n const anim = Animated.timing(progress, {\n toValue: 1,\n duration: effectiveDuration,\n easing: motionEasings.decelerate,\n useNativeDriver: shouldUseNativeDriver(),\n });\n anim.start();\n return () => anim.stop();\n }\n\n // Exit: animate out, then unmount once finished.\n if (effectiveDuration === 0) {\n progress.setValue(0);\n setMounted(false);\n return undefined;\n }\n const anim = Animated.timing(progress, {\n toValue: 0,\n duration: effectiveDuration,\n easing: motionEasings.accelerate,\n useNativeDriver: shouldUseNativeDriver(),\n });\n anim.start(({ finished }) => {\n if (finished) setMounted(false);\n });\n return () => anim.stop();\n }, [visible, duration, reduced, progress]);\n\n const style = useMemo(() => {\n const transform: Array<\n | { translateY: Animated.AnimatedInterpolation<number> }\n | { scale: Animated.AnimatedInterpolation<number> }\n > = [];\n if (translateY !== 0) {\n transform.push({\n translateY: progress.interpolate({ inputRange: [0, 1], outputRange: [translateY, 0] }),\n });\n }\n if (fromScale !== 1) {\n transform.push({\n scale: progress.interpolate({ inputRange: [0, 1], outputRange: [fromScale, 1] }),\n });\n }\n return { opacity: progress, transform };\n }, [progress, translateY, fromScale]);\n\n return { style, mounted };\n}\n","/**\n * FadeIn — fades its children in (with a small upward translate) once, on mount.\n * The lightweight, mount-only sibling of {@link useEnterExit} (which handles the\n * full enter/exit lifecycle). Under reduced-motion it renders its children at rest\n * immediately — no fade, no translate.\n */\nimport React, { useEffect, useMemo, useRef } from 'react';\n\nimport { Animated, type StyleProp, type ViewStyle } from 'react-native';\n\nimport { useReducedMotion } from '@dloizides/rn-web-hooks';\n\nimport { motionDurations, motionEasings } from '../motionTokens';\nimport { shouldUseNativeDriver } from '../motionUtils';\nimport { DEFAULT_FADE_TRANSLATE_Y, MOTION_TEST_IDS } from '../constants';\n\nexport interface FadeInProps {\n children: React.ReactNode;\n /** Fade duration in ms. Defaults to the `base` motion duration (200). */\n duration?: number;\n /** Delay before the fade starts, in ms. Default 0. */\n delay?: number;\n /** Enter translate-Y offset (px). `0` disables the translate. Default 8. */\n translateY?: number;\n style?: StyleProp<ViewStyle>;\n testID?: string;\n}\n\nexport const FadeIn = ({\n children,\n duration = motionDurations.base,\n delay = 0,\n translateY = DEFAULT_FADE_TRANSLATE_Y,\n style,\n testID = MOTION_TEST_IDS.fadeIn,\n}: FadeInProps): React.ReactElement => {\n const reduced = useReducedMotion();\n const progress = useRef(new Animated.Value(reduced ? 1 : 0)).current;\n\n useEffect(() => {\n if (reduced) {\n progress.setValue(1);\n return undefined;\n }\n const anim = Animated.timing(progress, {\n toValue: 1,\n duration,\n delay,\n easing: motionEasings.decelerate,\n useNativeDriver: shouldUseNativeDriver(),\n });\n anim.start();\n return () => anim.stop();\n }, [reduced, duration, delay, progress]);\n\n const animatedStyle = useMemo((): Animated.WithAnimatedObject<ViewStyle> => {\n if (translateY === 0) {\n return { opacity: progress };\n }\n return {\n opacity: progress,\n transform: [{ translateY: progress.interpolate({ inputRange: [0, 1], outputRange: [translateY, 0] }) }],\n };\n }, [progress, translateY]);\n\n return (\n <Animated.View style={[animatedStyle, style]} testID={testID}>\n {children}\n </Animated.View>\n );\n};\n\nexport default FadeIn;\n","/**\n * Collapse — an animated height expand/collapse that WORKS ON WEB.\n *\n * WHY NOT LayoutAnimation: RN's `LayoutAnimation` (what ui-layout's Accordion uses)\n * is a NATIVE-only no-op under react-native-web, so an app that relied on it got no\n * animation on the web build. Collapse instead measures the content's natural height\n * via `onLayout` and animates a real `Animated.Value` height — the same code path on\n * web and native. Height is a layout prop, so the native driver can never be used\n * here (`useNativeDriver: false`).\n *\n * The children stay MOUNTED at all times (only clipped by `overflow: hidden`), so\n * their state is preserved across open/close and screen readers still reach them.\n * Reduced-motion snaps to the target height with no animation.\n */\nimport React, { useCallback, useEffect, useRef, useState } from 'react';\n\nimport {\n Animated,\n type LayoutChangeEvent,\n StyleSheet,\n type StyleProp,\n View,\n type ViewStyle,\n} from 'react-native';\n\nimport { useReducedMotion } from '@dloizides/rn-web-hooks';\n\nimport { motionDurations, motionEasings } from '../motionTokens';\nimport { collapseTargetHeight, resolveDuration } from '../motionUtils';\nimport { MOTION_TEST_IDS } from '../constants';\n\nconst styles = StyleSheet.create({\n outer: {\n overflow: 'hidden',\n },\n});\n\nexport interface CollapseProps {\n /** Whether the content is expanded. */\n open: boolean;\n children: React.ReactNode;\n /** Expand/collapse duration in ms. Defaults to the `base` motion duration (200). */\n duration?: number;\n style?: StyleProp<ViewStyle>;\n testID?: string;\n}\n\nexport const Collapse = ({\n open,\n children,\n duration = motionDurations.base,\n style,\n testID = MOTION_TEST_IDS.collapse,\n}: CollapseProps): React.ReactElement => {\n const reduced = useReducedMotion();\n const [measured, setMeasured] = useState<number | null>(null);\n const heightAnim = useRef(new Animated.Value(0)).current;\n // Skip the FIRST animation: on mount we snap to the initial state, then animate\n // only subsequent open/close changes.\n const initialized = useRef(false);\n\n const onContentLayout = useCallback((event: LayoutChangeEvent): void => {\n const nextHeight = event.nativeEvent.layout.height;\n setMeasured((previous) => (previous === nextHeight ? previous : nextHeight));\n }, []);\n\n useEffect(() => {\n const target = collapseTargetHeight(open, measured);\n if (target === undefined) return undefined;\n\n if (!initialized.current) {\n heightAnim.setValue(target);\n initialized.current = true;\n return undefined;\n }\n\n const effectiveDuration = resolveDuration(duration, reduced);\n if (effectiveDuration === 0) {\n heightAnim.setValue(target);\n return undefined;\n }\n\n const anim = Animated.timing(heightAnim, {\n toValue: target,\n duration: effectiveDuration,\n easing: motionEasings.standard,\n // Height is a layout prop — the native driver cannot animate it.\n useNativeDriver: false,\n });\n anim.start();\n return () => anim.stop();\n }, [open, measured, duration, reduced, heightAnim]);\n\n // Until measured, leave height `auto` (undefined) so the content reports its\n // natural size; after that, drive the animated height.\n const outerHeight = measured === null ? undefined : heightAnim;\n\n return (\n <Animated.View style={[styles.outer, { height: outerHeight }, style]} testID={testID}>\n <View onLayout={onContentLayout}>{children}</View>\n </Animated.View>\n );\n};\n\nexport default Collapse;\n","/**\n * PressableScale — a `Pressable` that scales down on press-in and springs back on\n * press-out, giving tactile feedback without the flat opacity dip of a bare\n * `activeOpacity`. Built to replace `activeOpacity` usage in `@dloizides/ui-buttons`.\n *\n * It forwards EVERY `Pressable` prop (onPress, accessibility*, disabled, hitSlop,\n * …) so it is a drop-in wrapper; the scale is applied to an inner `Animated.View`\n * so the outer `Pressable` keeps its full press/a11y behaviour. Under reduced-motion\n * the scale is suppressed entirely (the element stays at scale 1).\n */\nimport React, { useCallback, useRef } from 'react';\n\nimport {\n Animated,\n type GestureResponderEvent,\n Pressable,\n type PressableProps,\n type PressableStateCallbackType,\n type StyleProp,\n type ViewStyle,\n} from 'react-native';\n\nimport { useReducedMotion } from '@dloizides/rn-web-hooks';\n\nimport { motionDurations, motionEasings } from '../motionTokens';\nimport { shouldUseNativeDriver } from '../motionUtils';\nimport { DEFAULT_PRESSED_SCALE, MOTION_TEST_IDS } from '../constants';\n\nexport interface PressableScaleProps extends PressableProps {\n /** Scale to shrink to on press-in. Default 0.96. */\n pressedScale?: number;\n /** Style applied to the inner animated wrapper that carries the scale transform. */\n innerStyle?: StyleProp<ViewStyle>;\n}\n\nexport const PressableScale = ({\n pressedScale = DEFAULT_PRESSED_SCALE,\n innerStyle,\n onPressIn,\n onPressOut,\n children,\n testID = MOTION_TEST_IDS.pressableScale,\n ...rest\n}: PressableScaleProps): React.ReactElement => {\n const reduced = useReducedMotion();\n const scale = useRef(new Animated.Value(1)).current;\n\n const animateTo = useCallback(\n (toValue: number): void => {\n if (reduced) {\n scale.setValue(1);\n return;\n }\n Animated.timing(scale, {\n toValue,\n duration: motionDurations.fast,\n easing: motionEasings.standard,\n useNativeDriver: shouldUseNativeDriver(),\n }).start();\n },\n [reduced, scale],\n );\n\n const handlePressIn = useCallback(\n (event: GestureResponderEvent): void => {\n animateTo(pressedScale);\n onPressIn?.(event);\n },\n [animateTo, pressedScale, onPressIn],\n );\n\n const handlePressOut = useCallback(\n (event: GestureResponderEvent): void => {\n animateTo(1);\n onPressOut?.(event);\n },\n [animateTo, onPressOut],\n );\n\n const renderInner = (state: PressableStateCallbackType): React.ReactNode => (\n <Animated.View style={[{ transform: [{ scale }] }, innerStyle]}>\n {typeof children === 'function' ? children(state) : children}\n </Animated.View>\n );\n\n return (\n <Pressable {...rest} testID={testID} onPressIn={handlePressIn} onPressOut={handlePressOut}>\n {renderInner}\n </Pressable>\n );\n};\n\nexport default PressableScale;\n","/**\n * Skeleton — a rounded placeholder block with a highlight band that sweeps across\n * it, upgrading the opacity-pulse skeleton in `@dloizides/ui-feedback` to a moving\n * shimmer (a stronger \"content is loading\" signal).\n *\n * The block measures its own pixel width via `onLayout`, then loops a highlight\n * `Animated.View` from just off the left edge to just off the right edge (transform\n * translateX — native-drivable on native, JS driver on web). Under reduced-motion\n * the sweep is suppressed and a static block is shown, so it never animates against\n * the user's OS preference.\n */\nimport React, { useCallback, useEffect, useRef, useState } from 'react';\n\nimport {\n Animated,\n Easing,\n type LayoutChangeEvent,\n StyleSheet,\n type StyleProp,\n View,\n type ViewStyle,\n} from 'react-native';\n\nimport { useReducedMotion } from '@dloizides/rn-web-hooks';\n\nimport { shouldUseNativeDriver, shimmerRange } from '../motionUtils';\nimport { DEFAULT_SKELETON_DURATION_MS, MOTION_TEST_IDS } from '../constants';\n\nconst DEFAULT_HEIGHT = 16;\nconst DEFAULT_BORDER_RADIUS = 4;\nconst DEFAULT_BG = 'rgba(0, 0, 0, 0.08)';\nconst DEFAULT_HIGHLIGHT = 'rgba(255, 255, 255, 0.35)';\nconst HIGHLIGHT_WIDTH_RATIO = 0.4;\n\nconst styles = StyleSheet.create({\n block: {\n overflow: 'hidden',\n },\n highlight: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n },\n});\n\nexport interface SkeletonProps {\n /** Block width. Number (px) or percentage string. Default '100%'. */\n width?: number | string;\n /** Block height in px. Default 16. */\n height?: number;\n /** Corner radius in px. Default 4. */\n borderRadius?: number;\n /** Shimmer sweep duration in ms. Default 1200. */\n duration?: number;\n /** Base block colour. */\n backgroundColor?: string;\n /** Sweeping highlight colour. */\n highlightColor?: string;\n style?: StyleProp<ViewStyle>;\n testID?: string;\n}\n\nexport const Skeleton = ({\n width = '100%',\n height = DEFAULT_HEIGHT,\n borderRadius = DEFAULT_BORDER_RADIUS,\n duration = DEFAULT_SKELETON_DURATION_MS,\n backgroundColor = DEFAULT_BG,\n highlightColor = DEFAULT_HIGHLIGHT,\n style,\n testID = MOTION_TEST_IDS.skeleton,\n}: SkeletonProps): React.ReactElement => {\n const reduced = useReducedMotion();\n const shimmer = useRef(new Animated.Value(0)).current;\n const [measuredWidth, setMeasuredWidth] = useState(0);\n\n const onLayout = useCallback((event: LayoutChangeEvent): void => {\n const nextWidth = event.nativeEvent.layout.width;\n setMeasuredWidth((previous) => (previous === nextWidth ? previous : nextWidth));\n }, []);\n\n useEffect(() => {\n if (reduced || measuredWidth === 0) return undefined;\n shimmer.setValue(0);\n const anim = Animated.loop(\n Animated.timing(shimmer, {\n toValue: 1,\n duration,\n easing: Easing.linear,\n useNativeDriver: shouldUseNativeDriver(),\n }),\n );\n anim.start();\n return () => anim.stop();\n }, [reduced, measuredWidth, duration, shimmer]);\n\n const [from, to] = shimmerRange(measuredWidth);\n const translateX = shimmer.interpolate({ inputRange: [0, 1], outputRange: [from, to] });\n const highlightWidth = measuredWidth * HIGHLIGHT_WIDTH_RATIO;\n\n return (\n <View\n accessibilityState={{ busy: true }}\n onLayout={onLayout}\n style={[styles.block, { width: width as ViewStyle['width'], height, borderRadius, backgroundColor }, style]}\n testID={testID}\n >\n {reduced || measuredWidth === 0 ? null : (\n <Animated.View\n style={[styles.highlight, { width: highlightWidth, backgroundColor: highlightColor, transform: [{ translateX }] }]}\n />\n )}\n </View>\n );\n};\n\nexport default Skeleton;\n"]}
package/package.json ADDED
@@ -0,0 +1,113 @@
1
+ {
2
+ "name": "@dloizides/ui-motion",
3
+ "version": "1.0.1",
4
+ "description": "Themable, brand-agnostic React Native (RN-web) motion primitives — useEnterExit, FadeIn, Collapse, PressableScale, Skeleton — built on RN Animated, driven by @dloizides/design-tokens motion tokens, and gated on @dloizides/rn-web-hooks useReducedMotion (every animation collapses to instant under reduced-motion). Part of the dloizides.com shared UI kit.",
5
+ "keywords": [
6
+ "react",
7
+ "react-native",
8
+ "react-native-web",
9
+ "ui",
10
+ "motion",
11
+ "animation",
12
+ "animated",
13
+ "reduced-motion",
14
+ "dloizides"
15
+ ],
16
+ "author": "dloizides",
17
+ "license": "MIT",
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "https://github.com/openmindednewby/ui-motion.git"
21
+ },
22
+ "homepage": "https://github.com/openmindednewby/ui-motion#readme",
23
+ "bugs": {
24
+ "url": "https://github.com/openmindednewby/ui-motion/issues"
25
+ },
26
+ "main": "./dist/index.js",
27
+ "module": "./dist/index.mjs",
28
+ "types": "./dist/index.d.ts",
29
+ "exports": {
30
+ ".": {
31
+ "react-native": {
32
+ "types": "./dist/index.d.ts",
33
+ "default": "./dist/index.js"
34
+ },
35
+ "browser": {
36
+ "types": "./dist/index.d.ts",
37
+ "default": "./dist/index.js"
38
+ },
39
+ "require": {
40
+ "types": "./dist/index.d.ts",
41
+ "default": "./dist/index.js"
42
+ },
43
+ "import": {
44
+ "types": "./dist/index.d.mts",
45
+ "default": "./dist/index.mjs"
46
+ },
47
+ "default": {
48
+ "types": "./dist/index.d.ts",
49
+ "default": "./dist/index.js"
50
+ }
51
+ }
52
+ },
53
+ "files": [
54
+ "dist",
55
+ "README.md",
56
+ "CHANGELOG.md"
57
+ ],
58
+ "sideEffects": false,
59
+ "engines": {
60
+ "node": ">=18.0.0"
61
+ },
62
+ "scripts": {
63
+ "build": "rimraf dist && tsup",
64
+ "build:watch": "tsup --watch",
65
+ "test": "jest",
66
+ "test:watch": "jest --watch",
67
+ "test:coverage": "jest --coverage",
68
+ "lint": "eslint src --ext .ts,.tsx",
69
+ "lint:fix": "eslint src --ext .ts,.tsx --fix",
70
+ "typecheck": "tsc --noEmit",
71
+ "clean": "rimraf dist",
72
+ "security:audit": "npm audit --audit-level=high",
73
+ "deps:outdated": "npm outdated || exit 0",
74
+ "deps:unused": "npx depcheck --ignores \"@types/jest,@types/node,@types/react,@types/react-dom,rimraf,react-native\"",
75
+ "deps:licenses": "npx license-checker --onlyAllow \"MIT;Apache-2.0;ISC;BSD-2-Clause;BSD-3-Clause;0BSD;Unlicense;CC0-1.0\"",
76
+ "deps:health": "npm run deps:outdated && npm run deps:unused",
77
+ "prepublishOnly": "npm run clean && npm run build && npm run test",
78
+ "version": "npm run build"
79
+ },
80
+ "dependencies": {
81
+ "@dloizides/design-tokens": "^1.7.0",
82
+ "@dloizides/rn-web-hooks": "^1.1.0"
83
+ },
84
+ "peerDependencies": {
85
+ "react": ">=18.0.0",
86
+ "react-native": ">=0.74.0"
87
+ },
88
+ "devDependencies": {
89
+ "@dloizides/design-tokens": "file:../design-tokens",
90
+ "@testing-library/dom": "^10.4.0",
91
+ "@testing-library/jest-dom": "^6.6.3",
92
+ "@testing-library/react": "^16.1.0",
93
+ "@types/jest": "^29.5.0",
94
+ "@types/node": "^20.19.32",
95
+ "@types/react": "^19.0.0",
96
+ "@types/react-dom": "^19.0.0",
97
+ "@typescript-eslint/eslint-plugin": "^7.0.0",
98
+ "@typescript-eslint/parser": "^7.0.0",
99
+ "eslint": "^8.57.0",
100
+ "eslint-plugin-react": "^7.34.0",
101
+ "eslint-plugin-react-hooks": "^4.6.0",
102
+ "jest": "^29.7.0",
103
+ "jest-environment-jsdom": "^29.7.0",
104
+ "react": "^19.2.4",
105
+ "react-dom": "^19.2.4",
106
+ "react-native": "0.81.5",
107
+ "react-native-web": "^0.21.0",
108
+ "rimraf": "^5.0.0",
109
+ "ts-jest": "^29.1.0",
110
+ "tsup": "^8.0.0",
111
+ "typescript": "^5.4.0"
112
+ }
113
+ }