@retray-dev/ui-kit 9.3.1 → 10.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/COMPONENTS.md +136 -22
- package/CONSUMER.md +48 -8
- package/FONTS.md +54 -13
- package/README.md +40 -3
- package/dist/Accordion.d.mts +1 -1
- package/dist/Accordion.d.ts +1 -1
- package/dist/Accordion.js +2 -2
- package/dist/Accordion.mjs +1 -1
- package/dist/ConfirmDialog.d.mts +6 -1
- package/dist/ConfirmDialog.d.ts +6 -1
- package/dist/ConfirmDialog.js +44 -14
- package/dist/ConfirmDialog.mjs +1 -1
- package/dist/ImageViewer.js +282 -141
- package/dist/ImageViewer.mjs +3 -1
- package/dist/Sheet.js +16 -13
- package/dist/Sheet.mjs +1 -1
- package/dist/Switch.js +40 -17
- package/dist/Switch.mjs +1 -1
- package/dist/{chunk-O3HA6TYM.mjs → chunk-DJ7RN37L.mjs} +2 -2
- package/dist/{chunk-FZZLPJ6B.mjs → chunk-KZL5VTYK.mjs} +43 -14
- package/dist/{chunk-QKH5ZOD5.mjs → chunk-WF2XDFRK.mjs} +40 -17
- package/dist/{chunk-Z4BVUWW6.mjs → chunk-WOEYDUJZ.mjs} +19 -31
- package/dist/{chunk-PFZTM6D5.mjs → chunk-Y2NS74WS.mjs} +9 -7
- package/dist/fonts.d.mts +39 -31
- package/dist/fonts.d.ts +39 -31
- package/dist/fonts.js +34 -39
- package/dist/fonts.mjs +35 -34
- package/dist/index.js +119 -76
- package/dist/index.mjs +5 -5
- package/package.json +3 -1
- package/scripts/build-apk.sh +84 -0
- package/scripts/copy-fonts.js +90 -0
- package/scripts/test-consumer-fonts.sh +82 -0
- package/src/components/Accordion/Accordion.tsx +7 -3
- package/src/components/ConfirmDialog/ConfirmDialog.tsx +61 -23
- package/src/components/ImageViewer/ImageViewer.tsx +25 -30
- package/src/components/Sheet/Sheet.tsx +10 -9
- package/src/components/Switch/Switch.tsx +30 -17
- package/src/fonts.ts +59 -40
package/dist/index.js
CHANGED
|
@@ -12,7 +12,7 @@ var Ionicons = require('@expo/vector-icons/Ionicons');
|
|
|
12
12
|
var pressto = require('pressto');
|
|
13
13
|
var Animated12 = require('react-native-reanimated');
|
|
14
14
|
var expoFont = require('expo-font');
|
|
15
|
-
var
|
|
15
|
+
var BottomSheet = require('@gorhom/bottom-sheet');
|
|
16
16
|
var reactNativeEase = require('react-native-ease');
|
|
17
17
|
var vectorIcons = require('@expo/vector-icons');
|
|
18
18
|
var expoLinearGradient = require('expo-linear-gradient');
|
|
@@ -32,6 +32,7 @@ var FontAwesome5__default = /*#__PURE__*/_interopDefault(FontAwesome5);
|
|
|
32
32
|
var MaterialIcons__default = /*#__PURE__*/_interopDefault(MaterialIcons);
|
|
33
33
|
var Ionicons__default = /*#__PURE__*/_interopDefault(Ionicons);
|
|
34
34
|
var Animated12__default = /*#__PURE__*/_interopDefault(Animated12);
|
|
35
|
+
var BottomSheet__default = /*#__PURE__*/_interopDefault(BottomSheet);
|
|
35
36
|
var RNSlider__default = /*#__PURE__*/_interopDefault(RNSlider);
|
|
36
37
|
|
|
37
38
|
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
@@ -1035,7 +1036,7 @@ function Input({ label, error, hint, disabled, prefix, suffix, prefixStyle, suff
|
|
|
1035
1036
|
},
|
|
1036
1037
|
effectivePrefix ? typeof effectivePrefix === "string" ? /* @__PURE__ */ React25__default.default.createElement(reactNative.Text, { style: [styles4.prefixText, { color: colors.foregroundMuted }, prefixStyle], allowFontScaling: true }, effectivePrefix) : /* @__PURE__ */ React25__default.default.createElement(reactNative.View, { style: styles4.prefixContainer }, effectivePrefix) : null,
|
|
1037
1038
|
sheetMode ? /* @__PURE__ */ React25__default.default.createElement(
|
|
1038
|
-
|
|
1039
|
+
BottomSheet.BottomSheetTextInput,
|
|
1039
1040
|
{
|
|
1040
1041
|
style: [
|
|
1041
1042
|
styles4.input,
|
|
@@ -2028,9 +2029,11 @@ var THUMB_SIZE = s(24);
|
|
|
2028
2029
|
var THUMB_OFFSET = s(3);
|
|
2029
2030
|
var THUMB_TRAVEL = TRACK_WIDTH - THUMB_SIZE - THUMB_OFFSET * 2;
|
|
2030
2031
|
var ICON_SIZE = s(13);
|
|
2032
|
+
var DISABLED_OPACITY = 0.45;
|
|
2031
2033
|
function Switch({ checked = false, onCheckedChange, disabled, style, accessibilityLabel }) {
|
|
2032
2034
|
const { colors } = useTheme();
|
|
2033
|
-
|
|
2035
|
+
const isDisabled = !!disabled;
|
|
2036
|
+
return /* @__PURE__ */ React25__default.default.createElement(reactNative.View, { style: [{ alignSelf: "flex-start" }, style] }, /* @__PURE__ */ React25__default.default.createElement(
|
|
2034
2037
|
reactNative.TouchableOpacity,
|
|
2035
2038
|
{
|
|
2036
2039
|
onPress: () => {
|
|
@@ -2042,47 +2045,68 @@ function Switch({ checked = false, onCheckedChange, disabled, style, accessibili
|
|
|
2042
2045
|
touchSoundDisabled: true,
|
|
2043
2046
|
accessibilityRole: "switch",
|
|
2044
2047
|
accessibilityLabel,
|
|
2045
|
-
accessibilityState: { checked, disabled:
|
|
2048
|
+
accessibilityState: { checked, disabled: isDisabled },
|
|
2046
2049
|
style: styles16.touchable
|
|
2047
2050
|
},
|
|
2048
|
-
/* @__PURE__ */ React25__default.default.createElement(
|
|
2051
|
+
/* @__PURE__ */ React25__default.default.createElement(reactNative.View, { style: styles16.trackContainer }, /* @__PURE__ */ React25__default.default.createElement(
|
|
2049
2052
|
reactNativeEase.EaseView,
|
|
2050
2053
|
{
|
|
2051
|
-
style: styles16.track,
|
|
2054
|
+
style: [styles16.track, isDisabled && styles16.disabledTrack],
|
|
2052
2055
|
animate: { backgroundColor: checked ? colors.primary : colors.surfaceStrong },
|
|
2053
2056
|
transition: COLOR_TRANSITION
|
|
2057
|
+
}
|
|
2058
|
+
), /* @__PURE__ */ React25__default.default.createElement(
|
|
2059
|
+
reactNativeEase.EaseView,
|
|
2060
|
+
{
|
|
2061
|
+
style: [styles16.trackBorder, { borderWidth: 1.5 }],
|
|
2062
|
+
pointerEvents: "none",
|
|
2063
|
+
animate: { borderColor: checked ? "transparent" : colors.border },
|
|
2064
|
+
transition: COLOR_TRANSITION
|
|
2065
|
+
}
|
|
2066
|
+
), /* @__PURE__ */ React25__default.default.createElement(
|
|
2067
|
+
reactNativeEase.EaseView,
|
|
2068
|
+
{
|
|
2069
|
+
style: [styles16.thumb, { backgroundColor: colors.primaryForeground }],
|
|
2070
|
+
animate: { translateX: checked ? THUMB_TRAVEL : 0 },
|
|
2071
|
+
transition: SPRING_ELASTIC
|
|
2054
2072
|
},
|
|
2055
2073
|
/* @__PURE__ */ React25__default.default.createElement(
|
|
2056
2074
|
reactNativeEase.EaseView,
|
|
2057
2075
|
{
|
|
2058
|
-
style:
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
}
|
|
2076
|
+
style: styles16.iconWrapper,
|
|
2077
|
+
animate: { opacity: checked ? isDisabled ? DISABLED_OPACITY : 1 : 0 },
|
|
2078
|
+
transition: OPACITY_TRANSITION
|
|
2079
|
+
},
|
|
2080
|
+
/* @__PURE__ */ React25__default.default.createElement(vectorIcons.Feather, { name: "check", size: ICON_SIZE, color: colors.primary })
|
|
2063
2081
|
),
|
|
2064
2082
|
/* @__PURE__ */ React25__default.default.createElement(
|
|
2065
2083
|
reactNativeEase.EaseView,
|
|
2066
2084
|
{
|
|
2067
|
-
style:
|
|
2068
|
-
animate: {
|
|
2069
|
-
transition:
|
|
2085
|
+
style: styles16.iconWrapper,
|
|
2086
|
+
animate: { opacity: checked ? 0 : isDisabled ? DISABLED_OPACITY : 1 },
|
|
2087
|
+
transition: OPACITY_TRANSITION
|
|
2070
2088
|
},
|
|
2071
|
-
/* @__PURE__ */ React25__default.default.createElement(
|
|
2072
|
-
/* @__PURE__ */ React25__default.default.createElement(reactNativeEase.EaseView, { style: styles16.iconWrapper, animate: { opacity: checked ? 0 : 1 }, transition: OPACITY_TRANSITION }, /* @__PURE__ */ React25__default.default.createElement(vectorIcons.Feather, { name: "x", size: ICON_SIZE, color: colors.foregroundMuted }))
|
|
2089
|
+
/* @__PURE__ */ React25__default.default.createElement(vectorIcons.Feather, { name: "x", size: ICON_SIZE, color: colors.foregroundMuted })
|
|
2073
2090
|
)
|
|
2074
|
-
)
|
|
2091
|
+
))
|
|
2075
2092
|
));
|
|
2076
2093
|
}
|
|
2077
2094
|
var styles16 = reactNative.StyleSheet.create({
|
|
2078
2095
|
touchable: {
|
|
2079
2096
|
alignSelf: "flex-start"
|
|
2080
2097
|
},
|
|
2081
|
-
|
|
2098
|
+
trackContainer: {
|
|
2099
|
+
position: "relative",
|
|
2082
2100
|
width: TRACK_WIDTH,
|
|
2083
|
-
height: TRACK_HEIGHT
|
|
2101
|
+
height: TRACK_HEIGHT
|
|
2102
|
+
},
|
|
2103
|
+
track: {
|
|
2104
|
+
...reactNative.StyleSheet.absoluteFillObject,
|
|
2084
2105
|
borderRadius: TRACK_HEIGHT / 2
|
|
2085
2106
|
},
|
|
2107
|
+
disabledTrack: {
|
|
2108
|
+
opacity: DISABLED_OPACITY
|
|
2109
|
+
},
|
|
2086
2110
|
trackBorder: {
|
|
2087
2111
|
...reactNative.StyleSheet.absoluteFillObject,
|
|
2088
2112
|
borderRadius: TRACK_HEIGHT / 2
|
|
@@ -2601,9 +2625,9 @@ function AccordionItemComponent({
|
|
|
2601
2625
|
},
|
|
2602
2626
|
accessibilityRole: "button",
|
|
2603
2627
|
accessibilityState: { expanded: isOpen },
|
|
2604
|
-
accessibilityLabel: item.trigger
|
|
2628
|
+
accessibilityLabel: typeof item.trigger === "string" ? item.trigger : void 0
|
|
2605
2629
|
},
|
|
2606
|
-
/* @__PURE__ */ React25__default.default.createElement(reactNative.View, { style: styles20.triggerContent }, resolvedIcon ? /* @__PURE__ */ React25__default.default.createElement(reactNative.View, { style: styles20.icon }, resolvedIcon) : null, /* @__PURE__ */ React25__default.default.createElement(reactNative.Text, { style: [styles20.triggerText, { color: colors.foreground }], allowFontScaling: true }, item.trigger)),
|
|
2630
|
+
/* @__PURE__ */ React25__default.default.createElement(reactNative.View, { style: styles20.triggerContent }, resolvedIcon ? /* @__PURE__ */ React25__default.default.createElement(reactNative.View, { style: styles20.icon }, resolvedIcon) : null, typeof item.trigger === "string" ? /* @__PURE__ */ React25__default.default.createElement(reactNative.Text, { style: [styles20.triggerText, { color: colors.foreground }], allowFontScaling: true }, item.trigger) : item.trigger),
|
|
2607
2631
|
/* @__PURE__ */ React25__default.default.createElement(Animated12__default.default.View, { style: [styles20.chevron, rotationStyle] }, /* @__PURE__ */ React25__default.default.createElement(vectorIcons.Entypo, { name: "chevron-down", size: 18, color: colors.foregroundMuted }))
|
|
2608
2632
|
), /* @__PURE__ */ React25__default.default.createElement(Animated12__default.default.View, { style: bodyStyle }, /* @__PURE__ */ React25__default.default.createElement(
|
|
2609
2633
|
reactNative.View,
|
|
@@ -2811,13 +2835,13 @@ function Sheet({
|
|
|
2811
2835
|
React25.useEffect(() => {
|
|
2812
2836
|
if (open) {
|
|
2813
2837
|
impactMedium();
|
|
2814
|
-
ref.current?.
|
|
2838
|
+
ref.current?.snapToIndex(0);
|
|
2815
2839
|
} else {
|
|
2816
|
-
ref.current?.
|
|
2840
|
+
ref.current?.close();
|
|
2817
2841
|
}
|
|
2818
2842
|
}, [open]);
|
|
2819
2843
|
const renderBackdrop = React25.useCallback((props) => /* @__PURE__ */ React25__default.default.createElement(
|
|
2820
|
-
|
|
2844
|
+
BottomSheet.BottomSheetBackdrop,
|
|
2821
2845
|
{
|
|
2822
2846
|
...props,
|
|
2823
2847
|
disappearsOnIndex: -1,
|
|
@@ -2834,7 +2858,7 @@ function Sheet({
|
|
|
2834
2858
|
) : children;
|
|
2835
2859
|
const effectiveSubtitle = subtitle ?? description;
|
|
2836
2860
|
const showHeader = !!(title || effectiveSubtitle || showCloseButton) && !customHeader;
|
|
2837
|
-
const headerNode = customHeader ? customHeader : showHeader ? /* @__PURE__ */ React25__default.default.createElement(reactNative.View, { style: styles22.header, accessibilityRole: "header" }, /* @__PURE__ */ React25__default.default.createElement(reactNative.View, { style: styles22.headerRow }, title ? /* @__PURE__ */ React25__default.default.createElement(reactNative.Text, { style: [styles22.title, { color: colors.foreground }], allowFontScaling: true }, title) : /* @__PURE__ */ React25__default.default.createElement(reactNative.View, { style: { flex: 1 } }), showCloseButton ? /* @__PURE__ */ React25__default.default.createElement(
|
|
2861
|
+
const headerNode = customHeader ? customHeader : showHeader ? /* @__PURE__ */ React25__default.default.createElement(reactNative.View, { style: [styles22.header, { backgroundColor: colors.card }], accessibilityRole: "header" }, /* @__PURE__ */ React25__default.default.createElement(reactNative.View, { style: styles22.headerRow }, title ? /* @__PURE__ */ React25__default.default.createElement(reactNative.Text, { style: [styles22.title, { color: colors.foreground }], allowFontScaling: true }, title) : /* @__PURE__ */ React25__default.default.createElement(reactNative.View, { style: { flex: 1 } }), showCloseButton ? /* @__PURE__ */ React25__default.default.createElement(
|
|
2838
2862
|
reactNative.TouchableOpacity,
|
|
2839
2863
|
{
|
|
2840
2864
|
onPress: onClose,
|
|
@@ -2851,7 +2875,7 @@ function Sheet({
|
|
|
2851
2875
|
const effectiveFooter = customFooter ? customFooter : footer;
|
|
2852
2876
|
const renderFooter = React25.useCallback((props) => {
|
|
2853
2877
|
if (!effectiveFooter) return null;
|
|
2854
|
-
return /* @__PURE__ */ React25__default.default.createElement(
|
|
2878
|
+
return /* @__PURE__ */ React25__default.default.createElement(BottomSheet.BottomSheetFooter, { ...props }, effectiveFooter);
|
|
2855
2879
|
}, [effectiveFooter]);
|
|
2856
2880
|
if (asDialog) {
|
|
2857
2881
|
return /* @__PURE__ */ React25__default.default.createElement(reactNative.Modal, { visible: open, transparent: true, animationType: "fade", onRequestClose: onClose }, /* @__PURE__ */ React25__default.default.createElement(reactNative.Pressable, { style: styles22.dialogBackdrop, onPress: onClose, accessibilityRole: "button", accessibilityLabel: "Close" }, /* @__PURE__ */ React25__default.default.createElement(
|
|
@@ -2882,13 +2906,14 @@ function Sheet({
|
|
|
2882
2906
|
const effectiveMaxHeight = maxHeight ?? DEFAULT_MAX_HEIGHT;
|
|
2883
2907
|
const useDynamicSizing = !snapPoints;
|
|
2884
2908
|
return /* @__PURE__ */ React25__default.default.createElement(
|
|
2885
|
-
|
|
2909
|
+
BottomSheet__default.default,
|
|
2886
2910
|
{
|
|
2887
2911
|
ref,
|
|
2912
|
+
index: -1,
|
|
2913
|
+
onClose,
|
|
2888
2914
|
enableDynamicSizing: useDynamicSizing,
|
|
2889
2915
|
snapPoints,
|
|
2890
2916
|
maxDynamicContentSize: useDynamicSizing ? effectiveMaxHeight : void 0,
|
|
2891
|
-
onDismiss: onClose,
|
|
2892
2917
|
backdropComponent: renderBackdrop,
|
|
2893
2918
|
footerComponent: effectiveFooter ? renderFooter : void 0,
|
|
2894
2919
|
backgroundStyle: [styles22.background, { backgroundColor: colors.card }],
|
|
@@ -2901,7 +2926,7 @@ function Sheet({
|
|
|
2901
2926
|
enableBlurKeyboardOnGesture
|
|
2902
2927
|
},
|
|
2903
2928
|
useScroll ? /* @__PURE__ */ React25__default.default.createElement(
|
|
2904
|
-
|
|
2929
|
+
BottomSheet.BottomSheetScrollView,
|
|
2905
2930
|
{
|
|
2906
2931
|
contentContainerStyle: [
|
|
2907
2932
|
styles22.scrollContent,
|
|
@@ -2910,11 +2935,12 @@ function Sheet({
|
|
|
2910
2935
|
style: contentStyle,
|
|
2911
2936
|
showsVerticalScrollIndicator: true,
|
|
2912
2937
|
indicatorStyle: "black",
|
|
2913
|
-
persistentScrollbar: isAndroid
|
|
2938
|
+
persistentScrollbar: isAndroid,
|
|
2939
|
+
stickyHeaderIndices: headerNode ? [0] : void 0
|
|
2914
2940
|
},
|
|
2915
2941
|
headerNode,
|
|
2916
2942
|
contentNode
|
|
2917
|
-
) : /* @__PURE__ */ React25__default.default.createElement(
|
|
2943
|
+
) : /* @__PURE__ */ React25__default.default.createElement(BottomSheet.BottomSheetView, { style: [styles22.content, contentStyle, style] }, headerNode, contentNode)
|
|
2918
2944
|
);
|
|
2919
2945
|
}
|
|
2920
2946
|
Sheet.Header = SheetHeader;
|
|
@@ -3900,26 +3926,29 @@ var styles29 = reactNative.StyleSheet.create({
|
|
|
3900
3926
|
function ConfirmDialog({
|
|
3901
3927
|
visible,
|
|
3902
3928
|
title,
|
|
3929
|
+
subtitle,
|
|
3903
3930
|
description,
|
|
3904
3931
|
confirmLabel = "Confirm",
|
|
3905
3932
|
cancelLabel = "Cancel",
|
|
3906
3933
|
confirmVariant = "primary",
|
|
3907
3934
|
loading = false,
|
|
3935
|
+
showCloseButton = false,
|
|
3908
3936
|
onConfirm,
|
|
3909
3937
|
onCancel
|
|
3910
3938
|
}) {
|
|
3911
3939
|
const { colors } = useTheme();
|
|
3912
3940
|
const ref = React25.useRef(null);
|
|
3941
|
+
const effectiveSubtitle = subtitle ?? description;
|
|
3913
3942
|
React25.useEffect(() => {
|
|
3914
3943
|
if (visible) {
|
|
3915
3944
|
impactMedium();
|
|
3916
|
-
ref.current?.
|
|
3945
|
+
ref.current?.snapToIndex(0);
|
|
3917
3946
|
} else {
|
|
3918
|
-
ref.current?.
|
|
3947
|
+
ref.current?.close();
|
|
3919
3948
|
}
|
|
3920
3949
|
}, [visible]);
|
|
3921
3950
|
const renderBackdrop = (props) => /* @__PURE__ */ React25__default.default.createElement(
|
|
3922
|
-
|
|
3951
|
+
BottomSheet.BottomSheetBackdrop,
|
|
3923
3952
|
{
|
|
3924
3953
|
...props,
|
|
3925
3954
|
disappearsOnIndex: -1,
|
|
@@ -3928,17 +3957,30 @@ function ConfirmDialog({
|
|
|
3928
3957
|
}
|
|
3929
3958
|
);
|
|
3930
3959
|
return /* @__PURE__ */ React25__default.default.createElement(
|
|
3931
|
-
|
|
3960
|
+
BottomSheet__default.default,
|
|
3932
3961
|
{
|
|
3933
3962
|
ref,
|
|
3963
|
+
index: -1,
|
|
3964
|
+
onClose: onCancel,
|
|
3934
3965
|
enableDynamicSizing: true,
|
|
3935
|
-
onDismiss: onCancel,
|
|
3936
3966
|
backdropComponent: renderBackdrop,
|
|
3937
3967
|
backgroundStyle: [styles30.background, { backgroundColor: colors.card }],
|
|
3938
3968
|
handleIndicatorStyle: [styles30.handle, { backgroundColor: colors.border }],
|
|
3939
3969
|
enablePanDownToClose: true
|
|
3940
3970
|
},
|
|
3941
|
-
/* @__PURE__ */ React25__default.default.createElement(
|
|
3971
|
+
/* @__PURE__ */ React25__default.default.createElement(BottomSheet.BottomSheetView, { style: styles30.content }, /* @__PURE__ */ React25__default.default.createElement(reactNative.View, { style: styles30.header, accessibilityRole: "header" }, /* @__PURE__ */ React25__default.default.createElement(reactNative.View, { style: styles30.headerRow }, /* @__PURE__ */ React25__default.default.createElement(reactNative.Text, { style: [styles30.title, { color: colors.foreground }], allowFontScaling: true }, title), showCloseButton ? /* @__PURE__ */ React25__default.default.createElement(
|
|
3972
|
+
reactNative.TouchableOpacity,
|
|
3973
|
+
{
|
|
3974
|
+
onPress: onCancel,
|
|
3975
|
+
style: styles30.closeButton,
|
|
3976
|
+
activeOpacity: 0.6,
|
|
3977
|
+
touchSoundDisabled: true,
|
|
3978
|
+
accessibilityRole: "button",
|
|
3979
|
+
accessibilityLabel: "Close",
|
|
3980
|
+
hitSlop: { top: 12, bottom: 12, left: 12, right: 12 }
|
|
3981
|
+
},
|
|
3982
|
+
/* @__PURE__ */ React25__default.default.createElement(vectorIcons.Feather, { name: "x", size: ms(18), color: colors.foregroundMuted })
|
|
3983
|
+
) : null), effectiveSubtitle ? /* @__PURE__ */ React25__default.default.createElement(reactNative.Text, { style: [styles30.subtitle, { color: colors.foregroundMuted }], allowFontScaling: true }, effectiveSubtitle) : null), /* @__PURE__ */ React25__default.default.createElement(reactNative.View, { style: styles30.actions }, /* @__PURE__ */ React25__default.default.createElement(
|
|
3942
3984
|
Button,
|
|
3943
3985
|
{
|
|
3944
3986
|
label: confirmLabel,
|
|
@@ -3985,19 +4027,32 @@ var styles30 = reactNative.StyleSheet.create({
|
|
|
3985
4027
|
borderRadius: ms(2)
|
|
3986
4028
|
},
|
|
3987
4029
|
content: {
|
|
3988
|
-
paddingHorizontal: s(
|
|
3989
|
-
paddingBottom: vs(32)
|
|
3990
|
-
|
|
4030
|
+
paddingHorizontal: s(16),
|
|
4031
|
+
paddingBottom: vs(32)
|
|
4032
|
+
},
|
|
4033
|
+
header: {
|
|
4034
|
+
paddingTop: vs(4),
|
|
4035
|
+
paddingBottom: vs(12),
|
|
4036
|
+
gap: vs(4)
|
|
4037
|
+
},
|
|
4038
|
+
headerRow: {
|
|
4039
|
+
flexDirection: "row",
|
|
4040
|
+
alignItems: "center",
|
|
4041
|
+
justifyContent: "space-between"
|
|
3991
4042
|
},
|
|
3992
4043
|
title: {
|
|
3993
4044
|
fontFamily: "Sohne-SemiBold",
|
|
3994
4045
|
fontSize: ms(18),
|
|
3995
|
-
|
|
4046
|
+
flex: 1
|
|
3996
4047
|
},
|
|
3997
|
-
|
|
4048
|
+
closeButton: {
|
|
4049
|
+
padding: s(4),
|
|
4050
|
+
marginLeft: s(8)
|
|
4051
|
+
},
|
|
4052
|
+
subtitle: {
|
|
3998
4053
|
fontFamily: "Sohne-Regular",
|
|
3999
|
-
fontSize: ms(
|
|
4000
|
-
lineHeight: mvs(
|
|
4054
|
+
fontSize: ms(14),
|
|
4055
|
+
lineHeight: mvs(20)
|
|
4001
4056
|
},
|
|
4002
4057
|
actions: {
|
|
4003
4058
|
gap: vs(10),
|
|
@@ -4620,7 +4675,7 @@ function VirtualListInner({ itemHeight, keyExtractor, renderItem, ...props }, re
|
|
|
4620
4675
|
}
|
|
4621
4676
|
var VirtualList = React25__default.default.forwardRef(VirtualListInner);
|
|
4622
4677
|
function RetrayProvider({ children, theme, colorScheme = "system" }) {
|
|
4623
|
-
return /* @__PURE__ */ React25__default.default.createElement(reactNativeSafeAreaContext.SafeAreaProvider, { initialMetrics: reactNativeSafeAreaContext.initialWindowMetrics }, /* @__PURE__ */ React25__default.default.createElement(reactNativeGestureHandler.GestureHandlerRootView, { style: styles37.root }, /* @__PURE__ */ React25__default.default.createElement(ThemeProvider, { theme, colorScheme }, /* @__PURE__ */ React25__default.default.createElement(
|
|
4678
|
+
return /* @__PURE__ */ React25__default.default.createElement(reactNativeSafeAreaContext.SafeAreaProvider, { initialMetrics: reactNativeSafeAreaContext.initialWindowMetrics }, /* @__PURE__ */ React25__default.default.createElement(reactNativeGestureHandler.GestureHandlerRootView, { style: styles37.root }, /* @__PURE__ */ React25__default.default.createElement(ThemeProvider, { theme, colorScheme }, /* @__PURE__ */ React25__default.default.createElement(BottomSheet.BottomSheetModalProvider, null, /* @__PURE__ */ React25__default.default.createElement(ToastProvider, null, children)))));
|
|
4624
4679
|
}
|
|
4625
4680
|
var styles37 = reactNative.StyleSheet.create({
|
|
4626
4681
|
root: { flex: 1 }
|
|
@@ -5381,17 +5436,12 @@ function ZoomableImage({ source, width, height, onZoomChange }) {
|
|
|
5381
5436
|
{ scale: scale2.value }
|
|
5382
5437
|
]
|
|
5383
5438
|
}));
|
|
5384
|
-
return /* @__PURE__ */ React25__default.default.createElement(reactNativeGestureHandler.GestureDetector, { gesture: composed }, /* @__PURE__ */ React25__default.default.createElement(
|
|
5385
|
-
Animated12__default.default.Image,
|
|
5386
|
-
{
|
|
5387
|
-
source,
|
|
5388
|
-
style: [{ width, height }, animatedStyle],
|
|
5389
|
-
resizeMode: "contain"
|
|
5390
|
-
}
|
|
5391
|
-
)));
|
|
5439
|
+
return /* @__PURE__ */ React25__default.default.createElement(reactNativeGestureHandler.GestureDetector, { gesture: composed }, /* @__PURE__ */ React25__default.default.createElement(reactNative.View, { style: [{ width, height }, styles44.imageWrap], collapsable: false }, /* @__PURE__ */ React25__default.default.createElement(Animated12__default.default.View, { style: [{ width, height }, animatedStyle] }, /* @__PURE__ */ React25__default.default.createElement(reactNative.Image, { source, style: { width, height }, resizeMode: "contain" }))));
|
|
5392
5440
|
}
|
|
5393
5441
|
function ImageViewer({ images, visible, onClose, initialIndex = 0 }) {
|
|
5394
|
-
const
|
|
5442
|
+
const window = reactNative.useWindowDimensions();
|
|
5443
|
+
const width = window.width > 0 ? window.width : reactNative.Dimensions.get("window").width;
|
|
5444
|
+
const height = window.height > 0 ? window.height : reactNative.Dimensions.get("window").height;
|
|
5395
5445
|
const insets = reactNativeSafeAreaContext.useSafeAreaInsets();
|
|
5396
5446
|
const [index, setIndex] = React25.useState(initialIndex);
|
|
5397
5447
|
const [pagingEnabled, setPagingEnabled] = React25.useState(true);
|
|
@@ -5434,7 +5484,7 @@ function ImageViewer({ images, visible, onClose, initialIndex = 0 }) {
|
|
|
5434
5484
|
scrollRef.current?.scrollTo({ x: page * width, animated: true });
|
|
5435
5485
|
setIndex(page);
|
|
5436
5486
|
};
|
|
5437
|
-
return /* @__PURE__ */ React25__default.default.createElement(reactNative.Modal, { visible, transparent: false, animationType: "fade", onRequestClose: onClose, statusBarTranslucent: true }, /* @__PURE__ */ React25__default.default.createElement(reactNativeGestureHandler.GestureHandlerRootView, { style: styles44.root }, /* @__PURE__ */ React25__default.default.createElement(Animated12__default.default.View, { style: [styles44.backdrop, backdropStyle], pointerEvents: "none" }), /* @__PURE__ */ React25__default.default.createElement(Animated12__default.default.View, { style: [styles44.container, dismissStyle] }, /* @__PURE__ */ React25__default.default.createElement(reactNativeGestureHandler.GestureDetector, { gesture: swipeDown }, /* @__PURE__ */ React25__default.default.createElement(
|
|
5487
|
+
return /* @__PURE__ */ React25__default.default.createElement(reactNative.Modal, { visible, transparent: false, animationType: "fade", onRequestClose: onClose, statusBarTranslucent: true }, /* @__PURE__ */ React25__default.default.createElement(reactNativeGestureHandler.GestureHandlerRootView, { style: styles44.root }, /* @__PURE__ */ React25__default.default.createElement(Animated12__default.default.View, { style: [styles44.backdrop, backdropStyle], pointerEvents: "none" }), /* @__PURE__ */ React25__default.default.createElement(Animated12__default.default.View, { style: [styles44.container, dismissStyle] }, /* @__PURE__ */ React25__default.default.createElement(reactNativeGestureHandler.GestureDetector, { gesture: swipeDown }, /* @__PURE__ */ React25__default.default.createElement(reactNative.View, { style: styles44.root, collapsable: false }, /* @__PURE__ */ React25__default.default.createElement(
|
|
5438
5488
|
reactNative.ScrollView,
|
|
5439
5489
|
{
|
|
5440
5490
|
ref: scrollRef,
|
|
@@ -5455,19 +5505,18 @@ function ImageViewer({ images, visible, onClose, initialIndex = 0 }) {
|
|
|
5455
5505
|
onZoomChange: (zoomed) => setPagingEnabled(!zoomed)
|
|
5456
5506
|
}
|
|
5457
5507
|
))
|
|
5458
|
-
))), /* @__PURE__ */ React25__default.default.createElement(
|
|
5459
|
-
|
|
5508
|
+
))), /* @__PURE__ */ React25__default.default.createElement(reactNative.View, { style: [styles44.closeButtonWrapper, { top: insets.top + vs(8) }] }, /* @__PURE__ */ React25__default.default.createElement(
|
|
5509
|
+
IconButton,
|
|
5460
5510
|
{
|
|
5461
|
-
|
|
5511
|
+
iconName: "x",
|
|
5512
|
+
size: "md",
|
|
5513
|
+
variant: "text",
|
|
5514
|
+
style: { backgroundColor: "rgba(255,255,255,0.18)" },
|
|
5515
|
+
iconColor: "#fff",
|
|
5462
5516
|
onPress: onClose,
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
accessibilityLabel: "Close",
|
|
5467
|
-
hitSlop: { top: 12, bottom: 12, left: 12, right: 12 }
|
|
5468
|
-
},
|
|
5469
|
-
renderIcon("x", 26, "#fff")
|
|
5470
|
-
), images.length > 1 ? /* @__PURE__ */ React25__default.default.createElement(reactNative.View, { style: [styles44.dots, { bottom: insets.bottom + vs(16) }], pointerEvents: "box-none" }, /* @__PURE__ */ React25__default.default.createElement(
|
|
5517
|
+
accessibilityLabel: "Close"
|
|
5518
|
+
}
|
|
5519
|
+
)), images.length > 1 ? /* @__PURE__ */ React25__default.default.createElement(reactNative.View, { style: [styles44.dots, { bottom: insets.bottom + vs(16) }], pointerEvents: "box-none" }, /* @__PURE__ */ React25__default.default.createElement(
|
|
5471
5520
|
PagerDots,
|
|
5472
5521
|
{
|
|
5473
5522
|
count: images.length,
|
|
@@ -5494,15 +5543,9 @@ var styles44 = reactNative.StyleSheet.create({
|
|
|
5494
5543
|
justifyContent: "center",
|
|
5495
5544
|
overflow: "hidden"
|
|
5496
5545
|
},
|
|
5497
|
-
|
|
5546
|
+
closeButtonWrapper: {
|
|
5498
5547
|
position: "absolute",
|
|
5499
|
-
right: s(12)
|
|
5500
|
-
width: s(40),
|
|
5501
|
-
height: s(40),
|
|
5502
|
-
borderRadius: s(20),
|
|
5503
|
-
backgroundColor: "rgba(0,0,0,0.4)",
|
|
5504
|
-
alignItems: "center",
|
|
5505
|
-
justifyContent: "center"
|
|
5548
|
+
right: s(12)
|
|
5506
5549
|
},
|
|
5507
5550
|
dots: {
|
|
5508
5551
|
position: "absolute",
|
|
@@ -5798,11 +5841,11 @@ function useConfirmDialog(options) {
|
|
|
5798
5841
|
|
|
5799
5842
|
Object.defineProperty(exports, "BottomSheetModalProvider", {
|
|
5800
5843
|
enumerable: true,
|
|
5801
|
-
get: function () { return
|
|
5844
|
+
get: function () { return BottomSheet.BottomSheetModalProvider; }
|
|
5802
5845
|
});
|
|
5803
5846
|
Object.defineProperty(exports, "SheetTextInput", {
|
|
5804
5847
|
enumerable: true,
|
|
5805
|
-
get: function () { return
|
|
5848
|
+
get: function () { return BottomSheet.BottomSheetTextInput; }
|
|
5806
5849
|
});
|
|
5807
5850
|
Object.defineProperty(exports, "toast", {
|
|
5808
5851
|
enumerable: true,
|
package/dist/index.mjs
CHANGED
|
@@ -4,11 +4,11 @@ export { Textarea } from './chunk-CZCQZHG6.mjs';
|
|
|
4
4
|
export { Toggle } from './chunk-KIHCWCWL.mjs';
|
|
5
5
|
export { VirtualList } from './chunk-NC5ZTR2Y.mjs';
|
|
6
6
|
export { Separator } from './chunk-MX6HRKMI.mjs';
|
|
7
|
-
export { BottomSheetModalProvider, Sheet, BottomSheetTextInput as SheetTextInput } from './chunk-
|
|
7
|
+
export { BottomSheetModalProvider, Sheet, BottomSheetTextInput as SheetTextInput } from './chunk-Y2NS74WS.mjs';
|
|
8
8
|
export { SheetSelect } from './chunk-URI2WBIV.mjs';
|
|
9
9
|
export { Skeleton } from './chunk-AJ7ZDNBT.mjs';
|
|
10
10
|
export { Slider } from './chunk-JMOZEC77.mjs';
|
|
11
|
-
export { Switch } from './chunk-
|
|
11
|
+
export { Switch } from './chunk-WF2XDFRK.mjs';
|
|
12
12
|
export { TabBar } from './chunk-MLF3EZFW.mjs';
|
|
13
13
|
export { Pressable } from './chunk-MBMXYJJV.mjs';
|
|
14
14
|
export { PricingCard } from './chunk-4I7D47FH.mjs';
|
|
@@ -31,7 +31,7 @@ export { ErrorBoundary } from './chunk-LXJIIOYQ.mjs';
|
|
|
31
31
|
export { Form, FormField, FormFooter, FormSection } from './chunk-6Q64UFIA.mjs';
|
|
32
32
|
export { ImageUpload } from './chunk-Y4GL2MHX.mjs';
|
|
33
33
|
export { Spinner } from './chunk-WBOOUHSS.mjs';
|
|
34
|
-
export { ImageViewer } from './chunk-
|
|
34
|
+
export { ImageViewer } from './chunk-WOEYDUJZ.mjs';
|
|
35
35
|
export { PagerDots } from './chunk-4K625MVM.mjs';
|
|
36
36
|
export { ButtonGroup } from './chunk-3BBOZ3OQ.mjs';
|
|
37
37
|
export { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from './chunk-ID72TK46.mjs';
|
|
@@ -39,11 +39,11 @@ export { CategoryStrip } from './chunk-VQ57HWPL.mjs';
|
|
|
39
39
|
import './chunk-YNROWHQJ.mjs';
|
|
40
40
|
export { Checkbox } from './chunk-AV4EMIRH.mjs';
|
|
41
41
|
export { Chip, ChipGroup } from './chunk-UREA2GYY.mjs';
|
|
42
|
-
export { ConfirmDialog } from './chunk-
|
|
42
|
+
export { ConfirmDialog } from './chunk-KZL5VTYK.mjs';
|
|
43
43
|
export { CurrencyDisplay } from './chunk-BRKYVJVV.mjs';
|
|
44
44
|
export { CurrencyInput } from './chunk-JUXSWN54.mjs';
|
|
45
45
|
export { Input } from './chunk-ZUR7AU5R.mjs';
|
|
46
|
-
export { Accordion } from './chunk-
|
|
46
|
+
export { Accordion } from './chunk-DJ7RN37L.mjs';
|
|
47
47
|
export { AlertBanner } from './chunk-6MKGPAR2.mjs';
|
|
48
48
|
export { AppHeader } from './chunk-AZJF2BLK.mjs';
|
|
49
49
|
export { IconButton } from './chunk-3U4SSNWP.mjs';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@retray-dev/ui-kit",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "10.1.0",
|
|
4
4
|
"description": "Personal UI Kit for React Native / Expo",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"files": [
|
|
26
26
|
"dist",
|
|
27
27
|
"src",
|
|
28
|
+
"scripts",
|
|
28
29
|
"COMPONENTS.md",
|
|
29
30
|
"CONSUMER.md",
|
|
30
31
|
"EXAMPLES.md",
|
|
@@ -32,6 +33,7 @@
|
|
|
32
33
|
"DESIGN.md"
|
|
33
34
|
],
|
|
34
35
|
"scripts": {
|
|
36
|
+
"postinstall": "node scripts/copy-fonts.js",
|
|
35
37
|
"build": "tsup",
|
|
36
38
|
"dev": "tsup --watch",
|
|
37
39
|
"typecheck": "tsc --noEmit",
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# build-apk.sh — Build a standalone release APK of the example app for phone install.
|
|
4
|
+
#
|
|
5
|
+
# Produces: build-output/retray-ui-kit-example.apk (signed with debug keystore,
|
|
6
|
+
# installable on any Android phone via "Install unknown apps").
|
|
7
|
+
#
|
|
8
|
+
# Requirements (already set up on this machine):
|
|
9
|
+
# - Android SDK at $ANDROID_HOME (default: ~/Library/Android/sdk)
|
|
10
|
+
# - Java 17 (JDK)
|
|
11
|
+
# - pnpm, node
|
|
12
|
+
#
|
|
13
|
+
# Usage:
|
|
14
|
+
# ./scripts/build-apk.sh # full build
|
|
15
|
+
# ./scripts/build-apk.sh --install # build, then adb install to connected phone
|
|
16
|
+
# ./scripts/build-apk.sh --clean # wipe android/ + gradle cache first (slow, fixes weird errors)
|
|
17
|
+
#
|
|
18
|
+
set -euo pipefail
|
|
19
|
+
|
|
20
|
+
# --- resolve repo root regardless of cwd ---
|
|
21
|
+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
22
|
+
EXAMPLE="$ROOT/example"
|
|
23
|
+
OUT_DIR="$ROOT/build-output"
|
|
24
|
+
APK_NAME="retray-ui-kit-example.apk"
|
|
25
|
+
|
|
26
|
+
export ANDROID_HOME="${ANDROID_HOME:-$HOME/Library/Android/sdk}"
|
|
27
|
+
|
|
28
|
+
DO_INSTALL=false
|
|
29
|
+
DO_CLEAN=false
|
|
30
|
+
for arg in "$@"; do
|
|
31
|
+
case "$arg" in
|
|
32
|
+
--install) DO_INSTALL=true ;;
|
|
33
|
+
--clean) DO_CLEAN=true ;;
|
|
34
|
+
*) echo "Unknown arg: $arg"; exit 1 ;;
|
|
35
|
+
esac
|
|
36
|
+
done
|
|
37
|
+
|
|
38
|
+
echo "==> repo: $ROOT"
|
|
39
|
+
echo "==> sdk: $ANDROID_HOME"
|
|
40
|
+
[ -d "$ANDROID_HOME" ] || { echo "ERROR: Android SDK not found at $ANDROID_HOME"; exit 1; }
|
|
41
|
+
|
|
42
|
+
# --- 1. build the ui-kit (example depends on dist/) ---
|
|
43
|
+
echo "==> [1/4] Building @retray-dev/ui-kit ..."
|
|
44
|
+
( cd "$ROOT" && pnpm build )
|
|
45
|
+
|
|
46
|
+
# --- 2. ensure deps + native android/ dir exist ---
|
|
47
|
+
echo "==> [2/4] Prebuild (generate android/ if missing) ..."
|
|
48
|
+
if $DO_CLEAN; then
|
|
49
|
+
echo " --clean: removing android/ and gradle build cache"
|
|
50
|
+
rm -rf "$EXAMPLE/android"
|
|
51
|
+
fi
|
|
52
|
+
# babel-preset-expo must be a top-level dep of example so Metro resolves it
|
|
53
|
+
# under pnpm hoisted layout. Declared in example/package.json devDependencies.
|
|
54
|
+
( cd "$ROOT" && pnpm install --frozen-lockfile=false )
|
|
55
|
+
if [ ! -d "$EXAMPLE/android" ]; then
|
|
56
|
+
( cd "$EXAMPLE" && CI=1 npx expo prebuild --platform android --no-install )
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
# --- 3. assemble release APK ---
|
|
60
|
+
echo "==> [3/4] Gradle assembleRelease (first run ~7 min) ..."
|
|
61
|
+
( cd "$EXAMPLE/android" && ANDROID_HOME="$ANDROID_HOME" ./gradlew assembleRelease )
|
|
62
|
+
|
|
63
|
+
# --- 4. copy to build-output/ ---
|
|
64
|
+
echo "==> [4/4] Copying APK ..."
|
|
65
|
+
SRC_APK="$EXAMPLE/android/app/build/outputs/apk/release/app-release.apk"
|
|
66
|
+
[ -f "$SRC_APK" ] || { echo "ERROR: APK not found at $SRC_APK"; exit 1; }
|
|
67
|
+
mkdir -p "$OUT_DIR"
|
|
68
|
+
cp "$SRC_APK" "$OUT_DIR/$APK_NAME"
|
|
69
|
+
|
|
70
|
+
echo ""
|
|
71
|
+
echo "✅ APK ready: $OUT_DIR/$APK_NAME ($(du -h "$OUT_DIR/$APK_NAME" | cut -f1))"
|
|
72
|
+
|
|
73
|
+
# --- optional install ---
|
|
74
|
+
if $DO_INSTALL; then
|
|
75
|
+
echo "==> adb install ..."
|
|
76
|
+
"$ANDROID_HOME/platform-tools/adb" install -r "$OUT_DIR/$APK_NAME"
|
|
77
|
+
echo "✅ Installed to connected device."
|
|
78
|
+
else
|
|
79
|
+
echo ""
|
|
80
|
+
echo "To put on your phone:"
|
|
81
|
+
echo " • USB: $ANDROID_HOME/platform-tools/adb install -r \"$OUT_DIR/$APK_NAME\""
|
|
82
|
+
echo " • or run again with --install"
|
|
83
|
+
echo " • or AirDrop/Drive the .apk and tap it (enable 'Install unknown apps')"
|
|
84
|
+
fi
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Postinstall script: copies Sohne font files to consumer project's assets/fonts/sohne/
|
|
4
|
+
*
|
|
5
|
+
* This runs automatically when a consumer installs @retray-dev/ui-kit.
|
|
6
|
+
* Fonts are copied from dist/assets/fonts/ to <consumer-root>/assets/fonts/sohne/
|
|
7
|
+
* so Metro can resolve require() calls in the consumer's App.tsx.
|
|
8
|
+
*/
|
|
9
|
+
const fs = require('fs')
|
|
10
|
+
const path = require('path')
|
|
11
|
+
|
|
12
|
+
// npm sets INIT_CWD to consumer project root, pnpm sets PROJECT_CWD
|
|
13
|
+
const consumerRoot =
|
|
14
|
+
process.env.INIT_CWD ||
|
|
15
|
+
process.env.PROJECT_CWD ||
|
|
16
|
+
process.cwd()
|
|
17
|
+
|
|
18
|
+
// Don't run when installing inside the ui-kit repo itself
|
|
19
|
+
const pkgPath = path.join(consumerRoot, 'package.json')
|
|
20
|
+
if (!fs.existsSync(pkgPath)) {
|
|
21
|
+
process.exit(0)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let pkg
|
|
25
|
+
try {
|
|
26
|
+
pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'))
|
|
27
|
+
} catch {
|
|
28
|
+
// Can't read package.json — skip silently
|
|
29
|
+
process.exit(0)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Skip if we're in the ui-kit repo itself
|
|
33
|
+
if (pkg.name === '@retray-dev/ui-kit') {
|
|
34
|
+
process.exit(0)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Source: dist/assets/fonts/ (relative to this script in scripts/)
|
|
38
|
+
const src = path.join(__dirname, '..', 'dist', 'assets', 'fonts')
|
|
39
|
+
|
|
40
|
+
// Destination: consumer's assets/fonts/sohne/
|
|
41
|
+
const dest = path.join(consumerRoot, 'assets', 'fonts', 'sohne')
|
|
42
|
+
|
|
43
|
+
// If source doesn't exist (maybe dist not built yet), skip gracefully
|
|
44
|
+
if (!fs.existsSync(src)) {
|
|
45
|
+
console.warn('[ui-kit] Font source not found:', src)
|
|
46
|
+
console.warn('[ui-kit] Run `pnpm build` in the ui-kit package first, or fonts will need manual setup.')
|
|
47
|
+
process.exit(0)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Create destination directory
|
|
51
|
+
try {
|
|
52
|
+
fs.mkdirSync(dest, { recursive: true })
|
|
53
|
+
} catch (err) {
|
|
54
|
+
console.warn('[ui-kit] Could not create font directory:', dest)
|
|
55
|
+
console.warn('[ui-kit] Error:', err.message)
|
|
56
|
+
console.warn('[ui-kit] You may need to copy fonts manually. See FONTS.md for setup.')
|
|
57
|
+
process.exit(0)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Copy .otf files (skip if already exists to avoid overwriting user modifications)
|
|
61
|
+
const files = fs.readdirSync(src).filter(f => f.endsWith('.otf'))
|
|
62
|
+
let copied = 0
|
|
63
|
+
let skipped = 0
|
|
64
|
+
|
|
65
|
+
for (const file of files) {
|
|
66
|
+
const srcFile = path.join(src, file)
|
|
67
|
+
const destFile = path.join(dest, file)
|
|
68
|
+
|
|
69
|
+
if (fs.existsSync(destFile)) {
|
|
70
|
+
skipped++
|
|
71
|
+
continue
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
fs.copyFileSync(srcFile, destFile)
|
|
76
|
+
copied++
|
|
77
|
+
} catch (err) {
|
|
78
|
+
console.warn(`[ui-kit] Failed to copy ${file}:`, err.message)
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (copied > 0) {
|
|
83
|
+
console.log(`[ui-kit] Copied ${copied} Sohne font files → assets/fonts/sohne/`)
|
|
84
|
+
}
|
|
85
|
+
if (skipped > 0 && copied === 0) {
|
|
86
|
+
// All fonts already present — no message needed
|
|
87
|
+
}
|
|
88
|
+
if (copied > 0 || (skipped > 0 && process.env.VERBOSE)) {
|
|
89
|
+
console.log('[ui-kit] Add SohneFonts to your App.tsx — see CONSUMER.md for the boilerplate.')
|
|
90
|
+
}
|