react-better-html 1.1.45 → 1.1.47

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.
@@ -38,30 +38,11 @@ const useBetterHtmlContext = () => {
38
38
  exports.useBetterHtmlContext = useBetterHtmlContext;
39
39
  const useTheme = () => {
40
40
  const context = (0, react_1.useContext)(betterHtmlContext);
41
- const [currentTheme, setCurrentTheme] = (0, react_1.useState)("light");
42
41
  if (context === undefined)
43
42
  throw new Error("`useTheme()` must be used within a `<BetterHtmlProvider>`. Make sure to add one at the root of your component tree.");
44
- (0, react_1.useEffect)(() => {
45
- const html = document.querySelector("html");
46
- if (!html)
47
- return;
48
- const observer = new MutationObserver((mutations) => {
49
- mutations.forEach((mutation) => {
50
- if (mutation.type === "attributes") {
51
- setCurrentTheme(html.getAttribute("data-theme"));
52
- }
53
- });
54
- });
55
- observer.observe(html, {
56
- attributes: true,
57
- });
58
- return () => {
59
- observer.disconnect();
60
- };
61
- }, []);
62
43
  return {
63
44
  ...context.theme,
64
- colors: context.theme.colors[currentTheme] ?? context.theme.colors.light,
45
+ colors: context.theme.colors[context.colorTheme] ?? context.theme.colors.light,
65
46
  };
66
47
  };
67
48
  exports.useTheme = useTheme;
@@ -109,6 +90,7 @@ function BetterHtmlProviderContent({ children }) {
109
90
  function BetterHtmlProvider({ value, plugins: pluginsToUse, children }) {
110
91
  const [loaders, setLoaders] = (0, react_1.useState)(value?.loaders ?? {});
111
92
  const [plugins] = (0, react_1.useState)(pluginsToUse ?? []);
93
+ const [colorTheme, setColorTheme] = (0, react_1.useState)(localStorage.getItem("theme") === "dark" ? "dark" : "light");
112
94
  const readyValue = (0, react_1.useMemo)(() => ({
113
95
  app: {
114
96
  ...app_1.appConfig,
@@ -130,6 +112,7 @@ function BetterHtmlProvider({ value, plugins: pluginsToUse, children }) {
130
112
  },
131
113
  },
132
114
  },
115
+ colorTheme,
133
116
  icons: {
134
117
  ...icons_1.icons,
135
118
  ...value?.icons,
@@ -144,12 +127,30 @@ function BetterHtmlProvider({ value, plugins: pluginsToUse, children }) {
144
127
  ...value?.components,
145
128
  },
146
129
  plugins,
147
- }), [value, loaders, plugins]);
130
+ }), [value, colorTheme, loaders, plugins]);
148
131
  (0, react_1.useEffect)(() => {
149
132
  plugins.forEach((plugin) => {
150
133
  plugin.initialize?.();
151
134
  });
152
135
  }, [plugins]);
136
+ (0, react_1.useEffect)(() => {
137
+ const html = document.querySelector("html");
138
+ if (!html)
139
+ return;
140
+ const observer = new MutationObserver((mutations) => {
141
+ mutations.forEach((mutation) => {
142
+ if (mutation.type === "attributes") {
143
+ setColorTheme(html.getAttribute("data-theme") === "dark" ? "dark" : "light");
144
+ }
145
+ });
146
+ });
147
+ observer.observe(html, {
148
+ attributes: true,
149
+ });
150
+ return () => {
151
+ observer.disconnect();
152
+ };
153
+ }, []);
153
154
  return ((0, jsx_runtime_1.jsx)(betterHtmlContext.Provider, { value: readyValue, children: (0, jsx_runtime_1.jsx)(BetterHtmlProviderContent, { children: children }) }));
154
155
  }
155
156
  exports.default = (0, react_1.memo)(BetterHtmlProvider);
@@ -0,0 +1,14 @@
1
+ import { ComponentMarginProps } from "../types/components";
2
+ type ColorThemeSwitchProps = {
3
+ withMoon?: boolean;
4
+ className?: string;
5
+ } & ComponentMarginProps;
6
+ type ColorThemeSwitchComponentType = {
7
+ (props: ColorThemeSwitchProps): React.ReactElement;
8
+ withText: (props: ColorThemeSwitchProps) => React.ReactElement;
9
+ };
10
+ declare const ColorThemeSwitchComponent: ColorThemeSwitchComponentType;
11
+ declare const ColorThemeSwitch: typeof ColorThemeSwitchComponent & {
12
+ withText: typeof ColorThemeSwitchComponent.withText;
13
+ };
14
+ export default ColorThemeSwitch;
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const jsx_runtime_1 = require("react/jsx-runtime");
7
+ const react_1 = require("react");
8
+ const hooks_1 = require("../utils/hooks");
9
+ const Div_1 = __importDefault(require("./Div"));
10
+ const Text_1 = __importDefault(require("./Text"));
11
+ const ToggleInput_1 = __importDefault(require("./ToggleInput"));
12
+ const BetterHtmlProvider_1 = require("./BetterHtmlProvider");
13
+ const ColorThemeSwitchComponent = function ColorThemeSwitch({ withMoon, className, ...props }) {
14
+ const form = (0, hooks_1.useForm)({
15
+ defaultValues: {
16
+ darkMode: localStorage.getItem("theme") === "dark",
17
+ },
18
+ });
19
+ (0, react_1.useEffect)(() => {
20
+ const timeout = setTimeout(() => {
21
+ window.document.body.parentElement?.setAttribute("data-theme", form.values.darkMode ? "dark" : "light");
22
+ localStorage.setItem("theme", form.values.darkMode ? "dark" : "light");
23
+ }, 0.2 * 1000);
24
+ return () => {
25
+ clearTimeout(timeout);
26
+ };
27
+ }, [form.values.darkMode]);
28
+ (0, react_1.useEffect)(() => {
29
+ const html = document.querySelector("html");
30
+ if (!html)
31
+ return;
32
+ const observer = new MutationObserver((mutations) => {
33
+ mutations.forEach((mutation) => {
34
+ if (mutation.type === "attributes") {
35
+ form.setFieldValue("darkMode", html.getAttribute("data-theme") === "dark");
36
+ }
37
+ });
38
+ });
39
+ observer.observe(html, {
40
+ attributes: true,
41
+ });
42
+ return () => {
43
+ observer.disconnect();
44
+ };
45
+ }, []);
46
+ return ((0, jsx_runtime_1.jsx)(ToggleInput_1.default.switch, { className: `react-better-html-color-theme-switch ${withMoon ? ` react-better-html-color-theme-switch-with-moon` : ""}${className ? ` ${className}` : ""}`, ...form.getSwitchProps("darkMode"), ...props }));
47
+ };
48
+ ColorThemeSwitchComponent.withText = function WithText({ withMoon, className, ...props }) {
49
+ const theme = (0, BetterHtmlProvider_1.useTheme)();
50
+ return ((0, jsx_runtime_1.jsxs)(Div_1.default.row, { width: "fit-content", alignItems: "center", gap: theme.styles.gap, userSelect: "none", ...props, children: [(0, jsx_runtime_1.jsx)(Text_1.default, { children: "Light" }), (0, jsx_runtime_1.jsx)(ColorThemeSwitchComponent, { withMoon: withMoon, className: className }), (0, jsx_runtime_1.jsx)(Text_1.default, { children: "Dark" })] }));
51
+ };
52
+ const ColorThemeSwitch = (0, react_1.memo)(ColorThemeSwitchComponent);
53
+ ColorThemeSwitch.withText = ColorThemeSwitchComponent.withText;
54
+ exports.default = ColorThemeSwitch;
@@ -53,6 +53,7 @@ const SwitchElement = styled_components_1.default.div.withConfig({
53
53
  shouldForwardProp: (prop) => !["theme", "checked", "disabled", "isMouseDown", "normalStyle", "hoverStyle"].includes(prop),
54
54
  }) `
55
55
  --width: ${(props) => componentSize * 2 - props.theme.styles.gap / 2}px;
56
+ --ball-size: ${componentSize - switchComponentBallGap * 2}px;
56
57
 
57
58
  position: relative;
58
59
  width: var(--width);
@@ -80,6 +81,27 @@ const SwitchElement = styled_components_1.default.div.withConfig({
80
81
  transition: ${(props) => props.theme.styles.transition};
81
82
  }
82
83
 
84
+ &.react-better-html-color-theme-switch-with-moon {
85
+ &::after {
86
+ content: "";
87
+ position: absolute;
88
+ width: ${(props) => componentSize -
89
+ switchComponentBallGap * 2 +
90
+ (props.isMouseDown ? switchComponentMouseDownDifference : 0)}px;
91
+ height: ${componentSize - switchComponentBallGap * 2}px;
92
+ background-color: ${(props) => (props.checked ? props.theme.colors.primary : "transparent")};
93
+ border-radius: 999px;
94
+ top: ${switchComponentBallGap}px;
95
+ left: ${switchComponentBallGap}px;
96
+ transform: translateX(
97
+ ${(props) => props.checked
98
+ ? `calc(var(--width) - ${componentSize + (props.isMouseDown ? switchComponentMouseDownDifference * 2 : 0)}px - calc(var(--ball-size) / 3))`
99
+ : "0px"}
100
+ );
101
+ transition: ${(props) => props.theme.styles.transition};
102
+ }
103
+ }
104
+
83
105
  ${(props) => props.normalStyle}
84
106
 
85
107
  &:hover {
package/dist/index.d.ts CHANGED
@@ -15,6 +15,7 @@ import ToggleInput from "./components/ToggleInput";
15
15
  import Form from "./components/Form";
16
16
  import Label from "./components/Label";
17
17
  import FormRow from "./components/FormRow";
18
+ import ColorThemeSwitch from "./components/ColorThemeSwitch";
18
19
  import BetterHtmlProvider, { useBetterHtmlContext, useTheme, useLoader, useLoaderControls } from "./components/BetterHtmlProvider";
19
20
  import { usePageResize, usePageScroll, useMediaQuery, useBooleanState, useDebounceState, useForm, useUrlQuery } from "./utils/hooks";
20
21
  import { generateRandomString, getBrowser, formatPhoneNumber, getFormErrorObject } from "./utils/functions";
@@ -28,4 +29,4 @@ import { type Color, type ColorName, type ColorTheme, type Colors, type Styles,
28
29
  import { type BrowserName } from "./types/other";
29
30
  import { isMobileDevice } from "./constants";
30
31
  export * from "./plugins";
31
- export { BetterHtmlProvider, Div, Text, Loader, Icon, Image, Button, Divider, Modal, ModalRef, PageHolder, PageHeader, Chip, InputField, Dropdown, DropdownOption, ToggleInput, Form, Label, FormRow, useBetterHtmlContext, useTheme, useLoader, useLoaderControls, usePageResize, usePageScroll, useMediaQuery, useBooleanState, useDebounceState, useForm, useUrlQuery, generateRandomString, getBrowser, formatPhoneNumber, getFormErrorObject, 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, };
32
+ export { BetterHtmlProvider, Div, Text, Loader, Icon, Image, Button, Divider, Modal, ModalRef, PageHolder, PageHeader, Chip, InputField, Dropdown, DropdownOption, ToggleInput, Form, Label, FormRow, ColorThemeSwitch, useBetterHtmlContext, useTheme, useLoader, useLoaderControls, usePageResize, usePageScroll, useMediaQuery, useBooleanState, useDebounceState, useForm, useUrlQuery, generateRandomString, getBrowser, formatPhoneNumber, getFormErrorObject, 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.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.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.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;
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"));
@@ -74,6 +74,8 @@ const Label_1 = __importDefault(require("./components/Label"));
74
74
  exports.Label = Label_1.default;
75
75
  const FormRow_1 = __importDefault(require("./components/FormRow"));
76
76
  exports.FormRow = FormRow_1.default;
77
+ const ColorThemeSwitch_1 = __importDefault(require("./components/ColorThemeSwitch"));
78
+ exports.ColorThemeSwitch = ColorThemeSwitch_1.default;
77
79
  const BetterHtmlProvider_1 = __importStar(require("./components/BetterHtmlProvider"));
78
80
  exports.BetterHtmlProvider = BetterHtmlProvider_1.default;
79
81
  Object.defineProperty(exports, "useBetterHtmlContext", { enumerable: true, get: function () { return BetterHtmlProvider_1.useBetterHtmlContext; } });
@@ -68,6 +68,7 @@ export declare function useForm<FormFields extends Record<string, string | numbe
68
68
  onSubmit: (event: React.FormEvent<HTMLFormElement>) => Promise<void>;
69
69
  reset: () => void;
70
70
  requiredFields: (keyof FormFields)[] | undefined;
71
+ isDirty: boolean;
71
72
  };
72
73
  export declare function useUrlQuery(): {
73
74
  setQuery: (query: Record<string, string>, keepHistory?: boolean) => void;
@@ -303,6 +303,7 @@ function useForm(options) {
303
303
  setValues(defaultValues);
304
304
  setErrors({});
305
305
  }, [defaultValues]);
306
+ const isDirty = (0, react_1.useMemo)(() => Object.keys(defaultValues).some((key) => defaultValues[key] !== values[key]), [defaultValues, values]);
306
307
  return {
307
308
  values,
308
309
  errors,
@@ -319,6 +320,7 @@ function useForm(options) {
319
320
  onSubmit: onSubmitFunction,
320
321
  reset,
321
322
  requiredFields,
323
+ isDirty,
322
324
  };
323
325
  }
324
326
  function useUrlQuery() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-better-html",
3
- "version": "1.1.45",
3
+ "version": "1.1.47",
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": [