react-better-html 1.1.30 → 1.1.32

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.
@@ -39,11 +39,11 @@ const DivComponent = (0, react_1.forwardRef)(function Div({ value, as, isTabAcce
39
39
  }, [onKeyDown, isTabAccessed]);
40
40
  return ((0, jsx_runtime_1.jsx)(DivStyledComponent, { as: as, tabIndex: isTabAccessed && !constants_1.isMobileDevice ? 0 : undefined, role: role ?? (onClick ? "button" : undefined), onClick: onClickElement, onKeyDown: onKeyDownElement, ...styledComponentStyles, ...dataProps, ...ariaProps, ...restProps, ref: ref, children: children }));
41
41
  });
42
- DivComponent.row = (0, react_1.forwardRef)(function Row(props, ref) {
43
- return ((0, jsx_runtime_1.jsx)(DivComponent, { display: "flex", flexDirection: props.invertFlexDirection ? "column" : "row", ref: ref, ...props }));
42
+ DivComponent.row = (0, react_1.forwardRef)(function Row({ invertFlexDirection, ...props }, ref) {
43
+ return (0, jsx_runtime_1.jsx)(DivComponent, { display: "flex", flexDirection: invertFlexDirection ? "column" : "row", ref: ref, ...props });
44
44
  });
45
- DivComponent.column = (0, react_1.forwardRef)(function Column(props, ref) {
46
- return ((0, jsx_runtime_1.jsx)(DivComponent, { display: "flex", flexDirection: props.invertFlexDirection ? "row" : "column", ref: ref, ...props }));
45
+ DivComponent.column = (0, react_1.forwardRef)(function Column({ invertFlexDirection, ...props }, ref) {
46
+ return (0, jsx_runtime_1.jsx)(DivComponent, { display: "flex", flexDirection: invertFlexDirection ? "row" : "column", ref: ref, ...props });
47
47
  });
48
48
  DivComponent.grid = (0, react_1.forwardRef)(function Grid(props, ref) {
49
49
  return (0, jsx_runtime_1.jsx)(DivComponent, { display: "grid", ref: ref, ...props });
@@ -24,6 +24,7 @@ export type DropdownProps<Value, Data> = {
24
24
  /** @default 0.5s */
25
25
  debounceDelay?: number;
26
26
  debounceIsLoading?: boolean;
27
+ debounceMinimumSymbolsRequired?: number;
27
28
  onChange?: (value: Value | undefined) => void;
28
29
  onChangeSearch?: (query: string) => void;
29
30
  renderOption?: (option: DropdownOption<Value, Data>, index: number, isSelected: boolean) => React.ReactNode;
@@ -12,9 +12,9 @@ const Div_1 = __importDefault(require("./Div"));
12
12
  const InputField_1 = __importDefault(require("./InputField"));
13
13
  const Icon_1 = __importDefault(require("./Icon"));
14
14
  const Button_1 = __importDefault(require("./Button"));
15
- const BetterHtmlProvider_1 = require("./BetterHtmlProvider");
16
15
  const Loader_1 = __importDefault(require("./Loader"));
17
- const DropdownComponent = (0, react_1.forwardRef)(function Dropdown({ label, errorText, infoText, required, disabled, options, value: controlledValue, placeholder = "Select an option", leftIcon, withSearch, withDebounce, debounceDelay = 0.5, debounceIsLoading, onChange, onChangeSearch, renderOption, ...props }, ref) {
16
+ const BetterHtmlProvider_1 = require("./BetterHtmlProvider");
17
+ const DropdownComponent = (0, react_1.forwardRef)(function Dropdown({ label, errorText, infoText, required, disabled, options, value: controlledValue, placeholder = "Select an option", leftIcon, withSearch, withDebounce, debounceDelay = 0.5, debounceIsLoading, debounceMinimumSymbolsRequired, 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);
@@ -150,7 +150,10 @@ const DropdownComponent = (0, react_1.forwardRef)(function Dropdown({ label, err
150
150
  : isSelected
151
151
  ? theme.colors.base
152
152
  : theme.colors.textPrimary, backgroundColor: isSelected ? theme.colors.primary : theme.colors.backgroundContent, filter: isFocused ? (isDisabled ? "brightness(0.95)" : "brightness(0.9)") : undefined, filterHover: focusedOptionIndex === undefined && !isDisabled ? "brightness(0.9)" : undefined, cursor: isDisabled ? "not-allowed" : "pointer", padding: `${theme.styles.space / 2}px ${theme.styles.space + theme.styles.gap}px`, value: option, onClickWithValue: onClickOption, onMouseMove: () => setFocusedOptionIndex(undefined), role: "option", "aria-selected": isSelected, "aria-disabled": isDisabled, children: renderOption ? renderOption(option, index, isSelected) : (0, jsx_runtime_1.jsx)(Text_1.default, { children: option.label }) }, JSON.stringify(option)));
153
- })) : ((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)(Text_1.default.unknown, { textAlign: "left", children: "No options" }) })) }), role: "combobox", "aria-expanded": isOpen, "aria-controls": "dropdown-list", "aria-haspopup": "listbox", "aria-label": label, ref: inputRef }), (0, jsx_runtime_1.jsxs)(Div_1.default.row, { position: "absolute", top: 46 / 2 + (label ? 16 + theme.styles.gap / 2 : 0), right: theme.styles.space + 1, alignItems: "center", gap: theme.styles.gap, transform: "translateY(-50%)", pointerEvents: "none", filter: disabled ? "brightness(0.9)" : undefined, opacity: disabled ? 0.6 : undefined, zIndex: isOpen || isOpenLate ? 1001 : undefined, children: [(0, jsx_runtime_1.jsx)(Button_1.default.icon, { icon: "XMark", position: "relative", size: 10, iconSize: 14, opacity: !withClearButton ? 0 : undefined, pointerEvents: withClearButton ? "all" : undefined, onClick: onClickClearButton, disabled: !withClearButton }), (0, jsx_runtime_1.jsx)(Icon_1.default, { name: "chevronDown", position: "relative", size: 16, color: theme.colors.textSecondary, transform: `rotate(${isOpen ? 180 : 0}deg)`, transition: theme.styles.transition, pointerEvents: "none" })] })] }) }));
153
+ })) : ((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)(Text_1.default.unknown, { textAlign: "left", children: debounceMinimumSymbolsRequired !== undefined &&
154
+ searchQuery.length < debounceMinimumSymbolsRequired
155
+ ? `Enter at least ${debounceMinimumSymbolsRequired} characters`
156
+ : "No options" }) })) }), role: "combobox", "aria-expanded": isOpen, "aria-controls": "dropdown-list", "aria-haspopup": "listbox", "aria-label": label, ref: inputRef }), (0, jsx_runtime_1.jsxs)(Div_1.default.row, { position: "absolute", top: 46 / 2 + (label ? 16 + theme.styles.gap / 2 : 0), right: theme.styles.space + 1, alignItems: "center", gap: theme.styles.gap, transform: "translateY(-50%)", pointerEvents: "none", filter: disabled ? "brightness(0.9)" : undefined, opacity: disabled ? 0.6 : undefined, zIndex: isOpen || isOpenLate ? 1001 : undefined, children: [(0, jsx_runtime_1.jsx)(Button_1.default.icon, { icon: "XMark", position: "relative", size: 10, iconSize: 14, opacity: !withClearButton ? 0 : undefined, pointerEvents: withClearButton ? "all" : undefined, onClick: onClickClearButton, disabled: !withClearButton }), (0, jsx_runtime_1.jsx)(Icon_1.default, { name: "chevronDown", position: "relative", size: 16, color: theme.colors.textSecondary, transform: `rotate(${isOpen ? 180 : 0}deg)`, transition: theme.styles.transition, pointerEvents: "none" })] })] }) }));
154
157
  });
155
158
  const Dropdown = (0, react_1.memo)(DropdownComponent);
156
159
  exports.default = Dropdown;
@@ -1,7 +1,9 @@
1
1
  import { ComponentMarginProps } from "../types/components";
2
2
  import { LoaderName } from "../types/loader";
3
- import { AnyOtherString } from "../types/app";
3
+ import { AnyOtherString, OmitProps } from "../types/app";
4
+ import { useForm } from "../utils/hooks";
4
5
  type FormProps = {
6
+ form?: OmitProps<ReturnType<typeof useForm>, "focusField">;
5
7
  submitButtonText?: string;
6
8
  submitButtonLoaderName?: LoaderName | AnyOtherString;
7
9
  submitButtonId?: string;
@@ -14,6 +16,6 @@ type FormProps = {
14
16
  onSubmit?: (value: React.FormEvent<HTMLFormElement>) => void;
15
17
  children?: React.ReactNode;
16
18
  } & ComponentMarginProps;
17
- declare function Form({ submitButtonText, submitButtonLoaderName, submitButtonId, actionButtonsLocation, gap, isSubmitting, isDestructive, onClickCancel, onSubmit, children, ...props }: FormProps): import("react/jsx-runtime").JSX.Element;
19
+ declare function Form({ form, submitButtonText, submitButtonLoaderName, submitButtonId, actionButtonsLocation, gap, isSubmitting, isDestructive, onClickCancel, onSubmit, children, ...props }: FormProps): import("react/jsx-runtime").JSX.Element;
18
20
  declare const _default: import("react").MemoExoticComponent<typeof Form>;
19
21
  export default _default;
@@ -8,13 +8,19 @@ const react_1 = require("react");
8
8
  const Div_1 = __importDefault(require("./Div"));
9
9
  const Button_1 = __importDefault(require("./Button"));
10
10
  const BetterHtmlProvider_1 = require("./BetterHtmlProvider");
11
- function Form({ submitButtonText, submitButtonLoaderName, submitButtonId, actionButtonsLocation = "right", gap, isSubmitting, isDestructive, onClickCancel, onSubmit, children, ...props }) {
11
+ function Form({ form, submitButtonText, submitButtonLoaderName, submitButtonId, actionButtonsLocation = "right", gap, isSubmitting, isDestructive, onClickCancel, onSubmit, children, ...props }) {
12
12
  const theme = (0, BetterHtmlProvider_1.useTheme)();
13
+ const submitIsDisabled = (0, react_1.useMemo)(() => {
14
+ if (!form || !form.requiredFields)
15
+ return false;
16
+ return Object.entries(form.values).some(([key, value]) => form.requiredFields?.includes(key) &&
17
+ (value === undefined || value === null || value?.toString().trim() === ""));
18
+ }, [form]);
13
19
  const SubmitButtonTag = isDestructive ? Button_1.default.destructive : Button_1.default;
14
20
  return ((0, jsx_runtime_1.jsx)(Div_1.default, { ...props, children: (0, jsx_runtime_1.jsxs)("form", { onSubmit: onSubmit, children: [gap !== undefined ? (0, jsx_runtime_1.jsx)(Div_1.default.column, { gap: gap, children: children }) : children, submitButtonText && ((0, jsx_runtime_1.jsxs)(Div_1.default.row, { alignItems: "center", justifyContent: actionButtonsLocation === "left"
15
21
  ? "flex-start"
16
22
  : actionButtonsLocation === "center"
17
23
  ? "center"
18
- : "flex-end", gap: theme.styles.gap, marginTop: theme.styles.space, children: [onClickCancel && (0, jsx_runtime_1.jsx)(Button_1.default.secondary, { text: "Cancel", onClick: onClickCancel }), (0, jsx_runtime_1.jsx)(SubmitButtonTag, { text: submitButtonText, isLoading: isSubmitting, loaderName: submitButtonLoaderName, id: submitButtonId, isSubmit: true })] }))] }) }));
24
+ : "flex-end", gap: theme.styles.gap, marginTop: theme.styles.space, children: [onClickCancel && (0, jsx_runtime_1.jsx)(Button_1.default.secondary, { text: "Cancel", onClick: onClickCancel }), (0, jsx_runtime_1.jsx)(SubmitButtonTag, { text: submitButtonText, isLoading: isSubmitting, loaderName: submitButtonLoaderName, disabled: submitIsDisabled, id: submitButtonId, isSubmit: true })] }))] }) }));
19
25
  }
20
26
  exports.default = (0, react_1.memo)(Form);
@@ -43,8 +43,9 @@ export declare function useBooleanState(initialValue?: boolean): [
43
43
  }
44
44
  ];
45
45
  export declare function useDebounceState<Value>(initialValue: Value, delay?: number): [value: Value, debouncedValue: Value, setValue: React.Dispatch<React.SetStateAction<Value>>, isLoading: boolean];
46
- export declare function useForm<FormFields extends Record<string, string | number | boolean | undefined>>({ defaultValues, onSubmit, validate, }: {
46
+ export declare function useForm<FormFields extends Record<string, string | number | boolean | undefined>>({ defaultValues, requiredFields, onSubmit, validate, }: {
47
47
  defaultValues: FormFields;
48
+ requiredFields?: (keyof FormFields)[];
48
49
  onSubmit?: (values: FormFields) => void | Promise<void>;
49
50
  validate?: (values: FormFields) => PartialRecord<keyof FormFields, string>;
50
51
  }): {
@@ -60,6 +61,7 @@ export declare function useForm<FormFields extends Record<string, string | numbe
60
61
  focusField: (field: keyof FormFields) => void;
61
62
  onSubmit: (event: React.FormEvent<HTMLFormElement>) => Promise<void>;
62
63
  reset: () => void;
64
+ requiredFields: (keyof FormFields)[] | undefined;
63
65
  };
64
66
  export declare function useUrlQuery(): {
65
67
  setQuery: (query: Record<string, string>, keepHistory?: boolean) => void;
@@ -156,7 +156,7 @@ function useDebounceState(initialValue, delay = 0.5) {
156
156
  }, [value, delay]);
157
157
  return [value, debouncedValue, setValue, isLoading];
158
158
  }
159
- function useForm({ defaultValues, onSubmit, validate, }) {
159
+ function useForm({ defaultValues, requiredFields, onSubmit, validate, }) {
160
160
  const inputFieldRefs = (0, react_1.useRef)({});
161
161
  const [inputTypes, setInputTypes] = (0, react_1.useState)({});
162
162
  const [values, setValues] = (0, react_1.useState)(defaultValues);
@@ -271,6 +271,7 @@ function useForm({ defaultValues, onSubmit, validate, }) {
271
271
  focusField,
272
272
  onSubmit: onSubmitFunction,
273
273
  reset,
274
+ requiredFields,
274
275
  };
275
276
  }
276
277
  function useUrlQuery() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-better-html",
3
- "version": "1.1.30",
3
+ "version": "1.1.32",
4
4
  "description": "A component library for react that is as close to plane html as possible",
5
5
  "main": "dist/index.js",
6
6
  "files": [