ferns-ui 0.34.1 → 0.35.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/dist/Avatar.d.ts +14 -0
- package/dist/Avatar.js +73 -8
- package/dist/Avatar.js.map +1 -1
- package/dist/Box.d.ts +1 -15
- package/dist/Box.js +185 -182
- package/dist/Box.js.map +1 -1
- package/dist/Common.d.ts +7 -5
- package/dist/Common.js.map +1 -1
- package/dist/TableRow.js.map +1 -1
- package/dist/TextField.js +3 -3
- package/dist/TextField.js.map +1 -1
- package/dist/Tooltip.d.ts +1 -1
- package/dist/Tooltip.js +5 -0
- package/dist/Tooltip.js.map +1 -1
- package/dist/Unifier.js +2 -1
- package/dist/Unifier.js.map +1 -1
- package/package.json +3 -2
- package/src/Avatar.tsx +177 -50
- package/src/Box.tsx +109 -100
- package/src/Common.ts +7 -9
- package/src/TableRow.tsx +1 -1
- package/src/TextField.tsx +3 -3
- package/src/Tooltip.tsx +8 -1
- package/src/Unifier.ts +2 -1
package/src/Box.tsx
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
/* eslint-disable react/prop-types */
|
|
2
|
+
import React, {useImperativeHandle} from "react";
|
|
2
3
|
import {
|
|
3
4
|
KeyboardAvoidingView,
|
|
4
5
|
Platform,
|
|
@@ -43,8 +44,31 @@ const ALIGN_SELF = {
|
|
|
43
44
|
|
|
44
45
|
const BORDER_WIDTH = 1;
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
// eslint-disable-next-line react/display-name
|
|
48
|
+
export const Box = React.forwardRef((props: BoxProps, ref) => {
|
|
49
|
+
useImperativeHandle(ref, () => ({
|
|
50
|
+
scrollToEnd: () => {
|
|
51
|
+
if (scrollRef && scrollRef.current) {
|
|
52
|
+
// HACK HACK HACK...but it works. Probably need to do some onContentSizeChange or onLayout to
|
|
53
|
+
// avoid this, but it works well enough.
|
|
54
|
+
setTimeout(() => {
|
|
55
|
+
scrollRef && scrollRef.current && (scrollRef.current as any).scrollToEnd();
|
|
56
|
+
}, 50);
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
scrollTo: (y: number) => {
|
|
61
|
+
if (scrollRef && scrollRef.current) {
|
|
62
|
+
// HACK HACK HACK...but it works. Probably need to do some onContentSizeChange or onLayout to
|
|
63
|
+
// avoid this, but it works well enough.
|
|
64
|
+
setTimeout(() => {
|
|
65
|
+
scrollRef && scrollRef.current && (scrollRef.current as any).scrollTo({y});
|
|
66
|
+
}, 50);
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
}));
|
|
70
|
+
|
|
71
|
+
const BOX_STYLE_MAP: {
|
|
48
72
|
[prop: string]: (
|
|
49
73
|
value: any,
|
|
50
74
|
all: {[prop: string]: any}
|
|
@@ -78,7 +102,7 @@ export class Box extends React.Component<BoxProps, {}> {
|
|
|
78
102
|
},
|
|
79
103
|
justifyContent: (value: JustifyContent) => ({justifyContent: ALIGN_CONTENT[value]}),
|
|
80
104
|
height: (value) => {
|
|
81
|
-
if (
|
|
105
|
+
if (props.border && !isNaN(Number(value))) {
|
|
82
106
|
return {height: Number(value) + 2 * 2};
|
|
83
107
|
} else {
|
|
84
108
|
return {height: value};
|
|
@@ -124,7 +148,7 @@ export class Box extends React.Component<BoxProps, {}> {
|
|
|
124
148
|
return {overflow: value};
|
|
125
149
|
},
|
|
126
150
|
width: (value) => {
|
|
127
|
-
if (
|
|
151
|
+
if (props.border && !isNaN(Number(value))) {
|
|
128
152
|
return {width: Number(value) + 2 * 2};
|
|
129
153
|
} else {
|
|
130
154
|
return {width: value};
|
|
@@ -181,119 +205,104 @@ export class Box extends React.Component<BoxProps, {}> {
|
|
|
181
205
|
},
|
|
182
206
|
};
|
|
183
207
|
|
|
184
|
-
scrollRef = React.createRef();
|
|
185
|
-
|
|
186
|
-
constructor(props: BoxProps) {
|
|
187
|
-
super(props);
|
|
188
|
-
if (props.scrollRef) {
|
|
189
|
-
this.scrollRef = props.scrollRef;
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
public scrollToEnd = () => {
|
|
194
|
-
if (this.scrollRef && this.scrollRef.current) {
|
|
195
|
-
// HACK HACK HACK...but it works. Probably need to do some onContentSizeChange or onLayout to
|
|
196
|
-
// avoid this, but it works well enough.
|
|
197
|
-
setTimeout(() => {
|
|
198
|
-
this.scrollRef && this.scrollRef.current && (this.scrollRef.current as any).scrollToEnd();
|
|
199
|
-
}, 50);
|
|
200
|
-
}
|
|
201
|
-
};
|
|
202
|
-
|
|
203
|
-
public scrollTo = (y: number) => {
|
|
204
|
-
if (this.scrollRef && this.scrollRef.current) {
|
|
205
|
-
// HACK HACK HACK...but it works. Probably need to do some onContentSizeChange or onLayout to
|
|
206
|
-
// avoid this, but it works well enough.
|
|
207
|
-
setTimeout(() => {
|
|
208
|
-
this.scrollRef && this.scrollRef.current && (this.scrollRef.current as any).scrollTo({y});
|
|
209
|
-
}, 50);
|
|
210
|
-
}
|
|
211
|
-
};
|
|
208
|
+
const scrollRef = props.scrollRef ?? React.createRef();
|
|
212
209
|
|
|
213
|
-
propsToStyle(): any {
|
|
210
|
+
const propsToStyle = (): any => {
|
|
214
211
|
let style: any = {};
|
|
215
|
-
for (const prop of Object.keys(
|
|
216
|
-
const value = (
|
|
217
|
-
if (
|
|
218
|
-
Object.assign(style,
|
|
212
|
+
for (const prop of Object.keys(props)) {
|
|
213
|
+
const value = (props as any)[prop];
|
|
214
|
+
if (BOX_STYLE_MAP[prop]) {
|
|
215
|
+
Object.assign(style, BOX_STYLE_MAP[prop](value, props));
|
|
219
216
|
} else if (prop !== "children" && prop !== "onClick") {
|
|
220
217
|
style[prop] = value;
|
|
221
218
|
// console.warn(`Box: unknown property ${prop}`);
|
|
222
219
|
}
|
|
223
220
|
}
|
|
224
221
|
|
|
225
|
-
if (
|
|
222
|
+
if (props.wrap && props.alignItems) {
|
|
226
223
|
console.warn("React Native doesn't support wrap and alignItems together.");
|
|
227
224
|
}
|
|
228
225
|
|
|
229
226
|
// Finally, dangerously set overrides.
|
|
230
|
-
if (
|
|
231
|
-
style = {...style, ...
|
|
227
|
+
if (props.dangerouslySetInlineStyle) {
|
|
228
|
+
style = {...style, ...props.dangerouslySetInlineStyle.__style};
|
|
232
229
|
}
|
|
233
230
|
|
|
234
231
|
return style;
|
|
235
|
-
}
|
|
232
|
+
};
|
|
236
233
|
|
|
237
|
-
|
|
238
|
-
|
|
234
|
+
const onHoverIn = () => {
|
|
235
|
+
props.onHoverStart?.();
|
|
236
|
+
};
|
|
239
237
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
style={this.propsToStyle()}
|
|
244
|
-
testID={this.props.testID ? `${this.props.testID}-clickable` : undefined}
|
|
245
|
-
// TODO: refactor this better..
|
|
246
|
-
onLayout={this.props.onLayout}
|
|
247
|
-
onPress={() => {
|
|
248
|
-
Unifier.utils.haptic();
|
|
249
|
-
this.props.onClick();
|
|
250
|
-
}}
|
|
251
|
-
>
|
|
252
|
-
{this.props.children}
|
|
253
|
-
</Pressable>
|
|
254
|
-
);
|
|
255
|
-
} else {
|
|
256
|
-
box = (
|
|
257
|
-
<View style={this.propsToStyle()} testID={this.props.testID}>
|
|
258
|
-
{this.props.children}
|
|
259
|
-
</View>
|
|
260
|
-
);
|
|
261
|
-
}
|
|
238
|
+
const onHoverOut = () => {
|
|
239
|
+
props.onHoverEnd?.();
|
|
240
|
+
};
|
|
262
241
|
|
|
263
|
-
|
|
264
|
-
const {justifyContent, alignContent, alignItems, ...scrollStyle} = this.propsToStyle();
|
|
242
|
+
let box;
|
|
265
243
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
244
|
+
if (props.onClick) {
|
|
245
|
+
box = (
|
|
246
|
+
<Pressable
|
|
247
|
+
style={propsToStyle()}
|
|
248
|
+
testID={props.testID ? `${props.testID}-clickable` : undefined}
|
|
249
|
+
onLayout={props.onLayout}
|
|
250
|
+
onPointerEnter={onHoverIn}
|
|
251
|
+
onPointerLeave={onHoverOut}
|
|
252
|
+
onPress={() => {
|
|
253
|
+
Unifier.utils.haptic();
|
|
254
|
+
props.onClick!();
|
|
255
|
+
}}
|
|
256
|
+
>
|
|
257
|
+
{props.children}
|
|
258
|
+
</Pressable>
|
|
259
|
+
);
|
|
260
|
+
} else {
|
|
261
|
+
box = (
|
|
262
|
+
<View
|
|
263
|
+
style={propsToStyle()}
|
|
264
|
+
testID={props.testID}
|
|
265
|
+
onPointerEnter={onHoverIn}
|
|
266
|
+
onPointerLeave={onHoverOut}
|
|
267
|
+
>
|
|
268
|
+
{props.children}
|
|
269
|
+
</View>
|
|
270
|
+
);
|
|
271
|
+
}
|
|
285
272
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
273
|
+
if (props.scroll) {
|
|
274
|
+
const {justifyContent, alignContent, alignItems, ...scrollStyle} = propsToStyle();
|
|
275
|
+
|
|
276
|
+
box = (
|
|
277
|
+
<ScrollView
|
|
278
|
+
ref={props.scrollRef || scrollRef}
|
|
279
|
+
contentContainerStyle={{justifyContent, alignContent, alignItems}}
|
|
280
|
+
horizontal={props.overflow === "scrollX"}
|
|
281
|
+
keyboardShouldPersistTaps="handled"
|
|
282
|
+
nestedScrollEnabled
|
|
283
|
+
scrollEventThrottle={50}
|
|
284
|
+
style={scrollStyle}
|
|
285
|
+
onScroll={(event) => {
|
|
286
|
+
if (props.onScroll && event) {
|
|
287
|
+
props.onScroll(event.nativeEvent.contentOffset.y);
|
|
288
|
+
}
|
|
289
|
+
}}
|
|
290
|
+
>
|
|
291
|
+
{box}
|
|
292
|
+
</ScrollView>
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if (props.avoidKeyboard) {
|
|
297
|
+
box = (
|
|
298
|
+
<KeyboardAvoidingView
|
|
299
|
+
behavior={Platform.OS === "ios" ? "padding" : "height"}
|
|
300
|
+
keyboardVerticalOffset={props.keyboardOffset}
|
|
301
|
+
style={{flex: 1, display: "flex"}}
|
|
302
|
+
>
|
|
303
|
+
<SafeAreaView style={{flex: 1, display: "flex"}}>{box}</SafeAreaView>
|
|
304
|
+
</KeyboardAvoidingView>
|
|
305
|
+
);
|
|
298
306
|
}
|
|
299
|
-
|
|
307
|
+
return box;
|
|
308
|
+
});
|
package/src/Common.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {ReactElement, ReactNode, SyntheticEvent} from "react";
|
|
1
|
+
import React, {ReactElement, ReactNode, SyntheticEvent} from "react";
|
|
2
2
|
import {ListRenderItemInfo} from "react-native";
|
|
3
3
|
|
|
4
4
|
export interface BaseProfile {
|
|
@@ -1932,14 +1932,12 @@ export interface BoxProps {
|
|
|
1932
1932
|
wrap?: boolean;
|
|
1933
1933
|
zIndex?: number | "auto";
|
|
1934
1934
|
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
className?: any;
|
|
1935
|
+
onClick?: () => void | Promise<void>;
|
|
1936
|
+
className?: string;
|
|
1938
1937
|
style?: any;
|
|
1939
|
-
|
|
1940
|
-
|
|
1938
|
+
onHoverStart?: () => void | Promise<void>;
|
|
1939
|
+
onHoverEnd?: () => void | Promise<void>;
|
|
1941
1940
|
scroll?: boolean;
|
|
1942
|
-
// Pattern Addition. Shadows!
|
|
1943
1941
|
shadow?: boolean;
|
|
1944
1942
|
border?: AllColors;
|
|
1945
1943
|
borderBottom?: AllColors;
|
|
@@ -1949,9 +1947,9 @@ export interface BoxProps {
|
|
|
1949
1947
|
|
|
1950
1948
|
avoidKeyboard?: boolean;
|
|
1951
1949
|
keyboardOffset?: number;
|
|
1952
|
-
scrollRef?: any
|
|
1950
|
+
scrollRef?: React.RefObject<any>;
|
|
1953
1951
|
onScroll?: (offsetY: number) => void;
|
|
1954
|
-
onLayout?: (event:
|
|
1952
|
+
onLayout?: (event: LayoutChangeEvent) => void;
|
|
1955
1953
|
testID?: string;
|
|
1956
1954
|
}
|
|
1957
1955
|
|
package/src/TableRow.tsx
CHANGED
|
@@ -40,7 +40,7 @@ export function TableRow({
|
|
|
40
40
|
}: Props): React.ReactElement {
|
|
41
41
|
const [isExpanded, setIsExpanded] = React.useState(expanded || false);
|
|
42
42
|
const {columns, hasDrawerContents} = useTableContext();
|
|
43
|
-
const rowRef = useRef<Box>(null);
|
|
43
|
+
const rowRef = useRef<typeof Box>(null);
|
|
44
44
|
|
|
45
45
|
const renderCellWithColumnIndex = (child: React.ReactNode, index: number) => {
|
|
46
46
|
if (!columns[index]) {
|
package/src/TextField.tsx
CHANGED
|
@@ -190,7 +190,7 @@ export function TextField({
|
|
|
190
190
|
} else if (type === "height") {
|
|
191
191
|
weightActionSheetRef?.current?.show();
|
|
192
192
|
}
|
|
193
|
-
}, [decimalRangeActionSheetRef, numberRangeActionSheetRef, type, weightActionSheetRef]);
|
|
193
|
+
}, [decimalRangeActionSheetRef, disabled, numberRangeActionSheetRef, type, weightActionSheetRef]);
|
|
194
194
|
|
|
195
195
|
let displayValue = value;
|
|
196
196
|
if (displayValue) {
|
|
@@ -297,8 +297,8 @@ export function TextField({
|
|
|
297
297
|
if (!isHandledByModal) {
|
|
298
298
|
setFocused(false);
|
|
299
299
|
}
|
|
300
|
-
if (onBlur
|
|
301
|
-
onBlur({value});
|
|
300
|
+
if (onBlur) {
|
|
301
|
+
onBlur({value: value ?? ""});
|
|
302
302
|
}
|
|
303
303
|
// if (type === "date") {
|
|
304
304
|
// actionSheetRef?.current?.hide();
|
package/src/Tooltip.tsx
CHANGED
|
@@ -118,7 +118,8 @@ const getTooltipPosition = ({
|
|
|
118
118
|
|
|
119
119
|
interface TooltipProps {
|
|
120
120
|
children: React.ReactElement;
|
|
121
|
-
text
|
|
121
|
+
// If text is undefined, the children will be rendered without a tooltip.
|
|
122
|
+
text?: string;
|
|
122
123
|
idealDirection?: "top" | "bottom" | "left" | "right";
|
|
123
124
|
bgColor?: "white" | "lightGray" | "gray" | "darkGray";
|
|
124
125
|
}
|
|
@@ -214,6 +215,12 @@ export const Tooltip = (props: TooltipProps) => {
|
|
|
214
215
|
}, [children.props]),
|
|
215
216
|
};
|
|
216
217
|
|
|
218
|
+
// Allow disabling tooltips when there is no string, otherwise you need to wrap the children in a function to
|
|
219
|
+
// determine if there should be a tooltip or not, which gets messy.
|
|
220
|
+
if (!text) {
|
|
221
|
+
return children;
|
|
222
|
+
}
|
|
223
|
+
|
|
217
224
|
return (
|
|
218
225
|
<>
|
|
219
226
|
{visible && (
|
package/src/Unifier.ts
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
/* eslint-disable @typescript-eslint/no-empty-function */
|
|
3
3
|
|
|
4
4
|
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
5
|
+
import * as Clipboard from "expo-clipboard";
|
|
5
6
|
import * as Font from "expo-font";
|
|
6
7
|
import {FontSource} from "expo-font";
|
|
7
8
|
import * as Haptics from "expo-haptics";
|
|
8
|
-
import {
|
|
9
|
+
import {Dimensions, Keyboard, Linking, Platform, Vibration} from "react-native";
|
|
9
10
|
|
|
10
11
|
import {PermissionKind, UnifiedTheme} from "./Common";
|
|
11
12
|
import {requestPermissions} from "./Permissions";
|