reactnatively-primitives 0.1.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.
- package/LICENSE +20 -0
- package/dist/index.d.mts +237 -0
- package/dist/index.d.ts +237 -0
- package/dist/index.js +467 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +453 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +71 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
import React4, { useMemo, useCallback, createContext, useState, forwardRef, isValidElement, cloneElement, useContext, useId, useEffect } from 'react';
|
|
2
|
+
import { View, StyleSheet, Pressable, Text } from 'react-native';
|
|
3
|
+
import Animated from 'react-native-reanimated';
|
|
4
|
+
import { GlassView } from 'reactnatively-glass';
|
|
5
|
+
import { useTheme, fontWeight, lineHeight, radii, fontSize } from 'reactnatively-theme';
|
|
6
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
7
|
+
import { usePressAnimation } from 'reactnatively-animations';
|
|
8
|
+
|
|
9
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
10
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
11
|
+
}) : x)(function(x) {
|
|
12
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
13
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
14
|
+
});
|
|
15
|
+
function resolveRadius(borderRadius) {
|
|
16
|
+
if (borderRadius === void 0) return void 0;
|
|
17
|
+
if (typeof borderRadius === "number") return borderRadius;
|
|
18
|
+
return radii[borderRadius];
|
|
19
|
+
}
|
|
20
|
+
function isGlassConfig(glass) {
|
|
21
|
+
return typeof glass === "object" && glass !== null;
|
|
22
|
+
}
|
|
23
|
+
var Surface = React4.memo(
|
|
24
|
+
({
|
|
25
|
+
glass,
|
|
26
|
+
elevation,
|
|
27
|
+
variant,
|
|
28
|
+
bg,
|
|
29
|
+
borderRadius,
|
|
30
|
+
border = false,
|
|
31
|
+
borderColor,
|
|
32
|
+
borderWidth = 1,
|
|
33
|
+
animated = false,
|
|
34
|
+
style,
|
|
35
|
+
contentStyle,
|
|
36
|
+
children,
|
|
37
|
+
...viewProps
|
|
38
|
+
}) => {
|
|
39
|
+
const resolvedRadius = useMemo(() => resolveRadius(borderRadius), [borderRadius]);
|
|
40
|
+
const solidStyle = useMemo(() => {
|
|
41
|
+
const s = {};
|
|
42
|
+
if (bg !== void 0) s["backgroundColor"] = bg;
|
|
43
|
+
if (resolvedRadius !== void 0) s["borderRadius"] = resolvedRadius;
|
|
44
|
+
if (border) {
|
|
45
|
+
s["borderWidth"] = borderWidth;
|
|
46
|
+
s["borderColor"] = borderColor ?? "transparent";
|
|
47
|
+
}
|
|
48
|
+
return s;
|
|
49
|
+
}, [bg, resolvedRadius, border, borderWidth, borderColor]);
|
|
50
|
+
const glassConfig = useMemo(() => {
|
|
51
|
+
if (!glass) return null;
|
|
52
|
+
if (isGlassConfig(glass)) return glass;
|
|
53
|
+
return {
|
|
54
|
+
elevation: elevation ?? 2,
|
|
55
|
+
variant: variant ?? "surface"
|
|
56
|
+
};
|
|
57
|
+
}, [glass, elevation, variant]);
|
|
58
|
+
if (glassConfig !== null) {
|
|
59
|
+
const GV = GlassView;
|
|
60
|
+
const glassEl = /* @__PURE__ */ jsx(
|
|
61
|
+
GV,
|
|
62
|
+
{
|
|
63
|
+
elevation: glassConfig.elevation ?? 2,
|
|
64
|
+
variant: glassConfig.variant ?? "surface",
|
|
65
|
+
highlight: glassConfig.highlight,
|
|
66
|
+
border: glassConfig.border ?? border,
|
|
67
|
+
borderWidth: glassConfig.borderWidth ?? (border ? borderWidth : void 0),
|
|
68
|
+
borderRadius: resolvedRadius ?? 16,
|
|
69
|
+
blurOverride: glassConfig.blurOverride,
|
|
70
|
+
tintOverride: glassConfig.tintOverride,
|
|
71
|
+
glow: glassConfig.glow,
|
|
72
|
+
contentStyle,
|
|
73
|
+
style: animated ? void 0 : style,
|
|
74
|
+
...viewProps,
|
|
75
|
+
children
|
|
76
|
+
}
|
|
77
|
+
);
|
|
78
|
+
if (animated) {
|
|
79
|
+
return /* @__PURE__ */ jsx(Animated.View, { style, children: glassEl });
|
|
80
|
+
}
|
|
81
|
+
return glassEl;
|
|
82
|
+
}
|
|
83
|
+
const solidContent = contentStyle ? /* @__PURE__ */ jsx(View, { style: [styles.contentWrapper, contentStyle], children }) : children;
|
|
84
|
+
if (animated) {
|
|
85
|
+
return /* @__PURE__ */ jsx(Animated.View, { style: [solidStyle, style], ...viewProps, children: solidContent });
|
|
86
|
+
}
|
|
87
|
+
return /* @__PURE__ */ jsx(View, { style: [solidStyle, style], ...viewProps, children: solidContent });
|
|
88
|
+
}
|
|
89
|
+
);
|
|
90
|
+
Surface.displayName = "Surface";
|
|
91
|
+
var styles = StyleSheet.create({
|
|
92
|
+
contentWrapper: {
|
|
93
|
+
position: "relative"
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
var triggerHaptic = null;
|
|
97
|
+
try {
|
|
98
|
+
const Haptics = __require("expo-haptics");
|
|
99
|
+
triggerHaptic = () => {
|
|
100
|
+
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light).catch(() => {
|
|
101
|
+
});
|
|
102
|
+
};
|
|
103
|
+
} catch {
|
|
104
|
+
}
|
|
105
|
+
var GlassPressable = React4.memo(
|
|
106
|
+
({
|
|
107
|
+
// Press animation
|
|
108
|
+
pressedScale = 0.97,
|
|
109
|
+
pressedOpacity = 0.9,
|
|
110
|
+
haptic = false,
|
|
111
|
+
// State
|
|
112
|
+
loading = false,
|
|
113
|
+
disabled = false,
|
|
114
|
+
// Surface passthrough
|
|
115
|
+
glass,
|
|
116
|
+
elevation,
|
|
117
|
+
variant,
|
|
118
|
+
bg,
|
|
119
|
+
borderRadius,
|
|
120
|
+
border,
|
|
121
|
+
borderColor,
|
|
122
|
+
borderWidth,
|
|
123
|
+
style,
|
|
124
|
+
contentStyle,
|
|
125
|
+
children,
|
|
126
|
+
// Pressable handlers
|
|
127
|
+
onPress,
|
|
128
|
+
onPressIn,
|
|
129
|
+
onPressOut,
|
|
130
|
+
onLongPress,
|
|
131
|
+
// rest of PressableProps (accessibilityRole, testID, etc.)
|
|
132
|
+
...pressableProps
|
|
133
|
+
}) => {
|
|
134
|
+
const isDisabled = disabled || loading;
|
|
135
|
+
const { animatedStyle, handlers } = usePressAnimation({
|
|
136
|
+
pressedScale,
|
|
137
|
+
pressedOpacity,
|
|
138
|
+
disabled: isDisabled
|
|
139
|
+
});
|
|
140
|
+
const handlePressIn = useCallback(
|
|
141
|
+
(e) => {
|
|
142
|
+
handlers.onPressIn();
|
|
143
|
+
if (haptic && triggerHaptic) triggerHaptic();
|
|
144
|
+
onPressIn?.(e);
|
|
145
|
+
},
|
|
146
|
+
[handlers, haptic, onPressIn]
|
|
147
|
+
);
|
|
148
|
+
const handlePressOut = useCallback(
|
|
149
|
+
(e) => {
|
|
150
|
+
handlers.onPressOut();
|
|
151
|
+
onPressOut?.(e);
|
|
152
|
+
},
|
|
153
|
+
[handlers, onPressOut]
|
|
154
|
+
);
|
|
155
|
+
const handlePress = useCallback(
|
|
156
|
+
(e) => {
|
|
157
|
+
if (!isDisabled) onPress?.(e);
|
|
158
|
+
},
|
|
159
|
+
[isDisabled, onPress]
|
|
160
|
+
);
|
|
161
|
+
const handleLongPress = useCallback(
|
|
162
|
+
(e) => {
|
|
163
|
+
if (!isDisabled) onLongPress?.(e);
|
|
164
|
+
},
|
|
165
|
+
[isDisabled, onLongPress]
|
|
166
|
+
);
|
|
167
|
+
return /* @__PURE__ */ jsx(
|
|
168
|
+
Pressable,
|
|
169
|
+
{
|
|
170
|
+
onPress: handlePress,
|
|
171
|
+
onPressIn: handlePressIn,
|
|
172
|
+
onPressOut: handlePressOut,
|
|
173
|
+
onLongPress: handleLongPress,
|
|
174
|
+
disabled: isDisabled,
|
|
175
|
+
style: styles2.pressable,
|
|
176
|
+
...pressableProps,
|
|
177
|
+
children: /* @__PURE__ */ jsx(Animated.View, { style: [animatedStyle, styles2.animatedContainer, isDisabled && styles2.disabled], children: /* @__PURE__ */ jsx(
|
|
178
|
+
Surface,
|
|
179
|
+
{
|
|
180
|
+
glass,
|
|
181
|
+
elevation,
|
|
182
|
+
variant,
|
|
183
|
+
bg,
|
|
184
|
+
borderRadius,
|
|
185
|
+
border,
|
|
186
|
+
borderColor,
|
|
187
|
+
borderWidth,
|
|
188
|
+
style,
|
|
189
|
+
contentStyle,
|
|
190
|
+
children
|
|
191
|
+
}
|
|
192
|
+
) })
|
|
193
|
+
}
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
);
|
|
197
|
+
GlassPressable.displayName = "GlassPressable";
|
|
198
|
+
var styles2 = StyleSheet.create({
|
|
199
|
+
pressable: {
|
|
200
|
+
// Pressable itself is transparent — layout handled by Animated.View + Surface
|
|
201
|
+
},
|
|
202
|
+
animatedContainer: {
|
|
203
|
+
// Animated.View wraps the Surface so scale/opacity transforms compose correctly
|
|
204
|
+
},
|
|
205
|
+
disabled: {
|
|
206
|
+
opacity: 0.45
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
var PortalContext = createContext(null);
|
|
210
|
+
|
|
211
|
+
// src/Portal/usePortal.ts
|
|
212
|
+
function usePortal() {
|
|
213
|
+
const ctx = useContext(PortalContext);
|
|
214
|
+
if (ctx === null) {
|
|
215
|
+
throw new Error(
|
|
216
|
+
"[Reactnatively] usePortal must be used inside a <PortalProvider>. Wrap your app root with <PortalProvider> to enable the portal system."
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
return ctx;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// src/Portal/Portal.tsx
|
|
223
|
+
function Portal({ children }) {
|
|
224
|
+
const ctx = usePortal();
|
|
225
|
+
const key = useId();
|
|
226
|
+
useEffect(() => {
|
|
227
|
+
ctx.mount(key, children);
|
|
228
|
+
return () => {
|
|
229
|
+
ctx.unmount(key);
|
|
230
|
+
};
|
|
231
|
+
}, [key]);
|
|
232
|
+
useEffect(() => {
|
|
233
|
+
ctx.update(key, children);
|
|
234
|
+
}, [ctx, key, children]);
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
Portal.displayName = "Portal";
|
|
238
|
+
var PortalHost = React4.memo(() => {
|
|
239
|
+
usePortal();
|
|
240
|
+
return /* @__PURE__ */ jsx(
|
|
241
|
+
View,
|
|
242
|
+
{
|
|
243
|
+
style: styles3.host,
|
|
244
|
+
pointerEvents: "box-none"
|
|
245
|
+
}
|
|
246
|
+
);
|
|
247
|
+
});
|
|
248
|
+
PortalHost.displayName = "PortalHost";
|
|
249
|
+
var styles3 = StyleSheet.create({
|
|
250
|
+
host: {
|
|
251
|
+
...StyleSheet.absoluteFillObject,
|
|
252
|
+
zIndex: 9999
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
var PortalProvider = React4.memo(({ children }) => {
|
|
256
|
+
const [entries, setEntries] = useState([]);
|
|
257
|
+
const mount = useCallback((key, element) => {
|
|
258
|
+
setEntries((prev) => {
|
|
259
|
+
if (prev.some((e) => e.key === key)) {
|
|
260
|
+
return prev.map((e) => e.key === key ? { key, element } : e);
|
|
261
|
+
}
|
|
262
|
+
return [...prev, { key, element }];
|
|
263
|
+
});
|
|
264
|
+
}, []);
|
|
265
|
+
const unmount = useCallback((key) => {
|
|
266
|
+
setEntries((prev) => prev.filter((e) => e.key !== key));
|
|
267
|
+
}, []);
|
|
268
|
+
const update = useCallback((key, element) => {
|
|
269
|
+
setEntries(
|
|
270
|
+
(prev) => prev.map((e) => e.key === key ? { key, element } : e)
|
|
271
|
+
);
|
|
272
|
+
}, []);
|
|
273
|
+
const contextValue = useMemo(
|
|
274
|
+
() => ({ mount, unmount, update }),
|
|
275
|
+
[mount, unmount, update]
|
|
276
|
+
);
|
|
277
|
+
return /* @__PURE__ */ jsxs(PortalContext.Provider, { value: contextValue, children: [
|
|
278
|
+
children,
|
|
279
|
+
/* @__PURE__ */ jsx(
|
|
280
|
+
View,
|
|
281
|
+
{
|
|
282
|
+
style: styles4.host,
|
|
283
|
+
pointerEvents: "box-none",
|
|
284
|
+
children: entries.map(({ key, element }) => /* @__PURE__ */ jsx(React4.Fragment, { children: element }, key))
|
|
285
|
+
}
|
|
286
|
+
)
|
|
287
|
+
] });
|
|
288
|
+
});
|
|
289
|
+
PortalProvider.displayName = "PortalProvider";
|
|
290
|
+
var styles4 = StyleSheet.create({
|
|
291
|
+
host: {
|
|
292
|
+
...StyleSheet.absoluteFillObject,
|
|
293
|
+
zIndex: 9999
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
var Slot = forwardRef(function Slot2({ children, ...slotProps }, ref) {
|
|
297
|
+
if (!isValidElement(children)) {
|
|
298
|
+
if (process.env.NODE_ENV !== "production") {
|
|
299
|
+
console.warn(
|
|
300
|
+
"[Reactnatively] <Slot> received a non-element child and rendered nothing. Pass a single valid React element as the child of Slot."
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
305
|
+
const childProps = children.props;
|
|
306
|
+
const mergedProps = {};
|
|
307
|
+
for (const key of Object.keys(slotProps)) {
|
|
308
|
+
mergedProps[key] = slotProps[key];
|
|
309
|
+
}
|
|
310
|
+
for (const key of Object.keys(childProps)) {
|
|
311
|
+
const slotHandler = slotProps[key];
|
|
312
|
+
const childHandler = childProps[key];
|
|
313
|
+
if (typeof slotHandler === "function" && typeof childHandler === "function") {
|
|
314
|
+
mergedProps[key] = (...args) => {
|
|
315
|
+
slotHandler(...args);
|
|
316
|
+
childHandler(...args);
|
|
317
|
+
};
|
|
318
|
+
} else {
|
|
319
|
+
mergedProps[key] = childProps[key] ?? slotProps[key];
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
if (slotProps.style !== void 0 || childProps.style !== void 0) {
|
|
323
|
+
mergedProps["style"] = [slotProps.style, childProps.style].filter(Boolean);
|
|
324
|
+
}
|
|
325
|
+
return cloneElement(children, {
|
|
326
|
+
...mergedProps,
|
|
327
|
+
ref
|
|
328
|
+
});
|
|
329
|
+
});
|
|
330
|
+
Slot.displayName = "Slot";
|
|
331
|
+
function buildVariantStyle(variant) {
|
|
332
|
+
switch (variant) {
|
|
333
|
+
case "display":
|
|
334
|
+
return {
|
|
335
|
+
fontSize: fontSize["6xl"],
|
|
336
|
+
fontWeight: fontWeight.black,
|
|
337
|
+
lineHeight: fontSize["6xl"] * lineHeight.tight
|
|
338
|
+
};
|
|
339
|
+
case "heading1":
|
|
340
|
+
return {
|
|
341
|
+
fontSize: fontSize["5xl"],
|
|
342
|
+
fontWeight: fontWeight.bold,
|
|
343
|
+
lineHeight: fontSize["5xl"] * lineHeight.tight
|
|
344
|
+
};
|
|
345
|
+
case "heading2":
|
|
346
|
+
return {
|
|
347
|
+
fontSize: fontSize["4xl"],
|
|
348
|
+
fontWeight: fontWeight.bold,
|
|
349
|
+
lineHeight: fontSize["4xl"] * lineHeight.tight
|
|
350
|
+
};
|
|
351
|
+
case "heading3":
|
|
352
|
+
case "heading":
|
|
353
|
+
return {
|
|
354
|
+
fontSize: fontSize["3xl"],
|
|
355
|
+
fontWeight: fontWeight.semibold,
|
|
356
|
+
lineHeight: fontSize["3xl"] * lineHeight.snug
|
|
357
|
+
};
|
|
358
|
+
case "heading4":
|
|
359
|
+
return {
|
|
360
|
+
fontSize: fontSize["2xl"],
|
|
361
|
+
fontWeight: fontWeight.semibold,
|
|
362
|
+
lineHeight: fontSize["2xl"] * lineHeight.snug
|
|
363
|
+
};
|
|
364
|
+
case "bodyLarge":
|
|
365
|
+
return {
|
|
366
|
+
fontSize: fontSize.lg,
|
|
367
|
+
fontWeight: fontWeight.normal,
|
|
368
|
+
lineHeight: fontSize.lg * lineHeight.normal
|
|
369
|
+
};
|
|
370
|
+
case "body":
|
|
371
|
+
return {
|
|
372
|
+
fontSize: fontSize.base,
|
|
373
|
+
fontWeight: fontWeight.normal,
|
|
374
|
+
lineHeight: fontSize.base * lineHeight.normal
|
|
375
|
+
};
|
|
376
|
+
case "label":
|
|
377
|
+
return {
|
|
378
|
+
fontSize: fontSize.sm,
|
|
379
|
+
fontWeight: fontWeight.medium,
|
|
380
|
+
lineHeight: fontSize.sm * lineHeight.snug,
|
|
381
|
+
letterSpacing: 0.1
|
|
382
|
+
};
|
|
383
|
+
case "caption":
|
|
384
|
+
return {
|
|
385
|
+
fontSize: fontSize.xs,
|
|
386
|
+
fontWeight: fontWeight.normal,
|
|
387
|
+
lineHeight: fontSize.xs * lineHeight.normal
|
|
388
|
+
};
|
|
389
|
+
case "overline":
|
|
390
|
+
return {
|
|
391
|
+
fontSize: fontSize["2xs"],
|
|
392
|
+
fontWeight: fontWeight.semibold,
|
|
393
|
+
lineHeight: fontSize["2xs"] * lineHeight.normal,
|
|
394
|
+
letterSpacing: 0.8,
|
|
395
|
+
textTransform: "uppercase"
|
|
396
|
+
};
|
|
397
|
+
case "code":
|
|
398
|
+
return {
|
|
399
|
+
fontSize: fontSize.sm,
|
|
400
|
+
fontWeight: fontWeight.normal,
|
|
401
|
+
lineHeight: fontSize.sm * lineHeight.relaxed,
|
|
402
|
+
fontFamily: "Courier"
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
var GlassText = React4.memo(
|
|
407
|
+
({
|
|
408
|
+
variant = "body",
|
|
409
|
+
color,
|
|
410
|
+
weight,
|
|
411
|
+
size,
|
|
412
|
+
leading,
|
|
413
|
+
uppercase = false,
|
|
414
|
+
style,
|
|
415
|
+
children,
|
|
416
|
+
...textProps
|
|
417
|
+
}) => {
|
|
418
|
+
const { theme } = useTheme();
|
|
419
|
+
const resolvedStyle = useMemo(() => {
|
|
420
|
+
const base = buildVariantStyle(variant);
|
|
421
|
+
const resolvedColor = color !== void 0 ? theme.colors[color] ?? color : theme.colors.text;
|
|
422
|
+
const resolvedSize = size ?? base.fontSize;
|
|
423
|
+
const resolvedWeight = weight ? fontWeight[weight] : base.fontWeight;
|
|
424
|
+
const resolvedLineHeight = leading ? resolvedSize * lineHeight[leading] : base.lineHeight;
|
|
425
|
+
return {
|
|
426
|
+
color: resolvedColor,
|
|
427
|
+
fontSize: resolvedSize,
|
|
428
|
+
fontWeight: resolvedWeight,
|
|
429
|
+
lineHeight: resolvedLineHeight,
|
|
430
|
+
fontFamily: base.fontFamily,
|
|
431
|
+
letterSpacing: base.letterSpacing,
|
|
432
|
+
textTransform: uppercase || base.textTransform === "uppercase" ? "uppercase" : base.textTransform
|
|
433
|
+
};
|
|
434
|
+
}, [variant, color, weight, size, leading, uppercase, theme]);
|
|
435
|
+
return /* @__PURE__ */ jsx(
|
|
436
|
+
Text,
|
|
437
|
+
{
|
|
438
|
+
style: [resolvedStyle, style],
|
|
439
|
+
allowFontScaling: false,
|
|
440
|
+
...textProps,
|
|
441
|
+
children
|
|
442
|
+
}
|
|
443
|
+
);
|
|
444
|
+
}
|
|
445
|
+
);
|
|
446
|
+
GlassText.displayName = "GlassText";
|
|
447
|
+
StyleSheet.create({
|
|
448
|
+
// Reserved for potential future static style helpers
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
export { GlassPressable, GlassText, Portal, PortalHost, PortalProvider, Slot, Surface, usePortal };
|
|
452
|
+
//# sourceMappingURL=index.mjs.map
|
|
453
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/Surface/Surface.tsx","../src/GlassPressable/GlassPressable.tsx","../src/Portal/portal-context.ts","../src/Portal/usePortal.ts","../src/Portal/Portal.tsx","../src/Portal/PortalHost.tsx","../src/Portal/PortalProvider.tsx","../src/Slot/Slot.tsx","../src/GlassText/GlassText.tsx"],"names":["React","jsx","styles","Animated","StyleSheet","View","useCallback","useMemo","Slot","fontSizeTokens","fontWeightTokens","lineHeightTokens"],"mappings":"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","file":"index.mjs","sourcesContent":["import React, { useMemo } from 'react';\nimport { View, StyleSheet } from 'react-native';\nimport Animated from 'react-native-reanimated';\nimport { GlassView } from 'reactnatively-glass';\nimport { radii } from 'reactnatively-theme';\nimport type { RadiiKey } from 'reactnatively-theme';\nimport type { SurfaceProps, GlassSurfaceConfig } from './Surface.types';\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\nfunction resolveRadius(borderRadius?: number | RadiiKey): number | undefined {\n if (borderRadius === undefined) return undefined;\n if (typeof borderRadius === 'number') return borderRadius;\n return radii[borderRadius as RadiiKey];\n}\n\nfunction isGlassConfig(glass: boolean | GlassSurfaceConfig): glass is GlassSurfaceConfig {\n return typeof glass === 'object' && glass !== null;\n}\n\n// ─── Component ────────────────────────────────────────────────────────────────\n\n/**\n * Surface — the unified rendering primitive.\n *\n * Handles three rendering paths:\n * 1. glass=true/config → GlassView (liquid glass layer stack)\n * 2. solid bg → plain View with backgroundColor\n * 3. animated=true → wraps whichever output in Animated.View\n *\n * All hooks are called unconditionally (Rules of Hooks). The glass/solid\n * branch decision happens in the return, not at hook call sites.\n */\nexport const Surface = React.memo<SurfaceProps>(\n ({\n glass,\n elevation,\n variant,\n bg,\n borderRadius,\n border = false,\n borderColor,\n borderWidth = 1,\n animated = false,\n style,\n contentStyle,\n children,\n ...viewProps\n }) => {\n // ── Hooks (must be called unconditionally) ────────────────────────────────\n\n const resolvedRadius = useMemo(() => resolveRadius(borderRadius), [borderRadius]);\n\n // Solid background style — computed regardless of glass mode (cheap, and\n // avoids conditional hook calls which violate the Rules of Hooks).\n // Returned as a plain object; TypeScript infers the shape to avoid\n // phantom type conflicts between multiple react-native version resolutions.\n const solidStyle = useMemo(() => {\n const s: Record<string, unknown> = {};\n if (bg !== undefined) s['backgroundColor'] = bg;\n if (resolvedRadius !== undefined) s['borderRadius'] = resolvedRadius;\n if (border) {\n s['borderWidth'] = borderWidth;\n s['borderColor'] = borderColor ?? 'transparent';\n }\n return s;\n }, [bg, resolvedRadius, border, borderWidth, borderColor]);\n\n // ── Glass config resolution ───────────────────────────────────────────────\n\n const glassConfig = useMemo((): GlassSurfaceConfig | null => {\n if (!glass) return null;\n if (isGlassConfig(glass)) return glass;\n return {\n elevation: elevation ?? 2,\n variant: variant ?? 'surface',\n };\n }, [glass, elevation, variant]);\n\n // ── Render ────────────────────────────────────────────────────────────────\n\n if (glassConfig !== null) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const GV = GlassView as React.ComponentType<any>;\n const glassEl = (\n <GV\n elevation={glassConfig.elevation ?? 2}\n variant={glassConfig.variant ?? 'surface'}\n highlight={glassConfig.highlight}\n border={glassConfig.border ?? border}\n borderWidth={glassConfig.borderWidth ?? (border ? borderWidth : undefined)}\n borderRadius={resolvedRadius ?? 16}\n blurOverride={glassConfig.blurOverride}\n tintOverride={glassConfig.tintOverride}\n glow={glassConfig.glow}\n contentStyle={contentStyle}\n style={animated ? undefined : style}\n {...viewProps}\n >\n {children}\n </GV>\n );\n\n if (animated) {\n return (\n <Animated.View style={style}>\n {glassEl}\n </Animated.View>\n );\n }\n\n return glassEl;\n }\n\n // ── Solid / plain path ────────────────────────────────────────────────────\n\n const solidContent = contentStyle ? (\n <View style={[styles.contentWrapper, contentStyle]}>{children}</View>\n ) : children;\n\n if (animated) {\n return (\n <Animated.View style={[solidStyle, style]} {...viewProps}>\n {solidContent}\n </Animated.View>\n );\n }\n\n return (\n <View style={[solidStyle, style]} {...viewProps}>\n {solidContent}\n </View>\n );\n },\n);\n\nSurface.displayName = 'Surface';\n\nconst styles = StyleSheet.create({\n contentWrapper: {\n position: 'relative',\n },\n});\n","import React, { useCallback } from 'react';\nimport { Pressable, StyleSheet, type GestureResponderEvent } from 'react-native';\nimport Animated from 'react-native-reanimated';\nimport { usePressAnimation } from 'reactnatively-animations';\nimport { Surface } from '../Surface/Surface';\nimport type { GlassPressableProps } from './GlassPressable.types';\n\n// ─── Haptics (optional peer dependency) ──────────────────────────────────────\n\nlet triggerHaptic: (() => void) | null = null;\n\ntry {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const Haptics = require('expo-haptics') as typeof import('expo-haptics');\n triggerHaptic = () => {\n Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light).catch(() => {\n // swallow — haptics are best-effort\n });\n };\n} catch {\n // expo-haptics not installed; haptic prop will be a no-op\n}\n\n// ─── Component ────────────────────────────────────────────────────────────────\n\n/**\n * GlassPressable — the interactive foundation of the Reactnatively component system.\n *\n * Layer order (outer → inner):\n * Pressable (touch target)\n * └─ Animated.View (scale + opacity spring animation)\n * └─ Surface (glass or solid background)\n * └─ children\n */\nexport const GlassPressable = React.memo<GlassPressableProps>(\n ({\n // Press animation\n pressedScale = 0.97,\n pressedOpacity = 0.90,\n haptic = false,\n // State\n loading = false,\n disabled = false,\n // Surface passthrough\n glass,\n elevation,\n variant,\n bg,\n borderRadius,\n border,\n borderColor,\n borderWidth,\n style,\n contentStyle,\n children,\n // Pressable handlers\n onPress,\n onPressIn,\n onPressOut,\n onLongPress,\n // rest of PressableProps (accessibilityRole, testID, etc.)\n ...pressableProps\n }) => {\n const isDisabled = disabled || loading;\n\n const { animatedStyle, handlers } = usePressAnimation({\n pressedScale,\n pressedOpacity,\n disabled: isDisabled,\n });\n\n const handlePressIn = useCallback(\n (e: GestureResponderEvent) => {\n handlers.onPressIn();\n if (haptic && triggerHaptic) triggerHaptic();\n onPressIn?.(e);\n },\n [handlers, haptic, onPressIn],\n );\n\n const handlePressOut = useCallback(\n (e: GestureResponderEvent) => {\n handlers.onPressOut();\n onPressOut?.(e);\n },\n [handlers, onPressOut],\n );\n\n const handlePress = useCallback(\n (e: GestureResponderEvent) => {\n if (!isDisabled) onPress?.(e);\n },\n [isDisabled, onPress],\n );\n\n const handleLongPress = useCallback(\n (e: GestureResponderEvent) => {\n if (!isDisabled) onLongPress?.(e);\n },\n [isDisabled, onLongPress],\n );\n\n return (\n <Pressable\n onPress={handlePress}\n onPressIn={handlePressIn}\n onPressOut={handlePressOut}\n onLongPress={handleLongPress}\n disabled={isDisabled}\n style={styles.pressable}\n {...pressableProps}\n >\n <Animated.View style={[animatedStyle, styles.animatedContainer, isDisabled && styles.disabled]}>\n <Surface\n glass={glass}\n elevation={elevation}\n variant={variant}\n bg={bg}\n borderRadius={borderRadius}\n border={border}\n borderColor={borderColor}\n borderWidth={borderWidth}\n style={style}\n contentStyle={contentStyle}\n >\n {children}\n </Surface>\n </Animated.View>\n </Pressable>\n );\n },\n);\n\nGlassPressable.displayName = 'GlassPressable';\n\nconst styles = StyleSheet.create({\n pressable: {\n // Pressable itself is transparent — layout handled by Animated.View + Surface\n },\n animatedContainer: {\n // Animated.View wraps the Surface so scale/opacity transforms compose correctly\n },\n disabled: {\n opacity: 0.45,\n },\n});\n","import { createContext } from 'react';\nimport type { ReactNode } from 'react';\n\nexport interface PortalEntry {\n key: string;\n element: ReactNode;\n}\n\nexport interface PortalContextValue {\n mount: (key: string, element: ReactNode) => void;\n unmount: (key: string) => void;\n update: (key: string, element: ReactNode) => void;\n}\n\nexport const PortalContext = createContext<PortalContextValue | null>(null);\n","import { useContext } from 'react';\nimport { PortalContext } from './portal-context';\nimport type { PortalContextValue } from './portal-context';\n\n/**\n * usePortal — access the portal mount/unmount/update API.\n *\n * @throws if called outside a PortalProvider.\n */\nexport function usePortal(): PortalContextValue {\n const ctx = useContext(PortalContext);\n if (ctx === null) {\n throw new Error(\n '[Reactnatively] usePortal must be used inside a <PortalProvider>. ' +\n 'Wrap your app root with <PortalProvider> to enable the portal system.',\n );\n }\n return ctx;\n}\n","import { useEffect, useId, type ReactNode } from 'react';\nimport { usePortal } from './usePortal';\n\ninterface PortalProps {\n children: ReactNode;\n}\n\n/**\n * Portal — mounts its children into the PortalProvider's host layer.\n *\n * Renders nothing at its own position in the tree; the children appear\n * above all other content at zIndex 9999 via the PortalProvider.\n *\n * Usage:\n * ```tsx\n * <Portal>\n * <ModalContent />\n * </Portal>\n * ```\n *\n * Lifecycle:\n * - mount → registers children in the portal registry\n * - update → keeps the portal in sync when children change\n * - unmount → removes children from the registry\n */\nexport function Portal({ children }: PortalProps): null {\n const ctx = usePortal();\n // useId produces a stable, unique key scoped to this component instance\n const key = useId();\n\n useEffect(() => {\n ctx.mount(key, children);\n return () => {\n ctx.unmount(key);\n };\n // mount/unmount are stable (useCallback in PortalProvider)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [key]);\n\n useEffect(() => {\n ctx.update(key, children);\n // update fires whenever children reference changes\n }, [ctx, key, children]);\n\n return null;\n}\n\nPortal.displayName = 'Portal';\n","import React from 'react';\nimport { View, StyleSheet } from 'react-native';\nimport { usePortal } from './usePortal';\n\n/**\n * PortalHost — an additional named host for portals that need to be\n * scoped below the root-level PortalProvider host.\n *\n * The root host is rendered automatically inside PortalProvider.\n * Use PortalHost if you want a secondary portal target inside a specific\n * screen or layout region (e.g. inside a bottom sheet for nested portals).\n *\n * Must be placed inside a PortalProvider.\n */\nexport const PortalHost = React.memo(() => {\n // Calling usePortal here validates we are inside a PortalProvider.\n // This component itself does not render portal entries — the primary\n // host is owned by PortalProvider. PortalHost serves as a marker /\n // secondary host for advanced scoping patterns.\n usePortal();\n\n return (\n <View\n style={styles.host}\n pointerEvents=\"box-none\"\n />\n );\n});\n\nPortalHost.displayName = 'PortalHost';\n\nconst styles = StyleSheet.create({\n host: {\n ...StyleSheet.absoluteFillObject,\n zIndex: 9999,\n },\n});\n","import React, { useState, useCallback, useMemo } from 'react';\nimport { View, StyleSheet } from 'react-native';\nimport type { ReactNode } from 'react';\nimport { PortalContext } from './portal-context';\nimport type { PortalEntry, PortalContextValue } from './portal-context';\n\ninterface PortalProviderProps {\n children: ReactNode;\n}\n\n/**\n * PortalProvider — must wrap the root of your app (alongside ThemeProvider).\n *\n * Maintains the registry of active portal entries and renders them in a\n * full-screen host view layered above all other content (zIndex 9999).\n *\n * Architecture:\n * - entries state holds { key, element }[] — a plain array so React\n * reconciles portal renders without needing forceUpdate hacks.\n * - mount/update/unmount are stable references via useCallback.\n */\nexport const PortalProvider = React.memo<PortalProviderProps>(({ children }) => {\n const [entries, setEntries] = useState<PortalEntry[]>([]);\n\n const mount = useCallback((key: string, element: ReactNode) => {\n setEntries((prev) => {\n // Avoid duplicate mounts for the same key\n if (prev.some((e) => e.key === key)) {\n return prev.map((e) => (e.key === key ? { key, element } : e));\n }\n return [...prev, { key, element }];\n });\n }, []);\n\n const unmount = useCallback((key: string) => {\n setEntries((prev) => prev.filter((e) => e.key !== key));\n }, []);\n\n const update = useCallback((key: string, element: ReactNode) => {\n setEntries((prev) =>\n prev.map((e) => (e.key === key ? { key, element } : e)),\n );\n }, []);\n\n const contextValue = useMemo<PortalContextValue>(\n () => ({ mount, unmount, update }),\n [mount, unmount, update],\n );\n\n return (\n <PortalContext.Provider value={contextValue}>\n {children}\n {/* Portal host — renders above all children, passes touches through when empty */}\n <View\n style={styles.host}\n pointerEvents=\"box-none\"\n >\n {entries.map(({ key, element }) => (\n <React.Fragment key={key}>{element}</React.Fragment>\n ))}\n </View>\n </PortalContext.Provider>\n );\n});\n\nPortalProvider.displayName = 'PortalProvider';\n\nconst styles = StyleSheet.create({\n host: {\n ...StyleSheet.absoluteFillObject,\n zIndex: 9999,\n },\n});\n","import React, { cloneElement, isValidElement, forwardRef } from 'react';\nimport type { StyleProp, ViewStyle } from 'react-native';\nimport type { Ref } from 'react';\n\ninterface SlotProps {\n children?: React.ReactNode;\n style?: StyleProp<ViewStyle>;\n [key: string]: unknown;\n}\n\n/**\n * Slot — Radix-style render delegation primitive.\n *\n * Merges its own props with the single child element's props, then renders\n * that child (not a wrapper element). Event handlers from both Slot and the\n * child are composed so both fire. Styles are merged with the child's styles\n * taking precedence.\n *\n * Usage — implementing `asChild` on a component:\n * ```tsx\n * function Button({ asChild, ...props }) {\n * const Comp = asChild ? Slot : Pressable;\n * return <Comp {...props} />;\n * }\n *\n * // Render a Link as a button:\n * <Button asChild>\n * <Link href=\"/home\" />\n * </Button>\n * ```\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const Slot = forwardRef<unknown, SlotProps>(function Slot(\n { children, ...slotProps },\n ref,\n) {\n if (!isValidElement(children)) {\n if (process.env.NODE_ENV !== 'production') {\n // eslint-disable-next-line no-console\n console.warn(\n '[Reactnatively] <Slot> received a non-element child and rendered nothing. ' +\n 'Pass a single valid React element as the child of Slot.',\n );\n }\n return null;\n }\n\n // Merge event handlers: compose both so neither is silently dropped.\n const childProps = children.props as Record<string, unknown>;\n const mergedProps: Record<string, unknown> = {};\n\n // Start with slot props\n for (const key of Object.keys(slotProps)) {\n mergedProps[key] = slotProps[key];\n }\n\n // Override with child props, composing function handlers\n for (const key of Object.keys(childProps)) {\n const slotHandler = slotProps[key];\n const childHandler = childProps[key];\n\n if (\n typeof slotHandler === 'function' &&\n typeof childHandler === 'function'\n ) {\n // Compose: Slot handler fires first, then child handler\n mergedProps[key] = (...args: unknown[]) => {\n (slotHandler as (...a: unknown[]) => void)(...args);\n (childHandler as (...a: unknown[]) => void)(...args);\n };\n } else {\n // Child prop wins (child is more specific)\n mergedProps[key] = childProps[key] ?? slotProps[key];\n }\n }\n\n // Style merging: [slotStyle, childStyle] — child style overrides slot style\n if (slotProps.style !== undefined || childProps.style !== undefined) {\n mergedProps['style'] = [slotProps.style, childProps.style].filter(Boolean);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return cloneElement(children as React.ReactElement<any>, {\n ...mergedProps,\n ref: ref as Ref<unknown>,\n });\n});\n\nSlot.displayName = 'Slot';\n","import React, { useMemo } from 'react';\nimport { Text, StyleSheet, type TextStyle } from 'react-native';\nimport { useTheme } from 'reactnatively-theme';\nimport { fontSize as fontSizeTokens, fontWeight as fontWeightTokens, lineHeight as lineHeightTokens } from 'reactnatively-theme';\nimport type { ThemeColorKey } from 'reactnatively-theme';\nimport type { TextProps } from 'react-native';\nimport type { ReactNode } from 'react';\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\n/** Semantic text roles — map to predefined size + weight + line-height combos */\nexport type GlassTextVariant =\n | 'display' // 52px / black — large hero text\n | 'heading1' // 40px / bold — page title\n | 'heading2' // 32px / bold — section title\n | 'heading3' // 26px / semibold\n | 'heading4' // 22px / semibold\n | 'heading' // alias → heading3\n | 'body' // 15px / normal — default body copy\n | 'bodyLarge' // 17px / normal\n | 'label' // 13px / medium — UI labels, tabs\n | 'caption' // 12px / normal — secondary info\n | 'overline' // 10px / semibold / uppercased — category labels\n | 'code'; // 13px / mono — code snippets\n\nexport type GlassTextWeight = keyof typeof fontWeightTokens;\n\nexport interface GlassTextProps extends Omit<TextProps, 'style'> {\n /** Semantic variant. Defaults to 'body'. */\n variant?: GlassTextVariant;\n /** Theme color key or any valid CSS/RN color string */\n color?: ThemeColorKey | string;\n /** Override font weight token */\n weight?: GlassTextWeight;\n /** Override font size in pixels */\n size?: number;\n /** Override line height multiplier */\n leading?: keyof typeof lineHeightTokens;\n /** Uppercase transform (auto-applied for 'overline' variant) */\n uppercase?: boolean;\n style?: TextStyle | TextStyle[];\n children?: ReactNode;\n}\n\n// ─── Variant definitions ──────────────────────────────────────────────────────\n\ninterface VariantStyle {\n fontSize: number;\n fontWeight: TextStyle['fontWeight'];\n lineHeight: number;\n fontFamily?: string;\n letterSpacing?: number;\n textTransform?: TextStyle['textTransform'];\n}\n\nfunction buildVariantStyle(variant: GlassTextVariant): VariantStyle {\n switch (variant) {\n case 'display':\n return {\n fontSize: fontSizeTokens['6xl'],\n fontWeight: fontWeightTokens.black,\n lineHeight: fontSizeTokens['6xl'] * lineHeightTokens.tight,\n };\n case 'heading1':\n return {\n fontSize: fontSizeTokens['5xl'],\n fontWeight: fontWeightTokens.bold,\n lineHeight: fontSizeTokens['5xl'] * lineHeightTokens.tight,\n };\n case 'heading2':\n return {\n fontSize: fontSizeTokens['4xl'],\n fontWeight: fontWeightTokens.bold,\n lineHeight: fontSizeTokens['4xl'] * lineHeightTokens.tight,\n };\n case 'heading3':\n case 'heading':\n return {\n fontSize: fontSizeTokens['3xl'],\n fontWeight: fontWeightTokens.semibold,\n lineHeight: fontSizeTokens['3xl'] * lineHeightTokens.snug,\n };\n case 'heading4':\n return {\n fontSize: fontSizeTokens['2xl'],\n fontWeight: fontWeightTokens.semibold,\n lineHeight: fontSizeTokens['2xl'] * lineHeightTokens.snug,\n };\n case 'bodyLarge':\n return {\n fontSize: fontSizeTokens.lg,\n fontWeight: fontWeightTokens.normal,\n lineHeight: fontSizeTokens.lg * lineHeightTokens.normal,\n };\n case 'body':\n return {\n fontSize: fontSizeTokens.base,\n fontWeight: fontWeightTokens.normal,\n lineHeight: fontSizeTokens.base * lineHeightTokens.normal,\n };\n case 'label':\n return {\n fontSize: fontSizeTokens.sm,\n fontWeight: fontWeightTokens.medium,\n lineHeight: fontSizeTokens.sm * lineHeightTokens.snug,\n letterSpacing: 0.1,\n };\n case 'caption':\n return {\n fontSize: fontSizeTokens.xs,\n fontWeight: fontWeightTokens.normal,\n lineHeight: fontSizeTokens.xs * lineHeightTokens.normal,\n };\n case 'overline':\n return {\n fontSize: fontSizeTokens['2xs'],\n fontWeight: fontWeightTokens.semibold,\n lineHeight: fontSizeTokens['2xs'] * lineHeightTokens.normal,\n letterSpacing: 0.8,\n textTransform: 'uppercase',\n };\n case 'code':\n return {\n fontSize: fontSizeTokens.sm,\n fontWeight: fontWeightTokens.normal,\n lineHeight: fontSizeTokens.sm * lineHeightTokens.relaxed,\n fontFamily: 'Courier',\n };\n }\n}\n\n// ─── Component ────────────────────────────────────────────────────────────────\n\n/**\n * GlassText — theme-aware text primitive.\n *\n * Automatically applies typography scale tokens and theme colors.\n * All variants are memoized; only re-resolves when props change.\n *\n * ```tsx\n * <GlassText variant=\"heading\" color=\"primary\">Hello</GlassText>\n * <GlassText variant=\"caption\" color=\"textMuted\">Fine print</GlassText>\n * <GlassText size={20} weight=\"bold\">Custom size</GlassText>\n * ```\n */\nexport const GlassText = React.memo<GlassTextProps>(\n ({\n variant = 'body',\n color,\n weight,\n size,\n leading,\n uppercase = false,\n style,\n children,\n ...textProps\n }) => {\n const { theme } = useTheme();\n\n const resolvedStyle = useMemo((): TextStyle => {\n const base = buildVariantStyle(variant);\n\n // Resolve color: theme key → theme color → fallback to raw string\n const resolvedColor =\n color !== undefined\n ? ((theme.colors as unknown as Record<string, string>)[color] ?? color)\n : theme.colors.text;\n\n const resolvedSize = size ?? base.fontSize;\n const resolvedWeight = weight ? fontWeightTokens[weight] : base.fontWeight;\n const resolvedLineHeight = leading\n ? resolvedSize * lineHeightTokens[leading]\n : base.lineHeight;\n\n return {\n color: resolvedColor,\n fontSize: resolvedSize,\n fontWeight: resolvedWeight,\n lineHeight: resolvedLineHeight,\n fontFamily: base.fontFamily,\n letterSpacing: base.letterSpacing,\n textTransform: (uppercase || base.textTransform === 'uppercase')\n ? 'uppercase'\n : base.textTransform,\n };\n }, [variant, color, weight, size, leading, uppercase, theme]);\n\n return (\n <Text\n style={[resolvedStyle, style]}\n allowFontScaling={false}\n {...textProps}\n >\n {children}\n </Text>\n );\n },\n);\n\nGlassText.displayName = 'GlassText';\n\n// Exported for consumers who need a static baseline without the hook\nexport const _styles = StyleSheet.create({\n // Reserved for potential future static style helpers\n});\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "reactnatively-primitives",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Base rendering primitives for the Reactnatively framework",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"sideEffects": false,
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"reactnatively-animations": "0.1.0",
|
|
21
|
+
"reactnatively-glass": "0.1.0",
|
|
22
|
+
"reactnatively-utils": "0.1.0",
|
|
23
|
+
"reactnatively-theme": "0.1.0"
|
|
24
|
+
},
|
|
25
|
+
"peerDependencies": {
|
|
26
|
+
"expo-blur": ">=13.0.0",
|
|
27
|
+
"react": ">=18.0.0",
|
|
28
|
+
"react-native": ">=0.73.0",
|
|
29
|
+
"react-native-gesture-handler": ">=2.14.0",
|
|
30
|
+
"react-native-linear-gradient": ">=2.8.0",
|
|
31
|
+
"react-native-reanimated": ">=3.6.0"
|
|
32
|
+
},
|
|
33
|
+
"peerDependenciesMeta": {
|
|
34
|
+
"expo-blur": {
|
|
35
|
+
"optional": true
|
|
36
|
+
},
|
|
37
|
+
"react-native-linear-gradient": {
|
|
38
|
+
"optional": true
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"tsup": "^8.2.4",
|
|
43
|
+
"typescript": "^5.5.3",
|
|
44
|
+
"@reactnatively/tsconfig": "0.0.0"
|
|
45
|
+
},
|
|
46
|
+
"keywords": [
|
|
47
|
+
"react-native",
|
|
48
|
+
"expo",
|
|
49
|
+
"primitives",
|
|
50
|
+
"ui",
|
|
51
|
+
"design-system",
|
|
52
|
+
"glass",
|
|
53
|
+
"liquid-glass",
|
|
54
|
+
"typescript"
|
|
55
|
+
],
|
|
56
|
+
"repository": {
|
|
57
|
+
"type": "git",
|
|
58
|
+
"url": "https://github.com/hakizimana-fred/reactnatively.git",
|
|
59
|
+
"directory": "packages/primitives"
|
|
60
|
+
},
|
|
61
|
+
"license": "MIT",
|
|
62
|
+
"publishConfig": {
|
|
63
|
+
"access": "public"
|
|
64
|
+
},
|
|
65
|
+
"scripts": {
|
|
66
|
+
"build": "tsup",
|
|
67
|
+
"dev": "tsup --watch",
|
|
68
|
+
"typecheck": "tsc --noEmit",
|
|
69
|
+
"clean": "rm -rf dist"
|
|
70
|
+
}
|
|
71
|
+
}
|