@streamplace/components 0.0.1 → 0.7.0

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 (169) hide show
  1. package/LICENSE +18 -0
  2. package/README.md +35 -0
  3. package/dist/components/chat/chat-box.js +109 -0
  4. package/dist/components/chat/chat-message.js +76 -0
  5. package/dist/components/chat/chat.js +56 -0
  6. package/dist/components/chat/mention-suggestions.js +39 -0
  7. package/dist/components/chat/mod-view.js +33 -0
  8. package/dist/components/mobile-player/fullscreen.js +69 -0
  9. package/dist/components/mobile-player/fullscreen.native.js +151 -0
  10. package/dist/components/mobile-player/player.js +103 -0
  11. package/dist/components/mobile-player/props.js +1 -0
  12. package/dist/components/mobile-player/shared.js +51 -0
  13. package/dist/components/mobile-player/ui/countdown.js +79 -0
  14. package/dist/components/mobile-player/ui/index.js +5 -0
  15. package/dist/components/mobile-player/ui/input.js +38 -0
  16. package/dist/components/mobile-player/ui/metrics.js +40 -0
  17. package/dist/components/mobile-player/ui/streamer-context-menu.js +4 -0
  18. package/dist/components/mobile-player/ui/viewer-context-menu.js +20 -0
  19. package/dist/components/mobile-player/use-webrtc.js +232 -0
  20. package/dist/components/mobile-player/video.js +375 -0
  21. package/dist/components/mobile-player/video.native.js +238 -0
  22. package/dist/components/mobile-player/webrtc-diagnostics.js +106 -0
  23. package/dist/components/mobile-player/webrtc-primitives.js +25 -0
  24. package/dist/components/mobile-player/webrtc-primitives.native.js +1 -0
  25. package/dist/components/ui/button.js +220 -0
  26. package/dist/components/ui/dialog.js +203 -0
  27. package/dist/components/ui/dropdown.js +148 -0
  28. package/dist/components/ui/icons.js +22 -0
  29. package/dist/components/ui/index.js +22 -0
  30. package/dist/components/ui/input.js +202 -0
  31. package/dist/components/ui/loader.js +7 -0
  32. package/dist/components/ui/primitives/button.js +121 -0
  33. package/dist/components/ui/primitives/input.js +202 -0
  34. package/dist/components/ui/primitives/modal.js +203 -0
  35. package/dist/components/ui/primitives/text.js +286 -0
  36. package/dist/components/ui/resizeable.js +101 -0
  37. package/dist/components/ui/text.js +175 -0
  38. package/dist/components/ui/textarea.js +17 -0
  39. package/dist/components/ui/toast.js +129 -0
  40. package/dist/components/ui/view.js +250 -0
  41. package/dist/hooks/index.js +9 -0
  42. package/dist/hooks/useAvatars.js +32 -0
  43. package/dist/hooks/useCameraToggle.js +9 -0
  44. package/dist/hooks/useKeyboard.js +33 -0
  45. package/dist/hooks/useKeyboardSlide.js +11 -0
  46. package/dist/hooks/useLivestreamInfo.js +62 -0
  47. package/dist/hooks/useOuterAndInnerDimensions.js +27 -0
  48. package/dist/hooks/usePlayerDimensions.js +19 -0
  49. package/dist/hooks/useSegmentTiming.js +62 -0
  50. package/dist/index.js +16 -0
  51. package/dist/lib/facet.js +88 -0
  52. package/dist/lib/theme/atoms.js +620 -0
  53. package/dist/lib/theme/atoms.types.js +5 -0
  54. package/dist/lib/theme/index.js +9 -0
  55. package/dist/lib/theme/theme.js +248 -0
  56. package/dist/lib/theme/tokens.js +383 -0
  57. package/dist/lib/utils.js +94 -0
  58. package/dist/livestream-provider/index.js +25 -0
  59. package/dist/livestream-provider/websocket.js +41 -0
  60. package/dist/livestream-store/chat.js +186 -0
  61. package/dist/livestream-store/context.js +2 -0
  62. package/dist/livestream-store/index.js +4 -0
  63. package/dist/livestream-store/livestream-state.js +1 -0
  64. package/dist/livestream-store/livestream-store.js +42 -0
  65. package/dist/livestream-store/stream-key.js +115 -0
  66. package/dist/livestream-store/websocket-consumer.js +55 -0
  67. package/dist/player-store/context.js +2 -0
  68. package/dist/player-store/index.js +6 -0
  69. package/dist/player-store/player-provider.js +52 -0
  70. package/dist/player-store/player-state.js +22 -0
  71. package/dist/player-store/player-store.js +159 -0
  72. package/dist/player-store/single-player-provider.js +109 -0
  73. package/dist/streamplace-provider/context.js +2 -0
  74. package/dist/streamplace-provider/index.js +16 -0
  75. package/dist/streamplace-provider/poller.js +46 -0
  76. package/dist/streamplace-provider/xrpc.js +0 -0
  77. package/dist/streamplace-store/block.js +23 -0
  78. package/dist/streamplace-store/index.js +3 -0
  79. package/dist/streamplace-store/stream.js +193 -0
  80. package/dist/streamplace-store/streamplace-store.js +37 -0
  81. package/dist/streamplace-store/user.js +47 -0
  82. package/dist/streamplace-store/xrpc.js +12 -0
  83. package/node-compile-cache/v22.15.0-x64-efe9a9df-0/37be0eec +0 -0
  84. package/node-compile-cache/v22.15.0-x64-efe9a9df-0/56540125 +0 -0
  85. package/node-compile-cache/v22.15.0-x64-efe9a9df-0/67b1eb60 +0 -0
  86. package/node-compile-cache/v22.15.0-x64-efe9a9df-0/7c275f90 +0 -0
  87. package/package.json +50 -8
  88. package/src/components/chat/chat-box.tsx +195 -0
  89. package/src/components/chat/chat-message.tsx +192 -0
  90. package/src/components/chat/chat.tsx +128 -0
  91. package/src/components/chat/mention-suggestions.tsx +71 -0
  92. package/src/components/chat/mod-view.tsx +118 -0
  93. package/src/components/mobile-player/fullscreen.native.tsx +193 -0
  94. package/src/components/mobile-player/fullscreen.tsx +79 -0
  95. package/src/components/mobile-player/player.tsx +134 -0
  96. package/src/components/mobile-player/props.tsx +11 -0
  97. package/src/components/mobile-player/shared.tsx +56 -0
  98. package/src/components/mobile-player/ui/countdown.tsx +119 -0
  99. package/src/components/mobile-player/ui/index.ts +5 -0
  100. package/src/components/mobile-player/ui/input.tsx +85 -0
  101. package/src/components/mobile-player/ui/metrics.tsx +69 -0
  102. package/src/components/mobile-player/ui/streamer-context-menu.tsx +3 -0
  103. package/src/components/mobile-player/ui/viewer-context-menu.tsx +70 -0
  104. package/src/components/mobile-player/use-webrtc.tsx +282 -0
  105. package/src/components/mobile-player/video.native.tsx +360 -0
  106. package/src/components/mobile-player/video.tsx +557 -0
  107. package/src/components/mobile-player/webrtc-diagnostics.tsx +149 -0
  108. package/src/components/mobile-player/webrtc-primitives.native.tsx +6 -0
  109. package/src/components/mobile-player/webrtc-primitives.tsx +33 -0
  110. package/src/components/ui/button.tsx +309 -0
  111. package/src/components/ui/dialog.tsx +376 -0
  112. package/src/components/ui/dropdown.tsx +399 -0
  113. package/src/components/ui/icons.tsx +50 -0
  114. package/src/components/ui/index.ts +33 -0
  115. package/src/components/ui/input.tsx +350 -0
  116. package/src/components/ui/loader.tsx +9 -0
  117. package/src/components/ui/primitives/button.tsx +292 -0
  118. package/src/components/ui/primitives/input.tsx +422 -0
  119. package/src/components/ui/primitives/modal.tsx +421 -0
  120. package/src/components/ui/primitives/text.tsx +499 -0
  121. package/src/components/ui/resizeable.tsx +169 -0
  122. package/src/components/ui/text.tsx +330 -0
  123. package/src/components/ui/textarea.tsx +34 -0
  124. package/src/components/ui/toast.tsx +203 -0
  125. package/src/components/ui/view.tsx +344 -0
  126. package/src/hooks/index.ts +9 -0
  127. package/src/hooks/useAvatars.tsx +44 -0
  128. package/src/hooks/useCameraToggle.ts +12 -0
  129. package/src/hooks/useKeyboard.tsx +41 -0
  130. package/src/hooks/useKeyboardSlide.ts +12 -0
  131. package/src/hooks/useLivestreamInfo.ts +67 -0
  132. package/src/hooks/useOuterAndInnerDimensions.tsx +32 -0
  133. package/src/hooks/usePlayerDimensions.ts +23 -0
  134. package/src/hooks/useSegmentTiming.tsx +88 -0
  135. package/src/index.tsx +27 -0
  136. package/src/lib/facet.ts +131 -0
  137. package/src/lib/theme/atoms.ts +760 -0
  138. package/src/lib/theme/atoms.types.ts +258 -0
  139. package/src/lib/theme/index.ts +48 -0
  140. package/src/lib/theme/theme.tsx +436 -0
  141. package/src/lib/theme/tokens.ts +409 -0
  142. package/src/lib/utils.ts +132 -0
  143. package/src/livestream-provider/index.tsx +48 -0
  144. package/src/livestream-provider/websocket.tsx +47 -0
  145. package/src/livestream-store/chat.tsx +261 -0
  146. package/src/livestream-store/context.tsx +10 -0
  147. package/src/livestream-store/index.tsx +4 -0
  148. package/src/livestream-store/livestream-state.tsx +21 -0
  149. package/src/livestream-store/livestream-store.tsx +59 -0
  150. package/src/livestream-store/stream-key.tsx +124 -0
  151. package/src/livestream-store/websocket-consumer.tsx +62 -0
  152. package/src/player-store/context.tsx +11 -0
  153. package/src/player-store/index.tsx +6 -0
  154. package/src/player-store/player-provider.tsx +89 -0
  155. package/src/player-store/player-state.tsx +187 -0
  156. package/src/player-store/player-store.tsx +239 -0
  157. package/src/player-store/single-player-provider.tsx +181 -0
  158. package/src/streamplace-provider/context.tsx +10 -0
  159. package/src/streamplace-provider/index.tsx +32 -0
  160. package/src/streamplace-provider/poller.tsx +55 -0
  161. package/src/streamplace-provider/xrpc.tsx +0 -0
  162. package/src/streamplace-store/block.tsx +29 -0
  163. package/src/streamplace-store/index.tsx +3 -0
  164. package/src/streamplace-store/stream.tsx +262 -0
  165. package/src/streamplace-store/streamplace-store.tsx +89 -0
  166. package/src/streamplace-store/user.tsx +57 -0
  167. package/src/streamplace-store/xrpc.tsx +15 -0
  168. package/tsconfig.json +9 -0
  169. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,148 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import BottomSheet, { BottomSheetView } from "@gorhom/bottom-sheet";
3
+ import * as DropdownMenuPrimitive from "@rn-primitives/dropdown-menu";
4
+ import { Check, CheckCircle, ChevronDown, ChevronRight, ChevronUp, Circle, } from "lucide-react-native";
5
+ import { forwardRef, useMemo, useRef } from "react";
6
+ import { Platform, Pressable, StyleSheet, Text, useWindowDimensions, View, } from "react-native";
7
+ import { a, bg, borderRadius, colors, fontSize, gap, h, layout, ml, mt, mx, p, pb, pl, pr, pt, px, py, right, textColors, } from "../../lib/theme/atoms";
8
+ import { objectFromObjects, TextContext as TextClassContext, } from "./primitives/text";
9
+ export const DropdownMenu = DropdownMenuPrimitive.Root;
10
+ export const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
11
+ export const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
12
+ export const DropdownMenuSub = DropdownMenuPrimitive.Sub;
13
+ export const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
14
+ export const DropdownMenuBottomSheet = forwardRef(function DropdownMenuBottomSheet({ overlayStyle, portalHost, children }, _ref) {
15
+ // Use the primitives' context to know if open
16
+ const { open, onOpenChange } = DropdownMenuPrimitive.useRootContext();
17
+ const snapPoints = useMemo(() => ["25%", "50%", "80%"], []);
18
+ const sheetRef = useRef(null);
19
+ return (_jsx(DropdownMenuPrimitive.Portal, { hostName: portalHost, children: _jsx(BottomSheet, { ref: sheetRef,
20
+ // why the heck is this 1-indexed
21
+ index: open ? 3 : -1, snapPoints: snapPoints, enablePanDownToClose: true, onClose: () => onOpenChange?.(false), style: [overlayStyle], backgroundStyle: [bg.black, a.radius.all.md, a.shadows.md, p[1]], handleIndicatorStyle: [
22
+ a.sizes.width[12],
23
+ a.sizes.height[1],
24
+ bg.gray[500],
25
+ ], children: _jsx(BottomSheetView, { style: [px[2]], children: typeof children === "function"
26
+ ? children({ pressed: true })
27
+ : children }) }) }));
28
+ });
29
+ export const DropdownMenuSubTrigger = forwardRef(({ inset, children, ...props }, ref) => {
30
+ const { open } = DropdownMenuPrimitive.useSubContext();
31
+ const Icon = Platform.OS === "web" ? ChevronRight : open ? ChevronUp : ChevronDown;
32
+ return (_jsx(TextClassContext.Provider, { value: objectFromObjects([
33
+ a.textColors.primary[500],
34
+ a.fontSize.base,
35
+ open && a.textColors.primary[700],
36
+ ]), children: _jsx(DropdownMenuPrimitive.SubTrigger, { ref: ref, ...props, children: _jsxs(View, { style: [
37
+ inset && gap[2],
38
+ layout.flex.row,
39
+ layout.flex.alignCenter,
40
+ p[2],
41
+ pr[8],
42
+ ], children: [children, _jsx(View, { style: [a.layout.position.absolute, a.position.right[1]], children: _jsx(Icon, { size: 18, color: colors.gray[200] }) })] }) }) }));
43
+ });
44
+ export const DropdownMenuSubContent = forwardRef((props, ref) => {
45
+ return (_jsx(DropdownMenuPrimitive.SubContent, { ref: ref, style: [
46
+ a.zIndex[50],
47
+ a.sizes.minWidth[32],
48
+ a.overflow.hidden,
49
+ a.radius.all.md,
50
+ a.borders.width.thin,
51
+ a.borders.color.gray[600],
52
+ mt[1],
53
+ bg.black,
54
+ p[1],
55
+ a.shadows.md,
56
+ ], ...props }));
57
+ });
58
+ export const DropdownMenuContent = forwardRef(({ overlayStyle, portalHost, ...props }, ref) => {
59
+ return (_jsx(DropdownMenuPrimitive.Portal, { hostName: portalHost, children: _jsx(DropdownMenuPrimitive.Overlay, { style: [
60
+ Platform.OS !== "web" ? StyleSheet.absoluteFill : undefined,
61
+ overlayStyle,
62
+ ], children: _jsx(DropdownMenuPrimitive.Content, { ref: ref, style: [
63
+ a.zIndex[50],
64
+ a.sizes.minWidth[32],
65
+ a.sizes.maxWidth[64],
66
+ a.overflow.hidden,
67
+ a.radius.all.md,
68
+ a.borders.width.thin,
69
+ a.borders.color.gray[800],
70
+ bg.gray[950],
71
+ p[2],
72
+ a.shadows.md,
73
+ ], ...props }) }) }));
74
+ });
75
+ export const ResponsiveDropdownMenuContent = forwardRef(({ children, ...props }, ref) => {
76
+ const { width } = useWindowDimensions();
77
+ // On web, you might want to always use the normal dropdown
78
+ const isBottomSheet = Platform.OS !== "web" && width < 800;
79
+ if (isBottomSheet) {
80
+ return (_jsx(DropdownMenuBottomSheet, { ref: ref, ...props, children: children }));
81
+ }
82
+ return (_jsx(DropdownMenuContent, { ref: ref, ...props, children: children }));
83
+ });
84
+ export const DropdownMenuItem = forwardRef(({ inset, disabled, style, children, ...props }, ref) => {
85
+ return (_jsx(Pressable, { ...props, children: _jsx(TextClassContext.Provider, { value: objectFromObjects([a.textColors.gray[900], a.fontSize.base]), children: _jsx(View, { style: [
86
+ a.layout.flex.row,
87
+ a.layout.flex.alignCenter,
88
+ a.radius.all.sm,
89
+ py[1],
90
+ pl[2],
91
+ pr[2],
92
+ ], children: typeof children === "function"
93
+ ? children({ pressed: true })
94
+ : children }) }) }));
95
+ });
96
+ export const DropdownMenuCheckboxItem = forwardRef(({ children, checked, ...props }, ref) => {
97
+ return (_jsx(DropdownMenuPrimitive.CheckboxItem, { ref: ref, checked: checked, closeOnPress: props.closeOnPress || false, ...props, children: _jsxs(View, { style: [
98
+ a.layout.flex.row,
99
+ a.layout.flex.alignCenter,
100
+ a.radius.all.sm,
101
+ py[1],
102
+ pl[2],
103
+ pr[2],
104
+ pr[8],
105
+ ], children: [children, _jsx(View, { style: [pl[1], layout.position.absolute, right[1]], children: checked ? (_jsx(CheckCircle, { size: 14, strokeWidth: 3, color: "white" })) : (_jsx(Circle, { size: 14, strokeWidth: 3, color: a.colors.gray[400] })) })] }) }));
106
+ });
107
+ export const DropdownMenuRadioItem = forwardRef(({ children, ...props }, ref) => {
108
+ return (_jsx(DropdownMenuPrimitive.RadioItem, { ref: ref, closeOnPress: props.closeOnPress || false, ...props, children: _jsxs(View, { style: [
109
+ a.layout.flex.row,
110
+ a.layout.flex.alignCenter,
111
+ a.radius.all.sm,
112
+ py[1],
113
+ pl[2],
114
+ pr[1],
115
+ ], children: [_jsx(View, { style: [pl[1], layout.position.absolute, right[1]], children: _jsx(DropdownMenuPrimitive.ItemIndicator, { children: _jsx(Check, { size: 14, strokeWidth: 3, color: "white" }) }) }), children] }) }));
116
+ });
117
+ export const DropdownMenuLabel = forwardRef(({ inset, ...props }, ref) => {
118
+ return (_jsx(Text, { ref: ref, style: [
119
+ px[2],
120
+ py[2],
121
+ a.textColors.gray[200],
122
+ a.fontSize.base,
123
+ inset && gap[2],
124
+ ], ...props }));
125
+ });
126
+ export const DropdownMenuSeparator = forwardRef((props, ref) => {
127
+ return (_jsx(View, { ref: ref, style: [mx[2], h[0.5] || { height: 0.5 }, bg.gray[800]], ...props }));
128
+ });
129
+ export function DropdownMenuShortcut(props) {
130
+ return (_jsx(Text, { style: [
131
+ ml.auto,
132
+ a.textColors.gray[500],
133
+ a.fontSize.sm,
134
+ a.letterSpacing.widest,
135
+ ], ...props }));
136
+ }
137
+ export const DropdownMenuGroup = forwardRef((props, ref) => {
138
+ const { inset, title, children, ...rest } = props;
139
+ return (_jsxs(View, { style: [pt[2], inset ? gap[2] : gap[1]], ref: ref, ...rest, children: [title && (_jsx(Text, { style: [textColors.gray[400], pb[1], pl[2]], children: title })), _jsx(View, { style: [
140
+ bg.gray[900],
141
+ Platform.OS === "web" ? px[2] : p[2],
142
+ gap[2],
143
+ { borderRadius: borderRadius.lg, gap: 10 },
144
+ ], children: children })] }));
145
+ });
146
+ export const DropdownMenuInfo = forwardRef(({ description, ...props }, ref) => {
147
+ return (_jsx(Text, { style: [textColors.gray[400], pt[1], pl[2], pb[2], fontSize.sm], children: description }));
148
+ });
@@ -0,0 +1,22 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useTheme } from "../../lib/theme";
3
+ // Size mapping
4
+ const sizeMap = {
5
+ sm: 16,
6
+ md: 20,
7
+ lg: 24,
8
+ xl: 32,
9
+ };
10
+ // HOC to create themed icons
11
+ export function createThemedIcon(IconComponent) {
12
+ return ({ variant = "default", size = "md", color, ...restProps }) => {
13
+ let theme = useTheme(); // Ensure theme is available
14
+ // Calculate size
15
+ const iconSize = typeof size === "number" ? size : sizeMap[size];
16
+ // Calculate color if not provided using atoms
17
+ const iconColor = color ||
18
+ theme.theme.colors[variant] ||
19
+ theme.theme.colors.secondaryForeground;
20
+ return (_jsx(IconComponent, { size: iconSize, color: iconColor, ...restProps }));
21
+ };
22
+ }
@@ -0,0 +1,22 @@
1
+ // Export primitive components
2
+ export * from "./primitives/button";
3
+ export * from "./primitives/input";
4
+ export * from "./primitives/modal";
5
+ export * from "./primitives/text";
6
+ // Export styled components
7
+ export * from "./button";
8
+ export * from "./dialog";
9
+ export * from "./dropdown";
10
+ export * from "./icons";
11
+ export * from "./input";
12
+ export * from "./loader";
13
+ export * from "./resizeable";
14
+ export * from "./text";
15
+ export * from "./toast";
16
+ export * from "./view";
17
+ // Component collections for easy importing
18
+ export { ButtonPrimitive } from "./primitives/button";
19
+ export { InputPrimitive } from "./primitives/input";
20
+ export { ModalPrimitive } from "./primitives/modal";
21
+ export { TextPrimitive } from "./primitives/text";
22
+ export * from "../../lib/theme";
@@ -0,0 +1,202 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cva } from "class-variance-authority";
3
+ import React, { forwardRef } from "react";
4
+ import { Platform, StyleSheet, TouchableWithoutFeedback } from "react-native";
5
+ import { useTheme } from "../../lib/theme/theme";
6
+ import { InputPrimitive } from "./primitives/input";
7
+ const inputVariants = cva("", {
8
+ variants: {
9
+ variant: {
10
+ default: "default",
11
+ filled: "filled",
12
+ underlined: "underlined",
13
+ },
14
+ size: {
15
+ sm: "sm",
16
+ md: "md",
17
+ lg: "lg",
18
+ },
19
+ },
20
+ defaultVariants: {
21
+ variant: "default",
22
+ size: "md",
23
+ },
24
+ });
25
+ export const Input = forwardRef(({ variant = "default", size = "md", label, description, error, required = false, leftAddon, rightAddon, disabled = false, containerStyle, inputStyle, ...props }, ref) => {
26
+ const { theme } = useTheme();
27
+ const [isFocused, setIsFocused] = React.useState(false);
28
+ const inputRef = React.useRef(null);
29
+ // Create dynamic styles based on theme
30
+ const styles = React.useMemo(() => createStyles(theme), [theme]);
31
+ // Get variant and size styles
32
+ const containerStyles = React.useMemo(() => {
33
+ const variantStyle = styles[`${variant}Container`];
34
+ const sizeStyle = styles[`${size}Container`];
35
+ const focusStyle = isFocused ? styles.focusedContainer : null;
36
+ return [variantStyle, sizeStyle, focusStyle];
37
+ }, [variant, size, styles, isFocused]);
38
+ const textStyles = React.useMemo(() => {
39
+ const variantTextStyle = styles[`${variant}Input`];
40
+ const sizeTextStyle = styles[`${size}Input`];
41
+ return [variantTextStyle, sizeTextStyle];
42
+ }, [variant, size, styles]);
43
+ const handleFocus = React.useCallback((event) => {
44
+ setIsFocused(true);
45
+ if (props.onFocus) {
46
+ props.onFocus(event);
47
+ }
48
+ }, [props.onFocus]);
49
+ const handleBlur = React.useCallback((event) => {
50
+ setIsFocused(false);
51
+ if (props.onBlur) {
52
+ props.onBlur(event);
53
+ }
54
+ }, [props.onBlur]);
55
+ const handleContainerPress = React.useCallback(() => {
56
+ if (inputRef.current && !disabled) {
57
+ inputRef.current.focus();
58
+ }
59
+ }, [disabled]);
60
+ const hasAddons = leftAddon || rightAddon;
61
+ if (hasAddons) {
62
+ return (_jsxs(InputPrimitive.Group, { children: [label && (_jsx(InputPrimitive.Label, { required: required, disabled: disabled, error: !!error, children: label })), _jsx(TouchableWithoutFeedback, { onPress: handleContainerPress, children: _jsxs(InputPrimitive.Container, { focused: isFocused, error: !!error, disabled: disabled, style: [containerStyles, containerStyle, { padding: 0 }], children: [leftAddon && (_jsx(InputPrimitive.Addon, { position: "left", children: leftAddon })), _jsx(InputPrimitive.Root, { ref: (node) => {
63
+ inputRef.current = node;
64
+ if (ref) {
65
+ if (typeof ref === "function") {
66
+ ref(node);
67
+ }
68
+ else {
69
+ ref.current = node;
70
+ }
71
+ }
72
+ }, disabled: disabled, error: !!error, onFocus: handleFocus, onBlur: handleBlur, style: [
73
+ textStyles,
74
+ styles.inputInContainer,
75
+ inputStyle,
76
+ { outline: "none" },
77
+ ], placeholderTextColor: disabled ? theme.colors.textDisabled : theme.colors.textMuted, ...props }), rightAddon && (_jsx(InputPrimitive.Addon, { position: "right", children: rightAddon }))] }) }), description && !error && (_jsx(InputPrimitive.Description, { disabled: disabled, children: description })), _jsx(InputPrimitive.Error, { visible: !!error, children: error })] }));
78
+ }
79
+ return (_jsxs(InputPrimitive.Group, { children: [label && (_jsx(InputPrimitive.Label, { required: required, disabled: disabled, error: !!error, children: label })), _jsx(InputPrimitive.Root, { ref: (node) => {
80
+ inputRef.current = node;
81
+ if (ref) {
82
+ if (typeof ref === "function") {
83
+ ref(node);
84
+ }
85
+ else {
86
+ ref.current = node;
87
+ }
88
+ }
89
+ }, disabled: disabled, error: !!error, onFocus: handleFocus, onBlur: handleBlur, style: [containerStyles, textStyles, containerStyle, inputStyle], placeholderTextColor: disabled ? theme.colors.textDisabled : theme.colors.textMuted, ...props }), description && !error && (_jsx(InputPrimitive.Description, { disabled: disabled, children: description })), _jsx(InputPrimitive.Error, { visible: !!error, children: error })] }));
90
+ });
91
+ Input.displayName = "Input";
92
+ // Create theme-aware styles
93
+ function createStyles(theme) {
94
+ return StyleSheet.create({
95
+ // Variant styles for containers
96
+ defaultContainer: {
97
+ backgroundColor: theme.colors.background,
98
+ borderWidth: 1,
99
+ borderColor: theme.colors.border,
100
+ borderRadius: theme.borderRadius.md,
101
+ },
102
+ filledContainer: {
103
+ backgroundColor: theme.colors.muted,
104
+ borderWidth: 0,
105
+ borderRadius: theme.borderRadius.md,
106
+ },
107
+ underlinedContainer: {
108
+ backgroundColor: "transparent",
109
+ borderWidth: 0,
110
+ borderBottomWidth: 1,
111
+ borderBottomColor: theme.colors.border,
112
+ borderRadius: 0,
113
+ paddingHorizontal: 0,
114
+ },
115
+ // Variant styles for inputs
116
+ defaultInput: {
117
+ color: theme.colors.text,
118
+ backgroundColor: "transparent",
119
+ },
120
+ filledInput: {
121
+ color: theme.colors.text,
122
+ backgroundColor: "transparent",
123
+ },
124
+ underlinedInput: {
125
+ color: theme.colors.text,
126
+ backgroundColor: "transparent",
127
+ },
128
+ // Size styles for containers
129
+ smContainer: {
130
+ paddingHorizontal: theme.spacing[3],
131
+ paddingVertical: theme.spacing[2],
132
+ minHeight: theme.touchTargets.minimum - 8,
133
+ },
134
+ mdContainer: {
135
+ paddingHorizontal: theme.spacing[3],
136
+ paddingVertical: theme.spacing[3],
137
+ minHeight: theme.touchTargets.minimum,
138
+ },
139
+ lgContainer: {
140
+ paddingHorizontal: theme.spacing[4],
141
+ paddingVertical: theme.spacing[4],
142
+ minHeight: theme.touchTargets.comfortable,
143
+ },
144
+ // Size styles for inputs
145
+ smInput: {
146
+ fontSize: 14,
147
+ lineHeight: 18,
148
+ ...Platform.select({
149
+ ios: {
150
+ paddingVertical: 0,
151
+ },
152
+ android: {
153
+ paddingVertical: 0,
154
+ textAlignVertical: "center",
155
+ },
156
+ }),
157
+ },
158
+ mdInput: {
159
+ fontSize: 16,
160
+ lineHeight: 20,
161
+ ...Platform.select({
162
+ ios: {
163
+ paddingVertical: 0,
164
+ },
165
+ android: {
166
+ paddingVertical: 0,
167
+ textAlignVertical: "center",
168
+ },
169
+ }),
170
+ },
171
+ lgInput: {
172
+ fontSize: 18,
173
+ lineHeight: 22,
174
+ ...Platform.select({
175
+ ios: {
176
+ paddingVertical: 0,
177
+ },
178
+ android: {
179
+ paddingVertical: 0,
180
+ textAlignVertical: "center",
181
+ },
182
+ }),
183
+ },
184
+ // Special style for inputs inside containers
185
+ inputInContainer: {
186
+ flex: 1,
187
+ paddingHorizontal: 0,
188
+ paddingVertical: 0,
189
+ borderWidth: 0,
190
+ backgroundColor: "transparent",
191
+ minHeight: "auto",
192
+ borderRadius: 0,
193
+ },
194
+ // Focus styles
195
+ focusedContainer: {
196
+ borderColor: theme.colors.primary,
197
+ borderWidth: 1,
198
+ },
199
+ });
200
+ }
201
+ // Export input variants for external use
202
+ export { inputVariants };
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { ActivityIndicator as RNActivityIndicator } from "react-native";
3
+ import { useTheme } from "../../lib/theme";
4
+ export function Loader(props) {
5
+ const { theme } = useTheme();
6
+ return _jsx(RNActivityIndicator, { color: theme.colors.primary, ...props });
7
+ }
@@ -0,0 +1,121 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import React, { forwardRef } from "react";
3
+ import { StyleSheet, Text, TouchableOpacity, View, } from "react-native";
4
+ // Button root primitive - handles all touch interactions
5
+ export const ButtonRoot = forwardRef(({ children, disabled = false, loading = false, onPress, onPressIn, onPressOut, onLongPress, accessibilityRole = "button", accessibilityLabel, accessibilityHint, accessibilityState, testID, style, activeOpacity = 0.7, ...props }, ref) => {
6
+ const handlePress = React.useCallback((event) => {
7
+ if (!disabled && !loading && onPress) {
8
+ onPress(event);
9
+ }
10
+ }, [disabled, loading, onPress]);
11
+ const handlePressIn = React.useCallback((event) => {
12
+ if (!disabled && !loading && onPressIn) {
13
+ onPressIn(event);
14
+ }
15
+ }, [disabled, loading, onPressIn]);
16
+ const handlePressOut = React.useCallback((event) => {
17
+ if (!disabled && !loading && onPressOut) {
18
+ onPressOut(event);
19
+ }
20
+ }, [disabled, loading, onPressOut]);
21
+ const handleLongPress = React.useCallback((event) => {
22
+ if (!disabled && !loading && onLongPress) {
23
+ onLongPress(event);
24
+ }
25
+ }, [disabled, loading, onLongPress]);
26
+ return (_jsx(TouchableOpacity, { ref: ref, onPress: handlePress, onPressIn: handlePressIn, onPressOut: handlePressOut, onLongPress: handleLongPress, disabled: disabled || loading, activeOpacity: disabled || loading ? 1 : activeOpacity, accessibilityRole: accessibilityRole, accessibilityLabel: accessibilityLabel, accessibilityHint: accessibilityHint, accessibilityState: {
27
+ disabled: disabled || loading,
28
+ busy: loading,
29
+ ...accessibilityState,
30
+ }, testID: testID, style: [
31
+ primitiveStyles.button,
32
+ (disabled || loading) && primitiveStyles.disabled,
33
+ style,
34
+ ], ...props, children: children }));
35
+ });
36
+ ButtonRoot.displayName = "ButtonRoot";
37
+ export const ButtonText = forwardRef(({ children, disabled, loading, style, ...props }, ref) => {
38
+ return (_jsx(Text, { ref: ref, style: [
39
+ primitiveStyles.text,
40
+ (disabled || loading) && primitiveStyles.textDisabled,
41
+ style,
42
+ ], ...props, children: children }));
43
+ });
44
+ ButtonText.displayName = "ButtonText";
45
+ export const ButtonIcon = forwardRef(({ children, position = "left", disabled, loading, style, ...props }, ref) => {
46
+ return (_jsx(View, { ref: ref, style: [
47
+ primitiveStyles.icon,
48
+ (disabled || loading) && primitiveStyles.iconDisabled,
49
+ style,
50
+ ], ...props, children: children }));
51
+ });
52
+ ButtonIcon.displayName = "ButtonIcon";
53
+ export const ButtonLoading = forwardRef(({ children, visible = false, style, ...props }, ref) => {
54
+ if (!visible)
55
+ return null;
56
+ return (_jsx(View, { ref: ref, style: [primitiveStyles.loading, style], ...props, children: children }));
57
+ });
58
+ ButtonLoading.displayName = "ButtonLoading";
59
+ export const ButtonContent = forwardRef(({ children, direction = "row", align = "center", justify = "center", style, ...props }, ref) => {
60
+ return (_jsx(View, { ref: ref, style: [
61
+ primitiveStyles.content,
62
+ {
63
+ flexDirection: direction,
64
+ alignItems: align,
65
+ justifyContent: justify,
66
+ },
67
+ style,
68
+ ], ...props, children: children }));
69
+ });
70
+ ButtonContent.displayName = "ButtonContent";
71
+ // Primitive styles (minimal, unstyled)
72
+ const primitiveStyles = StyleSheet.create({
73
+ button: {
74
+ flexDirection: "row",
75
+ alignItems: "center",
76
+ justifyContent: "center",
77
+ minHeight: 44, // iOS minimum touch target
78
+ minWidth: 44,
79
+ },
80
+ disabled: {
81
+ opacity: 0.5,
82
+ },
83
+ content: {
84
+ flexDirection: "row",
85
+ alignItems: "center",
86
+ justifyContent: "center",
87
+ flex: 1,
88
+ },
89
+ text: {
90
+ textAlign: "center",
91
+ },
92
+ textDisabled: {
93
+ opacity: 0.5,
94
+ },
95
+ icon: {
96
+ alignItems: "center",
97
+ justifyContent: "center",
98
+ },
99
+ iconLeft: {
100
+ marginRight: 8,
101
+ },
102
+ iconRight: {
103
+ marginLeft: 8,
104
+ },
105
+ iconDisabled: {
106
+ opacity: 0.5,
107
+ },
108
+ loading: {
109
+ position: "absolute",
110
+ alignItems: "center",
111
+ justifyContent: "center",
112
+ },
113
+ });
114
+ // Export primitive collection
115
+ export const ButtonPrimitive = {
116
+ Root: ButtonRoot,
117
+ Text: ButtonText,
118
+ Icon: ButtonIcon,
119
+ Loading: ButtonLoading,
120
+ Content: ButtonContent,
121
+ };