@streamplace/components 0.8.6 → 0.8.9

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.
@@ -1,42 +1,218 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DropdownMenuInfo = exports.DropdownMenuGroup = exports.DropdownMenuSeparator = exports.DropdownMenuLabel = exports.DropdownMenuRadioItem = exports.DropdownMenuCheckboxItem = exports.DropdownMenuItem = exports.ResponsiveDropdownMenuContent = exports.DropdownMenuContentWithoutPortal = exports.DropdownMenuContent = exports.DropdownMenuSubContent = exports.DropdownMenuSubTrigger = exports.DropdownMenuBottomSheet = exports.DropdownMenuRadioGroup = exports.DropdownMenuSub = exports.DropdownMenuPortal = exports.DropdownMenuTrigger = exports.DropdownMenu = void 0;
3
+ exports.DropdownMenuInfo = exports.DropdownMenuGroup = exports.DropdownMenuSeparator = exports.DropdownMenuLabel = exports.DropdownMenuRadioItem = exports.DropdownMenuCheckboxItem = exports.DropdownMenuItem = exports.ResponsiveDropdownMenuContent = exports.DropdownMenuContentWithoutPortal = exports.DropdownMenuContent = exports.DropdownMenuSubContent = exports.DropdownMenuSubTrigger = exports.DropdownMenuBottomSheet = exports.DropdownMenuSub = exports.DropdownMenuRadioGroup = exports.DropdownMenuPortal = exports.DropdownMenuTrigger = exports.DropdownMenu = void 0;
4
4
  exports.DropdownMenuShortcut = DropdownMenuShortcut;
5
5
  const tslib_1 = require("tslib");
6
6
  const jsx_runtime_1 = require("react/jsx-runtime");
7
7
  const bottom_sheet_1 = tslib_1.__importStar(require("@gorhom/bottom-sheet"));
8
8
  const DropdownMenuPrimitive = tslib_1.__importStar(require("@rn-primitives/dropdown-menu"));
9
9
  const lucide_react_native_1 = require("lucide-react-native");
10
- const react_1 = require("react");
10
+ const react_1 = tslib_1.__importStar(require("react"));
11
11
  const react_native_1 = require("react-native");
12
+ const react_native_reanimated_1 = tslib_1.__importStar(require("react-native-reanimated"));
13
+ const react_native_safe_area_context_1 = require("react-native-safe-area-context");
12
14
  const atoms_1 = require("../../lib/theme/atoms");
13
15
  const ui_1 = require("../../ui");
14
16
  const text_1 = require("./primitives/text");
15
17
  const text_2 = require("./text");
18
+ const NavigationStackContext = (0, react_1.createContext)(null);
19
+ const useNavigationStack = () => {
20
+ const context = (0, react_1.useContext)(NavigationStackContext);
21
+ return context;
22
+ };
23
+ const SubMenuContext = (0, react_1.createContext)(null);
16
24
  exports.DropdownMenu = DropdownMenuPrimitive.Root;
17
25
  exports.DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
18
26
  exports.DropdownMenuPortal = DropdownMenuPrimitive.Portal;
19
- exports.DropdownMenuSub = DropdownMenuPrimitive.Sub;
20
27
  exports.DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
21
- exports.DropdownMenuBottomSheet = (0, react_1.forwardRef)(function DropdownMenuBottomSheet({ overlayStyle, portalHost, children }, _ref) {
28
+ // Custom DropdownMenuSub that works with mobile navigation
29
+ exports.DropdownMenuSub = (0, react_1.forwardRef)(({ children, ...props }, ref) => {
30
+ const navStack = useNavigationStack();
31
+ const [subMenuTitle, setSubMenuTitle] = (0, react_1.useState)();
32
+ const renderContentRef = (0, react_1.useRef)(null);
33
+ const [subMenuKey, setSubMenuKey] = (0, react_1.useState)(null);
34
+ // If we're in a mobile navigation stack, use custom context
35
+ if (navStack) {
36
+ const trigger = () => {
37
+ if (renderContentRef.current) {
38
+ const key = `submenu-${Date.now()}`;
39
+ setSubMenuKey(key);
40
+ navStack.push({
41
+ key,
42
+ title: subMenuTitle,
43
+ // Store a function that always reads the latest content from the ref
44
+ content: (props) => {
45
+ const renderFn = renderContentRef.current;
46
+ return renderFn ? renderFn() : null;
47
+ },
48
+ });
49
+ }
50
+ };
51
+ const setRenderContent = (renderer) => {
52
+ renderContentRef.current = renderer;
53
+ };
54
+ const contextValue = react_1.default.useMemo(() => ({
55
+ renderContent: () => renderContentRef.current?.(),
56
+ setRenderContent,
57
+ title: subMenuTitle,
58
+ setTitle: setSubMenuTitle,
59
+ trigger,
60
+ key: subMenuKey,
61
+ }), [subMenuTitle, subMenuKey]);
62
+ return ((0, jsx_runtime_1.jsx)(SubMenuContext.Provider, { value: contextValue, children: children }));
63
+ }
64
+ // Web - use primitive
65
+ return ((0, jsx_runtime_1.jsx)(DropdownMenuPrimitive.Sub, { ref: ref, ...props, children: children }));
66
+ });
67
+ exports.DropdownMenuBottomSheet = (0, react_1.forwardRef)(function DropdownMenuBottomSheet({ overlayStyle, portalHost, children, ...rest }, _ref) {
22
68
  // Use the primitives' context to know if open
23
- const { open, onOpenChange } = DropdownMenuPrimitive.useRootContext();
24
- const { zero: zt } = (0, ui_1.useTheme)();
25
- const snapPoints = (0, react_1.useMemo)(() => ["25%", "50%", "80%"], []);
69
+ const { onOpenChange } = DropdownMenuPrimitive.useRootContext();
70
+ const { zero: zt, theme } = (0, ui_1.useTheme)();
26
71
  const sheetRef = (0, react_1.useRef)(null);
27
- return ((0, jsx_runtime_1.jsx)(DropdownMenuPrimitive.Portal, { hostName: portalHost, children: (0, jsx_runtime_1.jsx)(bottom_sheet_1.default, { ref: sheetRef,
28
- // why the heck is this 1-indexed
29
- index: open ? 3 : -1, snapPoints: snapPoints, enablePanDownToClose: true, enableDynamicSizing: true, enableContentPanningGesture: false, backdropComponent: ({ style }) => ((0, jsx_runtime_1.jsx)(react_native_1.Pressable, { style: [style, react_native_1.StyleSheet.absoluteFill], onPress: () => onOpenChange?.(false) })), onClose: () => onOpenChange?.(false), style: [overlayStyle], backgroundStyle: [zt.bg.popover, atoms_1.a.radius.all.md, atoms_1.a.shadows.md, atoms_1.p[1]], handleIndicatorStyle: [
30
- atoms_1.a.sizes.width[12],
31
- atoms_1.a.sizes.height[1],
32
- zt.bg.mutedForeground,
33
- ], children: (0, jsx_runtime_1.jsx)(bottom_sheet_1.BottomSheetView, { style: [atoms_1.px[4]], children: typeof children === "function"
34
- ? children({ pressed: true })
35
- : children }) }) }));
72
+ const { width } = (0, react_native_1.useWindowDimensions)();
73
+ const isWide = react_native_1.Platform.OS !== "web" && width >= 800;
74
+ const sheetWidth = isWide ? 450 : width;
75
+ const horizontalMargin = isWide ? (width - sheetWidth) / 2 : 0;
76
+ const insets = (0, react_native_safe_area_context_1.useSafeAreaInsets)();
77
+ // Navigation stack state
78
+ const [stack, setStack] = (0, react_1.useState)([
79
+ { key: "root", content: children },
80
+ ]);
81
+ // Update root content when children changes
82
+ react_1.default.useEffect(() => {
83
+ setStack((prev) => {
84
+ if (!Array.isArray(prev) || prev.length === 0) {
85
+ return [{ key: "root", content: children }];
86
+ }
87
+ // Update the root item content
88
+ const newStack = [...prev];
89
+ newStack[0] = { ...newStack[0], content: children };
90
+ return newStack;
91
+ });
92
+ }, [children]);
93
+ const slideAnim = (0, react_native_reanimated_1.useSharedValue)(0);
94
+ const fadeAnim = (0, react_native_reanimated_1.useSharedValue)(1);
95
+ const push = (item) => {
96
+ // First, update the stack
97
+ setStack((prev) => {
98
+ if (!Array.isArray(prev))
99
+ return [{ key: "root", content: children }, item];
100
+ return [...prev, item];
101
+ });
102
+ // Then animate from right to center with fade
103
+ slideAnim.value = 40;
104
+ fadeAnim.value = 0;
105
+ slideAnim.value = (0, react_native_reanimated_1.withTiming)(0, { duration: 350 });
106
+ fadeAnim.value = (0, react_native_reanimated_1.withTiming)(1, { duration: 350 });
107
+ };
108
+ const popStack = () => {
109
+ (0, react_1.startTransition)(() => {
110
+ setStack((prev) => {
111
+ if (!Array.isArray(prev) || prev.length <= 1) {
112
+ return [{ key: "root", content: children }];
113
+ }
114
+ return prev.slice(0, -1);
115
+ });
116
+ });
117
+ };
118
+ const resetAnimationValues = () => {
119
+ setTimeout(() => {
120
+ slideAnim.value = 0;
121
+ fadeAnim.value = 1;
122
+ }, 5);
123
+ };
124
+ const pop = () => {
125
+ if (stack.length <= 1)
126
+ return;
127
+ // Animate out to the right with fade
128
+ slideAnim.value = (0, react_native_reanimated_1.withTiming)(40, { duration: 150 });
129
+ fadeAnim.value = (0, react_native_reanimated_1.withTiming)(0, { duration: 150 }, (finished) => {
130
+ if (finished) {
131
+ // Update stack first with startTransition for smoother render
132
+ (0, react_native_reanimated_1.runOnJS)(popStack)();
133
+ // Then reset animation position after a brief delay to ensure component has unmounted
134
+ (0, react_native_reanimated_1.runOnJS)(resetAnimationValues)();
135
+ }
136
+ });
137
+ };
138
+ const animatedStyle = (0, react_native_reanimated_1.useAnimatedStyle)(() => ({
139
+ transform: [{ translateX: slideAnim.value }],
140
+ opacity: fadeAnim.value,
141
+ }));
142
+ const headerAnimatedStyle = (0, react_native_reanimated_1.useAnimatedStyle)(() => ({
143
+ opacity: fadeAnim.value,
144
+ }));
145
+ const currentLevel = stack[stack.length - 1];
146
+ const isNested = stack.length > 1;
147
+ const onBackgroundTap = () => {
148
+ if (sheetRef.current)
149
+ sheetRef.current?.close();
150
+ setTimeout(() => {
151
+ onOpenChange?.(false);
152
+ }, 300);
153
+ };
154
+ // Safety check - if no current level, don't render
155
+ if (!currentLevel) {
156
+ return null;
157
+ }
158
+ return ((0, jsx_runtime_1.jsx)(DropdownMenuPrimitive.Portal, { hostName: portalHost, children: (0, jsx_runtime_1.jsx)(NavigationStackContext.Provider, { value: { stack, push, pop, isNested }, children: (0, jsx_runtime_1.jsxs)(bottom_sheet_1.default, { ref: sheetRef, enablePanDownToClose: true, enableDynamicSizing: true, detached: isWide, bottomInset: isWide ? 0 : 0, backdropComponent: ({ style }) => ((0, jsx_runtime_1.jsx)(react_native_1.Pressable, { style: [style, react_native_1.StyleSheet.absoluteFill], onPress: () => onBackgroundTap() })), onClose: () => onOpenChange?.(false), style: [
159
+ overlayStyle,
160
+ react_native_1.StyleSheet.flatten(rest.style),
161
+ isWide && { marginHorizontal: horizontalMargin },
162
+ ], backgroundStyle: [zt.bg.popover, atoms_1.a.radius.all.md, atoms_1.a.shadows.md, atoms_1.p[1]], handleIndicatorStyle: [
163
+ atoms_1.a.sizes.width[12],
164
+ atoms_1.a.sizes.height[1],
165
+ zt.bg.mutedForeground,
166
+ ], children: [isNested && ((0, jsx_runtime_1.jsx)(react_native_reanimated_1.default.View, { style: [
167
+ headerAnimatedStyle,
168
+ atoms_1.a.layout.flex.row,
169
+ atoms_1.a.layout.flex.alignCenter,
170
+ atoms_1.px[4],
171
+ atoms_1.pb[2],
172
+ {
173
+ borderBottomWidth: 1,
174
+ borderBottomColor: theme.colors.border,
175
+ },
176
+ ], children: (0, jsx_runtime_1.jsxs)(react_native_1.Pressable, { onPress: pop, style: [
177
+ atoms_1.a.layout.flex.row,
178
+ atoms_1.a.layout.flex.alignCenter,
179
+ atoms_1.gap.all[2],
180
+ ], hitSlop: 80, children: [(0, jsx_runtime_1.jsx)(lucide_react_native_1.ChevronLeft, { size: 20, color: theme.colors.foreground }), currentLevel?.title ? ((0, jsx_runtime_1.jsx)(text_2.Text, { size: "lg", children: currentLevel.title })) : null] }) })), (0, jsx_runtime_1.jsx)(react_native_reanimated_1.default.View, { style: animatedStyle, children: (0, jsx_runtime_1.jsx)(bottom_sheet_1.BottomSheetScrollView, { style: [atoms_1.px[4]], contentContainerStyle: {
181
+ paddingBottom: insets.bottom + 50,
182
+ overflow: "hidden",
183
+ }, children: stack.map((level, index) => {
184
+ const isCurrent = index === stack.length - 1;
185
+ return ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: [{ display: isCurrent ? "flex" : "none" }], children: typeof level.content === "function"
186
+ ? level.content({ pressed: true })
187
+ : level.content }, level.key));
188
+ }) }) })] }) }) }));
36
189
  });
37
- exports.DropdownMenuSubTrigger = (0, react_1.forwardRef)(({ inset, children, ...props }, ref) => {
190
+ exports.DropdownMenuSubTrigger = (0, react_1.forwardRef)(({ inset, children, subMenuTitle, ...props }, ref) => {
191
+ const navStack = useNavigationStack();
192
+ const subMenuContext = (0, react_1.useContext)(SubMenuContext);
193
+ const { icons, theme } = (0, ui_1.useTheme)();
194
+ // Set the title in the submenu context if provided
195
+ react_1.default.useEffect(() => {
196
+ if (subMenuContext && subMenuTitle) {
197
+ subMenuContext.setTitle(subMenuTitle);
198
+ }
199
+ }, [subMenuContext, subMenuTitle]);
200
+ // If we're in a navigation stack (mobile bottom sheet), handle differently
201
+ if (navStack && subMenuContext) {
202
+ return ((0, jsx_runtime_1.jsx)(react_native_1.Pressable, { onPress: () => {
203
+ subMenuContext.trigger();
204
+ }, ...props, children: (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [
205
+ inset && atoms_1.gap[2],
206
+ atoms_1.layout.flex.row,
207
+ atoms_1.layout.flex.alignCenter,
208
+ atoms_1.a.radius.all.sm,
209
+ atoms_1.py[1],
210
+ atoms_1.pl[2],
211
+ atoms_1.pr[2],
212
+ ], children: [typeof children === "function" ? (children({ pressed: true })) : typeof children === "string" ? ((0, jsx_runtime_1.jsx)(text_2.Text, { children: children })) : (children), (0, jsx_runtime_1.jsx)(react_native_1.View, { style: [atoms_1.a.layout.position.absolute, atoms_1.a.position.right[1]], children: (0, jsx_runtime_1.jsx)(lucide_react_native_1.ChevronRight, { size: 18, color: icons.color.muted }) })] }) }));
213
+ }
214
+ // Web behavior - use primitive
38
215
  const { open } = DropdownMenuPrimitive.useSubContext();
39
- const { icons } = (0, ui_1.useTheme)();
40
216
  const Icon = react_native_1.Platform.OS === "web" ? lucide_react_native_1.ChevronRight : open ? lucide_react_native_1.ChevronUp : lucide_react_native_1.ChevronDown;
41
217
  return ((0, jsx_runtime_1.jsx)(text_1.TextContext.Provider, { value: (0, text_1.objectFromObjects)([
42
218
  atoms_1.a.textColors.primary[500],
@@ -50,8 +226,35 @@ exports.DropdownMenuSubTrigger = (0, react_1.forwardRef)(({ inset, children, ...
50
226
  atoms_1.pr[8],
51
227
  ], children: [children, (0, jsx_runtime_1.jsx)(react_native_1.View, { style: [atoms_1.a.layout.position.absolute, atoms_1.a.position.right[1]], children: (0, jsx_runtime_1.jsx)(Icon, { size: 18, color: icons.color.muted }) })] }) }) }));
52
228
  });
53
- exports.DropdownMenuSubContent = (0, react_1.forwardRef)((props, ref) => {
229
+ exports.DropdownMenuSubContent = (0, react_1.forwardRef)(({ children, ...props }, ref) => {
54
230
  const { zero: zt } = (0, ui_1.useTheme)();
231
+ const subMenuContext = (0, react_1.useContext)(SubMenuContext);
232
+ const navStack = useNavigationStack();
233
+ const prevChildrenRef = (0, react_1.useRef)(null);
234
+ // Register a render function that will be called fresh each time
235
+ react_1.default.useEffect(() => {
236
+ if (subMenuContext && navStack) {
237
+ // Only update if children reference actually changed
238
+ if (prevChildrenRef.current === children) {
239
+ return;
240
+ }
241
+ prevChildrenRef.current = children;
242
+ // Pass a function that returns the current children
243
+ subMenuContext.setRenderContent(() => children);
244
+ // Force a stack update to trigger rerender with the actual children
245
+ if (subMenuContext.key) {
246
+ // Store the children directly so React can handle updates
247
+ //navStack.updateContent(subMenuContext.key, children);
248
+ }
249
+ }
250
+ }, [children, subMenuContext, navStack]);
251
+ // On mobile, don't render the subcontent here - it'll be rendered in the nav stack
252
+ // But keep the component mounted so effects run when children change
253
+ if (navStack && subMenuContext) {
254
+ // Component stays mounted to track prop changes, but renders nothing
255
+ return null;
256
+ }
257
+ // Web - use primitive
55
258
  return ((0, jsx_runtime_1.jsx)(DropdownMenuPrimitive.SubContent, { ref: ref, style: [
56
259
  atoms_1.a.zIndex[50],
57
260
  atoms_1.a.sizes.minWidth[32],
@@ -63,10 +266,12 @@ exports.DropdownMenuSubContent = (0, react_1.forwardRef)((props, ref) => {
63
266
  zt.bg.popover,
64
267
  atoms_1.p[1],
65
268
  atoms_1.a.shadows.md,
66
- ], ...props }));
269
+ ], ...props, children: children }));
67
270
  });
68
- exports.DropdownMenuContent = (0, react_1.forwardRef)(({ overlayStyle, portalHost, ...props }, ref) => {
271
+ exports.DropdownMenuContent = (0, react_1.forwardRef)(({ overlayStyle, portalHost, style, children, ...props }, ref) => {
69
272
  const { zero: zt } = (0, ui_1.useTheme)();
273
+ const { height } = (0, react_native_1.useWindowDimensions)();
274
+ const maxHeight = height * 0.8;
70
275
  return ((0, jsx_runtime_1.jsx)(DropdownMenuPrimitive.Portal, { hostName: portalHost, children: (0, jsx_runtime_1.jsx)(DropdownMenuPrimitive.Overlay, { style: [
71
276
  react_native_1.Platform.OS !== "web" ? react_native_1.StyleSheet.absoluteFill : undefined,
72
277
  overlayStyle,
@@ -81,10 +286,15 @@ exports.DropdownMenuContent = (0, react_1.forwardRef)(({ overlayStyle, portalHos
81
286
  zt.bg.popover,
82
287
  atoms_1.p[2],
83
288
  atoms_1.a.shadows.md,
84
- ], ...props }) }) }));
289
+ style,
290
+ ], ...props, children: (0, jsx_runtime_1.jsx)(react_native_1.ScrollView, { style: { maxHeight }, showsVerticalScrollIndicator: true, children: typeof children === "function"
291
+ ? children({ pressed: false })
292
+ : children }) }) }) }));
85
293
  });
86
- exports.DropdownMenuContentWithoutPortal = (0, react_1.forwardRef)(({ overlayStyle, ...props }, ref) => {
294
+ exports.DropdownMenuContentWithoutPortal = (0, react_1.forwardRef)(({ overlayStyle, maxHeightPercentage = 0.8, children, style, ...props }, ref) => {
87
295
  const { theme } = (0, ui_1.useTheme)();
296
+ const { height } = (0, react_native_1.useWindowDimensions)();
297
+ const maxHeight = height * maxHeightPercentage;
88
298
  return ((0, jsx_runtime_1.jsx)(DropdownMenuPrimitive.Overlay, { style: [
89
299
  react_native_1.Platform.OS !== "web" ? react_native_1.StyleSheet.absoluteFill : undefined,
90
300
  overlayStyle,
@@ -92,21 +302,23 @@ exports.DropdownMenuContentWithoutPortal = (0, react_1.forwardRef)(({ overlaySty
92
302
  { zIndex: 999999 },
93
303
  atoms_1.a.sizes.minWidth[32],
94
304
  atoms_1.a.sizes.maxWidth[64],
95
- atoms_1.a.overflow.hidden,
96
305
  atoms_1.a.radius.all.md,
97
306
  atoms_1.a.borders.width.thin,
98
307
  { borderColor: theme.colors.border },
99
308
  { backgroundColor: theme.colors.popover },
100
309
  atoms_1.p[2],
101
310
  atoms_1.a.shadows.md,
102
- ], ...props }) }));
311
+ style,
312
+ ], ...props, children: (0, jsx_runtime_1.jsx)(react_native_1.ScrollView, { style: { maxHeight }, showsVerticalScrollIndicator: true, children: typeof children === "function"
313
+ ? children({ pressed: false })
314
+ : children }) }) }));
103
315
  });
104
316
  /// Responsive Dropdown Menu Content. On mobile this will render a *bottom sheet* that is **portaled to the root of the app**.
105
317
  /// Prefer passing scoped content in as **otherwise it may crash the app**.
106
318
  exports.ResponsiveDropdownMenuContent = (0, react_1.forwardRef)(({ children, ...props }, ref) => {
107
319
  const { width } = (0, react_native_1.useWindowDimensions)();
108
320
  // On web, you might want to always use the normal dropdown
109
- const isBottomSheet = react_native_1.Platform.OS !== "web" && width < 800;
321
+ const isBottomSheet = react_native_1.Platform.OS !== "web";
110
322
  if (isBottomSheet) {
111
323
  return ((0, jsx_runtime_1.jsx)(exports.DropdownMenuBottomSheet, { ref: ref, ...props, children: children }));
112
324
  }
@@ -137,6 +137,18 @@ exports.TextRoot = (0, react_1.forwardRef)(({ variant, size, weight, color, alig
137
137
  const variantStyles = getVariantStyles();
138
138
  // Calculate inherited values
139
139
  const inheritedContext = inherit && !reset && parentContext ? parentContext : {};
140
+ // Calculate fontSize first for line height calculation
141
+ let calculatedFontSize = inheritedContext.fontSize;
142
+ // Apply variant font size
143
+ if (variant && variantStyles[variant]?.fontSize) {
144
+ calculatedFontSize = variantStyles[variant].fontSize;
145
+ }
146
+ // Apply size-based font size
147
+ if (size) {
148
+ calculatedFontSize = typeof size === "number" ? size : sizeMap[size];
149
+ }
150
+ // Use default if still undefined
151
+ calculatedFontSize = calculatedFontSize || 16;
140
152
  // Calculate final styles
141
153
  const finalStyles = {
142
154
  // Start with inherited values
@@ -194,7 +206,9 @@ exports.TextRoot = (0, react_1.forwardRef)(({ variant, size, weight, color, alig
194
206
  }),
195
207
  // Apply line height
196
208
  ...(leading && {
197
- lineHeight: typeof leading === "number" ? leading : leadingMap[leading],
209
+ lineHeight: typeof leading === "number"
210
+ ? leading
211
+ : leadingMap[leading] * calculatedFontSize,
198
212
  }),
199
213
  // Apply letter spacing
200
214
  ...(tracking && {
@@ -231,7 +245,7 @@ exports.TextRoot = (0, react_1.forwardRef)(({ variant, size, weight, color, alig
231
245
  if (typeof fontSize === "number" && !styleObj.lineHeight && !leading) {
232
246
  return {
233
247
  ...styleObj,
234
- lineHeight: fontSize * 1.2,
248
+ lineHeight: fontSize,
235
249
  };
236
250
  }
237
251
  }
@@ -285,7 +299,7 @@ function createTextStyle(props) {
285
299
  if (props.leading === undefined) {
286
300
  style.lineHeight =
287
301
  typeof props.size === "number"
288
- ? props.size * 1.2 // Auto line height for numeric sizes
302
+ ? props.size
289
303
  : sizeLineHeightMap[props.size];
290
304
  }
291
305
  }
@@ -296,10 +310,11 @@ function createTextStyle(props) {
296
310
  style.textAlign = props.align;
297
311
  }
298
312
  if (props.leading) {
313
+ const fontSize = style.fontSize || 16; // default font size
299
314
  style.lineHeight =
300
315
  typeof props.leading === "number"
301
316
  ? props.leading
302
- : leadingMap[props.leading];
317
+ : leadingMap[props.leading] * fontSize;
303
318
  }
304
319
  if (props.tracking) {
305
320
  style.letterSpacing =
@@ -5,85 +5,54 @@ const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const lucide_react_native_1 = require("lucide-react-native");
6
6
  const react_1 = require("react");
7
7
  const react_native_1 = require("react-native");
8
+ const __1 = require("../..");
8
9
  const theme_1 = require("../../lib/theme/theme");
10
+ const ui_1 = require("../../ui");
11
+ const dropdown_1 = require("./dropdown");
9
12
  const text_1 = require("./text");
13
+ const { layout, px, py, borders, r, gap } = __1.zero;
10
14
  exports.Select = (0, react_1.forwardRef)(({ value, onValueChange, placeholder = "Select...", items, disabled = false, style, }, ref) => {
11
15
  const { theme } = (0, theme_1.useTheme)();
12
- const [isOpen, setIsOpen] = (0, react_1.useState)(false);
13
16
  const selectedItem = items.find((item) => item.value === value);
14
- const handleSelect = (itemValue) => {
15
- onValueChange(itemValue);
16
- setIsOpen(false);
17
- };
18
- const styles = createStyles(theme, disabled);
19
- return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)(react_native_1.TouchableOpacity, { ref: ref, style: [styles.container, style], onPress: () => !disabled && setIsOpen(true), disabled: disabled, children: [(0, jsx_runtime_1.jsx)(text_1.Text, { style: styles.value, children: selectedItem?.label || placeholder }), (0, jsx_runtime_1.jsx)(lucide_react_native_1.ChevronDown, { size: 16, color: theme.colors.textMuted })] }), (0, jsx_runtime_1.jsx)(react_native_1.Modal, { visible: isOpen, transparent: true, animationType: "fade", onRequestClose: () => setIsOpen(false), children: (0, jsx_runtime_1.jsx)(react_native_1.TouchableOpacity, { style: styles.overlay, activeOpacity: 1, onPress: () => setIsOpen(false), children: (0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.dropdown, children: (0, jsx_runtime_1.jsx)(react_native_1.FlatList, { data: items, keyExtractor: (item) => item.value, renderItem: ({ item }) => ((0, jsx_runtime_1.jsxs)(react_native_1.TouchableOpacity, { style: [
20
- styles.item,
21
- item.value === value && styles.selectedItem,
22
- ], onPress: () => handleSelect(item.value), children: [(0, jsx_runtime_1.jsx)(text_1.Text, { style: [
23
- styles.itemText,
24
- item.value === value ? styles.selectedItemText : {},
25
- ], children: item.label }), item.description && ((0, jsx_runtime_1.jsx)(text_1.Text, { style: styles.itemDescription, children: item.description }))] })), style: styles.list }) }) }) })] }));
17
+ return ((0, jsx_runtime_1.jsxs)(dropdown_1.DropdownMenu, { children: [(0, jsx_runtime_1.jsx)(dropdown_1.DropdownMenuTrigger, { disabled: disabled, children: (0, jsx_runtime_1.jsx)(react_native_1.View, { ref: ref, style: [
18
+ {
19
+ width: "100%",
20
+ paddingHorizontal: theme.spacing[3],
21
+ paddingVertical: theme.spacing[3],
22
+ borderWidth: 1,
23
+ borderColor: theme.colors.border,
24
+ borderRadius: theme.borderRadius.md,
25
+ backgroundColor: disabled
26
+ ? theme.colors.muted
27
+ : theme.colors.card,
28
+ minHeight: theme.touchTargets.minimum,
29
+ opacity: disabled ? 0.5 : 1,
30
+ },
31
+ style,
32
+ ], children: (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: {
33
+ flexDirection: "row",
34
+ alignItems: "center",
35
+ justifyContent: "space-between",
36
+ width: "100%",
37
+ gap: 8,
38
+ }, children: [(0, jsx_runtime_1.jsx)(text_1.Text, { style: {
39
+ fontSize: 16,
40
+ color: disabled
41
+ ? theme.colors.textDisabled
42
+ : theme.colors.text,
43
+ flex: 1,
44
+ }, children: selectedItem?.label || placeholder }), (0, jsx_runtime_1.jsx)(lucide_react_native_1.ChevronDown, { size: 16, color: theme.colors.textMuted })] }) }) }), (0, jsx_runtime_1.jsx)(dropdown_1.ResponsiveDropdownMenuContent, { align: "start", style: [
45
+ {
46
+ maxHeight: 400,
47
+ },
48
+ ], children: items.map((item, index) => ((0, jsx_runtime_1.jsxs)(react_native_1.View, { children: [(0, jsx_runtime_1.jsx)(dropdown_1.DropdownMenuItem, { onPress: () => onValueChange(item.value), children: (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: {
49
+ flexDirection: "row",
50
+ alignItems: "center",
51
+ justifyContent: "space-between",
52
+ width: "100%",
53
+ gap: 8,
54
+ }, children: [(0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [gap.all[1], py[1], ui_1.flex.values[1]], children: [(0, jsx_runtime_1.jsx)(text_1.Text, { style: {
55
+ fontWeight: item.value === value ? "500" : "400",
56
+ }, color: item.value === value ? "primary" : "default", children: item.label }), item.description && ((0, jsx_runtime_1.jsx)(text_1.Text, { size: "sm", color: "muted", children: item.description }))] }), item.value === value ? ((0, jsx_runtime_1.jsx)(lucide_react_native_1.Check, { size: 16, color: theme.colors.primary })) : ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: { width: 16 } }))] }) }), index < items.length - 1 && (0, jsx_runtime_1.jsx)(dropdown_1.DropdownMenuSeparator, {})] }, item.value))) })] }));
26
57
  });
27
58
  exports.Select.displayName = "Select";
28
- function createStyles(theme, disabled) {
29
- return react_native_1.StyleSheet.create({
30
- container: {
31
- flexDirection: "row",
32
- alignItems: "center",
33
- justifyContent: "space-between",
34
- paddingHorizontal: theme.spacing[3],
35
- paddingVertical: theme.spacing[3],
36
- borderWidth: 1,
37
- borderColor: theme.colors.border,
38
- borderRadius: theme.borderRadius.md,
39
- backgroundColor: disabled ? theme.colors.muted : theme.colors.card,
40
- minHeight: theme.touchTargets.minimum,
41
- },
42
- value: {
43
- fontSize: 16,
44
- color: disabled ? theme.colors.textDisabled : theme.colors.text,
45
- flex: 1,
46
- },
47
- overlay: {
48
- flex: 1,
49
- backgroundColor: "rgba(0, 0, 0, 0.5)",
50
- justifyContent: "center",
51
- alignItems: "center",
52
- },
53
- dropdown: {
54
- backgroundColor: theme.colors.background,
55
- borderRadius: theme.borderRadius.md,
56
- borderWidth: 1,
57
- borderColor: theme.colors.border,
58
- maxHeight: 300,
59
- width: "90%",
60
- maxWidth: 400,
61
- ...theme.shadows.lg,
62
- },
63
- list: {
64
- maxHeight: 300,
65
- },
66
- item: {
67
- paddingHorizontal: theme.spacing[4],
68
- paddingVertical: theme.spacing[3],
69
- borderBottomWidth: 1,
70
- borderBottomColor: theme.colors.border,
71
- },
72
- selectedItem: {
73
- backgroundColor: theme.colors.primary,
74
- },
75
- itemText: {
76
- fontSize: 16,
77
- color: theme.colors.text,
78
- },
79
- selectedItemText: {
80
- color: theme.colors.primaryForeground,
81
- fontWeight: "500",
82
- },
83
- itemDescription: {
84
- fontSize: 14,
85
- color: theme.colors.textMuted,
86
- marginTop: theme.spacing[1],
87
- },
88
- });
89
- }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@streamplace/components",
3
- "version": "0.8.6",
3
+ "version": "0.8.9",
4
4
  "description": "Streamplace React (Native) Components",
5
5
  "main": "dist/index.js",
6
6
  "types": "src/index.tsx",
@@ -56,5 +56,5 @@
56
56
  "start": "tsc --watch --preserveWatchOutput",
57
57
  "prepare": "tsc"
58
58
  },
59
- "gitHead": "a40860f005ba4da989cfe1a5c39d29fa3564fea6"
59
+ "gitHead": "2ac59bf91315b2b1f848842c1048a23bd74658b7"
60
60
  }
@@ -376,26 +376,11 @@ export const ContentMetadataForm = forwardRef<any, ContentMetadataFormProps>(
376
376
  layout.flex.row,
377
377
  layout.flex.alignCenter,
378
378
  w.percent[100],
379
+ gap.all[2],
379
380
  ]}
380
381
  >
381
- <Text
382
- style={[
383
- text.neutral[300],
384
- {
385
- minWidth: 100,
386
- textAlign: "left",
387
- paddingBottom: 8,
388
- fontSize: 14,
389
- },
390
- ]}
391
- >
392
- Content Warnings
393
- </Text>
394
- <Text
395
- style={[text.gray[500], { fontSize: 12, paddingBottom: 8 }]}
396
- >
397
- optional
398
- </Text>
382
+ <Text>Content Warnings</Text>
383
+ <Text muted>(optional)</Text>
399
384
  </View>
400
385
  <View style={[gap.all[2], w.percent[100]]}>
401
386
  {CONTENT_WARNINGS.map((warning) => (
@@ -424,26 +409,11 @@ export const ContentMetadataForm = forwardRef<any, ContentMetadataFormProps>(
424
409
  layout.flex.row,
425
410
  layout.flex.alignCenter,
426
411
  w.percent[100],
412
+ gap.all[2],
427
413
  ]}
428
414
  >
429
- <Text
430
- style={[
431
- text.neutral[300],
432
- {
433
- minWidth: 100,
434
- textAlign: "left",
435
- paddingBottom: 8,
436
- fontSize: 14,
437
- },
438
- ]}
439
- >
440
- Content Rights
441
- </Text>
442
- <Text
443
- style={[text.gray[500], { fontSize: 12, paddingBottom: 8 }]}
444
- >
445
- optional
446
- </Text>
415
+ <Text>Content Rights</Text>
416
+ <Text muted>(optional)</Text>
447
417
  </View>
448
418
 
449
419
  <View style={[gap.all[3], w.percent[100]]}>
@@ -674,21 +644,11 @@ export const ContentMetadataForm = forwardRef<any, ContentMetadataFormProps>(
674
644
  layout.flex.row,
675
645
  layout.flex.alignCenter,
676
646
  w.percent[100],
647
+ gap.all[2],
677
648
  ]}
678
649
  >
679
- <Text
680
- style={[
681
- text.neutral[300],
682
- { minWidth: 100, textAlign: "left", paddingBottom: 8 },
683
- ]}
684
- >
685
- Distribution
686
- </Text>
687
- <Text
688
- style={[text.gray[500], { fontSize: 12, paddingBottom: 8 }]}
689
- >
690
- optional
691
- </Text>
650
+ <Text>Distribution</Text>
651
+ <Text muted>(optional)</Text>
692
652
  </View>
693
653
 
694
654
  {/* allow everyone to distribute your content */}