@streamplace/components 0.7.27 → 0.7.30

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 (45) 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/chat/mod-view.js +21 -6
  4. package/dist/components/mobile-player/ui/autoplay-button.js +1 -0
  5. package/dist/components/mobile-player/ui/viewer-context-menu.js +1 -1
  6. package/dist/components/mobile-player/ui/viewer-loading-overlay.js +2 -2
  7. package/dist/components/mobile-player/use-webrtc.js +30 -0
  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/lib/theme/index.js +1 -2
  19. package/dist/lib/theme/theme.js +106 -54
  20. package/dist/lib/theme/tokens.js +94 -1
  21. package/dist/ui/index.js +2 -3
  22. package/node-compile-cache/v22.15.0-x64-efe9a9df-0/37be0eec +0 -0
  23. package/package.json +3 -2
  24. package/src/components/chat/chat-box.tsx +6 -3
  25. package/src/components/chat/chat.tsx +1 -0
  26. package/src/components/chat/mod-view.tsx +25 -5
  27. package/src/components/mobile-player/ui/autoplay-button.tsx +1 -0
  28. package/src/components/mobile-player/ui/viewer-context-menu.tsx +2 -2
  29. package/src/components/mobile-player/ui/viewer-loading-overlay.tsx +2 -2
  30. package/src/components/mobile-player/use-webrtc.tsx +31 -0
  31. package/src/components/ui/button.tsx +110 -172
  32. package/src/components/ui/dialog.tsx +96 -138
  33. package/src/components/ui/dropdown.tsx +60 -22
  34. package/src/components/ui/input.tsx +57 -144
  35. package/src/components/ui/primitives/button.tsx +0 -2
  36. package/src/components/ui/primitives/modal.tsx +0 -2
  37. package/src/components/ui/primitives/text.tsx +51 -8
  38. package/src/components/ui/text.tsx +42 -67
  39. package/src/components/ui/toast.tsx +108 -90
  40. package/src/components/ui/view.tsx +27 -41
  41. package/src/lib/theme/index.ts +0 -2
  42. package/src/lib/theme/theme.tsx +179 -72
  43. package/src/lib/theme/tokens.ts +97 -0
  44. package/src/ui/index.ts +0 -2
  45. 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
  }
@@ -25,6 +25,7 @@ exports.ModView = (0, react_1.forwardRef)(() => {
25
25
  const setReportModalOpen = (0, player_store_1.usePlayerStore)((x) => x.setReportModalOpen);
26
26
  const setReportSubject = (0, player_store_1.usePlayerStore)((x) => x.setReportSubject);
27
27
  const setModMessage = (0, player_store_1.usePlayerStore)((x) => x.setModMessage);
28
+ const deleteChatMessage = (0, livestream_store_1.useDeleteChatMessage)();
28
29
  // get the channel did
29
30
  const channelId = (0, player_store_1.usePlayerStore)((state) => state.src);
30
31
  // get the logged in user's identity
@@ -77,23 +78,37 @@ exports.ModView = (0, react_1.forwardRef)(() => {
77
78
  ? "Blocking..."
78
79
  : `Block user @${message.author.handle} from this channel` })) })] })), (0, jsx_runtime_1.jsxs)(ui_1.DropdownMenuGroup, { title: `User actions`, children: [(0, jsx_runtime_1.jsx)(ui_1.DropdownMenuItem, { onPress: () => {
79
80
  react_native_1.Linking.openURL(`https://${BSKY_FRONTEND_DOMAIN}/profile/${message.author.handle}`);
80
- }, children: (0, jsx_runtime_1.jsxs)(ui_1.Text, { color: "primary", children: ["View user on ", BSKY_FRONTEND_DOMAIN] }) }), message.author.did === agent?.did && ((0, jsx_runtime_1.jsx)(DeleteButton, { message: message })), message.author.did !== agent?.did && ((0, jsx_runtime_1.jsx)(ReportButton, { message: message, setReportModalOpen: setReportModalOpen, setReportSubject: setReportSubject }))] })] })) })] }));
81
+ }, children: (0, jsx_runtime_1.jsxs)(ui_1.Text, { color: "primary", children: ["View user on ", BSKY_FRONTEND_DOMAIN] }) }), message.author.did === agent?.did && ((0, jsx_runtime_1.jsx)(DeleteButton, { message: message, deleteChatMessage: deleteChatMessage })), message.author.did !== agent?.did && ((0, jsx_runtime_1.jsx)(ReportButton, { message: message, setReportModalOpen: setReportModalOpen, setReportSubject: setReportSubject }))] })] })) })] }));
81
82
  });
82
- function DeleteButton({ message, }) {
83
- const deleteChatMessage = (0, livestream_store_1.useDeleteChatMessage)();
84
- const [confirming, setConfirming] = (0, react_1.useState)(false);
83
+ var DeleteState;
84
+ (function (DeleteState) {
85
+ DeleteState[DeleteState["None"] = 0] = "None";
86
+ DeleteState[DeleteState["Confirmed"] = 1] = "Confirmed";
87
+ DeleteState[DeleteState["Deleting"] = 2] = "Deleting";
88
+ })(DeleteState || (DeleteState = {}));
89
+ function DeleteButton({ message, deleteChatMessage, }) {
90
+ const [confirming, setConfirming] = (0, react_1.useState)(DeleteState.None);
85
91
  const { onOpenChange } = (0, dropdown_menu_1.useRootContext)();
86
92
  return ((0, jsx_runtime_1.jsx)(ui_1.DropdownMenuItem, { onPress: () => {
87
93
  if (!message)
88
94
  return;
89
95
  if (!confirming) {
90
- setConfirming(true);
96
+ setConfirming(DeleteState.Confirmed);
91
97
  return;
92
98
  }
99
+ if (confirming === DeleteState.Confirmed) {
100
+ setConfirming(DeleteState.Deleting);
101
+ }
93
102
  deleteChatMessage(message.uri).then(() => {
103
+ // wait ~a second before resetting state to allow deletion to take effect
104
+ setTimeout(() => setConfirming(DeleteState.None), 1000);
94
105
  onOpenChange?.(false);
95
106
  });
96
- }, children: (0, jsx_runtime_1.jsx)(ui_1.Text, { color: "destructive", children: confirming ? "Are you sure?" : "Delete message" }) }));
107
+ }, children: (0, jsx_runtime_1.jsx)(ui_1.Text, { color: "destructive", children: confirming === DeleteState.Confirmed
108
+ ? "Are you sure? Click again to confirm."
109
+ : confirming === DeleteState.Deleting
110
+ ? "Deleting..."
111
+ : "Delete message" }) }));
97
112
  }
98
113
  function ReportButton({ message, setReportModalOpen, setReportSubject, }) {
99
114
  const { onOpenChange } = (0, dropdown_menu_1.useRootContext)();
@@ -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 */
@@ -247,3 +255,25 @@ function useWebRTCIngest({ endpoint, }) {
247
255
  }, [peerConnection, mediaStream, ingestLive]);
248
256
  return [mediaStream, setMediaStream];
249
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
+ }
@@ -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
- }