react-better-html 1.1.57 → 1.1.58

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.
@@ -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)();
@@ -1,5 +1,6 @@
1
1
  import { ComponentMarginProps } from "../types/components";
2
2
  export type ColorThemeSwitchProps = {
3
+ /** @default false */
3
4
  withMoon?: boolean;
4
5
  className?: string;
5
6
  } & ComponentMarginProps;
@@ -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 = "Select an option", leftIcon, inputFieldClassName, withSearch, withDebounce, debounceDelay = 0.5, debounceIsLoading, debounceMinimumSymbolsRequired, withoutClearButton, onChange, onChangeSearch, renderOption, ...props }, ref) {
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
- 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 : 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) => {
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,6 +9,7 @@ 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;
@@ -1,6 +1,8 @@
1
1
  export type LabelProps = {
2
2
  text?: string;
3
+ /** @default false */
3
4
  required?: boolean;
5
+ /** @default false */
4
6
  isError?: boolean;
5
7
  };
6
8
  declare function Label({ text, required, isError }: LabelProps): import("react/jsx-runtime").JSX.Element;
@@ -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; } });
@@ -71,7 +71,7 @@ export declare function useForm<FormFields extends Record<string | number, strin
71
71
  isDirty: boolean;
72
72
  };
73
73
  export declare function useUrlQuery(): {
74
- setQuery: (query: Record<string, string>, keepHistory?: boolean) => void;
74
+ setQuery: (query: Record<string, string | number>, keepHistory?: boolean) => void;
75
75
  getQuery: (name: string) => string | null;
76
76
  removeQuery: (name: string, keepHistory?: boolean) => void;
77
77
  };
@@ -338,7 +338,7 @@ function useUrlQuery() {
338
338
  navigate({
339
339
  search: (0, react_router_dom_1.createSearchParams)({
340
340
  ...currentSearchParams,
341
- ...query,
341
+ ...Object.fromEntries(Object.entries(query).map(([key, value]) => [key, value.toString()])),
342
342
  }).toString(),
343
343
  }, {
344
344
  replace: !keepHistory,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-better-html",
3
- "version": "1.1.57",
3
+ "version": "1.1.58",
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": [