ferns-ui 0.4.2 → 0.5.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/src/TapToEdit.tsx CHANGED
@@ -1,48 +1,118 @@
1
- import React from "react";
1
+ import React, {ReactElement, useState} from "react";
2
2
 
3
3
  import {Box} from "./Box";
4
4
  import {Button} from "./Button";
5
- import {TextFieldProps} from "./Common";
5
+ import {BoxProps} from "./Common";
6
+ import {Field, FieldProps} from "./Field";
6
7
  import {Icon} from "./Icon";
7
8
  import {Text} from "./Text";
8
- import {TextField} from "./TextField";
9
9
 
10
- interface TapToEditState {
11
- showEdit: boolean;
10
+ export interface TapToEditProps extends Omit<FieldProps, "handleChange"> {
11
+ title: string;
12
+ // Not required if not editable.
13
+ onSave?: (value: any) => void | Promise<void>;
14
+ // Defaults to true
15
+ editable?: boolean;
16
+ // For changing how the non-editing row renders
17
+ rowBoxProps?: Partial<BoxProps>;
18
+ transform?: (value: any) => string;
19
+ fieldComponent?: (setValue: () => void) => ReactElement;
12
20
  }
13
21
 
14
- export class TapToEdit extends React.Component<TextFieldProps, TapToEditState> {
15
- state = {showEdit: false};
22
+ export const TapToEdit = (props: TapToEditProps): ReactElement => {
23
+ const [editing, setEditing] = useState(false);
24
+ const [value, setValue] = useState(props.initialValue);
16
25
 
17
- render() {
18
- if (!this.state.showEdit) {
19
- return (
20
- <Box direction="row" display="flex" onClick={() => this.setState({showEdit: true})}>
21
- <Box marginRight={2}>
22
- <Icon color="primaryDark" name="edit" prefix="far" size="lg" />
23
- </Box>
24
- <Text>{this.props.children}</Text>
25
- </Box>
26
- );
27
- } else {
28
- return (
29
- <Box>
30
- <TextField {...this.props} />
31
- <Box paddingY={1} width={100}>
26
+ const {title, editable = true, rowBoxProps, transform, fieldComponent, ...fieldProps} = props;
27
+ if (editing) {
28
+ return (
29
+ <Box direction="column" maxWidth="100%" paddingX={3} paddingY={2} width="100%">
30
+ {fieldComponent ? (
31
+ fieldComponent(setValue as any)
32
+ ) : (
33
+ <Field
34
+ handleChange={(_: string, val: any): void => setValue(val)}
35
+ label={props.title}
36
+ {...fieldProps}
37
+ />
38
+ )}
39
+ <Box direction="row">
40
+ <Button
41
+ color="blue"
42
+ inline
43
+ text="Save"
44
+ onClick={async (): Promise<void> => {
45
+ if (!props.onSave) {
46
+ console.error("No onSave provided for editable TapToEdit");
47
+ } else {
48
+ await props.onSave(value);
49
+ }
50
+ setEditing(false);
51
+ }}
52
+ />
53
+ <Box marginLeft={2}>
32
54
  <Button
33
- color="primary"
55
+ color="red"
34
56
  inline
35
- text="Save"
36
- onClick={() => {
37
- this.setState({showEdit: false});
38
- if (this.props.onSubmitEditing) {
39
- this.props.onSubmitEditing();
40
- }
57
+ text="Cancel"
58
+ onClick={(): void => {
59
+ setEditing(false);
41
60
  }}
42
61
  />
43
62
  </Box>
44
63
  </Box>
45
- );
64
+ </Box>
65
+ );
66
+ } else {
67
+ let displayValue = value;
68
+ // If transform is present, that takes priority
69
+ if (transform) {
70
+ displayValue = transform(value);
71
+ } else {
72
+ // If no transform, try and display the value reasonably.
73
+ if (fieldProps?.type === "boolean") {
74
+ displayValue = value ? "Yes" : "No";
75
+ } else if (fieldProps?.type === "percent") {
76
+ // Prevent floating point errors from showing up by using parseFloat and precision. Pass through parseFloat again
77
+ // to trim off insignificant zeroes.
78
+ displayValue = `${parseFloat(parseFloat(String(value * 100)).toPrecision(7))}%`;
79
+ } else if (fieldProps?.type === "currency") {
80
+ // TODO: support currencies other than USD in Field and related components.
81
+ const formatter = new Intl.NumberFormat("en-US", {
82
+ style: "currency",
83
+ currency: "USD",
84
+ minimumFractionDigits: 2, // (this suffices for whole numbers, but will print 2500.10 as $2,500.1)
85
+ });
86
+ displayValue = formatter.format(value);
87
+ } else if (fieldProps?.type === "multiselect") {
88
+ // ???
89
+ displayValue = value.join(", ");
90
+ }
46
91
  }
92
+ return (
93
+ <Box
94
+ direction="row"
95
+ justifyContent="between"
96
+ maxWidth="100%"
97
+ paddingX={3}
98
+ paddingY={2}
99
+ width="100%"
100
+ {...rowBoxProps}
101
+ >
102
+ <Box>
103
+ <Text weight="bold">{title}:</Text>
104
+ </Box>
105
+ <Box direction="row" flex="shrink" marginLeft={2}>
106
+ <Box flex="shrink">
107
+ <Text overflow="breakWord">{displayValue}</Text>
108
+ </Box>
109
+ {editable && (
110
+ <Box marginLeft={2} onClick={(): void => setEditing(true)}>
111
+ <Icon color="darkGray" name="edit" size="lg" />
112
+ </Box>
113
+ )}
114
+ </Box>
115
+ </Box>
116
+ );
47
117
  }
48
- }
118
+ };
package/src/Unifier.ts CHANGED
@@ -366,6 +366,4 @@ class UnifierClass {
366
366
  };
367
367
  }
368
368
 
369
- const NOTIFICATION_TAB_KEY = "@unifier/tabNotifications";
370
-
371
369
  export const Unifier = new UnifierClass();