@streamplace/components 0.7.26 → 0.7.29

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 (61) hide show
  1. package/dist/components/chat/chat-box.js +2 -2
  2. package/dist/components/chat/chat.js +1 -1
  3. package/dist/components/mobile-player/ui/autoplay-button.js +1 -0
  4. package/dist/components/mobile-player/ui/viewer-context-menu.js +1 -1
  5. package/dist/components/mobile-player/ui/viewer-loading-overlay.js +2 -2
  6. package/dist/components/mobile-player/use-webrtc.js +37 -1
  7. package/dist/components/mobile-player/video.native.js +10 -1
  8. package/dist/components/ui/button.js +107 -155
  9. package/dist/components/ui/dialog.js +83 -116
  10. package/dist/components/ui/dropdown.js +41 -18
  11. package/dist/components/ui/input.js +53 -128
  12. package/dist/components/ui/primitives/button.js +0 -2
  13. package/dist/components/ui/primitives/modal.js +2 -2
  14. package/dist/components/ui/primitives/text.js +48 -8
  15. package/dist/components/ui/text.js +37 -66
  16. package/dist/components/ui/toast.js +78 -40
  17. package/dist/components/ui/view.js +28 -41
  18. package/dist/crypto-polyfill.js +0 -0
  19. package/dist/crypto-polyfill.native.js +24 -0
  20. package/dist/index.js +1 -0
  21. package/dist/lib/theme/index.js +1 -2
  22. package/dist/lib/theme/theme.js +106 -54
  23. package/dist/lib/theme/tokens.js +94 -1
  24. package/dist/livestream-store/chat.js +0 -2
  25. package/dist/livestream-store/stream-key.js +1 -1
  26. package/dist/player-store/player-provider.js +10 -2
  27. package/dist/player-store/single-player-provider.js +1 -1
  28. package/dist/streamplace-store/stream.js +1 -1
  29. package/dist/ui/index.js +2 -3
  30. package/node-compile-cache/v22.15.0-x64-efe9a9df-0/37be0eec +0 -0
  31. package/package.json +3 -2
  32. package/src/components/chat/chat-box.tsx +6 -3
  33. package/src/components/chat/chat.tsx +1 -0
  34. package/src/components/mobile-player/ui/autoplay-button.tsx +1 -0
  35. package/src/components/mobile-player/ui/viewer-context-menu.tsx +2 -2
  36. package/src/components/mobile-player/ui/viewer-loading-overlay.tsx +2 -2
  37. package/src/components/mobile-player/use-webrtc.tsx +41 -1
  38. package/src/components/mobile-player/video.native.tsx +19 -4
  39. package/src/components/ui/button.tsx +110 -172
  40. package/src/components/ui/dialog.tsx +96 -138
  41. package/src/components/ui/dropdown.tsx +60 -22
  42. package/src/components/ui/input.tsx +57 -144
  43. package/src/components/ui/primitives/button.tsx +0 -2
  44. package/src/components/ui/primitives/modal.tsx +0 -2
  45. package/src/components/ui/primitives/text.tsx +51 -8
  46. package/src/components/ui/text.tsx +42 -67
  47. package/src/components/ui/toast.tsx +108 -90
  48. package/src/components/ui/view.tsx +27 -41
  49. package/src/crypto-polyfill.native.tsx +24 -0
  50. package/src/crypto-polyfill.tsx +0 -0
  51. package/src/index.tsx +2 -0
  52. package/src/lib/theme/index.ts +0 -2
  53. package/src/lib/theme/theme.tsx +179 -72
  54. package/src/lib/theme/tokens.ts +97 -0
  55. package/src/livestream-store/chat.tsx +0 -3
  56. package/src/livestream-store/stream-key.tsx +1 -1
  57. package/src/player-store/player-provider.tsx +13 -1
  58. package/src/player-store/single-player-provider.tsx +1 -1
  59. package/src/streamplace-store/stream.tsx +1 -1
  60. package/src/ui/index.ts +0 -2
  61. package/tsconfig.tsbuildinfo +1 -1
@@ -290,7 +290,7 @@ function ChatBox({ isPopout, chatBoxStyle, emojiData, setIsChatVisible, }) {
290
290
  atoms_1.mb[2],
291
291
  atoms_1.gap.all[2],
292
292
  { justifyContent: "flex-end" },
293
- ], children: [(0, jsx_runtime_1.jsx)(__1.Button, { variant: "secondary", style: { borderRadius: 16, height: 36, maxWidth: 36 }, onPress: () => {
293
+ ], children: [(0, jsx_runtime_1.jsx)(__1.Button, { variant: "secondary", style: { borderRadius: 16, maxWidth: 44, aspectRatio: 1 }, "aria-label": "Insert Mention", onPress: () => {
294
294
  // if the last character is not @, add it
295
295
  !message.endsWith("@") && setMessage(message + "@");
296
296
  // get all the text after the last @
@@ -302,7 +302,7 @@ function ChatBox({ isPopout, chatBoxStyle, emojiData, setIsChatVisible, }) {
302
302
  textAreaRef.current?.focus();
303
303
  }, children: (0, jsx_runtime_1.jsx)(lucide_react_native_1.AtSignIcon, { size: 20, color: "white" }) }), (0, jsx_runtime_1.jsx)(react_native_1.Pressable, { onHoverOut: () => {
304
304
  setEmojiIconIndex(Math.floor(Math.random() * COOL_EMOJI_LIST.length));
305
- }, children: (0, jsx_runtime_1.jsx)(__1.Button, { variant: "secondary", style: { borderRadius: 16, height: 36, maxWidth: 36 }, onPress: () => setShowEmojiSelector(!showEmojiSelector), children: (0, jsx_runtime_1.jsx)(__1.Text, { children: COOL_EMOJI_LIST[emojiIconIndex] }) }) }), !isPopout && ((0, jsx_runtime_1.jsx)(__1.Button, { variant: "secondary", style: { borderRadius: 16, height: 36, maxWidth: 36 }, onPress: () => {
305
+ }, children: (0, jsx_runtime_1.jsx)(__1.Button, { variant: "secondary", "aria-label": "Insert Emoji", style: { borderRadius: 16, maxWidth: 44, aspectRatio: 1 }, onPress: () => setShowEmojiSelector(!showEmojiSelector), children: (0, jsx_runtime_1.jsx)(__1.Text, { children: COOL_EMOJI_LIST[emojiIconIndex] }) }) }), !isPopout && ((0, jsx_runtime_1.jsx)(__1.Button, { variant: "secondary", "aria-label": "Popout Chat", style: { borderRadius: 16, maxWidth: 44, aspectRatio: 1 }, onPress: () => {
306
306
  if (!linfo)
307
307
  return;
308
308
  const u = new URL(window.location.href);
@@ -156,5 +156,5 @@ function Chat({ shownMessages = SHOWN_MSGS, style: propsStyle, canModerate = fal
156
156
  atoms_1.flex.grow[1],
157
157
  atoms_1.flex.shrink[1],
158
158
  { minWidth: 0, maxWidth: "100%" },
159
- ], data: chat.slice(0, shownMessages), inverted: true, keyExtractor: keyExtractor, renderItem: ({ item, index }) => ((0, jsx_runtime_1.jsx)(ChatLine, { item: item, canModerate: canModerate })), removeClippedSubviews: true, maxToRenderPerBatch: 10, initialNumToRender: 10, updateCellsBatchingPeriod: 50, onScroll: handleScroll, scrollEventThrottle: 16 }), (0, jsx_runtime_1.jsx)(mod_view_1.ModView, {})] }));
159
+ ], data: chat.slice(0, shownMessages), inverted: true, keyExtractor: keyExtractor, renderItem: ({ item, index }) => ((0, jsx_runtime_1.jsx)(ChatLine, { item: item, canModerate: canModerate })), removeClippedSubviews: true, maxToRenderPerBatch: 10, initialNumToRender: 10, updateCellsBatchingPeriod: 50, onScroll: handleScroll, scrollEventThrottle: 16, nestedScrollEnabled: true }), (0, jsx_runtime_1.jsx)(mod_view_1.ModView, {})] }));
160
160
  }
@@ -19,6 +19,7 @@ function AutoplayButton() {
19
19
  .play()
20
20
  .then(() => {
21
21
  setAutoplayFailed(false);
22
+ setMuted(false);
22
23
  setUserInteraction();
23
24
  })
24
25
  .catch((err) => {
@@ -33,7 +33,7 @@ function ContextMenu({ dropdownPortalContainer, }) {
33
33
  const DropdownMenuContent = isMobile
34
34
  ? ui_1.ResponsiveDropdownMenuContent
35
35
  : ui_1.DropdownMenuContentWithoutPortal;
36
- return ((0, jsx_runtime_1.jsxs)(ui_1.DropdownMenu, { children: [(0, jsx_runtime_1.jsx)(ui_1.DropdownMenuTrigger, { children: (0, jsx_runtime_1.jsx)(lucide_react_native_1.Settings, { color: theme_1.colors.gray[200] }) }), (0, jsx_runtime_1.jsx)(Portal, { container: dropdownPortalContainer, children: (0, jsx_runtime_1.jsxs)(DropdownMenuContent, { side: "top", align: "end", children: [(0, jsx_runtime_1.jsx)(ui_1.DropdownMenuGroup, { title: "Resolution", children: (0, jsx_runtime_1.jsxs)(ui_1.DropdownMenuRadioGroup, { value: quality, onValueChange: setQuality, children: [(0, jsx_runtime_1.jsx)(ui_1.DropdownMenuRadioItem, { value: "source", children: (0, jsx_runtime_1.jsx)(ui_1.Text, { children: "Source (Original Quality)" }) }), qualities.map((r) => ((0, jsx_runtime_1.jsx)(ui_1.DropdownMenuRadioItem, { value: r.name, children: (0, jsx_runtime_1.jsx)(ui_1.Text, { children: r.name }) })))] }) }), (0, jsx_runtime_1.jsx)(ui_1.DropdownMenuGroup, { title: "Advanced", children: (0, jsx_runtime_1.jsx)(ui_1.DropdownMenuCheckboxItem, { checked: lowLatency, onCheckedChange: () => setLowLatency(!lowLatency), children: (0, jsx_runtime_1.jsx)(ui_1.Text, { children: "Low Latency" }) }) }), (0, jsx_runtime_1.jsx)(ui_1.DropdownMenuInfo, { description: "Reduces the delay between video and chat for a more real-time experience." }), (0, jsx_runtime_1.jsx)(ui_1.DropdownMenuGroup, { children: (0, jsx_runtime_1.jsx)(ui_1.DropdownMenuCheckboxItem, { checked: debugInfo, onCheckedChange: () => setShowDebugInfo(!debugInfo), children: (0, jsx_runtime_1.jsx)(ui_1.Text, { children: "Show Debug Info" }) }) }), (0, jsx_runtime_1.jsx)(ui_1.DropdownMenuGroup, { title: "Report", children: (0, jsx_runtime_1.jsx)(ReportButton, { livestream: livestream, setReportModalOpen: setReportModalOpen, setReportSubject: setReportSubject }) })] }) })] }));
36
+ return ((0, jsx_runtime_1.jsxs)(ui_1.DropdownMenu, { children: [(0, jsx_runtime_1.jsx)(ui_1.DropdownMenuTrigger, { children: (0, jsx_runtime_1.jsx)(lucide_react_native_1.Menu, { color: theme_1.colors.gray[200] }) }), (0, jsx_runtime_1.jsx)(Portal, { container: dropdownPortalContainer, children: (0, jsx_runtime_1.jsxs)(DropdownMenuContent, { side: "top", align: "end", children: [(0, jsx_runtime_1.jsx)(ui_1.DropdownMenuGroup, { title: "Resolution", children: (0, jsx_runtime_1.jsxs)(ui_1.DropdownMenuRadioGroup, { value: quality, onValueChange: setQuality, children: [(0, jsx_runtime_1.jsx)(ui_1.DropdownMenuRadioItem, { value: "source", children: (0, jsx_runtime_1.jsx)(ui_1.Text, { children: "Source (Original Quality)" }) }), qualities.map((r) => ((0, jsx_runtime_1.jsx)(ui_1.DropdownMenuRadioItem, { value: r.name, children: (0, jsx_runtime_1.jsx)(ui_1.Text, { children: r.name }) })))] }) }), (0, jsx_runtime_1.jsx)(ui_1.DropdownMenuGroup, { title: "Advanced", children: (0, jsx_runtime_1.jsx)(ui_1.DropdownMenuCheckboxItem, { checked: lowLatency, onCheckedChange: () => setLowLatency(!lowLatency), children: (0, jsx_runtime_1.jsx)(ui_1.Text, { children: "Low Latency" }) }) }), (0, jsx_runtime_1.jsx)(ui_1.DropdownMenuInfo, { description: "Reduces the delay between video and chat for a more real-time experience." }), (0, jsx_runtime_1.jsx)(ui_1.DropdownMenuGroup, { children: (0, jsx_runtime_1.jsx)(ui_1.DropdownMenuCheckboxItem, { checked: debugInfo, onCheckedChange: () => setShowDebugInfo(!debugInfo), children: (0, jsx_runtime_1.jsx)(ui_1.Text, { children: "Show Debug Info" }) }) }), (0, jsx_runtime_1.jsx)(ui_1.DropdownMenuGroup, { title: "Report", children: (0, jsx_runtime_1.jsx)(ReportButton, { livestream: livestream, setReportModalOpen: setReportModalOpen, setReportSubject: setReportSubject }) })] }) })] }));
37
37
  }
38
38
  function ReportButton({ livestream, setReportModalOpen, setReportSubject, }) {
39
39
  const { onOpenChange } = (0, dropdown_menu_1.useRootContext)();
@@ -9,7 +9,7 @@ const react_native_reanimated_1 = tslib_1.__importStar(require("react-native-rea
9
9
  const __1 = require("../../..");
10
10
  function ViewerLoadingOverlay() {
11
11
  const status = (0, __1.usePlayerStore)((x) => x.status);
12
- const theme = (0, __1.useTheme)();
12
+ const { theme, zero: zt } = (0, __1.useTheme)();
13
13
  const opacity = (0, react_native_reanimated_1.useSharedValue)(0);
14
14
  (0, react_1.useEffect)(() => {
15
15
  if (status === __1.PlayerStatus.PLAYING || status === __1.PlayerStatus.SUSPEND) {
@@ -32,7 +32,7 @@ function ViewerLoadingOverlay() {
32
32
  }
33
33
  let spinner = (0, jsx_runtime_1.jsx)(__1.Loader, { size: "large" });
34
34
  if (status === __1.PlayerStatus.PAUSE) {
35
- spinner = (0, jsx_runtime_1.jsx)(lucide_react_native_1.Play, { size: "$12", color: theme.styles.text.primary["color"] });
35
+ spinner = (0, jsx_runtime_1.jsx)(lucide_react_native_1.Play, { size: "$12", color: theme.colors.foreground });
36
36
  }
37
37
  return ((0, jsx_runtime_1.jsx)(react_native_reanimated_1.default.View, { style: [
38
38
  {
@@ -3,7 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.default = useWebRTC;
4
4
  exports.negotiateConnectionWithClientOffer = negotiateConnectionWithClientOffer;
5
5
  exports.useWebRTCIngest = useWebRTCIngest;
6
+ exports.forceStereoAudio = forceStereoAudio;
7
+ const tslib_1 = require("tslib");
6
8
  const react_1 = require("react");
9
+ const sdpTransform = tslib_1.__importStar(require("sdp-transform"));
7
10
  const __1 = require("../..");
8
11
  const webrtc_primitives_1 = require("./webrtc-primitives");
9
12
  function useWebRTC(endpoint) {
@@ -97,6 +100,11 @@ async function negotiateConnectionWithClientOffer(peerConnection, endpoint, bear
97
100
  offerToReceiveAudio: true,
98
101
  offerToReceiveVideo: true,
99
102
  });
103
+ if (!offer.sdp) {
104
+ throw Error("no SDP in offer");
105
+ }
106
+ const newSDP = forceStereoAudio(offer.sdp);
107
+ offer.sdp = newSDP;
100
108
  /** https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/setLocalDescription */
101
109
  await peerConnection.setLocalDescription(offer);
102
110
  /** Wait for ICE gathering to complete */
@@ -178,6 +186,11 @@ function useWebRTCIngest({ endpoint, }) {
178
186
  const ingestConnectionState = (0, __1.usePlayerStore)((x) => x.ingestConnectionState);
179
187
  const setIngestConnectionState = (0, __1.usePlayerStore)((x) => x.setIngestConnectionState);
180
188
  const storedKey = (0, __1.useStreamKey)();
189
+ (0, react_1.useEffect)(() => {
190
+ if (storedKey?.error) {
191
+ console.error("error creating stream key", storedKey.error);
192
+ }
193
+ }, [storedKey?.error]);
181
194
  const [peerConnection, setPeerConnection] = (0, react_1.useState)(null);
182
195
  const videoTransceiver = (0, react_1.useRef)(null);
183
196
  const audioTransceiver = (0, react_1.useRef)(null);
@@ -211,7 +224,8 @@ function useWebRTCIngest({ endpoint, }) {
211
224
  negotiateConnectionWithClientOffer(peerConnection, endpoint, storedKey.streamKey?.privateKey);
212
225
  });
213
226
  peerConnection.addEventListener("track", (ev) => {
214
- console.log(ev);
227
+ console.log(`got peerconnection track with ${ev.track.kind}`, ev.track.id);
228
+ // console.log(ev);
215
229
  });
216
230
  setPeerConnection(peerConnection);
217
231
  return () => {
@@ -241,3 +255,25 @@ function useWebRTCIngest({ endpoint, }) {
241
255
  }, [peerConnection, mediaStream, ingestLive]);
242
256
  return [mediaStream, setMediaStream];
243
257
  }
258
+ function forceStereoAudio(sdp) {
259
+ const parsedSDP = sdpTransform.parse(sdp);
260
+ const audioMedia = parsedSDP.media.find((m) => m.type === "audio");
261
+ if (!audioMedia) {
262
+ throw Error("no audio media in SDP");
263
+ }
264
+ const opusCodec = audioMedia.rtp.find((c) => c.codec === "opus");
265
+ if (!opusCodec) {
266
+ throw Error("no opus codec in SDP");
267
+ }
268
+ const opusFMTP = audioMedia.fmtp.find((c) => c.payload === opusCodec.payload);
269
+ if (!opusFMTP) {
270
+ throw Error("no opus fmtp in SDP");
271
+ }
272
+ const opusParams = sdpTransform.parseParams(opusFMTP.config);
273
+ opusParams.stereo = 1;
274
+ const newParams = Object.entries(opusParams)
275
+ .map(([k, v]) => `${k}=${v}`)
276
+ .join(";");
277
+ opusFMTP.config = newParams;
278
+ return sdpTransform.write(parsedSDP);
279
+ }
@@ -43,11 +43,20 @@ function VideoNative(props) {
43
43
  importPromise = Promise.resolve().then(() => __importStar(require("./video-async.native")));
44
44
  }
45
45
  const [videoNativeModule, setVideoNativeModule] = (0, react_1.useState)(null);
46
+ const [error, setError] = (0, react_1.useState)(null);
46
47
  (0, react_1.useEffect)(() => {
47
- importPromise?.then((module) => {
48
+ importPromise
49
+ ?.then((module) => {
48
50
  setVideoNativeModule(module);
51
+ })
52
+ .catch((err) => {
53
+ setError(err.message);
49
54
  });
50
55
  }, []);
56
+ if (error) {
57
+ console.error(error);
58
+ return ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: { flex: 1, justifyContent: "center", alignItems: "center" }, children: (0, jsx_runtime_1.jsx)(react_native_1.Text, { children: error }) }));
59
+ }
51
60
  if (!videoNativeModule) {
52
61
  return (0, jsx_runtime_1.jsx)(react_native_1.View, {});
53
62
  }
@@ -7,7 +7,7 @@ const class_variance_authority_1 = require("class-variance-authority");
7
7
  const react_1 = tslib_1.__importStar(require("react"));
8
8
  const react_native_1 = require("react-native");
9
9
  const theme_1 = require("../../lib/theme/theme");
10
- const tokens = tslib_1.__importStar(require("../../lib/theme/tokens"));
10
+ const zero = tslib_1.__importStar(require("../../ui"));
11
11
  const button_1 = require("./primitives/button");
12
12
  const text_1 = require("./primitives/text");
13
13
  // Button variants using class-variance-authority pattern
@@ -36,38 +36,113 @@ const buttonVariants = (0, class_variance_authority_1.cva)("", {
36
36
  });
37
37
  exports.buttonVariants = buttonVariants;
38
38
  exports.Button = (0, react_1.forwardRef)(({ variant = "primary", size = "md", children, leftIcon, rightIcon, loading = false, loadingText, disabled, style, ...props }, ref) => {
39
- const { theme } = (0, theme_1.useTheme)();
40
- // Create dynamic styles based on theme
41
- const styles = (0, react_1.useMemo)(() => createStyles(theme), [theme]);
42
- // Get variant styles
39
+ const { zero: zt, icons } = (0, theme_1.useTheme)();
40
+ // Get variant styles using theme.zero
43
41
  const buttonStyle = (0, react_1.useMemo)(() => {
44
- const variantStyle = styles[`${variant}Button`];
45
- const sizeStyle = styles[`${size}Button`];
46
- return [variantStyle, sizeStyle];
47
- }, [variant, size, styles]);
48
- // Get inner styles for button content
49
- const buttonInnerStyle = (0, react_1.useMemo)(() => {
50
- const sizeInnerStyle = styles[`${size}ButtonInner`];
51
- return sizeInnerStyle;
52
- }, [size, styles]);
53
- const textStyle = react_1.default.useMemo(() => {
54
- const variantTextStyle = styles[`${variant}Text`];
55
- const sizeTextStyle = styles[`${size}Text`];
56
- return [variantTextStyle, sizeTextStyle];
57
- }, [variant, size, styles]);
42
+ switch (variant) {
43
+ case "primary":
44
+ return zt.button.primary;
45
+ case "secondary":
46
+ return zt.button.secondary;
47
+ case "outline":
48
+ return zt.button.outline;
49
+ case "ghost":
50
+ return zt.button.ghost;
51
+ case "destructive":
52
+ return [zt.bg.destructive, zero.shadows.sm];
53
+ case "success":
54
+ return [zt.bg.success, zero.shadows.sm];
55
+ default:
56
+ return zt.button.primary;
57
+ }
58
+ }, [variant, zt]);
59
+ // Get text styles using theme.zero
60
+ const textStyle = (0, react_1.useMemo)(() => {
61
+ switch (variant) {
62
+ case "primary":
63
+ return [zt.text.primaryForeground, { fontWeight: "600" }];
64
+ case "secondary":
65
+ return [zt.text.secondaryForeground, { fontWeight: "500" }];
66
+ case "outline":
67
+ case "ghost":
68
+ return [zt.text.foreground, { fontWeight: "500" }];
69
+ case "destructive":
70
+ return [zt.text.destructiveForeground, { fontWeight: "600" }];
71
+ case "success":
72
+ return [zt.text.successForeground, { fontWeight: "600" }];
73
+ default:
74
+ return [zt.text.primaryForeground, { fontWeight: "600" }];
75
+ }
76
+ }, [variant, zt]);
77
+ // Size styles using theme.zero
78
+ const sizeStyles = (0, react_1.useMemo)(() => {
79
+ switch (size) {
80
+ case "sm":
81
+ return {
82
+ button: [
83
+ zero.px[3],
84
+ zero.py[2],
85
+ { borderRadius: zero.borderRadius.md },
86
+ ],
87
+ inner: { gap: 4 },
88
+ text: zt.text.sm,
89
+ };
90
+ case "lg":
91
+ return {
92
+ button: [
93
+ zero.px[6],
94
+ zero.py[3],
95
+ { borderRadius: zero.borderRadius.md },
96
+ ],
97
+ inner: { gap: 8 },
98
+ text: zt.text.lg,
99
+ };
100
+ case "xl":
101
+ return {
102
+ button: [
103
+ zero.px[8],
104
+ zero.py[4],
105
+ { borderRadius: zero.borderRadius.lg },
106
+ ],
107
+ inner: { gap: 12 },
108
+ text: zt.text.xl,
109
+ };
110
+ case "pill":
111
+ return {
112
+ button: [
113
+ zero.px[4],
114
+ zero.py[2],
115
+ { borderRadius: zero.borderRadius.full },
116
+ ],
117
+ inner: { gap: 4 },
118
+ text: zt.text.sm,
119
+ };
120
+ case "md":
121
+ default:
122
+ return {
123
+ button: [
124
+ zero.px[4],
125
+ zero.py[2],
126
+ { borderRadius: zero.borderRadius.md },
127
+ ],
128
+ inner: { gap: 6 },
129
+ text: zt.text.md,
130
+ };
131
+ }
132
+ }, [size, zt]);
58
133
  const iconSize = react_1.default.useMemo(() => {
59
134
  switch (size) {
60
135
  case "sm":
61
- return 16;
136
+ return icons.size.sm;
62
137
  case "lg":
63
- return 20;
138
+ return icons.size.lg;
64
139
  case "xl":
65
- return 24;
140
+ return icons.size.xl;
66
141
  case "md":
67
142
  default:
68
- return 18;
143
+ return icons.size.md;
69
144
  }
70
- }, [size]);
145
+ }, [size, icons]);
71
146
  const spinnerSize = (0, react_1.useMemo)(() => {
72
147
  switch (size) {
73
148
  case "sm":
@@ -84,140 +159,17 @@ exports.Button = (0, react_1.forwardRef)(({ variant = "primary", size = "md", ch
84
159
  switch (variant) {
85
160
  case "outline":
86
161
  case "ghost":
87
- return theme.colors.primary;
162
+ return icons.color.primary;
88
163
  case "secondary":
89
- return theme.colors.secondaryForeground;
164
+ return icons.color.secondary;
90
165
  case "destructive":
91
- return theme.colors.destructiveForeground;
166
+ return icons.color.destructive;
167
+ case "success":
168
+ return icons.color.success;
92
169
  default:
93
- return theme.colors.primaryForeground;
170
+ return icons.color.default;
94
171
  }
95
- }, [variant, theme.colors]);
96
- return ((0, jsx_runtime_1.jsx)(button_1.ButtonPrimitive.Root, { ref: ref, disabled: disabled || loading, style: [buttonStyle, style], ...props, children: (0, jsx_runtime_1.jsxs)(button_1.ButtonPrimitive.Content, { style: buttonInnerStyle, children: [loading && !leftIcon ? ((0, jsx_runtime_1.jsx)(button_1.ButtonPrimitive.Icon, { position: "left", children: (0, jsx_runtime_1.jsx)(react_native_1.ActivityIndicator, { size: spinnerSize, color: spinnerColor }) })) : leftIcon ? ((0, jsx_runtime_1.jsx)(button_1.ButtonPrimitive.Icon, { position: "left", style: { width: iconSize, height: iconSize }, children: leftIcon })) : null, (0, jsx_runtime_1.jsx)(text_1.TextPrimitive.Root, { style: textStyle, children: loading && loadingText ? loadingText : children }), loading && rightIcon ? ((0, jsx_runtime_1.jsx)(button_1.ButtonPrimitive.Icon, { position: "right", children: (0, jsx_runtime_1.jsx)(react_native_1.ActivityIndicator, { size: spinnerSize, color: spinnerColor }) })) : rightIcon ? ((0, jsx_runtime_1.jsx)(button_1.ButtonPrimitive.Icon, { position: "right", style: { width: iconSize, height: iconSize }, children: rightIcon })) : null] }) }));
172
+ }, [variant, icons]);
173
+ return ((0, jsx_runtime_1.jsx)(button_1.ButtonPrimitive.Root, { ref: ref, disabled: disabled || loading, style: [buttonStyle, sizeStyles.button, style], ...props, children: (0, jsx_runtime_1.jsxs)(button_1.ButtonPrimitive.Content, { style: sizeStyles.inner, children: [loading && !leftIcon ? ((0, jsx_runtime_1.jsx)(button_1.ButtonPrimitive.Icon, { position: "left", children: (0, jsx_runtime_1.jsx)(react_native_1.ActivityIndicator, { size: spinnerSize, color: spinnerColor }) })) : leftIcon ? ((0, jsx_runtime_1.jsx)(button_1.ButtonPrimitive.Icon, { position: "left", style: { width: iconSize, height: iconSize }, children: leftIcon })) : null, (0, jsx_runtime_1.jsx)(text_1.TextPrimitive.Root, { style: [textStyle, sizeStyles.text], children: loading && loadingText ? loadingText : children }), loading && rightIcon ? ((0, jsx_runtime_1.jsx)(button_1.ButtonPrimitive.Icon, { position: "right", children: (0, jsx_runtime_1.jsx)(react_native_1.ActivityIndicator, { size: spinnerSize, color: spinnerColor }) })) : rightIcon ? ((0, jsx_runtime_1.jsx)(button_1.ButtonPrimitive.Icon, { position: "right", style: { width: iconSize, height: iconSize }, children: rightIcon })) : null] }) }));
97
174
  });
98
175
  exports.Button.displayName = "Button";
99
- // Create theme-based styles
100
- function createStyles(theme) {
101
- return react_native_1.StyleSheet.create({
102
- // Variant styles
103
- primaryButton: {
104
- backgroundColor: theme.colors.primary,
105
- borderWidth: 0,
106
- ...theme.shadows.sm,
107
- },
108
- primaryText: {
109
- color: theme.colors.primaryForeground,
110
- fontWeight: "600",
111
- },
112
- secondaryButton: {
113
- backgroundColor: theme.colors.secondary,
114
- borderWidth: 0,
115
- },
116
- secondaryText: {
117
- color: theme.colors.secondaryForeground,
118
- fontWeight: "500",
119
- },
120
- outlineButton: {
121
- backgroundColor: "transparent",
122
- borderWidth: 1,
123
- borderColor: theme.colors.border,
124
- },
125
- outlineText: {
126
- color: theme.colors.foreground,
127
- fontWeight: "500",
128
- },
129
- ghostButton: {
130
- backgroundColor: "transparent",
131
- borderWidth: 0,
132
- },
133
- ghostText: {
134
- color: theme.colors.foreground,
135
- fontWeight: "500",
136
- },
137
- destructiveButton: {
138
- backgroundColor: theme.colors.destructive,
139
- borderWidth: 0,
140
- ...theme.shadows.sm,
141
- },
142
- destructiveText: {
143
- color: theme.colors.destructiveForeground,
144
- fontWeight: "600",
145
- },
146
- successButton: {
147
- backgroundColor: theme.colors.success,
148
- borderWidth: 0,
149
- ...theme.shadows.sm,
150
- },
151
- successText: {
152
- color: theme.colors.successForeground,
153
- fontWeight: "600",
154
- },
155
- pillButton: {
156
- paddingHorizontal: theme.spacing[2],
157
- paddingVertical: theme.spacing[1],
158
- borderRadius: tokens.borderRadius.full,
159
- minHeight: tokens.touchTargets.minimum / 2,
160
- },
161
- pillText: {
162
- color: theme.colors.primaryForeground,
163
- fontWeight: "400",
164
- },
165
- // Size styles
166
- smButton: {
167
- paddingHorizontal: theme.spacing[3],
168
- paddingVertical: theme.spacing[2],
169
- borderRadius: tokens.borderRadius.md,
170
- minHeight: tokens.touchTargets.minimum,
171
- gap: theme.spacing[1],
172
- },
173
- smButtonInner: {
174
- gap: theme.spacing[1],
175
- },
176
- smText: {
177
- fontSize: 14,
178
- lineHeight: 16,
179
- },
180
- mdButton: {
181
- paddingHorizontal: theme.spacing[4],
182
- paddingVertical: theme.spacing[3],
183
- borderRadius: tokens.borderRadius.md,
184
- minHeight: tokens.touchTargets.minimum,
185
- gap: theme.spacing[2],
186
- },
187
- mdButtonInner: {
188
- gap: theme.spacing[2],
189
- },
190
- mdText: {
191
- fontSize: 16,
192
- lineHeight: 18,
193
- },
194
- lgButton: {
195
- paddingHorizontal: theme.spacing[6],
196
- paddingVertical: theme.spacing[4],
197
- borderRadius: tokens.borderRadius.md,
198
- minHeight: tokens.touchTargets.comfortable,
199
- gap: theme.spacing[3],
200
- },
201
- lgButtonInner: {
202
- gap: theme.spacing[3],
203
- },
204
- lgText: {
205
- fontSize: 18,
206
- lineHeight: 20,
207
- },
208
- xlButton: {
209
- paddingHorizontal: theme.spacing[8],
210
- paddingVertical: theme.spacing[5],
211
- borderRadius: tokens.borderRadius.lg,
212
- minHeight: tokens.touchTargets.large,
213
- gap: theme.spacing[4],
214
- },
215
- xlButtonInner: {
216
- gap: theme.spacing[4],
217
- },
218
- xlText: {
219
- fontSize: 20,
220
- lineHeight: 24,
221
- },
222
- });
223
- }