react-better-html 1.1.36 → 1.1.38

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.
@@ -1,10 +1,10 @@
1
+ import { ComponentMarginProps } from "../types/components";
1
2
  type DividerProps = {
2
3
  /** @default 1 */
3
4
  width?: number;
4
5
  /** @default border */
5
6
  backgroundColor?: string;
6
- paddingBlock?: number;
7
- };
7
+ } & ComponentMarginProps;
8
8
  type VerticalDividerProps = DividerProps & {
9
9
  /** @default "100%" */
10
10
  height?: number;
@@ -9,12 +9,12 @@ const Div_1 = __importDefault(require("./Div"));
9
9
  const Text_1 = __importDefault(require("./Text"));
10
10
  const BetterHtmlProvider_1 = require("./BetterHtmlProvider");
11
11
  exports.default = {
12
- vertical: (0, react_1.memo)(function Divider({ width = 1, backgroundColor, paddingBlock, height }) {
12
+ vertical: (0, react_1.memo)(function Divider({ width = 1, backgroundColor, height, ...props }) {
13
13
  const theme = (0, BetterHtmlProvider_1.useTheme)();
14
- return ((0, jsx_runtime_1.jsx)(Div_1.default, { width: width, height: height ?? "100%", flexShrink: 0, backgroundColor: backgroundColor ?? theme.colors.border, paddingBlock: paddingBlock }));
14
+ return ((0, jsx_runtime_1.jsx)(Div_1.default, { width: width, height: height ?? "100%", flexShrink: 0, backgroundColor: backgroundColor ?? theme.colors.border, ...props }));
15
15
  }),
16
- horizontal: (0, react_1.memo)(function Divider({ width = 1, backgroundColor, paddingBlock, text, textColor, }) {
16
+ horizontal: (0, react_1.memo)(function Divider({ width = 1, backgroundColor, text, textColor, ...props }) {
17
17
  const theme = (0, BetterHtmlProvider_1.useTheme)();
18
- return ((0, jsx_runtime_1.jsxs)(Div_1.default.row, { alignItems: "center", gap: text ? theme.styles.space : undefined, paddingBlock: paddingBlock, children: [(0, jsx_runtime_1.jsx)(Div_1.default, { flex: 1, height: width, flexShrink: 0, backgroundColor: backgroundColor ?? theme.colors.border }), text && (0, jsx_runtime_1.jsx)(Text_1.default, { color: textColor ?? theme.colors.textSecondary, children: text }), (0, jsx_runtime_1.jsx)(Div_1.default, { flex: 1, height: width, flexShrink: 0, backgroundColor: backgroundColor ?? theme.colors.border })] }));
18
+ return ((0, jsx_runtime_1.jsxs)(Div_1.default.row, { alignItems: "center", gap: text ? theme.styles.space : undefined, ...props, children: [(0, jsx_runtime_1.jsx)(Div_1.default, { flex: 1, height: width, flexShrink: 0, backgroundColor: backgroundColor ?? theme.colors.border }), text && (0, jsx_runtime_1.jsx)(Text_1.default, { color: textColor ?? theme.colors.textSecondary, children: text }), (0, jsx_runtime_1.jsx)(Div_1.default, { flex: 1, height: width, flexShrink: 0, backgroundColor: backgroundColor ?? theme.colors.border })] }));
19
19
  }),
20
20
  };
@@ -141,7 +141,7 @@ 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
- 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, placeholder: withSearch ? (selectedOption ? selectedOption.label : placeholder) : placeholder, leftIcon: leftIcon, className: `react-better-html-dropdown${isOpen ? " react-better-html-dropdown-open" : ""}${inputFieldClassName ? ` ${inputFieldClassName}` : ""}`, zIndex: isOpen || isOpenLate ? 1001 : undefined, 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) => {
144
+ 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, placeholder: withSearch ? (selectedOption ? selectedOption.label : placeholder) : placeholder, 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
145
  const isSelected = option.value === value;
146
146
  const isDisabled = option.disabled;
147
147
  const isFocused = index === focusedOptionIndex;
@@ -65,6 +65,10 @@ const InputElement = styled_components_1.default.input.withConfig({
65
65
  border-bottom-left-radius: 0px;
66
66
  border-bottom-right-radius: 0px;
67
67
  }
68
+
69
+ &.react-better-html-dropdown-open-late {
70
+ z-index: 1001;
71
+ }
68
72
  }
69
73
 
70
74
  ${(props) => props.normalStyle}
@@ -131,7 +135,7 @@ const InputFieldComponent = (0, react_1.forwardRef)(function InputField({ label,
131
135
  }, [withDebounce, onChangeValue, debouncedValue]);
132
136
  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: 1002 })), (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 }))] }));
133
137
  });
134
- InputFieldComponent.multiline = (0, react_1.forwardRef)(function Multiline({ label, errorText, infoText, onChange, onChangeValue, required, ...props }, ref) {
138
+ InputFieldComponent.multiline = (0, react_1.forwardRef)(function Multiline({ label, placeholder, errorText, infoText, onChange, onChangeValue, required, ...props }, ref) {
135
139
  const theme = (0, BetterHtmlProvider_1.useTheme)();
136
140
  const styledComponentStyles = (0, hooks_1.useStyledComponentStyles)(props, theme);
137
141
  const dataProps = (0, hooks_1.useComponentPropsWithPrefix)(props, "data");
@@ -141,7 +145,7 @@ InputFieldComponent.multiline = (0, react_1.forwardRef)(function Multiline({ lab
141
145
  onChange?.(event);
142
146
  onChangeValue?.(event.target.value);
143
147
  }, [onChange, onChangeValue]);
144
- return ((0, jsx_runtime_1.jsxs)(Div_1.default.column, { gap: theme.styles.gap / 2, children: [label && (0, jsx_runtime_1.jsx)(Label_1.default, { text: label, required: required, isError: !!errorText }), (0, jsx_runtime_1.jsx)(TextareaElement, { theme: theme, required: required, onChange: onChangeElement, ...styledComponentStyles, ...dataProps, ...ariaProps, ...restProps, ref: ref }), (errorText || infoText) && ((0, jsx_runtime_1.jsx)(Text_1.default, { as: "span", display: "block", marginTop: theme.styles.gap / 2, color: errorText ? theme.colors.error : theme.colors.textSecondary, fontSize: 14, children: errorText || infoText }))] }));
148
+ return ((0, jsx_runtime_1.jsxs)(Div_1.default.column, { gap: theme.styles.gap / 2, children: [label && (0, jsx_runtime_1.jsx)(Label_1.default, { text: label, required: required, isError: !!errorText }), (0, jsx_runtime_1.jsx)(TextareaElement, { theme: theme, required: required, placeholder: placeholder ?? label, onChange: onChangeElement, ...styledComponentStyles, ...dataProps, ...ariaProps, ...restProps, ref: ref }), (errorText || infoText) && ((0, jsx_runtime_1.jsx)(Text_1.default, { as: "span", display: "block", marginTop: theme.styles.gap / 2, color: errorText ? theme.colors.error : theme.colors.textSecondary, fontSize: 14, children: errorText || infoText }))] }));
145
149
  });
146
150
  InputFieldComponent.email = (0, react_1.forwardRef)(function Email({ ...props }, ref) {
147
151
  return ((0, jsx_runtime_1.jsx)(InputFieldComponent, { type: "email", placeholder: "your@email.here", autoComplete: "email", autoCorrect: "off", autoCapitalize: "off", ref: ref, ...props }));
package/dist/index.d.ts CHANGED
@@ -15,6 +15,7 @@ import Form from "./components/Form";
15
15
  import Label from "./components/Label";
16
16
  import BetterHtmlProvider, { useBetterHtmlContext, useTheme, useLoader, useLoaderControls } from "./components/BetterHtmlProvider";
17
17
  import { usePageResize, useMediaQuery, useBooleanState, useDebounceState, useForm, useUrlQuery } from "./utils/hooks";
18
+ import { generateRandomString, getBrowser, formatPhoneNumber } from "./utils/functions";
18
19
  import { type OmitProps, type ExcludeOptions, type PickValue, type PartialRecord, type DeepPartialRecord, type PickAllRequired } from "./types/app";
19
20
  import { type AppConfig, type BetterHtmlConfig } from "./types/config";
20
21
  import { type AssetName, type AssetsConfig } from "./types/asset";
@@ -24,4 +25,4 @@ import { type PluginName, type BetterHtmlPlugin } from "./types/plugin";
24
25
  import { type Color, type ColorName, type ColorTheme, type Colors, type Styles, type Theme, type ThemeConfig } from "./types/theme";
25
26
  import { isMobileDevice } from "./constants";
26
27
  export * from "./plugins";
27
- export { BetterHtmlProvider, Div, Text, Loader, Icon, Image, Button, Divider, Modal, ModalRef, PageHolder, Chip, InputField, Dropdown, DropdownOption, ToggleInput, Form, Label, useBetterHtmlContext, useTheme, useLoader, useLoaderControls, usePageResize, useMediaQuery, useBooleanState, useDebounceState, useForm, useUrlQuery, OmitProps, ExcludeOptions, PickValue, PartialRecord, DeepPartialRecord, PickAllRequired, AppConfig, BetterHtmlConfig, AssetName, AssetsConfig, IconName, IconsConfig, LoaderName, PluginName, BetterHtmlPlugin, LoaderConfig, Color, ColorName, ColorTheme, Colors, Styles, Theme, ThemeConfig, isMobileDevice, };
28
+ export { BetterHtmlProvider, Div, Text, Loader, Icon, Image, Button, Divider, Modal, ModalRef, PageHolder, Chip, InputField, Dropdown, DropdownOption, ToggleInput, Form, Label, useBetterHtmlContext, useTheme, useLoader, useLoaderControls, usePageResize, useMediaQuery, useBooleanState, useDebounceState, useForm, useUrlQuery, generateRandomString, getBrowser, formatPhoneNumber, OmitProps, ExcludeOptions, PickValue, PartialRecord, DeepPartialRecord, PickAllRequired, AppConfig, BetterHtmlConfig, AssetName, AssetsConfig, IconName, IconsConfig, LoaderName, PluginName, BetterHtmlPlugin, LoaderConfig, Color, ColorName, ColorTheme, Colors, Styles, Theme, ThemeConfig, 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.useUrlQuery = exports.useForm = exports.useDebounceState = exports.useBooleanState = exports.useMediaQuery = exports.usePageResize = exports.useLoaderControls = exports.useLoader = exports.useTheme = exports.useBetterHtmlContext = exports.Label = exports.Form = exports.ToggleInput = exports.Dropdown = exports.InputField = exports.Chip = 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.formatPhoneNumber = exports.getBrowser = exports.generateRandomString = exports.useUrlQuery = exports.useForm = exports.useDebounceState = exports.useBooleanState = exports.useMediaQuery = exports.usePageResize = exports.useLoaderControls = exports.useLoader = exports.useTheme = exports.useBetterHtmlContext = exports.Label = exports.Form = exports.ToggleInput = exports.Dropdown = exports.InputField = exports.Chip = 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"));
@@ -83,6 +83,10 @@ Object.defineProperty(exports, "useBooleanState", { enumerable: true, get: funct
83
83
  Object.defineProperty(exports, "useDebounceState", { enumerable: true, get: function () { return hooks_1.useDebounceState; } });
84
84
  Object.defineProperty(exports, "useForm", { enumerable: true, get: function () { return hooks_1.useForm; } });
85
85
  Object.defineProperty(exports, "useUrlQuery", { enumerable: true, get: function () { return hooks_1.useUrlQuery; } });
86
+ const functions_1 = require("./utils/functions");
87
+ Object.defineProperty(exports, "generateRandomString", { enumerable: true, get: function () { return functions_1.generateRandomString; } });
88
+ Object.defineProperty(exports, "getBrowser", { enumerable: true, get: function () { return functions_1.getBrowser; } });
89
+ Object.defineProperty(exports, "formatPhoneNumber", { enumerable: true, get: function () { return functions_1.formatPhoneNumber; } });
86
90
  const constants_1 = require("./constants");
87
91
  Object.defineProperty(exports, "isMobileDevice", { enumerable: true, get: function () { return constants_1.isMobileDevice; } });
88
92
  __exportStar(require("./plugins"), exports);
@@ -1 +1,3 @@
1
- export {};
1
+ export declare const generateRandomString: (stringLength: number) => string;
2
+ export declare const getBrowser: () => "firefox" | "chrome" | "safari" | "edge" | "opera" | undefined;
3
+ export declare const formatPhoneNumber: (phoneNumber: string) => string;
@@ -1,2 +1,51 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatPhoneNumber = exports.getBrowser = exports.generateRandomString = void 0;
4
+ const countries_1 = require("../constants/countries");
5
+ const generateRandomString = (stringLength) => {
6
+ const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
7
+ let result = "";
8
+ for (let index = 0; index < stringLength; index++) {
9
+ result += characters.charAt(Math.floor(Math.random() * characters.length));
10
+ }
11
+ return result;
12
+ };
13
+ exports.generateRandomString = generateRandomString;
14
+ const getBrowser = () => {
15
+ const userAgent = navigator.userAgent.toLowerCase();
16
+ if (userAgent.includes("firefox"))
17
+ return "firefox";
18
+ if (userAgent.includes("chrome") && !userAgent.includes("edg"))
19
+ return "chrome";
20
+ if (userAgent.includes("safari") && !userAgent.includes("chrome"))
21
+ return "safari";
22
+ if (userAgent.includes("edg"))
23
+ return "edge";
24
+ if (userAgent.includes("opr") || userAgent.includes("opera"))
25
+ return "opera";
26
+ return;
27
+ };
28
+ exports.getBrowser = getBrowser;
29
+ const formatPhoneNumber = (phoneNumber) => {
30
+ const cleanPhoneNumber = phoneNumber.replace(/\D/g, "");
31
+ const country = countries_1.countries.find((country) => country.phoneNumberExtension === cleanPhoneNumber.slice(0, country.phoneNumberExtension.length));
32
+ if (!country)
33
+ return phoneNumber;
34
+ let phonNumberRest = cleanPhoneNumber.slice(country.phoneNumberExtension.length);
35
+ if (country.phoneNumberFormat) {
36
+ let formattedNumber = "";
37
+ let index = 0;
38
+ for (const char of country.phoneNumberFormat) {
39
+ if (char === "X" && index < phonNumberRest.length) {
40
+ formattedNumber += phonNumberRest[index];
41
+ index++;
42
+ }
43
+ else {
44
+ formattedNumber += char;
45
+ }
46
+ }
47
+ phonNumberRest = formattedNumber.replace(/X/g, "").trim();
48
+ }
49
+ return `+${country.phoneNumberExtension} ${phonNumberRest}`;
50
+ };
51
+ exports.formatPhoneNumber = formatPhoneNumber;
@@ -187,6 +187,7 @@ function useForm({ defaultValues, requiredFields, onSubmit, validate, }) {
187
187
  const getInputFieldProps = (0, react_1.useCallback)((field) => {
188
188
  const type = inputTypes[field] ?? "text";
189
189
  return {
190
+ required: requiredFields?.includes(field),
190
191
  value: values[field]?.toString() ?? "",
191
192
  onChangeValue: (newValue) => {
192
193
  const readyValue = type === "number" ? (newValue ? Number(newValue) : undefined) : newValue;
@@ -206,8 +207,8 @@ function useForm({ defaultValues, requiredFields, onSubmit, validate, }) {
206
207
  };
207
208
  }, [values, setFieldValue, inputTypes, errors]);
208
209
  const getTextAreaProps = (0, react_1.useCallback)((field) => {
209
- const type = inputTypes[field] ?? "text";
210
210
  return {
211
+ required: requiredFields?.includes(field),
211
212
  value: values[field]?.toString() ?? "",
212
213
  onChangeValue: (newValue) => {
213
214
  setFieldValue(field, newValue);
@@ -217,6 +218,7 @@ function useForm({ defaultValues, requiredFields, onSubmit, validate, }) {
217
218
  }, [values, setFieldValue, inputTypes, errors]);
218
219
  const getDropdownFieldProps = (0, react_1.useCallback)((field) => {
219
220
  return {
221
+ required: requiredFields?.includes(field),
220
222
  value: values[field],
221
223
  onChange: (value) => {
222
224
  setFieldValue(field, value);
@@ -226,6 +228,7 @@ function useForm({ defaultValues, requiredFields, onSubmit, validate, }) {
226
228
  }, [values, errors, setFieldValue]);
227
229
  const getCheckboxProps = (0, react_1.useCallback)((field) => {
228
230
  return {
231
+ required: requiredFields?.includes(field),
229
232
  checked: values[field],
230
233
  onChange: (checked) => {
231
234
  setFieldValue(field, checked);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-better-html",
3
- "version": "1.1.36",
3
+ "version": "1.1.38",
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": [