@alextheman/components 7.0.1 → 7.0.3

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.
@@ -92,7 +92,7 @@ interface QueryBoundaryErrorProps {
92
92
  declare function QueryBoundaryError({
93
93
  children,
94
94
  logError
95
- }: QueryBoundaryErrorProps): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | import("react/jsx-runtime").JSX.Element | null | undefined;
95
+ }: QueryBoundaryErrorProps): string | number | bigint | boolean | import("react/jsx-runtime").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | null | undefined;
96
96
  //#endregion
97
97
  //#region src/QueryBoundary/QueryBoundaryNullable.d.ts
98
98
  interface QueryBoundaryNullablePropsWithUndefinedOrNull {
@@ -0,0 +1,95 @@
1
+ import { createFormHook as createFormHook$1 } from "@tanstack/react-form";
2
+ import { ButtonProps } from "@mui/material/Button";
3
+ import { TextFieldProps } from "@mui/material/TextField";
4
+ import { ComponentType } from "react";
5
+
6
+ //#region src/form/createFormHook.d.ts
7
+ interface AlexFieldComponents {
8
+ TextField: typeof TextField;
9
+ }
10
+ interface AlexFormComponents {
11
+ SubmitButton: typeof SubmitButton;
12
+ }
13
+ /** Create the hooks for your app form with `@tanstack/react-form` using our default configuration. */
14
+ declare function createFormHook<FieldComponents extends Record<string, ComponentType<any>> = Record<string, never>, FormComponents extends Record<string, ComponentType<any>> = Record<string, never>>(options?: Partial<Omit<Parameters<typeof createFormHook$1>[0], "formComponents" | "fieldComponents"> & {
15
+ fieldComponents?: FieldComponents;
16
+ formComponents?: FormComponents;
17
+ }>): ReturnType<typeof createFormHook$1<AlexFieldComponents & FieldComponents, AlexFormComponents & FormComponents>>;
18
+ //#endregion
19
+ //#region src/form/SubmitButton.d.ts
20
+ interface SubmitButtonProps extends Omit<ButtonProps, "type"> {
21
+ /** An option to disable the button on submit if the form is not dirty. */
22
+ disableClean?: boolean;
23
+ /** The label for the button. */
24
+ label?: string;
25
+ }
26
+ /**
27
+ * A Submit Button for use with TanStack Form's app form pattern. Must be used in a `<form.AppForm />` context.
28
+ *
29
+ * This should be initialised in your app form in the following way:
30
+ *
31
+ * ```typescript
32
+ * const { useAppForm } = createFormHook({
33
+ * fieldContext,
34
+ * formContext,
35
+ * formComponents: {
36
+ * SubmitButton,
37
+ * },
38
+ * });
39
+ * ```
40
+ * And then used as such:
41
+ *
42
+ * ```tsx
43
+ * <form.AppField>
44
+ * ...
45
+ * </form.AppField>
46
+ * <form.AppForm>
47
+ * <form.SubmitButton />
48
+ * </form.AppForm>
49
+ * ```
50
+ */
51
+ declare function SubmitButton({
52
+ disableClean,
53
+ label,
54
+ ...buttonProps
55
+ }: SubmitButtonProps): import("react/jsx-runtime").JSX.Element;
56
+ //#endregion
57
+ //#region src/form/TextField.d.ts
58
+ /**
59
+ * A text field component for use with TanStack Form's app form pattern. Must be used in a `<form.AppField />` context.
60
+ *
61
+ * This should be initialised in your app form in the following way:
62
+ *
63
+ * ```typescript
64
+ * const { useAppForm } = createFormHook({
65
+ * fieldContext,
66
+ * formContext,
67
+ * fieldComponents: {
68
+ * TextField,
69
+ * },
70
+ * });
71
+ * ```
72
+ * And then used as such:
73
+ *
74
+ * ```tsx
75
+ * <form.AppField name="firstName">
76
+ * {(field) => {
77
+ * return <field.TextField />
78
+ * }}
79
+ * </form.AppField>
80
+ * <form.AppForm>
81
+ * <form.SubmitButton />
82
+ * </form.AppForm>
83
+ * ```
84
+ */
85
+ declare function TextField({
86
+ label,
87
+ type,
88
+ ...props
89
+ }: TextFieldProps): import("react/jsx-runtime").JSX.Element;
90
+ //#endregion
91
+ //#region src/form/formHooks.d.ts
92
+ declare const fieldContext: import("react").Context<import("@tanstack/react-form").AnyFieldApi>, formContext: import("react").Context<import("@tanstack/react-form").AnyFormApi>, useFieldContext: <TData>() => import("@tanstack/react-form").FieldApi<any, string, TData, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any>, useFormContext: () => import("@tanstack/react-form").ReactFormExtendedApi<Record<string, never>, any, any, any, any, any, any, any, any, any, any, any>;
93
+ //#endregion
94
+ export { SubmitButton, type SubmitButtonProps, TextField, createFormHook, fieldContext, formContext, useFieldContext, useFormContext };
95
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,2 @@
1
+ import{omitProperties as e}from"@alextheman/utility";import{createFormHook as t,createFormHookContexts as n}from"@tanstack/react-form";import r from"@mui/material/Button";import{jsx as i}from"react/jsx-runtime";import a from"@mui/material/TextField";const{fieldContext:o,formContext:s,useFieldContext:c,useFormContext:l}=n();function u(n){return t({fieldContext:o,formContext:s,fieldComponents:{TextField:f,...n?.fieldComponents},formComponents:{SubmitButton:d,...n?.formComponents},...e(n??{},[`formComponents`,`fieldComponents`])})}function d({disableClean:e,label:t=`Submit`,...n}){let a=l();return i(r,{color:`primary`,disabled:n.disabled||e&&!a.state.isDirty,loading:a.state.isSubmitting,type:`submit`,variant:`contained`,...n,children:t})}function f({label:e,type:t,...n}){let r=c();return i(a,{...n,label:e,error:r.state.meta.errors.length!==0,type:t??`text`,value:r.state.value,onChange:e=>r.handleChange(e.target.value),onBlur:r.handleBlur,placeholder:typeof e==`string`?e:r.name,helperText:r.state.meta.errors[0]??``})}export{d as SubmitButton,f as TextField,u as createFormHook,o as fieldContext,s as formContext,c as useFieldContext,l as useFormContext};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["createTanstackFormHook"],"sources":["../../src/form/formHooks.ts","../../src/form/createFormHook.ts","../../src/form/SubmitButton.tsx","../../src/form/TextField.tsx"],"sourcesContent":["import { createFormHookContexts } from \"@tanstack/react-form\";\n\nexport const { fieldContext, formContext, useFieldContext, useFormContext } =\n createFormHookContexts();\n","import type { ComponentType } from \"react\";\n\nimport { omitProperties } from \"@alextheman/utility\";\nimport { createFormHook as createTanstackFormHook } from \"@tanstack/react-form\";\n\nimport { SubmitButton, TextField } from \"src/form\";\nimport { fieldContext, formContext } from \"src/form/formHooks\";\n\nexport interface AlexFieldComponents {\n TextField: typeof TextField;\n}\n\nexport interface AlexFormComponents {\n SubmitButton: typeof SubmitButton;\n}\n\n/** Create the hooks for your app form with `@tanstack/react-form` using our default configuration. */\nfunction createFormHook<\n FieldComponents extends Record<string, ComponentType<any>> = Record<string, never>,\n FormComponents extends Record<string, ComponentType<any>> = Record<string, never>,\n>(\n options?: Partial<\n Omit<Parameters<typeof createTanstackFormHook>[0], \"formComponents\" | \"fieldComponents\"> & {\n fieldComponents?: FieldComponents;\n formComponents?: FormComponents;\n }\n >,\n): ReturnType<\n typeof createTanstackFormHook<\n AlexFieldComponents & FieldComponents,\n AlexFormComponents & FormComponents\n >\n> {\n return createTanstackFormHook({\n fieldContext,\n formContext,\n fieldComponents: {\n TextField,\n ...options?.fieldComponents,\n } as AlexFieldComponents & FieldComponents,\n formComponents: {\n SubmitButton,\n ...options?.formComponents,\n } as AlexFormComponents & FormComponents,\n ...omitProperties(options ?? {}, [\"formComponents\", \"fieldComponents\"]),\n });\n}\n\nexport default createFormHook;\n","import type { ButtonProps } from \"@mui/material/Button\";\n\nimport Button from \"@mui/material/Button\";\n\nimport { useFormContext } from \"src/form/formHooks\";\n\nexport interface SubmitButtonProps extends Omit<ButtonProps, \"type\"> {\n /** An option to disable the button on submit if the form is not dirty. */\n disableClean?: boolean;\n /** The label for the button. */\n label?: string;\n}\n\n/**\n * A Submit Button for use with TanStack Form's app form pattern. Must be used in a `<form.AppForm />` context.\n *\n * This should be initialised in your app form in the following way:\n *\n * ```typescript\n * const { useAppForm } = createFormHook({\n * fieldContext,\n * formContext,\n * formComponents: {\n * SubmitButton,\n * },\n * });\n * ```\n * And then used as such:\n *\n * ```tsx\n * <form.AppField>\n * ...\n * </form.AppField>\n * <form.AppForm>\n * <form.SubmitButton />\n * </form.AppForm>\n * ```\n */\nfunction SubmitButton({ disableClean, label = \"Submit\", ...buttonProps }: SubmitButtonProps) {\n const form = useFormContext();\n\n return (\n <Button\n color=\"primary\"\n disabled={buttonProps.disabled || (disableClean && !form.state.isDirty)}\n loading={form.state.isSubmitting}\n type=\"submit\"\n variant=\"contained\"\n {...buttonProps}\n >\n {label}\n </Button>\n );\n}\n\nexport default SubmitButton;\n","import type { TextFieldProps as MUITextFieldProps } from \"@mui/material/TextField\";\n\nimport MUITextField from \"@mui/material/TextField\";\n\nimport { useFieldContext } from \"src/form/formHooks\";\n\n/**\n * A text field component for use with TanStack Form's app form pattern. Must be used in a `<form.AppField />` context.\n *\n * This should be initialised in your app form in the following way:\n *\n * ```typescript\n * const { useAppForm } = createFormHook({\n * fieldContext,\n * formContext,\n * fieldComponents: {\n * TextField,\n * },\n * });\n * ```\n * And then used as such:\n *\n * ```tsx\n * <form.AppField name=\"firstName\">\n * {(field) => {\n * return <field.TextField />\n * }}\n * </form.AppField>\n * <form.AppForm>\n * <form.SubmitButton />\n * </form.AppForm>\n * ```\n */\nfunction TextField({ label, type, ...props }: MUITextFieldProps) {\n const field = useFieldContext();\n\n return (\n <MUITextField\n {...props}\n label={label}\n error={field.state.meta.errors.length !== 0}\n type={type ?? \"text\"}\n value={field.state.value}\n onChange={(event) => {\n return field.handleChange(event.target.value);\n }}\n onBlur={field.handleBlur}\n placeholder={typeof label === \"string\" ? label : field.name}\n helperText={field.state.meta.errors[0] ?? \"\"}\n />\n );\n}\n\nexport default TextField;\n"],"mappings":"0PAEA,KAAa,CAAE,eAAc,cAAa,kBAAiB,kBACzD,EAAuB,ECczB,SAAS,EAIP,EAWA,CACA,OAAOA,EAAuB,CAC5B,eACA,cACA,gBAAiB,CACf,YACA,GAAG,GAAS,eACd,EACA,eAAgB,CACd,eACA,GAAG,GAAS,cACd,EACA,GAAG,EAAe,GAAW,CAAC,EAAG,CAAC,iBAAkB,iBAAiB,CAAC,CACxE,CAAC,CACH,CCRA,SAAS,EAAa,CAAE,eAAc,QAAQ,SAAU,GAAG,GAAkC,CAC3F,IAAM,EAAO,EAAe,EAE5B,OACE,EAAC,EAAD,CACE,MAAM,UACN,SAAU,EAAY,UAAa,GAAgB,CAAC,EAAK,MAAM,QAC/D,QAAS,EAAK,MAAM,aACpB,KAAK,SACL,QAAQ,YACR,GAAI,WAEH,CACK,CAAA,CAEZ,CCpBA,SAAS,EAAU,CAAE,QAAO,OAAM,GAAG,GAA4B,CAC/D,IAAM,EAAQ,EAAgB,EAE9B,OACE,EAAC,EAAD,CACE,GAAI,EACG,QACP,MAAO,EAAM,MAAM,KAAK,OAAO,SAAW,EAC1C,KAAM,GAAQ,OACd,MAAO,EAAM,MAAM,MACnB,SAAW,GACF,EAAM,aAAa,EAAM,OAAO,KAAK,EAE9C,OAAQ,EAAM,WACd,YAAa,OAAO,GAAU,SAAW,EAAQ,EAAM,KACvD,WAAY,EAAM,MAAM,KAAK,OAAO,IAAM,EAC3C,CAAA,CAEL"}
@@ -32,5 +32,9 @@ declare function ThemeProvider({
32
32
  themeOptions
33
33
  }: ThemeProviderProps): import("react/jsx-runtime").JSX.Element;
34
34
  //#endregion
35
- export { type ThemeContextValue, ThemeProvider, type ThemeProviderProps, useThemeContext };
35
+ //#region src/theme/ThemeToggle.d.ts
36
+ /** A toggle to switch between dark mode and light mode. Must be used in a `ThemeProvider`. */
37
+ declare function ThemeToggle(): import("react/jsx-runtime").JSX.Element;
38
+ //#endregion
39
+ export { type ThemeContextValue, ThemeProvider, type ThemeProviderProps, ThemeToggle, useThemeContext };
36
40
  //# sourceMappingURL=index.d.ts.map
@@ -1,2 +1,2 @@
1
- import{omitProperties as e}from"@alextheman/utility";import{DataError as t}from"@alextheman/utility/v6";import n from"@mui/material/CssBaseline";import{ThemeProvider as r,createTheme as i}from"@mui/material/styles";import{createContext as a,use as o,useMemo as s,useState as c}from"react";import{jsx as l,jsxs as u}from"react/jsx-runtime";const d=a(void 0);function f({strict:e=!0}={}){let n=o(d);if(e&&!n)throw new t({strict:e,context:n},`MODE_PROVIDER_NOT_FOUND`,`Could not find the ModeProvider context. Please double-check that it is present.`);return n}function p({children:t,mode:a=`dark`,themeOptions:o}){let[f,p]=c(a),m=s(()=>i({palette:{mode:f,...e(o?.palette??{},[`mode`])},components:{MuiPaper:{styleOverrides:{root:({theme:e})=>({border:1,borderStyle:`solid`,borderColor:e.palette.divider}),...o?.components?.MuiPaper?.styleOverrides},...e(o?.components?.MuiPaper??{},`styleOverrides`)},...e(o?.components??{},`MuiPaper`)},...e(o??{},[`components`,`palette`])}),[f,o]);return l(d,{value:{mode:f,toggleMode:()=>{p(e=>e===`light`?`dark`:`light`)}},children:u(r,{theme:m,children:[l(n,{}),t]})})}export{p as ThemeProvider,f as useThemeContext};
1
+ import{omitProperties as e}from"@alextheman/utility";import{DataError as t}from"@alextheman/utility/v6";import n from"@mui/material/CssBaseline";import{ThemeProvider as r,createTheme as i,styled as a}from"@mui/material/styles";import{createContext as o,use as s,useMemo as c,useState as l}from"react";import{jsx as u,jsxs as d}from"react/jsx-runtime";import f from"@mui/material/Tooltip";import{MdOutlineDarkMode as p,MdOutlineLightMode as m}from"react-icons/md";import h from"@mui/material/Box";import g from"@mui/material/Switch";const _=o(void 0);function v({strict:e=!0}={}){let n=s(_);if(e&&!n)throw new t({strict:e,context:n},`MODE_PROVIDER_NOT_FOUND`,`Could not find the ModeProvider context. Please double-check that it is present.`);return n}function y({children:t,mode:a=`dark`,themeOptions:o}){let[s,f]=l(a),p=c(()=>i({palette:{mode:s,...e(o?.palette??{},[`mode`])},components:{MuiPaper:{styleOverrides:{root:({theme:e})=>({border:1,borderStyle:`solid`,borderColor:e.palette.divider}),...o?.components?.MuiPaper?.styleOverrides},...e(o?.components?.MuiPaper??{},`styleOverrides`)},...e(o?.components??{},`MuiPaper`)},...e(o??{},[`components`,`palette`])}),[s,o]);return u(_,{value:{mode:s,toggleMode:()=>{f(e=>e===`light`?`dark`:`light`)}},children:d(r,{theme:p,children:[u(n,{}),t]})})}const b=a(g)(()=>({padding:8,"& .MuiSwitch-track":{borderRadius:11,"&::before, &::after":{content:`""`,position:`absolute`,top:`50%`,transform:`translateY(-50%)`,fontSize:16,width:28,height:28}}}));function x({checkedIcon:e,checkedIconStyles:t,uncheckedIcon:n,uncheckedIconStyles:r,...i}){let a={borderRadius:`50%`,borderColor:`white`,backgroundColor:`white`,display:`flex`,alignItems:`center`,justifyContent:`center`,padding:.25},o={color:`black`,maxWidth:16.5,maxHeight:16.5};return u(b,{checkedIcon:u(h,{sx:a,children:u(e,{style:{...o,...t}})}),icon:u(h,{sx:a,children:u(n,{style:{...o,...r}})}),...i})}function S(){let{mode:e,toggleMode:t}=v(),n=e===`dark`,r=`Enable ${n?`light`:`dark`} mode`;return u(f,{title:r,children:u(x,{uncheckedIcon:m,checkedIcon:p,checked:n,onChange:t,"aria-label":r})})}export{y as ThemeProvider,S as ThemeToggle,v as useThemeContext};
2
2
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["MuiThemeProvider"],"sources":["../../src/theme/ThemeProvider.tsx"],"sourcesContent":["import type { OptionalOnCondition } from \"@alextheman/utility\";\nimport type { PaletteMode, ThemeOptions } from \"@mui/material/styles\";\nimport type { ReactNode } from \"react\";\n\nimport type { ContextHookOptions } from \"src/root/types\";\n\nimport { omitProperties } from \"@alextheman/utility\";\nimport { DataError } from \"@alextheman/utility/v6\";\nimport CssBaseline from \"@mui/material/CssBaseline\";\nimport { createTheme, ThemeProvider as MuiThemeProvider } from \"@mui/material/styles\";\nimport { createContext, use, useMemo, useState } from \"react\";\n\nexport interface ThemeContextValue {\n toggleMode: () => void;\n mode: PaletteMode;\n}\n\nconst ThemeContext = createContext<ThemeContextValue | undefined>(undefined);\n\n/** Access the mode context directly. */\nexport function useThemeContext<Strict extends boolean = true>({\n strict = true as Strict,\n}: ContextHookOptions<Strict> = {}): OptionalOnCondition<Strict, ThemeContextValue> {\n const context = use(ThemeContext);\n if (strict && !context) {\n throw new DataError(\n { strict, context },\n \"MODE_PROVIDER_NOT_FOUND\",\n \"Could not find the ModeProvider context. Please double-check that it is present.\",\n );\n }\n return context as OptionalOnCondition<Strict, ThemeContextValue>;\n}\n\nexport interface ThemeProviderProps {\n /** The children that will have access to the current mode. */\n children: ReactNode;\n /** The initial mode. */\n mode?: PaletteMode;\n /** Extra options to apply on top of our default theme options */\n themeOptions?: ThemeOptions;\n}\n\n/** Provides information about the current theme mode to its children components. */\nfunction ThemeProvider({ children, mode: modeProp = \"dark\", themeOptions }: ThemeProviderProps) {\n const [mode, setMode] = useState<PaletteMode>(modeProp);\n\n const theme = useMemo(() => {\n return createTheme({\n palette: {\n mode,\n ...omitProperties(themeOptions?.palette ?? {}, [\"mode\"]),\n },\n components: {\n MuiPaper: {\n styleOverrides: {\n root: ({ theme }) => {\n return {\n border: 1,\n borderStyle: \"solid\",\n borderColor: theme.palette.divider,\n };\n },\n ...themeOptions?.components?.MuiPaper?.styleOverrides,\n },\n ...omitProperties(themeOptions?.components?.MuiPaper ?? {}, \"styleOverrides\"),\n },\n ...omitProperties(themeOptions?.components ?? {}, \"MuiPaper\"),\n },\n ...omitProperties(themeOptions ?? {}, [\"components\", \"palette\"]),\n });\n }, [mode, themeOptions]);\n\n return (\n <ThemeContext\n value={{\n mode,\n toggleMode: () => {\n setMode((prev) => {\n return prev === \"light\" ? \"dark\" : \"light\";\n });\n },\n }}\n >\n <MuiThemeProvider theme={theme}>\n <CssBaseline />\n {children}\n </MuiThemeProvider>\n </ThemeContext>\n );\n}\n\nexport default ThemeProvider;\n"],"mappings":"mVAiBA,MAAM,EAAe,EAA6C,IAAA,EAAS,EAG3E,SAAgB,EAA+C,CAC7D,SAAS,IACqB,CAAC,EAAmD,CAClF,IAAM,EAAU,EAAI,CAAY,EAChC,GAAI,GAAU,CAAC,EACb,MAAM,IAAI,EACR,CAAE,SAAQ,SAAQ,EAClB,0BACA,kFACF,EAEF,OAAO,CACT,CAYA,SAAS,EAAc,CAAE,WAAU,KAAM,EAAW,OAAQ,gBAAoC,CAC9F,GAAM,CAAC,EAAM,GAAW,EAAsB,CAAQ,EAEhD,EAAQ,MACL,EAAY,CACjB,QAAS,CACP,OACA,GAAG,EAAe,GAAc,SAAW,CAAC,EAAG,CAAC,MAAM,CAAC,CACzD,EACA,WAAY,CACV,SAAU,CACR,eAAgB,CACd,MAAO,CAAE,YACA,CACL,OAAQ,EACR,YAAa,QACb,YAAa,EAAM,QAAQ,OAC7B,GAEF,GAAG,GAAc,YAAY,UAAU,cACzC,EACA,GAAG,EAAe,GAAc,YAAY,UAAY,CAAC,EAAG,gBAAgB,CAC9E,EACA,GAAG,EAAe,GAAc,YAAc,CAAC,EAAG,UAAU,CAC9D,EACA,GAAG,EAAe,GAAgB,CAAC,EAAG,CAAC,aAAc,SAAS,CAAC,CACjE,CAAC,EACA,CAAC,EAAM,CAAY,CAAC,EAEvB,OACE,EAAC,EAAD,CACE,MAAO,CACL,OACA,eAAkB,CAChB,EAAS,GACA,IAAS,QAAU,OAAS,OACpC,CACH,CACF,WAEA,EAACA,EAAD,CAAyB,iBAAzB,CACE,EAAC,EAAD,CAAc,CAAA,EACb,CACe,GACN,CAAA,CAElB"}
1
+ {"version":3,"file":"index.js","names":["MuiThemeProvider"],"sources":["../../src/theme/ThemeProvider.tsx","../../src/root/components/SwitchWithIcons.tsx","../../src/theme/ThemeToggle.tsx"],"sourcesContent":["import type { OptionalOnCondition } from \"@alextheman/utility\";\nimport type { PaletteMode, ThemeOptions } from \"@mui/material/styles\";\nimport type { ReactNode } from \"react\";\n\nimport type { ContextHookOptions } from \"src/root/types\";\n\nimport { omitProperties } from \"@alextheman/utility\";\nimport { DataError } from \"@alextheman/utility/v6\";\nimport CssBaseline from \"@mui/material/CssBaseline\";\nimport { createTheme, ThemeProvider as MuiThemeProvider } from \"@mui/material/styles\";\nimport { createContext, use, useMemo, useState } from \"react\";\n\nexport interface ThemeContextValue {\n toggleMode: () => void;\n mode: PaletteMode;\n}\n\nconst ThemeContext = createContext<ThemeContextValue | undefined>(undefined);\n\n/** Access the mode context directly. */\nexport function useThemeContext<Strict extends boolean = true>({\n strict = true as Strict,\n}: ContextHookOptions<Strict> = {}): OptionalOnCondition<Strict, ThemeContextValue> {\n const context = use(ThemeContext);\n if (strict && !context) {\n throw new DataError(\n { strict, context },\n \"MODE_PROVIDER_NOT_FOUND\",\n \"Could not find the ModeProvider context. Please double-check that it is present.\",\n );\n }\n return context as OptionalOnCondition<Strict, ThemeContextValue>;\n}\n\nexport interface ThemeProviderProps {\n /** The children that will have access to the current mode. */\n children: ReactNode;\n /** The initial mode. */\n mode?: PaletteMode;\n /** Extra options to apply on top of our default theme options */\n themeOptions?: ThemeOptions;\n}\n\n/** Provides information about the current theme mode to its children components. */\nfunction ThemeProvider({ children, mode: modeProp = \"dark\", themeOptions }: ThemeProviderProps) {\n const [mode, setMode] = useState<PaletteMode>(modeProp);\n\n const theme = useMemo(() => {\n return createTheme({\n palette: {\n mode,\n ...omitProperties(themeOptions?.palette ?? {}, [\"mode\"]),\n },\n components: {\n MuiPaper: {\n styleOverrides: {\n root: ({ theme }) => {\n return {\n border: 1,\n borderStyle: \"solid\",\n borderColor: theme.palette.divider,\n };\n },\n ...themeOptions?.components?.MuiPaper?.styleOverrides,\n },\n ...omitProperties(themeOptions?.components?.MuiPaper ?? {}, \"styleOverrides\"),\n },\n ...omitProperties(themeOptions?.components ?? {}, \"MuiPaper\"),\n },\n ...omitProperties(themeOptions ?? {}, [\"components\", \"palette\"]),\n });\n }, [mode, themeOptions]);\n\n return (\n <ThemeContext\n value={{\n mode,\n toggleMode: () => {\n setMode((prev) => {\n return prev === \"light\" ? \"dark\" : \"light\";\n });\n },\n }}\n >\n <MuiThemeProvider theme={theme}>\n <CssBaseline />\n {children}\n </MuiThemeProvider>\n </ThemeContext>\n );\n}\n\nexport default ThemeProvider;\n","import type { CommonProps } from \"@mui/material/OverridableComponent\";\nimport type { SwitchProps } from \"@mui/material/Switch\";\nimport type { ComponentType, CSSProperties } from \"react\";\n\nimport Box from \"@mui/material/Box\";\nimport { styled } from \"@mui/material/styles\";\nimport Switch from \"@mui/material/Switch\";\n\nexport interface SwitchWithIconsProps extends Omit<SwitchProps, \"icon\" | \"checkedIcon\"> {\n /** The icon to show when the switch is in a checked state. */\n checkedIcon: ComponentType<{ style?: CSSProperties }>;\n /** Additional styling to apply to the icon that shows when checked. */\n checkedIconStyles?: CommonProps[\"style\"];\n /** The icon to show when the switch is in an unchecked state. */\n uncheckedIcon: ComponentType<{ style?: CSSProperties }>;\n /** Additional styling to apply to the icon that shows when unchecked. */\n uncheckedIconStyles?: CommonProps[\"style\"];\n}\n\nconst StyledSwitch = styled(Switch)(() => {\n return {\n padding: 8,\n \"& .MuiSwitch-track\": {\n borderRadius: 11,\n \"&::before, &::after\": {\n content: '\"\"',\n position: \"absolute\",\n top: \"50%\",\n transform: \"translateY(-50%)\",\n fontSize: 16,\n width: 28,\n height: 28,\n },\n },\n };\n});\n\n/** Renders a switch with your provided icons. */\nfunction SwitchWithIcons({\n checkedIcon: CheckedIcon,\n checkedIconStyles,\n uncheckedIcon: UncheckedIcon,\n uncheckedIconStyles,\n ...switchProps\n}: SwitchWithIconsProps) {\n const boxSx = {\n borderRadius: \"50%\",\n borderColor: \"white\",\n backgroundColor: \"white\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: 0.25,\n };\n const defaultIconStyles = { color: \"black\", maxWidth: 16.5, maxHeight: 16.5 };\n return (\n <StyledSwitch\n checkedIcon={\n <Box sx={boxSx}>\n <CheckedIcon style={{ ...defaultIconStyles, ...checkedIconStyles }} />\n </Box>\n }\n icon={\n <Box sx={boxSx}>\n <UncheckedIcon style={{ ...defaultIconStyles, ...uncheckedIconStyles }} />\n </Box>\n }\n {...switchProps}\n />\n );\n}\n\nexport default SwitchWithIcons;\n","import Tooltip from \"@mui/material/Tooltip\";\nimport { MdOutlineDarkMode, MdOutlineLightMode } from \"react-icons/md\";\n\nimport SwitchWithIcons from \"src/root/components/SwitchWithIcons\";\nimport { useThemeContext } from \"src/theme/ThemeProvider\";\n\n/** A toggle to switch between dark mode and light mode. Must be used in a `ThemeProvider`. */\nfunction ThemeToggle() {\n const { mode, toggleMode } = useThemeContext();\n const isDarkMode = mode === \"dark\";\n const modeText = `Enable ${isDarkMode ? \"light\" : \"dark\"} mode`;\n\n return (\n <Tooltip title={modeText}>\n <SwitchWithIcons\n uncheckedIcon={MdOutlineLightMode}\n checkedIcon={MdOutlineDarkMode}\n checked={isDarkMode}\n onChange={toggleMode}\n aria-label={modeText}\n />\n </Tooltip>\n );\n}\n\nexport default ThemeToggle;\n"],"mappings":"ohBAiBA,MAAM,EAAe,EAA6C,IAAA,EAAS,EAG3E,SAAgB,EAA+C,CAC7D,SAAS,IACqB,CAAC,EAAmD,CAClF,IAAM,EAAU,EAAI,CAAY,EAChC,GAAI,GAAU,CAAC,EACb,MAAM,IAAI,EACR,CAAE,SAAQ,SAAQ,EAClB,0BACA,kFACF,EAEF,OAAO,CACT,CAYA,SAAS,EAAc,CAAE,WAAU,KAAM,EAAW,OAAQ,gBAAoC,CAC9F,GAAM,CAAC,EAAM,GAAW,EAAsB,CAAQ,EAEhD,EAAQ,MACL,EAAY,CACjB,QAAS,CACP,OACA,GAAG,EAAe,GAAc,SAAW,CAAC,EAAG,CAAC,MAAM,CAAC,CACzD,EACA,WAAY,CACV,SAAU,CACR,eAAgB,CACd,MAAO,CAAE,YACA,CACL,OAAQ,EACR,YAAa,QACb,YAAa,EAAM,QAAQ,OAC7B,GAEF,GAAG,GAAc,YAAY,UAAU,cACzC,EACA,GAAG,EAAe,GAAc,YAAY,UAAY,CAAC,EAAG,gBAAgB,CAC9E,EACA,GAAG,EAAe,GAAc,YAAc,CAAC,EAAG,UAAU,CAC9D,EACA,GAAG,EAAe,GAAgB,CAAC,EAAG,CAAC,aAAc,SAAS,CAAC,CACjE,CAAC,EACA,CAAC,EAAM,CAAY,CAAC,EAEvB,OACE,EAAC,EAAD,CACE,MAAO,CACL,OACA,eAAkB,CAChB,EAAS,GACA,IAAS,QAAU,OAAS,OACpC,CACH,CACF,WAEA,EAACA,EAAD,CAAyB,iBAAzB,CACE,EAAC,EAAD,CAAc,CAAA,EACb,CACe,GACN,CAAA,CAElB,CCvEA,MAAM,EAAe,EAAO,CAAM,OACzB,CACL,QAAS,EACT,qBAAsB,CACpB,aAAc,GACd,sBAAuB,CACrB,QAAS,KACT,SAAU,WACV,IAAK,MACL,UAAW,mBACX,SAAU,GACV,MAAO,GACP,OAAQ,EACV,CACF,CACF,EACD,EAGD,SAAS,EAAgB,CACvB,YAAa,EACb,oBACA,cAAe,EACf,sBACA,GAAG,GACoB,CACvB,IAAM,EAAQ,CACZ,aAAc,MACd,YAAa,QACb,gBAAiB,QACjB,QAAS,OACT,WAAY,SACZ,eAAgB,SAChB,QAAS,GACX,EACM,EAAoB,CAAE,MAAO,QAAS,SAAU,KAAM,UAAW,IAAK,EAC5E,OACE,EAAC,EAAD,CACE,YACE,EAAC,EAAD,CAAK,GAAI,WACP,EAAC,EAAD,CAAa,MAAO,CAAE,GAAG,EAAmB,GAAG,CAAkB,CAAI,CAAA,CAClE,CAAA,EAEP,KACE,EAAC,EAAD,CAAK,GAAI,WACP,EAAC,EAAD,CAAe,MAAO,CAAE,GAAG,EAAmB,GAAG,CAAoB,CAAI,CAAA,CACtE,CAAA,EAEP,GAAI,CACL,CAAA,CAEL,CC/DA,SAAS,GAAc,CACrB,GAAM,CAAE,OAAM,cAAe,EAAgB,EACvC,EAAa,IAAS,OACtB,EAAW,UAAU,EAAa,QAAU,OAAO,OAEzD,OACE,EAAC,EAAD,CAAS,MAAO,WACd,EAAC,EAAD,CACE,cAAe,EACf,YAAa,EACb,QAAS,EACT,SAAU,EACV,aAAY,CACb,CAAA,CACM,CAAA,CAEb"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alextheman/components",
3
- "version": "7.0.1",
3
+ "version": "7.0.3",
4
4
  "description": "A package containing common React components used across my projects.",
5
5
  "repository": {
6
6
  "type": "git",