react-better-html 1.1.31 → 1.1.33

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.
@@ -24,7 +24,7 @@ export type DropdownProps<Value, Data> = {
24
24
  /** @default 0.5s */
25
25
  debounceDelay?: number;
26
26
  debounceIsLoading?: boolean;
27
- debounceMinimumSymbolsRequired?: string;
27
+ debounceMinimumSymbolsRequired?: number;
28
28
  onChange?: (value: Value | undefined) => void;
29
29
  onChangeSearch?: (query: string) => void;
30
30
  renderOption?: (option: DropdownOption<Value, Data>, index: number, isSelected: boolean) => React.ReactNode;
@@ -12,8 +12,8 @@ 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"));
16
+ const BetterHtmlProvider_1 = require("./BetterHtmlProvider");
17
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);
@@ -150,7 +150,8 @@ 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: debounceMinimumSymbolsRequired !== undefined
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
154
155
  ? `Enter at least ${debounceMinimumSymbolsRequired} characters`
155
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" })] })] }) }));
156
157
  });
@@ -1,10 +1,13 @@
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;
10
+ submitButtonIsDisabled?: boolean;
8
11
  /** @default "right" */
9
12
  actionButtonsLocation?: "left" | "center" | "right";
10
13
  gap?: React.CSSProperties["gap"];
@@ -14,6 +17,6 @@ type FormProps = {
14
17
  onSubmit?: (value: React.FormEvent<HTMLFormElement>) => void;
15
18
  children?: React.ReactNode;
16
19
  } & ComponentMarginProps;
17
- declare function Form({ submitButtonText, submitButtonLoaderName, submitButtonId, actionButtonsLocation, gap, isSubmitting, isDestructive, onClickCancel, onSubmit, children, ...props }: FormProps): import("react/jsx-runtime").JSX.Element;
20
+ declare function Form({ form, submitButtonText, submitButtonLoaderName, submitButtonId, submitButtonIsDisabled, actionButtonsLocation, gap, isSubmitting, isDestructive, onClickCancel, onSubmit, children, ...props }: FormProps): import("react/jsx-runtime").JSX.Element;
18
21
  declare const _default: import("react").MemoExoticComponent<typeof Form>;
19
22
  export default _default;
@@ -8,13 +8,20 @@ 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, submitButtonIsDisabled, actionButtonsLocation = "right", gap, isSubmitting, isDestructive, onClickCancel, onSubmit, children, ...props }) {
12
12
  const theme = (0, BetterHtmlProvider_1.useTheme)();
13
+ const submitButtonIsDisabledInternal = (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;
20
+ const submitButtonIsDisabledFinal = submitButtonIsDisabled || submitButtonIsDisabledInternal;
14
21
  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
22
  ? "flex-start"
16
23
  : actionButtonsLocation === "center"
17
24
  ? "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 })] }))] }) }));
25
+ : "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: submitButtonIsDisabledFinal, id: submitButtonId, isSubmit: true })] }))] }) }));
19
26
  }
20
27
  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.31",
3
+ "version": "1.1.33",
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": [