react-better-html 1.1.57 → 1.1.59
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/components/BetterHtmlProvider.js +4 -0
- package/dist/components/Button.d.ts +2 -1
- package/dist/components/Button.js +2 -2
- package/dist/components/ColorThemeSwitch.d.ts +1 -0
- package/dist/components/Div.d.ts +1 -0
- package/dist/components/Dropdown.d.ts +7 -0
- package/dist/components/Dropdown.js +3 -2
- package/dist/components/Form.d.ts +3 -0
- package/dist/components/InputField.d.ts +9 -1
- package/dist/components/InputField.js +69 -3
- package/dist/components/Label.d.ts +2 -0
- package/dist/components/Modal.js +1 -1
- package/dist/components/PageHeader.d.ts +1 -0
- package/dist/components/Table.d.ts +44 -0
- package/dist/components/Table.js +154 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +3 -1
- package/dist/utils/hooks.d.ts +8 -1
- package/dist/utils/hooks.js +76 -1
- package/package.json +1 -1
|
@@ -26,6 +26,10 @@ const GlobalStyle = (0, styled_components_1.createGlobalStyle) `
|
|
|
26
26
|
text-decoration: none;
|
|
27
27
|
color: inherit;
|
|
28
28
|
}
|
|
29
|
+
|
|
30
|
+
.react-better-html-no-scrollbar::-webkit-scrollbar {
|
|
31
|
+
display: none;
|
|
32
|
+
}
|
|
29
33
|
`;
|
|
30
34
|
const betterHtmlContext = (0, react_1.createContext)(undefined);
|
|
31
35
|
const useBetterHtmlContext = () => {
|
|
@@ -5,10 +5,11 @@ import { LoaderName } from "../types/loader";
|
|
|
5
5
|
import { AnyOtherString, OmitProps } from "../types/app";
|
|
6
6
|
import { ComponentHoverStyle, ComponentStyle } from "../types/components";
|
|
7
7
|
export type ButtonProps<Value> = {
|
|
8
|
-
href?: string;
|
|
9
8
|
text?: string;
|
|
10
9
|
value?: Value;
|
|
10
|
+
href?: string;
|
|
11
11
|
download?: string;
|
|
12
|
+
target?: React.ComponentProps<"a">["target"];
|
|
12
13
|
icon?: IconName | AnyOtherString;
|
|
13
14
|
/** @default "left" */
|
|
14
15
|
iconPosition?: "left" | "right";
|
|
@@ -104,7 +104,7 @@ const ButtonElement = styled_components_1.default.button.withConfig({
|
|
|
104
104
|
${(props) => props.hoverStyle}
|
|
105
105
|
}
|
|
106
106
|
`;
|
|
107
|
-
const ButtonComponent = function Button({ href, text, value, download, icon, iconPosition = "left", iconColor, iconSize, image, imagePosition = "left", imageWidth, imageHeight, loaderName, loaderSize, isLoading, disabled, isSmall, isSubmit, onClick, onClickWithValue, ...props }) {
|
|
107
|
+
const ButtonComponent = function Button({ href, text, value, download, target, icon, iconPosition = "left", iconColor, iconSize, image, imagePosition = "left", imageWidth, imageHeight, loaderName, loaderSize, isLoading, disabled, isSmall, isSubmit, onClick, onClickWithValue, ...props }) {
|
|
108
108
|
const theme = (0, BetterHtmlProvider_1.useTheme)();
|
|
109
109
|
const isLoadingHook = (0, BetterHtmlProvider_1.useLoader)(loaderName);
|
|
110
110
|
const betterHtmlContext = (0, BetterHtmlProvider_1.useBetterHtmlContext)();
|
|
@@ -122,7 +122,7 @@ const ButtonComponent = function Button({ href, text, value, download, icon, ico
|
|
|
122
122
|
}, [onClick, onClickWithValue, value]);
|
|
123
123
|
const iconComponent = icon ? ((0, jsx_runtime_1.jsx)(Div_1.default.row, { height: 20, alignItems: "center", justifyContent: "center", children: (0, jsx_runtime_1.jsx)(Icon_1.default, { name: icon, color: iconColor ?? props.color ?? theme.colors.base, size: iconSize ?? parseInt(styledComponentStyles.normalStyle.fontSize?.toString() ?? "16") }) })) : undefined;
|
|
124
124
|
const imageComponent = image ? ((0, jsx_runtime_1.jsx)(Image_1.default, { name: image, color: iconColor ?? props.color ?? theme.colors.base, width: imageWidth ?? parseInt(styledComponentStyles.normalStyle.fontSize?.toString() ?? "16"), height: imageHeight })) : undefined;
|
|
125
|
-
return ((0, jsx_runtime_1.jsxs)(ButtonElement, { as: (href ? "a" : "button"), theme: theme, isSmall: isSmall, withText: text !== undefined, isLoading: isLoadingElement, disabled: disabled, href: href, download: download, type: isSubmit && !isLoadingElement ? "submit" : "button", onClick: !disabled && !isLoadingElement ? onClickElement : undefined, ...styledComponentStyles, ...dataProps, ...ariaProps, ...restProps, children: [(0, jsx_runtime_1.jsxs)(Div_1.default.row, { alignItems: "center", justifyContent: "center", gap: 10, pointerEvents: "none", opacity: isLoadingElement ? 0 : 1, transition: theme.styles.transition, children: [iconPosition === "left" && iconComponent, imagePosition === "left" && imageComponent, text, iconPosition === "right" && iconComponent, imagePosition === "right" && imageComponent] }), (0, jsx_runtime_1.jsx)(Div_1.default.row, { position: "absolute", width: "100%", height: "100%", top: 0, left: 0, pointerEvents: "none", alignItems: "center", justifyContent: "center", opacity: isLoadingElement ? 1 : 0, transition: theme.styles.transition, children: (0, jsx_runtime_1.jsx)(Loader_1.default, { color: props.color ?? theme.colors.base, size: loaderSize, disabled: !isLoadingElement }) })] }));
|
|
125
|
+
return ((0, jsx_runtime_1.jsxs)(ButtonElement, { as: (href ? "a" : "button"), theme: theme, isSmall: isSmall, withText: text !== undefined, isLoading: isLoadingElement, disabled: disabled, href: href, download: download, target: target, type: isSubmit && !isLoadingElement ? "submit" : "button", onClick: !disabled && !isLoadingElement ? onClickElement : undefined, ...styledComponentStyles, ...dataProps, ...ariaProps, ...restProps, children: [(0, jsx_runtime_1.jsxs)(Div_1.default.row, { alignItems: "center", justifyContent: "center", gap: 10, pointerEvents: "none", opacity: isLoadingElement ? 0 : 1, transition: theme.styles.transition, children: [iconPosition === "left" && iconComponent, imagePosition === "left" && imageComponent, text, iconPosition === "right" && iconComponent, imagePosition === "right" && imageComponent] }), (0, jsx_runtime_1.jsx)(Div_1.default.row, { position: "absolute", width: "100%", height: "100%", top: 0, left: 0, pointerEvents: "none", alignItems: "center", justifyContent: "center", opacity: isLoadingElement ? 1 : 0, transition: theme.styles.transition, children: (0, jsx_runtime_1.jsx)(Loader_1.default, { color: props.color ?? theme.colors.base, size: loaderSize, disabled: !isLoadingElement }) })] }));
|
|
126
126
|
};
|
|
127
127
|
ButtonComponent.secondary = function Secondary({ className, ...props }) {
|
|
128
128
|
const theme = (0, BetterHtmlProvider_1.useTheme)();
|
package/dist/components/Div.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export type DivProps<Value> = {
|
|
|
5
5
|
value?: Value;
|
|
6
6
|
/** @default "div" */
|
|
7
7
|
as?: WebTarget;
|
|
8
|
+
/** @default false */
|
|
8
9
|
isTabAccessed?: boolean;
|
|
9
10
|
onClickWithValue?: (value: Value) => void;
|
|
10
11
|
} & OmitProps<React.ComponentProps<"div">, "style" | "defaultValue"> & ComponentStyle & ComponentHoverStyle;
|
|
@@ -5,6 +5,7 @@ import { DivProps } from "./Div";
|
|
|
5
5
|
export type DropdownOption<Value, Data = unknown> = {
|
|
6
6
|
value: Value;
|
|
7
7
|
label: string;
|
|
8
|
+
/** @default false */
|
|
8
9
|
disabled?: boolean;
|
|
9
10
|
searchValues?: string[];
|
|
10
11
|
data?: Data;
|
|
@@ -13,7 +14,9 @@ export type DropdownProps<Value, Data = unknown> = {
|
|
|
13
14
|
label?: string;
|
|
14
15
|
errorText?: string;
|
|
15
16
|
infoText?: string;
|
|
17
|
+
/** @default false */
|
|
16
18
|
required?: boolean;
|
|
19
|
+
/** @default false */
|
|
17
20
|
disabled?: boolean;
|
|
18
21
|
options: DropdownOption<Value, Data>[];
|
|
19
22
|
value?: Value;
|
|
@@ -21,12 +24,16 @@ export type DropdownProps<Value, Data = unknown> = {
|
|
|
21
24
|
placeholder?: string;
|
|
22
25
|
leftIcon?: IconName | AnyOtherString;
|
|
23
26
|
inputFieldClassName?: string;
|
|
27
|
+
/** @default false */
|
|
24
28
|
withSearch?: boolean;
|
|
29
|
+
/** @default false */
|
|
25
30
|
withDebounce?: boolean;
|
|
26
31
|
/** @default 0.5s */
|
|
27
32
|
debounceDelay?: number;
|
|
33
|
+
/** @default false */
|
|
28
34
|
debounceIsLoading?: boolean;
|
|
29
35
|
debounceMinimumSymbolsRequired?: number;
|
|
36
|
+
/** @default false */
|
|
30
37
|
withoutClearButton?: boolean;
|
|
31
38
|
onChange?: (value: Value | undefined) => void;
|
|
32
39
|
onChangeSearch?: (query: string) => void;
|
|
@@ -14,7 +14,7 @@ const Icon_1 = __importDefault(require("./Icon"));
|
|
|
14
14
|
const Button_1 = __importDefault(require("./Button"));
|
|
15
15
|
const Loader_1 = __importDefault(require("./Loader"));
|
|
16
16
|
const BetterHtmlProvider_1 = require("./BetterHtmlProvider");
|
|
17
|
-
const DropdownComponent = (0, react_1.forwardRef)(function Dropdown({ label, errorText, infoText, required, disabled, options, value: controlledValue, defaultValue, placeholder
|
|
17
|
+
const DropdownComponent = (0, react_1.forwardRef)(function Dropdown({ label, errorText, infoText, required, disabled, options, value: controlledValue, defaultValue, placeholder, leftIcon, inputFieldClassName, withSearch, withDebounce, debounceDelay = 0.5, debounceIsLoading, debounceMinimumSymbolsRequired, withoutClearButton, onChange, onChangeSearch, renderOption, ...props }, ref) {
|
|
18
18
|
const theme = (0, BetterHtmlProvider_1.useTheme)();
|
|
19
19
|
const dropdownHolderRef = (0, react_1.useRef)(null);
|
|
20
20
|
const inputRef = (0, react_1.useRef)(null);
|
|
@@ -141,7 +141,8 @@ const DropdownComponent = (0, react_1.forwardRef)(function Dropdown({ label, err
|
|
|
141
141
|
}, [withDebounce, onChangeSearch, debouncedSearchQuery]);
|
|
142
142
|
const displayValue = withSearch && isFocused ? searchQuery : selectedOption?.label ?? "";
|
|
143
143
|
const withClearButton = isOpen && selectedOption;
|
|
144
|
-
|
|
144
|
+
const readyPlaceholder = placeholder ? placeholder : `Select an ${label?.toLowerCase() ?? "option"}`;
|
|
145
|
+
return ((0, jsx_runtime_1.jsx)(Div_1.default.column, { width: "100%", position: "relative", userSelect: "none", ...props, ref: dropdownHolderRef, children: (0, jsx_runtime_1.jsxs)(Div_1.default.row, { position: "relative", width: "100%", children: [(0, jsx_runtime_1.jsx)(InputField_1.default, { label: label, errorText: errorText, infoText: infoText, required: required, disabled: disabled, readOnly: !withSearch, value: displayValue, cursor: !withSearch ? "pointer" : undefined, placeholder: withSearch ? (selectedOption ? selectedOption.label : readyPlaceholder) : readyPlaceholder, leftIcon: leftIcon, className: `react-better-html-dropdown${isOpen ? " react-better-html-dropdown-open" : ""}${isOpenLate ? " react-better-html-dropdown-open-late" : ""}${inputFieldClassName ? ` ${inputFieldClassName}` : ""}`, onClick: !disabled ? setIsOpen.toggle : undefined, onFocus: setIsFocused.setTrue, onBlur: setIsFocused.setFalse, onKeyDown: onKeyDownInputField, onChangeValue: withSearch ? onChangeValue : undefined, insideInputFieldComponent: (0, jsx_runtime_1.jsx)(Div_1.default, { position: "absolute", top: "100%", left: 0, width: "100%", maxHeight: 300, backgroundColor: theme.colors.backgroundContent, border: `1px solid ${isFocused ? theme.colors.primary : theme.colors.border}`, borderTop: "none", borderBottomLeftRadius: theme.styles.borderRadius, borderBottomRightRadius: theme.styles.borderRadius, boxShadow: "0px 10px 20px #00000020", zIndex: 1000, overflowY: "auto", opacity: !isOpen ? 0 : undefined, pointerEvents: !isOpen ? "none" : undefined, transform: `translateY(${!isOpen ? -10 : 0}px)`, transition: theme.styles.transition, role: "listbox", "aria-label": label, children: isLoadingDebouncedSearchQuery || debounceIsLoading ? ((0, jsx_runtime_1.jsx)(Div_1.default, { padding: `${theme.styles.space / 2}px ${theme.styles.space + theme.styles.gap}px`, children: (0, jsx_runtime_1.jsx)(Loader_1.default.text, {}) })) : filteredOptions.length ? (filteredOptions.map((option, index) => {
|
|
145
146
|
const isSelected = option.value === value;
|
|
146
147
|
const isDisabled = option.disabled;
|
|
147
148
|
const isFocused = index === focusedOptionIndex;
|
|
@@ -7,11 +7,14 @@ export type FormProps = {
|
|
|
7
7
|
submitButtonText?: string;
|
|
8
8
|
submitButtonLoaderName?: LoaderName | AnyOtherString;
|
|
9
9
|
submitButtonId?: string;
|
|
10
|
+
/** @default false */
|
|
10
11
|
submitButtonIsDisabled?: boolean;
|
|
11
12
|
/** @default "right" */
|
|
12
13
|
actionButtonsLocation?: "left" | "center" | "right";
|
|
13
14
|
gap?: React.CSSProperties["gap"];
|
|
15
|
+
/** @default false */
|
|
14
16
|
isSubmitting?: boolean;
|
|
17
|
+
/** @default false */
|
|
15
18
|
isDestructive?: boolean;
|
|
16
19
|
onClickCancel?: () => void;
|
|
17
20
|
onSubmit?: (value: React.FormEvent<HTMLFormElement>) => void;
|
|
@@ -9,12 +9,15 @@ export type InputFieldProps = {
|
|
|
9
9
|
leftIcon?: IconName | AnyOtherString;
|
|
10
10
|
rightIcon?: IconName | AnyOtherString;
|
|
11
11
|
insideInputFieldComponent?: React.ReactNode;
|
|
12
|
+
/** @default false */
|
|
12
13
|
withDebounce?: boolean;
|
|
13
14
|
/** @default 0.5s */
|
|
14
15
|
debounceDelay?: number;
|
|
15
16
|
onChangeValue?: (value: string) => void;
|
|
16
17
|
onClickRightIcon?: () => void;
|
|
18
|
+
holderRef?: React.ForwardedRef<HTMLDivElement>;
|
|
17
19
|
} & OmitProps<React.ComponentProps<"input">, "style" | "ref"> & ComponentStyle & ComponentHoverStyle;
|
|
20
|
+
export type TextareaFieldProps = OmitProps<InputFieldProps, "type"> & OmitProps<React.ComponentProps<"textarea">, "style" | "ref">;
|
|
18
21
|
type InputFieldComponentType = {
|
|
19
22
|
(props: ComponentPropWithRef<HTMLInputElement, InputFieldProps>): React.ReactElement;
|
|
20
23
|
multiline: (props: ComponentPropWithRef<HTMLTextAreaElement, TextareaFieldProps>) => React.ReactElement;
|
|
@@ -22,14 +25,19 @@ type InputFieldComponentType = {
|
|
|
22
25
|
password: (props: ComponentPropWithRef<HTMLInputElement, InputFieldProps>) => React.ReactElement;
|
|
23
26
|
search: (props: ComponentPropWithRef<HTMLInputElement, InputFieldProps>) => React.ReactElement;
|
|
24
27
|
phoneNumber: (props: ComponentPropWithRef<HTMLInputElement, OmitProps<InputFieldProps, "type">>) => React.ReactElement;
|
|
28
|
+
date: (props: ComponentPropWithRef<HTMLInputElement, InputFieldProps>) => React.ReactElement;
|
|
29
|
+
dateTime: (props: ComponentPropWithRef<HTMLInputElement, InputFieldProps>) => React.ReactElement;
|
|
30
|
+
time: (props: ComponentPropWithRef<HTMLInputElement, InputFieldProps>) => React.ReactElement;
|
|
25
31
|
};
|
|
26
32
|
declare const InputFieldComponent: InputFieldComponentType;
|
|
27
|
-
export type TextareaFieldProps = OmitProps<InputFieldProps, "type"> & OmitProps<React.ComponentProps<"textarea">, "style" | "ref">;
|
|
28
33
|
declare const InputField: typeof InputFieldComponent & {
|
|
29
34
|
multiline: typeof InputFieldComponent.multiline;
|
|
30
35
|
email: typeof InputFieldComponent.email;
|
|
31
36
|
password: typeof InputFieldComponent.password;
|
|
32
37
|
search: typeof InputFieldComponent.search;
|
|
33
38
|
phoneNumber: typeof InputFieldComponent.phoneNumber;
|
|
39
|
+
date: typeof InputFieldComponent.date;
|
|
40
|
+
dateTime: typeof InputFieldComponent.dateTime;
|
|
41
|
+
time: typeof InputFieldComponent.time;
|
|
34
42
|
};
|
|
35
43
|
export default InputField;
|
|
@@ -47,6 +47,13 @@ const InputElement = styled_components_1.default.input.withConfig({
|
|
|
47
47
|
cursor: not-allowed;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
&[type="date"]::-webkit-calendar-picker-indicator,
|
|
51
|
+
&[type="datetime-local"]::-webkit-calendar-picker-indicator,
|
|
52
|
+
&[type="time"]::-webkit-calendar-picker-indicator {
|
|
53
|
+
display: none;
|
|
54
|
+
-webkit-appearance: none;
|
|
55
|
+
}
|
|
56
|
+
|
|
50
57
|
&.react-better-html-phone-number-holder {
|
|
51
58
|
border-right: none;
|
|
52
59
|
border-top-right-radius: 0px;
|
|
@@ -71,6 +78,15 @@ const InputElement = styled_components_1.default.input.withConfig({
|
|
|
71
78
|
}
|
|
72
79
|
}
|
|
73
80
|
|
|
81
|
+
&.react-better-html-inputField-dateTime-opened {
|
|
82
|
+
border-bottom-left-radius: 0px;
|
|
83
|
+
border-bottom-right-radius: 0px;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
&.react-better-html-inputField-dateTime-opened-late {
|
|
87
|
+
z-index: 1001;
|
|
88
|
+
}
|
|
89
|
+
|
|
74
90
|
${(props) => props.normalStyle}
|
|
75
91
|
|
|
76
92
|
&:hover {
|
|
@@ -111,7 +127,9 @@ const TextareaElement = styled_components_1.default.textarea.withConfig({
|
|
|
111
127
|
${(props) => props.hoverStyle}
|
|
112
128
|
}
|
|
113
129
|
`;
|
|
114
|
-
const
|
|
130
|
+
const hours = Array.from({ length: 24 }, (_, index) => index);
|
|
131
|
+
const minutes = Array.from({ length: 60 }, (_, index) => index);
|
|
132
|
+
const InputFieldComponent = (0, react_1.forwardRef)(function InputField({ label, errorText, infoText, leftIcon, rightIcon, insideInputFieldComponent, withDebounce, debounceDelay = 0.5, onChange, onChangeValue, onClickRightIcon, holderRef, required, placeholder, ...props }, ref) {
|
|
115
133
|
const theme = (0, BetterHtmlProvider_1.useTheme)();
|
|
116
134
|
const [_, debouncedValue, setDebouncedValue] = (0, hooks_1.useDebounceState)(props.value?.toString() ?? "", debounceDelay);
|
|
117
135
|
const styledComponentStylesWithoutExcluded = (0, hooks_1.useStyledComponentStyles)(props, theme, true);
|
|
@@ -135,7 +153,7 @@ const InputFieldComponent = (0, react_1.forwardRef)(function InputField({ label,
|
|
|
135
153
|
return;
|
|
136
154
|
onChangeValue?.(debouncedValue);
|
|
137
155
|
}, [withDebounce, onChangeValue, debouncedValue]);
|
|
138
|
-
return ((0, jsx_runtime_1.jsxs)(Div_1.default.column, { width: "100%", gap: theme.styles.gap / 2, ...styledComponentStylesWithExcluded, children: [label && (0, jsx_runtime_1.jsx)(Label_1.default, { text: label, required: required, isError: !!errorText }), (0, jsx_runtime_1.jsxs)(Div_1.default, { position: "relative", width: "100%", children: [leftIcon && ((0, jsx_runtime_1.jsx)(Icon_1.default, { name: leftIcon, position: "absolute", top: 46 / 2, left: theme.styles.space + 1, transform: "translateY(-50%)", pointerEvents: "none", zIndex: props.className?.includes("react-better-html-dropdown-open-late") ? 1002 : 1 })), (0, jsx_runtime_1.jsx)(InputElement, { theme: theme, withLeftIcon: leftIcon !== undefined, withRightIcon: rightIcon !== undefined, required: required, placeholder: placeholder ?? label, onChange: onChangeElement, ...styledComponentStylesWithoutExcluded, ...dataProps, ...ariaProps, ...restProps, ref: ref }), rightIcon ? (onClickRightIcon ? ((0, jsx_runtime_1.jsx)(Button_1.default.icon, { icon: rightIcon, position: "absolute", top: 46 / 2, right: theme.styles.space + 1 - theme.styles.space / 2, transform: "translateY(-50%)", onClick: onClickRightIcon })) : ((0, jsx_runtime_1.jsx)(Icon_1.default, { name: rightIcon, position: "absolute", top: 46 / 2, right: theme.styles.space + 1, transform: "translateY(-50%)", pointerEvents: "none" }))) : undefined, insideInputFieldComponent] }), (errorText || infoText) && ((0, jsx_runtime_1.jsx)(Text_1.default, { as: "span", display: "block", fontSize: 14, color: errorText ? theme.colors.error : theme.colors.textSecondary, children: errorText || infoText }))] }));
|
|
156
|
+
return ((0, jsx_runtime_1.jsxs)(Div_1.default.column, { width: "100%", gap: theme.styles.gap / 2, ...styledComponentStylesWithExcluded, ref: holderRef, children: [label && (0, jsx_runtime_1.jsx)(Label_1.default, { text: label, required: required, isError: !!errorText }), (0, jsx_runtime_1.jsxs)(Div_1.default, { position: "relative", width: "100%", children: [leftIcon && ((0, jsx_runtime_1.jsx)(Icon_1.default, { name: leftIcon, position: "absolute", top: 46 / 2, left: theme.styles.space + 1, transform: "translateY(-50%)", pointerEvents: "none", zIndex: props.className?.includes("react-better-html-dropdown-open-late") ? 1002 : 1 })), (0, jsx_runtime_1.jsx)(InputElement, { theme: theme, withLeftIcon: leftIcon !== undefined, withRightIcon: rightIcon !== undefined, required: required, placeholder: placeholder ?? label, onChange: onChangeElement, ...styledComponentStylesWithoutExcluded, ...dataProps, ...ariaProps, ...restProps, ref: ref }), rightIcon ? (onClickRightIcon ? ((0, jsx_runtime_1.jsx)(Button_1.default.icon, { icon: rightIcon, position: "absolute", top: 46 / 2, right: theme.styles.space + 1 - theme.styles.space / 2, transform: "translateY(-50%)", onClick: onClickRightIcon })) : ((0, jsx_runtime_1.jsx)(Icon_1.default, { name: rightIcon, position: "absolute", top: 46 / 2, right: theme.styles.space + 1, transform: "translateY(-50%)", pointerEvents: "none" }))) : undefined, insideInputFieldComponent] }), (errorText || infoText) && ((0, jsx_runtime_1.jsx)(Text_1.default, { as: "span", display: "block", fontSize: 14, color: errorText ? theme.colors.error : theme.colors.textSecondary, children: errorText || infoText }))] }));
|
|
139
157
|
});
|
|
140
158
|
InputFieldComponent.multiline = (0, react_1.forwardRef)(function Multiline({ label, placeholder, errorText, infoText, leftIcon, rightIcon, onChange, onChangeValue, onClickRightIcon, required, ...props }, ref) {
|
|
141
159
|
const theme = (0, BetterHtmlProvider_1.useTheme)();
|
|
@@ -193,7 +211,52 @@ InputFieldComponent.phoneNumber = (0, react_1.forwardRef)(function PhoneNumber({
|
|
|
193
211
|
setDropdownValue(country.phoneNumberExtension);
|
|
194
212
|
setInputFieldValue(newValue.slice(country?.phoneNumberExtension.length + 1));
|
|
195
213
|
}, [value]);
|
|
196
|
-
return ((0, jsx_runtime_1.jsxs)(Div_1.default, { children: [label && (0, jsx_runtime_1.jsx)(Label_1.default, { text: label, required: props.required, isError: !!props.errorText }), (0, jsx_runtime_1.jsxs)(Div_1.default.row, { children: [(0, jsx_runtime_1.jsx)(Dropdown_1.default, { options: options, renderOption: renderOption, width: 130, withSearch: true, placeholder: "+00", inputFieldClassName: "react-better-html-phone-number-holder", defaultValue: defaultValue, value: dropdownValue, onChange: setDropdownValue, withoutClearButton: true }), (0, jsx_runtime_1.jsx)(InputFieldComponent, { placeholder: "Phone number", className: "react-better-html-phone-number", value: inputFieldValue, onChangeValue: onChangeValueElement, ref: ref, ...props })] })] }));
|
|
214
|
+
return ((0, jsx_runtime_1.jsxs)(Div_1.default, { width: "100%", children: [label && (0, jsx_runtime_1.jsx)(Label_1.default, { text: label, required: props.required, isError: !!props.errorText }), (0, jsx_runtime_1.jsxs)(Div_1.default.row, { children: [(0, jsx_runtime_1.jsx)(Dropdown_1.default, { options: options, renderOption: renderOption, width: 130, minWidth: 110, withSearch: true, placeholder: "+00", inputFieldClassName: "react-better-html-phone-number-holder", defaultValue: defaultValue, value: dropdownValue, onChange: setDropdownValue, withoutClearButton: true }), (0, jsx_runtime_1.jsx)(InputFieldComponent, { placeholder: "Phone number", className: "react-better-html-phone-number", value: inputFieldValue, onChangeValue: onChangeValueElement, ref: ref, ...props })] })] }));
|
|
215
|
+
});
|
|
216
|
+
InputFieldComponent.date = (0, react_1.forwardRef)(function Date({ className, onFocus, onBlur, ...props }, ref) {
|
|
217
|
+
const theme = (0, BetterHtmlProvider_1.useTheme)();
|
|
218
|
+
const holderRef = (0, react_1.useRef)(null);
|
|
219
|
+
const { internalValue, setInternalValue, inputFieldProps, insideInputFieldComponentProps } = (0, hooks_1.useComponentInputFieldDateProps)(props, holderRef);
|
|
220
|
+
return ((0, jsx_runtime_1.jsx)(InputFieldComponent, { type: "date", insideInputFieldComponent: (0, jsx_runtime_1.jsx)(Div_1.default, { position: "absolute", top: "100%", left: 0, width: "100%", maxHeight: 300, backgroundColor: theme.colors.backgroundContent, borderBottomLeftRadius: theme.styles.borderRadius, borderBottomRightRadius: theme.styles.borderRadius, boxShadow: "0px 10px 20px #00000020", overflowY: "auto", ...insideInputFieldComponentProps, children: "Hello there" }), holderRef: holderRef, ref: ref, ...props, ...inputFieldProps }));
|
|
221
|
+
});
|
|
222
|
+
InputFieldComponent.dateTime = (0, react_1.forwardRef)(function DateTime({ className, onFocus, onBlur, ...props }, ref) {
|
|
223
|
+
const theme = (0, BetterHtmlProvider_1.useTheme)();
|
|
224
|
+
const holderRef = (0, react_1.useRef)(null);
|
|
225
|
+
const { internalValue, setInternalValue, inputFieldProps, insideInputFieldComponentProps } = (0, hooks_1.useComponentInputFieldDateProps)(props, holderRef);
|
|
226
|
+
return ((0, jsx_runtime_1.jsx)(InputFieldComponent, { type: "datetime-local", insideInputFieldComponent: (0, jsx_runtime_1.jsx)(Div_1.default, { position: "absolute", top: "100%", left: 0, width: "100%", maxHeight: 300, backgroundColor: theme.colors.backgroundContent, borderBottomLeftRadius: theme.styles.borderRadius, borderBottomRightRadius: theme.styles.borderRadius, boxShadow: "0px 10px 20px #00000020", overflowY: "auto", ...insideInputFieldComponentProps, children: "Hello there" }), holderRef: holderRef, ref: ref, ...props, ...inputFieldProps }));
|
|
227
|
+
});
|
|
228
|
+
InputFieldComponent.time = (0, react_1.forwardRef)(function Time({ ...props }, ref) {
|
|
229
|
+
const theme = (0, BetterHtmlProvider_1.useTheme)();
|
|
230
|
+
const holderRef = (0, react_1.useRef)(null);
|
|
231
|
+
const selectedHourRef = (0, react_1.useRef)(null);
|
|
232
|
+
const selectedMinuteRef = (0, react_1.useRef)(null);
|
|
233
|
+
const { internalValue, setInternalValue, inputFieldProps, insideInputFieldComponentProps, isOpen } = (0, hooks_1.useComponentInputFieldDateProps)(props, holderRef);
|
|
234
|
+
const onClickHour = (0, react_1.useCallback)((hour) => {
|
|
235
|
+
const value = `${hour.toString().padStart(2, "0")}:${internalValue?.toString().split(":")[1] || "00"}`;
|
|
236
|
+
inputFieldProps.onChangeValue?.(value);
|
|
237
|
+
setInternalValue(value);
|
|
238
|
+
}, [internalValue, inputFieldProps.onChangeValue]);
|
|
239
|
+
const onClickMinute = (0, react_1.useCallback)((minute) => {
|
|
240
|
+
const value = `${internalValue?.toString().split(":")[0] || "00"}:${minute.toString().padStart(2, "0")}`;
|
|
241
|
+
inputFieldProps.onChangeValue?.(value);
|
|
242
|
+
setInternalValue(value);
|
|
243
|
+
}, [internalValue, inputFieldProps.onChangeValue]);
|
|
244
|
+
(0, react_1.useEffect)(() => {
|
|
245
|
+
if (isOpen && selectedHourRef.current)
|
|
246
|
+
selectedHourRef.current.scrollIntoView({ block: "nearest", behavior: "instant" });
|
|
247
|
+
if (isOpen && selectedMinuteRef.current)
|
|
248
|
+
selectedMinuteRef.current.scrollIntoView({ block: "nearest", behavior: "instant" });
|
|
249
|
+
}, [isOpen]);
|
|
250
|
+
const valueHour = parseInt(internalValue?.toString().split(":")?.[0]).toString();
|
|
251
|
+
const valueMinute = parseInt(internalValue?.toString().split(":")?.[1]).toString();
|
|
252
|
+
const buttonWidth = 50;
|
|
253
|
+
return ((0, jsx_runtime_1.jsx)(InputFieldComponent, { type: "time", insideInputFieldComponent: (0, jsx_runtime_1.jsx)(Div_1.default, { position: "absolute", top: "100%", left: 0, width: buttonWidth * 2 + 2, height: 300, backgroundColor: theme.colors.backgroundContent, borderBottomLeftRadius: theme.styles.borderRadius, borderBottomRightRadius: theme.styles.borderRadius, boxShadow: "0px 10px 20px #00000020", overflowY: "auto", ...insideInputFieldComponentProps, children: (0, jsx_runtime_1.jsxs)(Div_1.default.row, { height: "100%", children: [(0, jsx_runtime_1.jsx)(Div_1.default, { className: "react-better-html-no-scrollbar", width: buttonWidth, height: "100%", overflowY: "auto", children: hours.map((hour) => {
|
|
254
|
+
const isSelected = hour.toString() === valueHour;
|
|
255
|
+
return ((0, jsx_runtime_1.jsx)(Div_1.default.row, { alignItems: "center", justifyContent: "center", color: isSelected ? theme.colors.base : theme.colors.textPrimary, backgroundColor: isSelected ? theme.colors.primary : theme.colors.backgroundContent, filterHover: "brightness(0.9)", cursor: "pointer", padding: `${theme.styles.space / 2}px ${theme.styles.space + theme.styles.gap}px`, value: hour, onClickWithValue: onClickHour, ref: isSelected ? selectedHourRef : undefined, children: (0, jsx_runtime_1.jsx)(Text_1.default, { textAlign: "center", children: hour.toString().padStart(2, "0") }) }, hour));
|
|
256
|
+
}) }), (0, jsx_runtime_1.jsx)(Div_1.default, { className: "react-better-html-no-scrollbar", width: buttonWidth, height: "100%", overflowY: "auto", children: minutes.map((minute) => {
|
|
257
|
+
const isSelected = minute.toString() === valueMinute;
|
|
258
|
+
return ((0, jsx_runtime_1.jsx)(Div_1.default.row, { alignItems: "center", justifyContent: "center", color: isSelected ? theme.colors.base : theme.colors.textPrimary, backgroundColor: isSelected ? theme.colors.primary : theme.colors.backgroundContent, filterHover: "brightness(0.9)", cursor: "pointer", padding: `${theme.styles.space / 2}px ${theme.styles.space + theme.styles.gap}px`, value: minute, onClickWithValue: onClickMinute, ref: isSelected ? selectedMinuteRef : undefined, children: (0, jsx_runtime_1.jsx)(Text_1.default, { textAlign: "center", children: minute.toString().padStart(2, "0") }) }, minute));
|
|
259
|
+
}) })] }) }), holderRef: holderRef, ref: ref, ...props, ...inputFieldProps, minWidth: buttonWidth * 2 + 2 }));
|
|
197
260
|
});
|
|
198
261
|
const InputField = (0, react_1.memo)(InputFieldComponent);
|
|
199
262
|
InputField.multiline = InputFieldComponent.multiline;
|
|
@@ -201,4 +264,7 @@ InputField.email = InputFieldComponent.email;
|
|
|
201
264
|
InputField.password = InputFieldComponent.password;
|
|
202
265
|
InputField.search = InputFieldComponent.search;
|
|
203
266
|
InputField.phoneNumber = InputFieldComponent.phoneNumber;
|
|
267
|
+
InputField.date = InputFieldComponent.date;
|
|
268
|
+
InputField.dateTime = InputFieldComponent.dateTime;
|
|
269
|
+
InputField.time = InputFieldComponent.time;
|
|
204
270
|
exports.default = InputField;
|
package/dist/components/Modal.js
CHANGED
|
@@ -87,7 +87,7 @@ const ModalComponent = (0, react_1.forwardRef)(function Modal({ maxWidth, title,
|
|
|
87
87
|
isOpened,
|
|
88
88
|
};
|
|
89
89
|
}, [onClickOpen, onClickClose, isOpened]);
|
|
90
|
-
return ((0, jsx_runtime_1.jsx)(DialogStylesElement, { theme: theme, colorTheme: colorTheme, opacity: !isOpened ? 0 : 1, onClose: onClickClose, ref: dialogRef, children: isOpenedLate ? ((0, jsx_runtime_1.jsx)(Div_1.default.column, { position: "relative", width: "100%", maxWidth: maxWidth ?? app.contentMaxWidth / 1.3, minHeight: `calc(100% - ${theme.styles.space * 2}px)`, alignItems: "center", justifyContent: "center", marginBlock: theme.styles.space, marginInline: "auto", transform: `translateY(${theme.styles.space}px)`, transition: theme.styles.transition, animation: isOpened ? "fadeInAnimation 0.2s ease forwards" : "fadeOutAnimation 0.2s ease forwards", children: (0, jsx_runtime_1.jsxs)(Div_1.default, { position: "relative", width: "100%", minHeight: 32 + theme.styles.space * 2, backgroundColor: theme.colors.backgroundBase, borderRadius: theme.styles.borderRadius * 2, paddingInline: !title ? theme.styles.space + theme.styles.gap : undefined, paddingBlock: !title ? theme.styles.space : undefined, overflow: overflow, children: [title ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)(Div_1.default.row, { alignItems: "center", gap: theme.styles.gap, backgroundColor: headerBackgroundColor, borderTopLeftRadius: theme.styles.borderRadius * 2, borderTopRightRadius: theme.styles.borderRadius * 2, paddingInline: theme.styles.space + theme.styles.gap, paddingBlock: theme.styles.space, transition: theme.styles.transition, children: [(0, jsx_runtime_1.jsxs)(Div_1.default.column, { flex: 1, gap: theme.styles.gap / 2, children: [(0, jsx_runtime_1.jsx)(Text_1.default, { as: "h1", color: titleColor ?? theme.colors.textPrimary, transition: theme.styles.transition, children: title }), description && ((0, jsx_runtime_1.jsx)(Text_1.default, { color: descriptionColor ?? theme.colors.textSecondary, transition: theme.styles.transition, children: description }))] }), (0, jsx_runtime_1.jsx)(Button_1.default.icon, { icon: "XMark", marginTop: 1, iconColor: titleColor, onClick: onClickClose, transition: theme.styles.transition })] }), (0, jsx_runtime_1.jsx)(Divider_1.default.horizontal, {})] })) : ((0, jsx_runtime_1.jsx)(Div_1.default, { position: "absolute", top: theme.styles.space, right: theme.styles.space, children: (0, jsx_runtime_1.jsx)(Button_1.default.icon, { icon: "XMark", onClick: onClickClose }) })), (0, jsx_runtime_1.jsx)(Div_1.default, { paddingInline: title ? theme.styles.space + theme.styles.gap : undefined, paddingBlock: title ? theme.styles.space : undefined, children: children })] }) })) : undefined }));
|
|
90
|
+
return ((0, jsx_runtime_1.jsx)(DialogStylesElement, { theme: theme, colorTheme: colorTheme, opacity: !isOpened ? 0 : 1, onClose: onClickClose, ref: dialogRef, children: isOpenedLate ? ((0, jsx_runtime_1.jsx)(Div_1.default.column, { position: "relative", width: "100%", maxWidth: maxWidth ?? app.contentMaxWidth / 1.3, minHeight: `calc(100% - ${theme.styles.space * 2}px)`, alignItems: "center", justifyContent: "center", marginBlock: theme.styles.space, marginInline: "auto", transform: `translateY(${theme.styles.space}px)`, transition: theme.styles.transition, animation: isOpened ? "fadeInAnimation 0.2s ease forwards" : "fadeOutAnimation 0.2s ease forwards", children: (0, jsx_runtime_1.jsxs)(Div_1.default, { position: "relative", width: "100%", minHeight: 32 + theme.styles.space * 2, backgroundColor: theme.colors.backgroundBase, borderRadius: theme.styles.borderRadius * 2, paddingInline: !title ? theme.styles.space + theme.styles.gap : undefined, paddingBlock: !title ? theme.styles.space : undefined, overflow: overflow, children: [title ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)(Div_1.default.row, { alignItems: "center", gap: theme.styles.gap, backgroundColor: headerBackgroundColor, borderTopLeftRadius: theme.styles.borderRadius * 2 - 1, borderTopRightRadius: theme.styles.borderRadius * 2 - 1, paddingInline: theme.styles.space + theme.styles.gap, paddingBlock: theme.styles.space, transition: theme.styles.transition, children: [(0, jsx_runtime_1.jsxs)(Div_1.default.column, { flex: 1, gap: theme.styles.gap / 2, children: [(0, jsx_runtime_1.jsx)(Text_1.default, { as: "h1", color: titleColor ?? theme.colors.textPrimary, transition: theme.styles.transition, children: title }), description && ((0, jsx_runtime_1.jsx)(Text_1.default, { color: descriptionColor ?? theme.colors.textSecondary, transition: theme.styles.transition, children: description }))] }), (0, jsx_runtime_1.jsx)(Button_1.default.icon, { icon: "XMark", marginTop: 1, iconColor: titleColor, onClick: onClickClose, transition: theme.styles.transition })] }), (0, jsx_runtime_1.jsx)(Divider_1.default.horizontal, {})] })) : ((0, jsx_runtime_1.jsx)(Div_1.default, { position: "absolute", top: theme.styles.space, right: theme.styles.space, children: (0, jsx_runtime_1.jsx)(Button_1.default.icon, { icon: "XMark", onClick: onClickClose }) })), (0, jsx_runtime_1.jsx)(Div_1.default, { paddingInline: title ? theme.styles.space + theme.styles.gap : undefined, paddingBlock: title ? theme.styles.space : undefined, children: children })] }) })) : undefined }));
|
|
91
91
|
});
|
|
92
92
|
ModalComponent.confirmation = (0, react_1.forwardRef)(function Confirmation({ continueButtonLoaderName, onContinue, onCancel, ...props }, ref) {
|
|
93
93
|
const theme = (0, BetterHtmlProvider_1.useTheme)();
|
|
@@ -10,6 +10,7 @@ export type PageHeaderProps = {
|
|
|
10
10
|
description?: string;
|
|
11
11
|
textAlign?: React.CSSProperties["textAlign"];
|
|
12
12
|
rightElement?: React.ReactNode;
|
|
13
|
+
/** @default false */
|
|
13
14
|
lightMode?: boolean;
|
|
14
15
|
} & Pick<ComponentMarginProps, "marginBottom">;
|
|
15
16
|
declare function PageHeader({ imageUrl, imageSize, title, titleAs, titleRightElement, description, textAlign, rightElement, lightMode, marginBottom, }: PageHeaderProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
import { ComponentMarginProps, ComponentPropWithRef } from "../types/components";
|
|
3
|
+
import { ToggleInputProps } from "./ToggleInput";
|
|
4
|
+
import { ImageProps } from "./Image";
|
|
5
|
+
type TextColumn<DataItem> = {
|
|
6
|
+
type: "text";
|
|
7
|
+
keyName: keyof DataItem;
|
|
8
|
+
format?: (value: any) => string;
|
|
9
|
+
};
|
|
10
|
+
type ElementColumn<DataItem> = {
|
|
11
|
+
type: "element";
|
|
12
|
+
render: (item: DataItem, index: number) => ReactNode;
|
|
13
|
+
};
|
|
14
|
+
type ImageColumn<DataItem> = {
|
|
15
|
+
type: "image";
|
|
16
|
+
keyName?: keyof DataItem;
|
|
17
|
+
} & ImageProps;
|
|
18
|
+
type CheckboxColumn<DataItem> = {
|
|
19
|
+
type: "checkbox";
|
|
20
|
+
keyName?: keyof DataItem;
|
|
21
|
+
} & ToggleInputProps<boolean>;
|
|
22
|
+
export type TableColumn<DataItem> = {
|
|
23
|
+
label?: string;
|
|
24
|
+
width?: string | number;
|
|
25
|
+
align?: "left" | "center" | "right";
|
|
26
|
+
} & (TextColumn<DataItem> | ElementColumn<DataItem> | ImageColumn<DataItem> | CheckboxColumn<DataItem>);
|
|
27
|
+
export type TableProps<DataItem> = {
|
|
28
|
+
columns: TableColumn<DataItem>[];
|
|
29
|
+
data: DataItem[];
|
|
30
|
+
/** @default false */
|
|
31
|
+
isStriped?: boolean;
|
|
32
|
+
/** @default false */
|
|
33
|
+
withStickyHeader?: boolean;
|
|
34
|
+
/** @default "No data available" */
|
|
35
|
+
noDataItemsMessage?: string;
|
|
36
|
+
onClickRow?: (item: DataItem, index: number) => void;
|
|
37
|
+
onClickAllCheckboxes?: () => void;
|
|
38
|
+
} & ComponentMarginProps;
|
|
39
|
+
type TableComponentType = {
|
|
40
|
+
<DataItem>(props: ComponentPropWithRef<HTMLDivElement, TableProps<DataItem>>): React.ReactElement;
|
|
41
|
+
};
|
|
42
|
+
declare const TableComponent: TableComponentType;
|
|
43
|
+
declare const Table: typeof TableComponent;
|
|
44
|
+
export default Table;
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
40
|
+
const react_1 = require("react");
|
|
41
|
+
const styled_components_1 = __importStar(require("styled-components"));
|
|
42
|
+
const Div_1 = __importDefault(require("./Div"));
|
|
43
|
+
const ToggleInput_1 = __importDefault(require("./ToggleInput"));
|
|
44
|
+
const Image_1 = __importDefault(require("./Image"));
|
|
45
|
+
const BetterHtmlProvider_1 = require("./BetterHtmlProvider");
|
|
46
|
+
const Text_1 = __importDefault(require("./Text"));
|
|
47
|
+
const defaultImageWidth = 120;
|
|
48
|
+
const TableStyledComponent = styled_components_1.default.table.withConfig({
|
|
49
|
+
shouldForwardProp: (prop) => !["isStriped", "withHover", "withStickyHeader", "theme"].includes(prop),
|
|
50
|
+
}) `
|
|
51
|
+
width: 100%;
|
|
52
|
+
border-collapse: collapse;
|
|
53
|
+
border-spacing: 0;
|
|
54
|
+
|
|
55
|
+
tr {
|
|
56
|
+
background-color: ${(props) => props.theme.colors.backgroundContent};
|
|
57
|
+
|
|
58
|
+
&.isHeader {
|
|
59
|
+
background-color: ${(props) => props.theme.colors.backgroundSecondary};
|
|
60
|
+
font-weight: 700;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
&.isClickable {
|
|
64
|
+
cursor: pointer;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
${(props) => props.isStriped
|
|
68
|
+
? (0, styled_components_1.css) `
|
|
69
|
+
&:nth-child(even) {
|
|
70
|
+
background-color: ${props.theme.colors.backgroundSecondary};
|
|
71
|
+
}
|
|
72
|
+
`
|
|
73
|
+
: ""}
|
|
74
|
+
|
|
75
|
+
${(props) => props.withHover
|
|
76
|
+
? (0, styled_components_1.css) `
|
|
77
|
+
transition: ${(props) => props.theme.styles.transition};
|
|
78
|
+
|
|
79
|
+
&:not(.isHeader):hover {
|
|
80
|
+
background-color: ${props.theme.colors.backgroundSecondary}20;
|
|
81
|
+
}
|
|
82
|
+
`
|
|
83
|
+
: ""}
|
|
84
|
+
|
|
85
|
+
th {
|
|
86
|
+
font-size: 18px;
|
|
87
|
+
text-align: left;
|
|
88
|
+
padding: ${(props) => props.theme.styles.space}px;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
td {
|
|
92
|
+
border-top: 1px solid ${(props) => props.theme.colors.border}60;
|
|
93
|
+
padding: ${(props) => props.theme.styles.gap}px ${(props) => props.theme.styles.space}px;
|
|
94
|
+
|
|
95
|
+
&.noData {
|
|
96
|
+
text-align: center;
|
|
97
|
+
padding: ${(props) => props.theme.styles.space}px;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
`;
|
|
102
|
+
const ThStyledComponent = styled_components_1.default.th.withConfig({
|
|
103
|
+
shouldForwardProp: (prop) => !["width", "textAlign"].includes(prop),
|
|
104
|
+
}) `
|
|
105
|
+
${(props) => (props.width ? `width: ${props.width}px;` : "")}
|
|
106
|
+
${(props) => (props.textAlign ? `text-align: ${props.textAlign} !important;` : "")}
|
|
107
|
+
`;
|
|
108
|
+
const TdStyledComponent = styled_components_1.default.td.withConfig({
|
|
109
|
+
shouldForwardProp: (prop) => !["width", "textAlign"].includes(prop),
|
|
110
|
+
}) `
|
|
111
|
+
${(props) => (props.textAlign ? `text-align: ${props.textAlign} !important;` : "")}
|
|
112
|
+
`;
|
|
113
|
+
const TableComponent = (0, react_1.forwardRef)(function Table({ columns, data, isStriped, withStickyHeader, noDataItemsMessage = "No data available", onClickRow, onClickAllCheckboxes, ...props }, ref) {
|
|
114
|
+
const theme = (0, BetterHtmlProvider_1.useTheme)();
|
|
115
|
+
const renderCellContent = (0, react_1.useCallback)((column, item, index) => {
|
|
116
|
+
switch (column.type) {
|
|
117
|
+
case "text": {
|
|
118
|
+
const value = item[column.keyName];
|
|
119
|
+
return column.format ? column.format(value) : String(value ?? "");
|
|
120
|
+
}
|
|
121
|
+
case "element": {
|
|
122
|
+
return column.render(item, index);
|
|
123
|
+
}
|
|
124
|
+
case "image": {
|
|
125
|
+
const { type, keyName, ...props } = column;
|
|
126
|
+
const src = keyName ? item[keyName] : undefined;
|
|
127
|
+
return ((0, jsx_runtime_1.jsx)(Image_1.default, { src: src, width: defaultImageWidth, borderRadius: theme.styles.borderRadius / 2, ...props }));
|
|
128
|
+
}
|
|
129
|
+
case "checkbox": {
|
|
130
|
+
const { type, keyName, ...props } = column;
|
|
131
|
+
const checked = keyName ? item[keyName] : false;
|
|
132
|
+
return (0, jsx_runtime_1.jsx)(ToggleInput_1.default.checkbox, { checked: checked, ...props });
|
|
133
|
+
}
|
|
134
|
+
default: {
|
|
135
|
+
return (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, {});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}, [theme]);
|
|
139
|
+
const onClickRowElement = (0, react_1.useCallback)((item, index) => {
|
|
140
|
+
onClickRow?.(item, index);
|
|
141
|
+
}, [onClickRow]);
|
|
142
|
+
const everythingIsChecked = (0, react_1.useMemo)(() => {
|
|
143
|
+
if (!columns.some((column) => column.type === "checkbox"))
|
|
144
|
+
return false;
|
|
145
|
+
const keyName = columns.find((column) => column.type === "checkbox")?.keyName;
|
|
146
|
+
if (!keyName)
|
|
147
|
+
return false;
|
|
148
|
+
return data.every((item) => item[keyName]);
|
|
149
|
+
}, [data]);
|
|
150
|
+
return ((0, jsx_runtime_1.jsx)(Div_1.default, { border: `1px solid ${theme.colors.border}`, borderRadius: theme.styles.borderRadius * 2, overflow: "auto", ...props, ref: ref, children: (0, jsx_runtime_1.jsxs)(TableStyledComponent, { isStriped: isStriped, withHover: onClickRow !== undefined, withStickyHeader: withStickyHeader, theme: theme, children: [(0, jsx_runtime_1.jsx)("thead", { children: (0, jsx_runtime_1.jsx)("tr", { className: "isHeader", children: columns.map((column, index) => ((0, jsx_runtime_1.jsx)(ThStyledComponent, { width: column.type === "image" ? defaultImageWidth : column.type === "checkbox" ? 26 : column.width, textAlign: column.align, children: column.label ??
|
|
151
|
+
(column.type === "checkbox" && onClickAllCheckboxes ? ((0, jsx_runtime_1.jsx)(ToggleInput_1.default.checkbox, { checked: everythingIsChecked, onChange: onClickAllCheckboxes })) : ("")) }, column.type + column.label + index))) }) }), (0, jsx_runtime_1.jsx)("tbody", { children: data.length > 0 ? (data.map((item, rowIndex) => ((0, jsx_runtime_1.jsx)("tr", { className: onClickRow ? "isClickable" : undefined, onClick: () => onClickRowElement(item, rowIndex), children: columns.map((column, colIndex) => ((0, jsx_runtime_1.jsx)(TdStyledComponent, { textAlign: column.align, children: renderCellContent(column, item, rowIndex) }, column.type + column.label + colIndex))) }, JSON.stringify(item) + rowIndex)))) : ((0, jsx_runtime_1.jsx)("tr", { children: (0, jsx_runtime_1.jsx)("td", { className: "noData", colSpan: columns.length, children: (0, jsx_runtime_1.jsx)(Text_1.default.unknown, { children: noDataItemsMessage }) }) })) })] }) }));
|
|
152
|
+
});
|
|
153
|
+
const Table = (0, react_1.memo)(TableComponent);
|
|
154
|
+
exports.default = Table;
|
package/dist/index.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ import Form, { type FormProps } from "./components/Form";
|
|
|
16
16
|
import Label, { type LabelProps } from "./components/Label";
|
|
17
17
|
import FormRow, { type FormRowProps } from "./components/FormRow";
|
|
18
18
|
import ColorThemeSwitch, { type ColorThemeSwitchProps } from "./components/ColorThemeSwitch";
|
|
19
|
+
import Table, { type TableColumn } from "./components/Table";
|
|
19
20
|
import BetterHtmlProvider, { useBetterHtmlContext, useTheme, useLoader, useLoaderControls, type BetterHtmlProviderValue } from "./components/BetterHtmlProvider";
|
|
20
21
|
import { usePageResize, usePageScroll, useMediaQuery, useBooleanState, useDebounceState, useForm, useUrlQuery } from "./utils/hooks";
|
|
21
22
|
import { generateRandomString, getBrowser, formatPhoneNumber, getFormErrorObject } from "./utils/functions";
|
|
@@ -30,4 +31,4 @@ import { type Color, type ColorName, type ColorTheme, type Colors, type Styles,
|
|
|
30
31
|
import { type BrowserName } from "./types/other";
|
|
31
32
|
import { isMobileDevice } from "./constants";
|
|
32
33
|
export * from "./plugins";
|
|
33
|
-
export { BetterHtmlProvider, BetterHtmlProviderValue, Div, DivProps, Text, TextProps, TextAs, Loader, LoaderProps, Icon, IconProps, Image, ImageProps, Button, ButtonProps, Divider, HorizontalDividerProps, VerticalDividerProps, Modal, ModalProps, ModalRef, PageHolder, PageHolderProps, PageHeader, PageHeaderProps, Chip, ChipProps, InputField, InputFieldProps, TextareaFieldProps, Dropdown, DropdownOption, DropdownProps, ToggleInput, ToggleInputRef, ToggleInputProps, Form, FormProps, Label, LabelProps, FormRow, FormRowProps, ColorThemeSwitch, ColorThemeSwitchProps, useBetterHtmlContext, useTheme, useLoader, useLoaderControls, usePageResize, usePageScroll, useMediaQuery, useBooleanState, useDebounceState, useForm, useUrlQuery, generateRandomString, getBrowser, formatPhoneNumber, getFormErrorObject, loaderControls, OmitProps, ExcludeOptions, PickValue, PartialRecord, DeepPartialRecord, PickAllRequired, AppConfig, BetterHtmlConfig, AssetName, AssetsConfig, IconName, IconsConfig, LoaderName, PluginName, BetterHtmlPlugin, LoaderConfig, Color, ColorName, ColorTheme, Colors, Styles, Theme, ThemeConfig, BrowserName, isMobileDevice, };
|
|
34
|
+
export { BetterHtmlProvider, BetterHtmlProviderValue, Div, DivProps, Text, TextProps, TextAs, Loader, LoaderProps, Icon, IconProps, Image, ImageProps, Button, ButtonProps, Divider, HorizontalDividerProps, VerticalDividerProps, Modal, ModalProps, ModalRef, PageHolder, PageHolderProps, PageHeader, PageHeaderProps, Chip, ChipProps, InputField, InputFieldProps, TextareaFieldProps, Dropdown, DropdownOption, DropdownProps, ToggleInput, ToggleInputRef, ToggleInputProps, Form, FormProps, Label, LabelProps, FormRow, FormRowProps, ColorThemeSwitch, ColorThemeSwitchProps, Table, TableColumn, useBetterHtmlContext, useTheme, useLoader, useLoaderControls, usePageResize, usePageScroll, useMediaQuery, useBooleanState, useDebounceState, useForm, useUrlQuery, generateRandomString, getBrowser, formatPhoneNumber, getFormErrorObject, loaderControls, OmitProps, ExcludeOptions, PickValue, PartialRecord, DeepPartialRecord, PickAllRequired, AppConfig, BetterHtmlConfig, AssetName, AssetsConfig, IconName, IconsConfig, LoaderName, PluginName, BetterHtmlPlugin, LoaderConfig, Color, ColorName, ColorTheme, Colors, Styles, Theme, ThemeConfig, BrowserName, isMobileDevice, };
|
package/dist/index.js
CHANGED
|
@@ -39,7 +39,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
39
39
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
40
40
|
};
|
|
41
41
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
-
exports.isMobileDevice = exports.loaderControls = exports.getFormErrorObject = exports.formatPhoneNumber = exports.getBrowser = exports.generateRandomString = exports.useUrlQuery = exports.useForm = exports.useDebounceState = exports.useBooleanState = exports.useMediaQuery = exports.usePageScroll = exports.usePageResize = exports.useLoaderControls = exports.useLoader = exports.useTheme = exports.useBetterHtmlContext = exports.ColorThemeSwitch = exports.FormRow = exports.Label = exports.Form = exports.ToggleInput = exports.Dropdown = exports.InputField = exports.Chip = exports.PageHeader = exports.PageHolder = exports.Modal = exports.Divider = exports.Button = exports.Image = exports.Icon = exports.Loader = exports.Text = exports.Div = exports.BetterHtmlProvider = void 0;
|
|
42
|
+
exports.isMobileDevice = exports.loaderControls = exports.getFormErrorObject = exports.formatPhoneNumber = exports.getBrowser = exports.generateRandomString = exports.useUrlQuery = exports.useForm = exports.useDebounceState = exports.useBooleanState = exports.useMediaQuery = exports.usePageScroll = exports.usePageResize = exports.useLoaderControls = exports.useLoader = exports.useTheme = exports.useBetterHtmlContext = exports.Table = exports.ColorThemeSwitch = exports.FormRow = exports.Label = exports.Form = exports.ToggleInput = exports.Dropdown = exports.InputField = exports.Chip = exports.PageHeader = exports.PageHolder = exports.Modal = exports.Divider = exports.Button = exports.Image = exports.Icon = exports.Loader = exports.Text = exports.Div = exports.BetterHtmlProvider = void 0;
|
|
43
43
|
const Div_1 = __importDefault(require("./components/Div"));
|
|
44
44
|
exports.Div = Div_1.default;
|
|
45
45
|
const Text_1 = __importDefault(require("./components/Text"));
|
|
@@ -76,6 +76,8 @@ const FormRow_1 = __importDefault(require("./components/FormRow"));
|
|
|
76
76
|
exports.FormRow = FormRow_1.default;
|
|
77
77
|
const ColorThemeSwitch_1 = __importDefault(require("./components/ColorThemeSwitch"));
|
|
78
78
|
exports.ColorThemeSwitch = ColorThemeSwitch_1.default;
|
|
79
|
+
const Table_1 = __importDefault(require("./components/Table"));
|
|
80
|
+
exports.Table = Table_1.default;
|
|
79
81
|
const BetterHtmlProvider_1 = __importStar(require("./components/BetterHtmlProvider"));
|
|
80
82
|
exports.BetterHtmlProvider = BetterHtmlProvider_1.default;
|
|
81
83
|
Object.defineProperty(exports, "useBetterHtmlContext", { enumerable: true, get: function () { return BetterHtmlProvider_1.useBetterHtmlContext; } });
|
package/dist/utils/hooks.d.ts
CHANGED
|
@@ -13,6 +13,13 @@ excludeProps?: boolean): {
|
|
|
13
13
|
export declare function useComponentPropsWithPrefix<Props extends Record<string, any>, Prefix extends string>(props: Props, prefix: Prefix): Record<`${Prefix}-${string}`, any>;
|
|
14
14
|
export declare function useComponentPropsWithExcludedStyle<Props extends Record<string, any>>(props: Props): Partial<Props>;
|
|
15
15
|
export declare function useComponentPropsWithoutStyle<Props extends Record<string, any>>(props: Props): Partial<Props>;
|
|
16
|
+
export declare function useComponentInputFieldDateProps(props: InputFieldProps, holderRef: React.RefObject<HTMLDivElement | null>): {
|
|
17
|
+
internalValue: string;
|
|
18
|
+
setInternalValue: React.Dispatch<React.SetStateAction<string>>;
|
|
19
|
+
inputFieldProps: InputFieldProps;
|
|
20
|
+
insideInputFieldComponentProps: InputFieldProps;
|
|
21
|
+
isOpen: boolean;
|
|
22
|
+
};
|
|
16
23
|
export declare function usePageResize(): {
|
|
17
24
|
width: number;
|
|
18
25
|
height: number;
|
|
@@ -71,7 +78,7 @@ export declare function useForm<FormFields extends Record<string | number, strin
|
|
|
71
78
|
isDirty: boolean;
|
|
72
79
|
};
|
|
73
80
|
export declare function useUrlQuery(): {
|
|
74
|
-
setQuery: (query: Record<string, string>, keepHistory?: boolean) => void;
|
|
81
|
+
setQuery: (query: Record<string, string | number>, keepHistory?: boolean) => void;
|
|
75
82
|
getQuery: (name: string) => string | null;
|
|
76
83
|
removeQuery: (name: string, keepHistory?: boolean) => void;
|
|
77
84
|
};
|
package/dist/utils/hooks.js
CHANGED
|
@@ -4,6 +4,7 @@ exports.useStyledComponentStyles = useStyledComponentStyles;
|
|
|
4
4
|
exports.useComponentPropsWithPrefix = useComponentPropsWithPrefix;
|
|
5
5
|
exports.useComponentPropsWithExcludedStyle = useComponentPropsWithExcludedStyle;
|
|
6
6
|
exports.useComponentPropsWithoutStyle = useComponentPropsWithoutStyle;
|
|
7
|
+
exports.useComponentInputFieldDateProps = useComponentInputFieldDateProps;
|
|
7
8
|
exports.usePageResize = usePageResize;
|
|
8
9
|
exports.usePageScroll = usePageScroll;
|
|
9
10
|
exports.useMediaQuery = useMediaQuery;
|
|
@@ -97,6 +98,80 @@ function useComponentPropsWithoutStyle(props) {
|
|
|
97
98
|
return previousValue;
|
|
98
99
|
}, {}), [props]);
|
|
99
100
|
}
|
|
101
|
+
function useComponentInputFieldDateProps(props, holderRef) {
|
|
102
|
+
const theme = (0, BetterHtmlProvider_1.useTheme)();
|
|
103
|
+
const [isOpen, setIsOpen] = useBooleanState();
|
|
104
|
+
const [isOpenLate, setIsOpenLate] = useBooleanState();
|
|
105
|
+
const [isFocused, setIsFocused] = useBooleanState();
|
|
106
|
+
const [internalValue, setInternalValue] = (0, react_1.useState)(props.value?.toString() ?? "");
|
|
107
|
+
const inputFieldProps = (0, react_1.useMemo)(() => ({
|
|
108
|
+
value: internalValue,
|
|
109
|
+
className: `${isOpen ? "react-better-html-inputField-dateTime-opened" : ""}${isOpenLate ? " react-better-html-inputField-dateTime-opened-late" : ""}${props.className ? ` ${props.className}` : ""}`,
|
|
110
|
+
onClick: (event) => {
|
|
111
|
+
if (props.disabled)
|
|
112
|
+
return;
|
|
113
|
+
setIsOpen.setTrue();
|
|
114
|
+
props.onClick?.(event);
|
|
115
|
+
},
|
|
116
|
+
onFocus: (event) => {
|
|
117
|
+
setIsFocused.setTrue();
|
|
118
|
+
props.onFocus?.(event);
|
|
119
|
+
},
|
|
120
|
+
onBlur: (event) => {
|
|
121
|
+
setIsFocused.setFalse();
|
|
122
|
+
props.onBlur?.(event);
|
|
123
|
+
},
|
|
124
|
+
onChangeValue: (value) => {
|
|
125
|
+
setInternalValue(value);
|
|
126
|
+
props.onChangeValue?.(value);
|
|
127
|
+
},
|
|
128
|
+
}), [props, internalValue, isOpen, isOpenLate]);
|
|
129
|
+
const insideInputFieldComponentProps = (0, react_1.useMemo)(() => ({
|
|
130
|
+
border: `1px solid ${isFocused ? theme.colors.primary : theme.colors.border}`,
|
|
131
|
+
borderTop: "none",
|
|
132
|
+
opacity: !isOpen ? 0 : undefined,
|
|
133
|
+
pointerEvents: !isOpen ? "none" : undefined,
|
|
134
|
+
transform: `translateY(${!isOpen ? -10 : 0}px)`,
|
|
135
|
+
zIndex: 1000,
|
|
136
|
+
transition: theme.styles.transition,
|
|
137
|
+
}), [isOpen, isFocused]);
|
|
138
|
+
(0, react_1.useEffect)(() => {
|
|
139
|
+
if (props.value === undefined || props.value === null)
|
|
140
|
+
return;
|
|
141
|
+
setInternalValue(props.value.toString());
|
|
142
|
+
}, [props.value]);
|
|
143
|
+
(0, react_1.useEffect)(() => {
|
|
144
|
+
if (isOpen) {
|
|
145
|
+
setIsOpenLate.setTrue();
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
const timeout = setTimeout(setIsOpenLate.setFalse, 0.2 * 1000);
|
|
149
|
+
return () => {
|
|
150
|
+
clearTimeout(timeout);
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
}, [isOpen]);
|
|
154
|
+
(0, react_1.useEffect)(() => {
|
|
155
|
+
const handleClickOutside = (event) => {
|
|
156
|
+
if (holderRef.current && !holderRef.current.contains(event.target)) {
|
|
157
|
+
setIsOpen.setFalse();
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
if (isOpen) {
|
|
161
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
162
|
+
}
|
|
163
|
+
return () => {
|
|
164
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
165
|
+
};
|
|
166
|
+
}, [isOpen]);
|
|
167
|
+
return {
|
|
168
|
+
internalValue,
|
|
169
|
+
setInternalValue,
|
|
170
|
+
inputFieldProps,
|
|
171
|
+
insideInputFieldComponentProps,
|
|
172
|
+
isOpen,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
100
175
|
function usePageResize() {
|
|
101
176
|
const [width, setWidth] = (0, react_1.useState)(window.innerWidth);
|
|
102
177
|
const [height, setHeight] = (0, react_1.useState)(window.innerHeight);
|
|
@@ -338,7 +413,7 @@ function useUrlQuery() {
|
|
|
338
413
|
navigate({
|
|
339
414
|
search: (0, react_router_dom_1.createSearchParams)({
|
|
340
415
|
...currentSearchParams,
|
|
341
|
-
...query,
|
|
416
|
+
...Object.fromEntries(Object.entries(query).map(([key, value]) => [key, value.toString()])),
|
|
342
417
|
}).toString(),
|
|
343
418
|
}, {
|
|
344
419
|
replace: !keepHistory,
|