react-better-html 1.1.181 → 1.1.183

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/index.d.mts CHANGED
@@ -2,6 +2,7 @@ import { WebTarget } from 'styled-components';
2
2
  import * as react from 'react';
3
3
  import { ComponentProps, ReactNode } from 'react';
4
4
  import * as react_jsx_runtime from 'react/jsx-runtime';
5
+ import { useNavigate, useLocation, useInRouterContext, useSearchParams } from 'react-router-dom';
5
6
 
6
7
  type PluginName = "alerts" | "react-router-dom" | "localStorage";
7
8
  type BetterHtmlPluginConstructor<T extends object = object> = (config?: T) => BetterHtmlPlugin<T>;
@@ -930,6 +931,36 @@ declare const Foldable: typeof FoldableComponent & {
930
931
  box: typeof FoldableComponent.box;
931
932
  };
932
933
 
934
+ type MenuItem = {
935
+ text: string;
936
+ iconName: IconName | AnyOtherString;
937
+ href?: string;
938
+ onClick?: (item: MenuItem) => void;
939
+ disabled?: boolean;
940
+ hidden?: boolean;
941
+ children?: MenuItem[];
942
+ };
943
+ type SideMenuProps = {
944
+ items: MenuItem[];
945
+ logoAssetName?: AssetName | AnyOtherString;
946
+ logoUrl?: string;
947
+ logoText?: string;
948
+ logoFontFamily?: string;
949
+ collapsable?: boolean;
950
+ widthMobileHandle?: boolean;
951
+ };
952
+ type SideMenuComponentType = {
953
+ (props: SideMenuProps): React.ReactElement;
954
+ pageHolder: (props: SideMenuPageHolderProps) => React.ReactElement;
955
+ };
956
+ declare const SideMenuComponent: SideMenuComponentType;
957
+ type SideMenuPageHolderProps = PageHolderProps & {
958
+ outsideComponent?: React.ReactNode;
959
+ };
960
+ declare const SideMenu: typeof SideMenuComponent & {
961
+ pageHolder: typeof SideMenuComponent.pageHolder;
962
+ };
963
+
933
964
  type AppConfig = {
934
965
  contentMaxWidth: number;
935
966
  };
@@ -951,6 +982,10 @@ type BetterHtmlConfig = {
951
982
  style?: ComponentStyleConfig<"default" | "secondary" | "destructive" | "icon" | "upload">;
952
983
  tagReplacement?: ComponentTagReplacementConfig<"buttonComponent" | "linkComponent">;
953
984
  };
985
+ sideMenu?: {
986
+ /** @default 300 */
987
+ width?: number;
988
+ };
954
989
  };
955
990
  };
956
991
 
@@ -1020,6 +1055,12 @@ declare const alertControls: {
1020
1055
  createAlert: (alert: OmitProps<Alert, "id">) => Alert;
1021
1056
  removeAlert: (alertId: string) => void;
1022
1057
  };
1058
+ declare const sideMenuControls: {
1059
+ expand: () => void;
1060
+ collapse: () => void;
1061
+ open: () => void;
1062
+ close: () => void;
1063
+ };
1023
1064
  declare const colorThemeControls: {
1024
1065
  toggleTheme: (theme?: ColorTheme) => void;
1025
1066
  };
@@ -1053,7 +1094,12 @@ type AlertsPluginOptions = {
1053
1094
  declare const defaultAlertsPluginOptions: Required<AlertsPluginOptions>;
1054
1095
  declare const alertsPlugin: BetterHtmlPluginConstructor<AlertsPluginOptions>;
1055
1096
 
1056
- type ReactRouterDomPluginOptions = {};
1097
+ type ReactRouterDomPluginOptions = {
1098
+ useNavigate: typeof useNavigate;
1099
+ useLocation: typeof useLocation;
1100
+ useInRouterContext: typeof useInRouterContext;
1101
+ useSearchParams: typeof useSearchParams;
1102
+ };
1057
1103
  declare const defaultReactRouterDomPluginOptions: Required<ReactRouterDomPluginOptions>;
1058
1104
  declare const reactRouterDomPlugin: BetterHtmlPluginConstructor<ReactRouterDomPluginOptions>;
1059
1105
 
@@ -1071,4 +1117,4 @@ type LocalStoragePluginOptions = {
1071
1117
  declare const defaultLocalStoragePluginOptions: Required<LocalStoragePluginOptions>;
1072
1118
  declare const localStoragePlugin: BetterHtmlPluginConstructor<LocalStoragePluginOptions>;
1073
1119
 
1074
- export { type Alert, type AlertType, type AlertsPluginOptions, type AppConfig, type AssetName, type AssetsConfig, type BetterHtmlConfig, type BetterHtmlPlugin, _default as BetterHtmlProvider, type BetterHtmlProviderConfig, type BrowserName, Button, type ButtonProps, Chip, type ChipProps, type Color, type ColorName, type ColorTheme, ColorThemeSwitch, type ColorThemeSwitchProps, type Colors, type ComponentHoverStyle, type ComponentMarginProps, type ComponentPaddingProps, type DeepPartialRecord, Div, type DivProps, _default$3 as Divider, Dropdown, type DropdownOption, type DropdownProps, type ExcludeOptions, Foldable, type FoldableProps, type FoldableRef, Form, type FormProps, FormRow, type FormRowProps, type HorizontalDividerProps, _default$5 as Icon, type IconName, type IconProps, type IconsConfig, _default$4 as Image, type ImageProps, InputField, type InputFieldProps, _default$1 as Label, type LabelProps, Loader, type LoaderConfig, type LoaderName, type LoaderProps, type LocalStoragePluginOptions, Modal, type ModalProps, type ModalRef, type OmitProps, PageHeader, type PageHeaderProps, PageHolder, type PageHolderProps, type PartialRecord, type PickAllRequired, type PickValue, type PluginName, type ReactRouterDomPluginOptions, type Styles, type TabGroup, Table, type TableColumn, type TableFilterData, type TableProps, type TableRef, Tabs, type TabsProps, type TabsRef, Text, type TextAs, type TextProps, type TextareaFieldProps, type Theme, type ThemeConfig, _default$2 as ToggleInput, type ToggleInputProps, type ToggleInputRef, Tooltip, type TooltipProps, type TooltipRef, type VerticalDividerProps, alertControls, alertsPlugin, colorThemeControls, countries, darkenColor, defaultAlertsPluginOptions, defaultLocalStoragePluginOptions, defaultReactRouterDomPluginOptions, desaturateColor, eventPreventDefault, eventPreventStop, eventStopPropagation, filterHover, formatPhoneNumber, generateLocalStorage, generateRandomString, getBrowser, getFormErrorObject, isMobileDevice, lightenColor, loaderControls, localStoragePlugin, reactRouterDomPlugin, saturateColor, useAlertControls, useBetterHtmlContext, useBooleanState, useDebounceState, useForm, useLoader, useLoaderControls, useMediaQuery, usePageResize, usePageScroll, useTheme, useUrlQuery };
1120
+ export { type Alert, type AlertType, type AlertsPluginOptions, type AppConfig, type AssetName, type AssetsConfig, type BetterHtmlConfig, type BetterHtmlPlugin, _default as BetterHtmlProvider, type BetterHtmlProviderConfig, type BrowserName, Button, type ButtonProps, Chip, type ChipProps, type Color, type ColorName, type ColorTheme, ColorThemeSwitch, type ColorThemeSwitchProps, type Colors, type ComponentHoverStyle, type ComponentMarginProps, type ComponentPaddingProps, type DeepPartialRecord, Div, type DivProps, _default$3 as Divider, Dropdown, type DropdownOption, type DropdownProps, type ExcludeOptions, Foldable, type FoldableProps, type FoldableRef, Form, type FormProps, FormRow, type FormRowProps, type HorizontalDividerProps, _default$5 as Icon, type IconName, type IconProps, type IconsConfig, _default$4 as Image, type ImageProps, InputField, type InputFieldProps, _default$1 as Label, type LabelProps, Loader, type LoaderConfig, type LoaderName, type LoaderProps, type LocalStoragePluginOptions, type MenuItem, Modal, type ModalProps, type ModalRef, type OmitProps, PageHeader, type PageHeaderProps, PageHolder, type PageHolderProps, type PartialRecord, type PickAllRequired, type PickValue, type PluginName, type ReactRouterDomPluginOptions, SideMenu, type Styles, type TabGroup, Table, type TableColumn, type TableFilterData, type TableProps, type TableRef, Tabs, type TabsProps, type TabsRef, Text, type TextAs, type TextProps, type TextareaFieldProps, type Theme, type ThemeConfig, _default$2 as ToggleInput, type ToggleInputProps, type ToggleInputRef, Tooltip, type TooltipProps, type TooltipRef, type VerticalDividerProps, alertControls, alertsPlugin, colorThemeControls, countries, darkenColor, defaultAlertsPluginOptions, defaultLocalStoragePluginOptions, defaultReactRouterDomPluginOptions, desaturateColor, eventPreventDefault, eventPreventStop, eventStopPropagation, filterHover, formatPhoneNumber, generateLocalStorage, generateRandomString, getBrowser, getFormErrorObject, isMobileDevice, lightenColor, loaderControls, localStoragePlugin, reactRouterDomPlugin, saturateColor, sideMenuControls, useAlertControls, useBetterHtmlContext, useBooleanState, useDebounceState, useForm, useLoader, useLoaderControls, useMediaQuery, usePageResize, usePageScroll, useTheme, useUrlQuery };
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ import { WebTarget } from 'styled-components';
2
2
  import * as react from 'react';
3
3
  import { ComponentProps, ReactNode } from 'react';
4
4
  import * as react_jsx_runtime from 'react/jsx-runtime';
5
+ import { useNavigate, useLocation, useInRouterContext, useSearchParams } from 'react-router-dom';
5
6
 
6
7
  type PluginName = "alerts" | "react-router-dom" | "localStorage";
7
8
  type BetterHtmlPluginConstructor<T extends object = object> = (config?: T) => BetterHtmlPlugin<T>;
@@ -930,6 +931,36 @@ declare const Foldable: typeof FoldableComponent & {
930
931
  box: typeof FoldableComponent.box;
931
932
  };
932
933
 
934
+ type MenuItem = {
935
+ text: string;
936
+ iconName: IconName | AnyOtherString;
937
+ href?: string;
938
+ onClick?: (item: MenuItem) => void;
939
+ disabled?: boolean;
940
+ hidden?: boolean;
941
+ children?: MenuItem[];
942
+ };
943
+ type SideMenuProps = {
944
+ items: MenuItem[];
945
+ logoAssetName?: AssetName | AnyOtherString;
946
+ logoUrl?: string;
947
+ logoText?: string;
948
+ logoFontFamily?: string;
949
+ collapsable?: boolean;
950
+ widthMobileHandle?: boolean;
951
+ };
952
+ type SideMenuComponentType = {
953
+ (props: SideMenuProps): React.ReactElement;
954
+ pageHolder: (props: SideMenuPageHolderProps) => React.ReactElement;
955
+ };
956
+ declare const SideMenuComponent: SideMenuComponentType;
957
+ type SideMenuPageHolderProps = PageHolderProps & {
958
+ outsideComponent?: React.ReactNode;
959
+ };
960
+ declare const SideMenu: typeof SideMenuComponent & {
961
+ pageHolder: typeof SideMenuComponent.pageHolder;
962
+ };
963
+
933
964
  type AppConfig = {
934
965
  contentMaxWidth: number;
935
966
  };
@@ -951,6 +982,10 @@ type BetterHtmlConfig = {
951
982
  style?: ComponentStyleConfig<"default" | "secondary" | "destructive" | "icon" | "upload">;
952
983
  tagReplacement?: ComponentTagReplacementConfig<"buttonComponent" | "linkComponent">;
953
984
  };
985
+ sideMenu?: {
986
+ /** @default 300 */
987
+ width?: number;
988
+ };
954
989
  };
955
990
  };
956
991
 
@@ -1020,6 +1055,12 @@ declare const alertControls: {
1020
1055
  createAlert: (alert: OmitProps<Alert, "id">) => Alert;
1021
1056
  removeAlert: (alertId: string) => void;
1022
1057
  };
1058
+ declare const sideMenuControls: {
1059
+ expand: () => void;
1060
+ collapse: () => void;
1061
+ open: () => void;
1062
+ close: () => void;
1063
+ };
1023
1064
  declare const colorThemeControls: {
1024
1065
  toggleTheme: (theme?: ColorTheme) => void;
1025
1066
  };
@@ -1053,7 +1094,12 @@ type AlertsPluginOptions = {
1053
1094
  declare const defaultAlertsPluginOptions: Required<AlertsPluginOptions>;
1054
1095
  declare const alertsPlugin: BetterHtmlPluginConstructor<AlertsPluginOptions>;
1055
1096
 
1056
- type ReactRouterDomPluginOptions = {};
1097
+ type ReactRouterDomPluginOptions = {
1098
+ useNavigate: typeof useNavigate;
1099
+ useLocation: typeof useLocation;
1100
+ useInRouterContext: typeof useInRouterContext;
1101
+ useSearchParams: typeof useSearchParams;
1102
+ };
1057
1103
  declare const defaultReactRouterDomPluginOptions: Required<ReactRouterDomPluginOptions>;
1058
1104
  declare const reactRouterDomPlugin: BetterHtmlPluginConstructor<ReactRouterDomPluginOptions>;
1059
1105
 
@@ -1071,4 +1117,4 @@ type LocalStoragePluginOptions = {
1071
1117
  declare const defaultLocalStoragePluginOptions: Required<LocalStoragePluginOptions>;
1072
1118
  declare const localStoragePlugin: BetterHtmlPluginConstructor<LocalStoragePluginOptions>;
1073
1119
 
1074
- export { type Alert, type AlertType, type AlertsPluginOptions, type AppConfig, type AssetName, type AssetsConfig, type BetterHtmlConfig, type BetterHtmlPlugin, _default as BetterHtmlProvider, type BetterHtmlProviderConfig, type BrowserName, Button, type ButtonProps, Chip, type ChipProps, type Color, type ColorName, type ColorTheme, ColorThemeSwitch, type ColorThemeSwitchProps, type Colors, type ComponentHoverStyle, type ComponentMarginProps, type ComponentPaddingProps, type DeepPartialRecord, Div, type DivProps, _default$3 as Divider, Dropdown, type DropdownOption, type DropdownProps, type ExcludeOptions, Foldable, type FoldableProps, type FoldableRef, Form, type FormProps, FormRow, type FormRowProps, type HorizontalDividerProps, _default$5 as Icon, type IconName, type IconProps, type IconsConfig, _default$4 as Image, type ImageProps, InputField, type InputFieldProps, _default$1 as Label, type LabelProps, Loader, type LoaderConfig, type LoaderName, type LoaderProps, type LocalStoragePluginOptions, Modal, type ModalProps, type ModalRef, type OmitProps, PageHeader, type PageHeaderProps, PageHolder, type PageHolderProps, type PartialRecord, type PickAllRequired, type PickValue, type PluginName, type ReactRouterDomPluginOptions, type Styles, type TabGroup, Table, type TableColumn, type TableFilterData, type TableProps, type TableRef, Tabs, type TabsProps, type TabsRef, Text, type TextAs, type TextProps, type TextareaFieldProps, type Theme, type ThemeConfig, _default$2 as ToggleInput, type ToggleInputProps, type ToggleInputRef, Tooltip, type TooltipProps, type TooltipRef, type VerticalDividerProps, alertControls, alertsPlugin, colorThemeControls, countries, darkenColor, defaultAlertsPluginOptions, defaultLocalStoragePluginOptions, defaultReactRouterDomPluginOptions, desaturateColor, eventPreventDefault, eventPreventStop, eventStopPropagation, filterHover, formatPhoneNumber, generateLocalStorage, generateRandomString, getBrowser, getFormErrorObject, isMobileDevice, lightenColor, loaderControls, localStoragePlugin, reactRouterDomPlugin, saturateColor, useAlertControls, useBetterHtmlContext, useBooleanState, useDebounceState, useForm, useLoader, useLoaderControls, useMediaQuery, usePageResize, usePageScroll, useTheme, useUrlQuery };
1120
+ export { type Alert, type AlertType, type AlertsPluginOptions, type AppConfig, type AssetName, type AssetsConfig, type BetterHtmlConfig, type BetterHtmlPlugin, _default as BetterHtmlProvider, type BetterHtmlProviderConfig, type BrowserName, Button, type ButtonProps, Chip, type ChipProps, type Color, type ColorName, type ColorTheme, ColorThemeSwitch, type ColorThemeSwitchProps, type Colors, type ComponentHoverStyle, type ComponentMarginProps, type ComponentPaddingProps, type DeepPartialRecord, Div, type DivProps, _default$3 as Divider, Dropdown, type DropdownOption, type DropdownProps, type ExcludeOptions, Foldable, type FoldableProps, type FoldableRef, Form, type FormProps, FormRow, type FormRowProps, type HorizontalDividerProps, _default$5 as Icon, type IconName, type IconProps, type IconsConfig, _default$4 as Image, type ImageProps, InputField, type InputFieldProps, _default$1 as Label, type LabelProps, Loader, type LoaderConfig, type LoaderName, type LoaderProps, type LocalStoragePluginOptions, type MenuItem, Modal, type ModalProps, type ModalRef, type OmitProps, PageHeader, type PageHeaderProps, PageHolder, type PageHolderProps, type PartialRecord, type PickAllRequired, type PickValue, type PluginName, type ReactRouterDomPluginOptions, SideMenu, type Styles, type TabGroup, Table, type TableColumn, type TableFilterData, type TableProps, type TableRef, Tabs, type TabsProps, type TabsRef, Text, type TextAs, type TextProps, type TextareaFieldProps, type Theme, type ThemeConfig, _default$2 as ToggleInput, type ToggleInputProps, type ToggleInputRef, Tooltip, type TooltipProps, type TooltipRef, type VerticalDividerProps, alertControls, alertsPlugin, colorThemeControls, countries, darkenColor, defaultAlertsPluginOptions, defaultLocalStoragePluginOptions, defaultReactRouterDomPluginOptions, desaturateColor, eventPreventDefault, eventPreventStop, eventStopPropagation, filterHover, formatPhoneNumber, generateLocalStorage, generateRandomString, getBrowser, getFormErrorObject, isMobileDevice, lightenColor, loaderControls, localStoragePlugin, reactRouterDomPlugin, saturateColor, sideMenuControls, useAlertControls, useBetterHtmlContext, useBooleanState, useDebounceState, useForm, useLoader, useLoaderControls, useMediaQuery, usePageResize, usePageScroll, useTheme, useUrlQuery };
package/dist/index.js CHANGED
@@ -48,6 +48,7 @@ __export(index_exports, {
48
48
  Modal: () => Modal_default,
49
49
  PageHeader: () => PageHeader_default,
50
50
  PageHolder: () => PageHolder_default,
51
+ SideMenu: () => SideMenu_default,
51
52
  Table: () => Table_default,
52
53
  Tabs: () => Tabs_default,
53
54
  Text: () => Text_default,
@@ -77,6 +78,7 @@ __export(index_exports, {
77
78
  localStoragePlugin: () => localStoragePlugin,
78
79
  reactRouterDomPlugin: () => reactRouterDomPlugin,
79
80
  saturateColor: () => saturateColor,
81
+ sideMenuControls: () => sideMenuControls,
80
82
  useAlertControls: () => useAlertControls,
81
83
  useBetterHtmlContext: () => useBetterHtmlContext,
82
84
  useBooleanState: () => useBooleanState,
@@ -103,7 +105,7 @@ var isMobileDevice = /Mobi|Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Op
103
105
 
104
106
  // src/utils/hooks.ts
105
107
  var import_react10 = require("react");
106
- var import_react_router_dom = require("react-router-dom");
108
+ var import_react_router_dom2 = require("react-router-dom");
107
109
 
108
110
  // src/constants/css.ts
109
111
  var cssProps = {
@@ -1612,6 +1614,7 @@ var appConfig = {
1612
1614
  contentMaxWidth: 1100
1613
1615
  };
1614
1616
  var defaultAlertDuration = 2.3 * 1e3;
1617
+ var defaultSideMenuWidth = 300;
1615
1618
 
1616
1619
  // src/components/alerts/AlertsHolder.tsx
1617
1620
  var import_react8 = require("react");
@@ -1641,7 +1644,13 @@ var alertsPlugin = (options) => ({
1641
1644
  });
1642
1645
 
1643
1646
  // src/plugins/reactRouterDom.ts
1644
- var defaultReactRouterDomPluginOptions = {};
1647
+ var import_react_router_dom = require("react-router-dom");
1648
+ var defaultReactRouterDomPluginOptions = {
1649
+ useNavigate: import_react_router_dom.useNavigate,
1650
+ useLocation: import_react_router_dom.useLocation,
1651
+ useInRouterContext: import_react_router_dom.useInRouterContext,
1652
+ useSearchParams: import_react_router_dom.useSearchParams
1653
+ };
1645
1654
  var reactRouterDomPlugin = (options) => ({
1646
1655
  name: "react-router-dom",
1647
1656
  initialize: () => {
@@ -2628,6 +2637,8 @@ function BetterHtmlProvider({ config, plugins, children }) {
2628
2637
  );
2629
2638
  const [loaders, setLoaders] = (0, import_react9.useState)(config?.loaders ?? {});
2630
2639
  const [alerts, setAlerts] = (0, import_react9.useState)([]);
2640
+ const [sideMenuIsCollapsed, setSideMenuIsCollapsed] = useBooleanState();
2641
+ const [sideMenuIsOpenMobile, setSideMenuIsOpenMobile] = useBooleanState();
2631
2642
  const [tabGroups, setTabGroups] = (0, import_react9.useState)([]);
2632
2643
  const [tabsWithDots, setTabsWithDots] = (0, import_react9.useState)([]);
2633
2644
  const readyConfig = (0, import_react9.useMemo)(
@@ -2665,6 +2676,10 @@ function BetterHtmlProvider({ config, plugins, children }) {
2665
2676
  setLoaders,
2666
2677
  alerts,
2667
2678
  setAlerts,
2679
+ sideMenuIsCollapsed,
2680
+ setSideMenuIsCollapsed,
2681
+ sideMenuIsOpenMobile,
2682
+ setSideMenuIsOpenMobile,
2668
2683
  components: {
2669
2684
  ...config?.components
2670
2685
  },
@@ -2678,7 +2693,7 @@ function BetterHtmlProvider({ config, plugins, children }) {
2678
2693
  }
2679
2694
  }
2680
2695
  }),
2681
- [config, colorTheme, loaders, alerts, tabGroups, tabsWithDots]
2696
+ [config, colorTheme, loaders, alerts, sideMenuIsCollapsed, sideMenuIsOpenMobile, tabGroups, tabsWithDots]
2682
2697
  );
2683
2698
  (0, import_react9.useEffect)(() => {
2684
2699
  if (!plugins) return;
@@ -3185,14 +3200,15 @@ function useUrlQuery() {
3185
3200
  "`useUrlQuery` hook requires the `react-router-dom` plugin to be added to the `plugins` prop in `<BetterHtmlProvider>`."
3186
3201
  );
3187
3202
  }
3188
- const isInRouterContext = (0, import_react_router_dom.useInRouterContext)();
3203
+ const reactRouterDomPluginConfig = reactRouterDomPlugin2.getConfig();
3204
+ const isInRouterContext = reactRouterDomPluginConfig.useInRouterContext();
3189
3205
  if (!isInRouterContext) {
3190
3206
  throw new Error(
3191
3207
  "`useUrlQuery` hook must be used inside a React Router context. Make sure your component is wrapped in a `<BrowserRouter>`, or another Router component."
3192
3208
  );
3193
3209
  }
3194
- const navigate = (0, import_react_router_dom.useNavigate)();
3195
- const [searchParams] = (0, import_react_router_dom.useSearchParams)();
3210
+ const navigate = reactRouterDomPluginConfig.useNavigate();
3211
+ const [searchParams] = reactRouterDomPluginConfig.useSearchParams();
3196
3212
  const setQuery = (0, import_react10.useCallback)(
3197
3213
  (query, keepHistory = true) => {
3198
3214
  const currentSearchParams = {};
@@ -3201,7 +3217,7 @@ function useUrlQuery() {
3201
3217
  });
3202
3218
  navigate(
3203
3219
  {
3204
- search: (0, import_react_router_dom.createSearchParams)({
3220
+ search: (0, import_react_router_dom2.createSearchParams)({
3205
3221
  ...currentSearchParams,
3206
3222
  ...Object.fromEntries(Object.entries(query).map(([key, value]) => [key, value.toString()]))
3207
3223
  }).toString()
@@ -5580,6 +5596,24 @@ var alertControls = {
5580
5596
  externalBetterHtmlContextValue.setAlerts((oldValue) => oldValue.filter((alert) => alert.id !== alertId));
5581
5597
  }
5582
5598
  };
5599
+ var sideMenuControls = {
5600
+ expand: () => {
5601
+ if (!checkBetterHtmlContextValue(externalBetterHtmlContextValue, "sideMenuControls.expand")) return;
5602
+ externalBetterHtmlContextValue.setSideMenuIsCollapsed.setFalse();
5603
+ },
5604
+ collapse: () => {
5605
+ if (!checkBetterHtmlContextValue(externalBetterHtmlContextValue, "sideMenuControls.collapse")) return;
5606
+ externalBetterHtmlContextValue.setSideMenuIsCollapsed.setTrue();
5607
+ },
5608
+ open: () => {
5609
+ if (!checkBetterHtmlContextValue(externalBetterHtmlContextValue, "sideMenuControls.open")) return;
5610
+ externalBetterHtmlContextValue.setSideMenuIsOpenMobile.setTrue();
5611
+ },
5612
+ close: () => {
5613
+ if (!checkBetterHtmlContextValue(externalBetterHtmlContextValue, "sideMenuControls.close")) return;
5614
+ externalBetterHtmlContextValue.setSideMenuIsOpenMobile.setFalse();
5615
+ }
5616
+ };
5583
5617
  var colorThemeControls = {
5584
5618
  toggleTheme: (theme2) => {
5585
5619
  if (!checkBetterHtmlContextValue(externalBetterHtmlContextValue, "colorThemeControls.toggleTheme")) return;
@@ -8588,7 +8622,7 @@ var TableComponent = (0, import_react25.forwardRef)(function Table({
8588
8622
  value: value.value,
8589
8623
  onClickWithValue: onClickFilterListItem,
8590
8624
  children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(Div_default.row, { alignItems: "center", gap: theme2.styles.gap / 2, children: [
8591
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Text_default, { children: value.label ?? value.value }),
8625
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Text_default, { children: value.label || value.value }),
8592
8626
  openedFilterColumn.withTotalNumber && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
8593
8627
  Text_default,
8594
8628
  {
@@ -9331,6 +9365,305 @@ var Foldable2 = (0, import_react28.memo)(FoldableComponent);
9331
9365
  Foldable2.box = FoldableComponent.box;
9332
9366
  var Foldable_default = Foldable2;
9333
9367
 
9368
+ // src/components/SideMenu.tsx
9369
+ var import_react29 = require("react");
9370
+ var import_jsx_runtime27 = require("react/jsx-runtime");
9371
+ var MenuItemComponent = (0, import_react29.memo)(function MenuItemComponent2({ item, onClick }) {
9372
+ const reactRouterDomPlugin2 = usePlugin("react-router-dom");
9373
+ if (!reactRouterDomPlugin2) {
9374
+ throw new Error(
9375
+ "`SideMenu` component requires the `react-router-dom` plugin to be added to the `plugins` prop in `<BetterHtmlProvider>`."
9376
+ );
9377
+ }
9378
+ const reactRouterDomPluginConfig = reactRouterDomPlugin2.getConfig();
9379
+ const theme2 = useTheme();
9380
+ const mediaQuery = useMediaQuery();
9381
+ const location = reactRouterDomPluginConfig.useLocation();
9382
+ const { colorTheme, components, sideMenuIsCollapsed } = useBetterHtmlContextInternal();
9383
+ const [isOpened, setIsOpened] = useBooleanState();
9384
+ const onClickElement = (0, import_react29.useCallback)(() => {
9385
+ if (item.disabled) return;
9386
+ onClick?.();
9387
+ item.onClick?.(item);
9388
+ }, [onClick, item]);
9389
+ const isCollapsed = sideMenuIsCollapsed && !mediaQuery.size1000;
9390
+ const isActive = item.href ? location.pathname === "/" ? location.pathname === item.href : location.pathname.startsWith(item.href) && item.href !== "/" : false;
9391
+ const iconSize = 16;
9392
+ const paddingBlock = theme2.styles.gap;
9393
+ const paddingLeft = theme2.styles.gap + 2;
9394
+ const iconGap = theme2.styles.gap;
9395
+ const lineHeight = 20;
9396
+ const lineWidth = 2;
9397
+ const lineEndRadius = iconSize / 2 + iconGap * 2;
9398
+ const content = /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
9399
+ Div_default.row,
9400
+ {
9401
+ alignItems: "center",
9402
+ gap: iconGap,
9403
+ whiteSpace: "nowrap",
9404
+ backgroundColor: isActive ? `${theme2.colors.primary}20` : theme2.colors.backgroundBase,
9405
+ borderRadius: theme2.styles.borderRadius,
9406
+ paddingBlock,
9407
+ paddingLeft: isCollapsed ? theme2.styles.space : paddingLeft,
9408
+ paddingRight: theme2.styles.space,
9409
+ filterHover: `brightness(${colorTheme === "dark" ? isActive ? 0.8 : 1.3 : isActive ? 0.8 : 0.95})`,
9410
+ overflow: isCollapsed ? "hidden" : void 0,
9411
+ cursor: item.disabled ? "not-allowed" : "pointer",
9412
+ opacity: item.disabled ? 0.6 : void 0,
9413
+ onClick: item.children ? setIsOpened.toggle : void 0,
9414
+ children: [
9415
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Icon_default, { name: item.iconName, color: theme2.colors.primary, size: iconSize, flexShrink: 0 }),
9416
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
9417
+ Text_default,
9418
+ {
9419
+ flex: 1,
9420
+ lineHeight: `${lineHeight}px`,
9421
+ color: isActive ? theme2.colors.primary : theme2.colors.textPrimary,
9422
+ opacity: isCollapsed ? 0 : void 0,
9423
+ transition: theme2.styles.transition,
9424
+ children: item.text
9425
+ }
9426
+ ),
9427
+ item.children && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
9428
+ Icon_default,
9429
+ {
9430
+ name: "chevronDown",
9431
+ color: theme2.colors.textSecondary,
9432
+ size: 14,
9433
+ transform: isOpened ? "rotate(180deg)" : void 0,
9434
+ transition: theme2.styles.transition
9435
+ }
9436
+ )
9437
+ ]
9438
+ }
9439
+ );
9440
+ (0, import_react29.useEffect)(() => {
9441
+ if (!item.children) return;
9442
+ const toBeOpened = item.children.some(
9443
+ (child) => child.href ? location.pathname === "/" ? location.pathname === child.href : location.pathname.startsWith(child.href) && child.href !== "/" : false
9444
+ );
9445
+ setIsOpened.setState(toBeOpened);
9446
+ }, [item]);
9447
+ const LinkComponentTag = components.button?.tagReplacement?.linkComponent ?? "a";
9448
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Div_default, { width: "100%", children: [
9449
+ item.href ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(LinkComponentTag, { to: item.href, href: item.href, onClick: onClickElement, children: content }) : content,
9450
+ item.children && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
9451
+ Div_default.column,
9452
+ {
9453
+ position: "relative",
9454
+ maxHeight: isOpened ? 1e3 : 0,
9455
+ gap: theme2.styles.gap / 2,
9456
+ marginTop: isOpened ? theme2.styles.gap / 2 : void 0,
9457
+ paddingLeft: paddingLeft + iconSize + iconGap,
9458
+ overflow: "hidden",
9459
+ transition: `max-height ${theme2.styles.transition}, margin-top ${theme2.styles.transition}`,
9460
+ children: [
9461
+ item.children.map((child) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(MenuItemComponent2, { item: child, onClick }, child.text)),
9462
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
9463
+ Div_default,
9464
+ {
9465
+ position: "absolute",
9466
+ height: `calc(100% - ${paddingBlock + lineHeight / 2 + lineEndRadius / 2}px)`,
9467
+ top: 0,
9468
+ left: paddingLeft + iconSize / 2,
9469
+ zIndex: -1,
9470
+ children: [
9471
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
9472
+ Div_default,
9473
+ {
9474
+ position: "relative",
9475
+ width: lineWidth,
9476
+ height: "100%",
9477
+ backgroundColor: theme2.colors.border,
9478
+ zIndex: 1
9479
+ }
9480
+ ),
9481
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
9482
+ Div_default,
9483
+ {
9484
+ position: "absolute",
9485
+ width: lineEndRadius,
9486
+ height: lineEndRadius,
9487
+ top: `calc(100% - ${lineEndRadius / 2}px)`,
9488
+ left: 0,
9489
+ border: `${lineWidth}px solid ${theme2.colors.border}`,
9490
+ borderRadius: 999,
9491
+ borderTopColor: theme2.colors.backgroundBase,
9492
+ borderLeftColor: theme2.colors.backgroundBase,
9493
+ borderRightColor: theme2.colors.backgroundBase,
9494
+ transform: "rotate(45deg)"
9495
+ }
9496
+ )
9497
+ ]
9498
+ }
9499
+ )
9500
+ ]
9501
+ }
9502
+ )
9503
+ ] });
9504
+ });
9505
+ var SideMenuComponent = function SideMenu({
9506
+ items,
9507
+ logoAssetName,
9508
+ logoUrl,
9509
+ logoText,
9510
+ logoFontFamily,
9511
+ collapsable,
9512
+ widthMobileHandle
9513
+ }) {
9514
+ const theme2 = useTheme();
9515
+ const mediaQuery = useMediaQuery();
9516
+ const { components, sideMenuIsCollapsed, setSideMenuIsCollapsed, sideMenuIsOpenMobile, setSideMenuIsOpenMobile } = useBetterHtmlContextInternal();
9517
+ const onClickXButton = (0, import_react29.useCallback)(() => {
9518
+ setSideMenuIsOpenMobile.setFalse();
9519
+ }, []);
9520
+ const readyItems = (0, import_react29.useMemo)(() => items.filter((item) => !item.hidden), [items]);
9521
+ const isCollapsed = sideMenuIsCollapsed && !mediaQuery.size1000;
9522
+ const LinkComponentTag = components.button?.tagReplacement?.linkComponent ?? "a";
9523
+ const sideMenuWidth = components.sideMenu?.width ?? defaultSideMenuWidth;
9524
+ const sideMenuCollapsedWidth = theme2.styles.space + theme2.styles.space * 2 + 16 + 1 + theme2.styles.space;
9525
+ const logoSize = sideMenuCollapsedWidth - theme2.styles.space * 2;
9526
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
9527
+ Div_default.column,
9528
+ {
9529
+ position: "fixed",
9530
+ width: mediaQuery.size1000 ? "100%" : isCollapsed ? sideMenuCollapsedWidth : sideMenuWidth,
9531
+ height: "100svh",
9532
+ backgroundColor: theme2.colors.backgroundBase,
9533
+ borderRight: `solid 1px ${theme2.colors.border}`,
9534
+ transform: !mediaQuery.size1000 || sideMenuIsOpenMobile ? "translateX(0)" : "translateX(-100%)",
9535
+ paddingInline: theme2.styles.space,
9536
+ paddingTop: logoAssetName || logoUrl ? theme2.styles.gap : theme2.styles.space,
9537
+ paddingBottom: theme2.styles.space,
9538
+ transition: mediaQuery.size1000 ? !isCollapsed ? `transform ${theme2.styles.transition}` : "none" : theme2.styles.transition,
9539
+ userSelect: "none",
9540
+ zIndex: 11,
9541
+ children: [
9542
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Div_default.column, { width: "100%", height: "100%", gap: theme2.styles.space, children: [
9543
+ (logoAssetName || logoUrl || mediaQuery.size1000) && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Div_default.row, { alignItems: "center", children: [
9544
+ (logoAssetName || logoUrl) && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(LinkComponentTag, { to: "/", href: "/", onClick: onClickXButton, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
9545
+ Div_default.row,
9546
+ {
9547
+ alignItems: "center",
9548
+ width: sideMenuCollapsedWidth ? logoSize : void 0,
9549
+ height: logoSize,
9550
+ whiteSpace: "nowrap",
9551
+ gap: theme2.styles.gap,
9552
+ children: [
9553
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
9554
+ Image_default,
9555
+ {
9556
+ name: logoAssetName,
9557
+ src: logoUrl,
9558
+ width: logoSize,
9559
+ height: logoSize,
9560
+ objectFit: "contain"
9561
+ }
9562
+ ),
9563
+ logoText && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
9564
+ Text_default,
9565
+ {
9566
+ fontFamily: logoFontFamily,
9567
+ fontSize: 22,
9568
+ fontWeight: 800,
9569
+ opacity: !isCollapsed ? 1 : 0,
9570
+ transition: theme2.styles.transition,
9571
+ userSelect: "none",
9572
+ children: logoText
9573
+ }
9574
+ )
9575
+ ]
9576
+ }
9577
+ ) }),
9578
+ mediaQuery.size1000 && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Button_default.icon, { icon: "XMark", marginLeft: "auto", onClick: onClickXButton })
9579
+ ] }),
9580
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Div_default.column, { gap: theme2.styles.gap / 2, children: readyItems.map((item) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(MenuItemComponent, { item, onClick: onClickXButton }, item.text)) }),
9581
+ collapsable && !mediaQuery.size1000 && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
9582
+ Div_default.row,
9583
+ {
9584
+ alignItems: "center",
9585
+ justifyContent: "center",
9586
+ backgroundColor: theme2.colors.backgroundBase,
9587
+ borderRadius: theme2.styles.borderRadius,
9588
+ marginTop: "auto",
9589
+ cursor: "pointer",
9590
+ filterHover: filterHover().z1,
9591
+ paddingBlock: theme2.styles.gap,
9592
+ isTabAccessed: true,
9593
+ onClick: setSideMenuIsCollapsed.toggle,
9594
+ children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
9595
+ Icon_default,
9596
+ {
9597
+ name: "chevronRight",
9598
+ size: 20,
9599
+ color: theme2.colors.textSecondary,
9600
+ transform: `rotate(${isCollapsed ? 0 : 180}deg)`,
9601
+ transition: theme2.styles.transition
9602
+ }
9603
+ )
9604
+ }
9605
+ )
9606
+ ] }),
9607
+ widthMobileHandle && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
9608
+ Div_default.row,
9609
+ {
9610
+ position: "absolute",
9611
+ top: theme2.styles.space,
9612
+ left: "100%",
9613
+ backgroundColor: theme2.colors.backgroundBase,
9614
+ border: `solid 1px ${theme2.colors.border}`,
9615
+ borderLeft: "none",
9616
+ borderTopRightRadius: theme2.styles.borderRadius,
9617
+ borderBottomRightRadius: theme2.styles.borderRadius,
9618
+ alignItems: "center",
9619
+ cursor: "pointer",
9620
+ opacity: !mediaQuery.size1000 ? 0 : void 0,
9621
+ pointerEvents: !mediaQuery.size1000 ? "none" : void 0,
9622
+ padding: theme2.styles.gap,
9623
+ paddingRight: (theme2.styles.space + theme2.styles.gap) / 2,
9624
+ transform: !mediaQuery.size1000 ? "translateX(-100%)" : void 0,
9625
+ transition: theme2.styles.transition,
9626
+ onClick: setSideMenuIsOpenMobile.toggle,
9627
+ children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
9628
+ Icon_default,
9629
+ {
9630
+ name: "chevronRight",
9631
+ size: 20,
9632
+ color: theme2.colors.textSecondary,
9633
+ transform: sideMenuIsOpenMobile ? "rotate(180deg)" : void 0,
9634
+ transition: theme2.styles.transition
9635
+ }
9636
+ )
9637
+ }
9638
+ )
9639
+ ]
9640
+ }
9641
+ );
9642
+ };
9643
+ SideMenuComponent.pageHolder = function SideMenuPageHolder({ outsideComponent, ...props }) {
9644
+ const theme2 = useTheme();
9645
+ const mediaQuery = useMediaQuery();
9646
+ const { components, sideMenuIsCollapsed } = useBetterHtmlContextInternal();
9647
+ const sideMenuWidth = components.sideMenu?.width ?? defaultSideMenuWidth;
9648
+ const sideMenuCollapsedWidth = theme2.styles.space + theme2.styles.space * 2 + 16 + 1 + theme2.styles.space;
9649
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
9650
+ Div_default,
9651
+ {
9652
+ position: "relative",
9653
+ width: "100%",
9654
+ paddingLeft: !mediaQuery.size1000 ? !sideMenuIsCollapsed ? sideMenuWidth : sideMenuCollapsedWidth : void 0,
9655
+ transition: theme2.styles.transition,
9656
+ children: [
9657
+ outsideComponent,
9658
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(PageHolder_default, { ...props })
9659
+ ]
9660
+ }
9661
+ );
9662
+ };
9663
+ var SideMenu2 = (0, import_react29.memo)(SideMenuComponent);
9664
+ SideMenu2.pageHolder = SideMenuComponent.pageHolder;
9665
+ var SideMenu_default = SideMenu2;
9666
+
9334
9667
  // src/utils/localStorage.ts
9335
9668
  function generateLocalStorage() {
9336
9669
  return {
@@ -9415,6 +9748,7 @@ function generateLocalStorage() {
9415
9748
  Modal,
9416
9749
  PageHeader,
9417
9750
  PageHolder,
9751
+ SideMenu,
9418
9752
  Table,
9419
9753
  Tabs,
9420
9754
  Text,
@@ -9444,6 +9778,7 @@ function generateLocalStorage() {
9444
9778
  localStoragePlugin,
9445
9779
  reactRouterDomPlugin,
9446
9780
  saturateColor,
9781
+ sideMenuControls,
9447
9782
  useAlertControls,
9448
9783
  useBetterHtmlContext,
9449
9784
  useBooleanState,