@xyo-network/react-access-gate 7.0.0 → 7.0.2

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.
@@ -2,7 +2,7 @@ import type { Meta } from '@storybook/react-vite';
2
2
  import { AccessCodeGateFlexbox } from './AccessCodeGateFlexbox.tsx';
3
3
  declare const _default: Meta;
4
4
  export default _default;
5
- declare const Default: import("storybook/internal/csf").AnnotatedStoryFn<import("@storybook/react-vite").ReactRenderer, AccessCodeGateFlexbox>;
6
- declare const WithAccessCodes: import("storybook/internal/csf").AnnotatedStoryFn<import("@storybook/react-vite").ReactRenderer, AccessCodeGateFlexbox>;
5
+ declare const Default: import(".store/storybook-virtual-fa39dd25b7/package/internal/csf").AnnotatedStoryFn<import("@storybook/react-vite").ReactRenderer, AccessCodeGateFlexbox>;
6
+ declare const WithAccessCodes: import(".store/storybook-virtual-fa39dd25b7/package/internal/csf").AnnotatedStoryFn<import("@storybook/react-vite").ReactRenderer, AccessCodeGateFlexbox>;
7
7
  export { Default, WithAccessCodes };
8
8
  //# sourceMappingURL=AccessCodeGateFlexbox.stories.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AccessCodeGateFlexbox.stories.d.ts","sourceRoot":"","sources":["../../../src/components/AccessCodeGateFlexbox.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAW,MAAM,uBAAuB,CAAA;AAK1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAA;wBAO9D,IAAI;AAHT,wBAGS;AAkCT,QAAA,MAAM,OAAO,yHAAoB,CAAA;AACjC,QAAA,MAAM,eAAe,yHAAmC,CAAA;AAExD,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,CAAA"}
1
+ {"version":3,"file":"AccessCodeGateFlexbox.stories.d.ts","sourceRoot":"","sources":["../../../src/components/AccessCodeGateFlexbox.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAW,MAAM,uBAAuB,CAAA;AAK1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAA;wBAO9D,IAAI;AAHT,wBAGS;AAkCT,QAAA,MAAM,OAAO,2JAAoB,CAAA;AACjC,QAAA,MAAM,eAAe,2JAAmC,CAAA;AAExD,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"CodeTextField.d.ts","sourceRoot":"","sources":["../../../src/components/CodeTextField.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAInD,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,OAAO,CAAA;AACrD,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,MAAM,MAAM,kBAAkB,GAAG,cAAc,GAAG;IAChD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,YAAY,CAAC,EAAE,QAAQ,CAAC,cAAc,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC,CAAA;IAC3D,SAAS,CAAC,EAAE,OAAO,GAAG,IAAI,CAAA;CAC3B,CAAA;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA0BtD,CAAA"}
1
+ {"version":3,"file":"CodeTextField.d.ts","sourceRoot":"","sources":["../../../src/components/CodeTextField.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAInD,OAAO,KAAK,EACV,QAAQ,EAAiB,cAAc,EACxC,MAAM,OAAO,CAAA;AACd,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,MAAM,MAAM,kBAAkB,GAAG,cAAc,GAAG;IAChD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,YAAY,CAAC,EAAE,QAAQ,CAAC,cAAc,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC,CAAA;IAC3D,SAAS,CAAC,EAAE,OAAO,GAAG,IAAI,CAAA;CAC3B,CAAA;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA0BtD,CAAA"}
@@ -1,75 +1,79 @@
1
- var __defProp = Object.defineProperty;
2
- var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
-
4
1
  // src/components/AccessCodeGateFlexbox.tsx
5
2
  import { FormControl } from "@mui/material";
6
3
  import { ButtonEx } from "@xylabs/react-button";
7
4
  import { FlexGrowCol, FlexGrowRow } from "@xylabs/react-flexbox";
8
- import React2, { useCallback, useEffect, useState } from "react";
5
+ import {
6
+ useCallback,
7
+ useEffect,
8
+ useState
9
+ } from "react";
9
10
 
10
11
  // src/components/CodeTextField.tsx
11
12
  import { CheckCircleOutline, ErrorOutline } from "@mui/icons-material";
12
- import { InputAdornment, styled, TextField } from "@mui/material";
13
- import React from "react";
14
- var CodeTextField = /* @__PURE__ */ __name(({ codeInput, disabled, onEnter, setCodeInput, validCode, ...props }) => /* @__PURE__ */ React.createElement(StyledTextField, {
15
- InputProps: {
16
- endAdornment: /* @__PURE__ */ React.createElement(InputAdornment, {
17
- position: "start"
18
- }, /* @__PURE__ */ React.createElement(CheckCircleOutline, {
19
- sx: {
20
- display: validCode === null ? "block" : "hidden",
21
- visibility: "hidden"
22
- }
23
- }), /* @__PURE__ */ React.createElement(CheckCircleOutline, {
24
- color: "success",
25
- fontSize: "medium",
26
- sx: {
27
- position: "absolute",
28
- visibility: validCode === true ? "visible" : "hidden"
29
- }
30
- }), /* @__PURE__ */ React.createElement(ErrorOutline, {
31
- color: "error",
32
- fontSize: "medium",
33
- sx: {
34
- position: "absolute",
35
- visibility: validCode === false ? "visible" : "hidden"
36
- }
37
- }))
38
- },
39
- onKeyUp: /* @__PURE__ */ __name((event) => event.key === "Enter" && !disabled ? onEnter?.() : null, "onKeyUp"),
40
- autoFocus: true,
41
- size: "small",
42
- value: codeInput ?? "",
43
- onChange: /* @__PURE__ */ __name((event) => setCodeInput?.(event.target.value), "onChange"),
13
+ import {
14
+ InputAdornment,
15
+ styled,
16
+ TextField
17
+ } from "@mui/material";
18
+ import { jsx, jsxs } from "react/jsx-runtime";
19
+ var CodeTextField = ({
20
+ codeInput,
21
+ disabled,
22
+ onEnter,
23
+ setCodeInput,
24
+ validCode,
44
25
  ...props
45
- }), "CodeTextField");
46
- var StyledTextField = styled(TextField, {
47
- name: "StyledTextField"
48
- })(() => ({
49
- "& .MuiInputBase-root": {
50
- paddingRight: 0
26
+ }) => /* @__PURE__ */ jsx(
27
+ StyledTextField,
28
+ {
29
+ InputProps: {
30
+ endAdornment: /* @__PURE__ */ jsxs(InputAdornment, { position: "start", children: [
31
+ /* @__PURE__ */ jsx(CheckCircleOutline, { sx: { display: validCode === null ? "block" : "hidden", visibility: "hidden" } }),
32
+ /* @__PURE__ */ jsx(
33
+ CheckCircleOutline,
34
+ {
35
+ color: "success",
36
+ fontSize: "medium",
37
+ sx: { position: "absolute", visibility: validCode === true ? "visible" : "hidden" }
38
+ }
39
+ ),
40
+ /* @__PURE__ */ jsx(ErrorOutline, { color: "error", fontSize: "medium", sx: { position: "absolute", visibility: validCode === false ? "visible" : "hidden" } })
41
+ ] })
42
+ },
43
+ onKeyUp: (event) => event.key === "Enter" && !disabled ? onEnter?.() : null,
44
+ autoFocus: true,
45
+ size: "small",
46
+ value: codeInput ?? "",
47
+ onChange: (event) => setCodeInput?.(event.target.value),
48
+ ...props
51
49
  }
52
- }));
50
+ );
51
+ var StyledTextField = styled(TextField, { name: "StyledTextField" })(() => ({ "& .MuiInputBase-root": { paddingRight: 0 } }));
53
52
 
54
53
  // src/components/AccessCodeGateFlexbox.tsx
55
- var AccessCodeGateFlexbox = /* @__PURE__ */ __name(({ children, onCodeInputChange, onAccessCodeSuccess, successRedirectDelay = 1500, userAccessCodes, validAccessCodes, validateFunction, ...props }) => {
54
+ import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
55
+ var AccessCodeGateFlexbox = ({
56
+ children,
57
+ onCodeInputChange,
58
+ onAccessCodeSuccess,
59
+ successRedirectDelay = 1500,
60
+ userAccessCodes,
61
+ validAccessCodes,
62
+ validateFunction,
63
+ ...props
64
+ }) => {
56
65
  const [initialized, setInitialized] = useState(false);
57
66
  const [accessGranted, setAccessGranted] = useState(false);
58
67
  const [codeInput, setCodeInput] = useState();
59
68
  const [validCode, setValidCode] = useState(null);
60
69
  const disabled = validateFunction ? !validateFunction(codeInput) : !codeInput;
61
- const validateCode = useCallback((accessCode) => accessCode ? validAccessCodes?.includes(accessCode) : false, [
62
- validAccessCodes
63
- ]);
70
+ const validateCode = useCallback((accessCode) => accessCode ? validAccessCodes?.includes(accessCode) : false, [validAccessCodes]);
64
71
  useEffect(() => {
65
72
  if (onCodeInputChange) {
66
73
  onCodeInputChange(codeInput);
67
74
  }
68
- }, [
69
- codeInput,
70
- onCodeInputChange
71
- ]);
72
- const onEnter = /* @__PURE__ */ __name(() => {
75
+ }, [codeInput, onCodeInputChange]);
76
+ const onEnter = () => {
73
77
  onCodeInputChange?.(codeInput);
74
78
  if (codeInput) {
75
79
  const granted = validateCode(codeInput);
@@ -83,12 +87,10 @@ var AccessCodeGateFlexbox = /* @__PURE__ */ __name(({ children, onCodeInputChang
83
87
  setValidCode(false);
84
88
  }
85
89
  }
86
- }, "onEnter");
90
+ };
87
91
  useEffect(() => {
88
92
  setValidCode(null);
89
- }, [
90
- codeInput
91
- ]);
93
+ }, [codeInput]);
92
94
  useEffect(() => {
93
95
  if (userAccessCodes) {
94
96
  const granted = userAccessCodes.some((code) => validateCode(code));
@@ -98,52 +100,42 @@ var AccessCodeGateFlexbox = /* @__PURE__ */ __name(({ children, onCodeInputChang
98
100
  }
99
101
  }
100
102
  setInitialized(true);
101
- }, [
102
- onAccessCodeSuccess,
103
- userAccessCodes,
104
- validateCode
105
- ]);
106
- return /* @__PURE__ */ React2.createElement(React2.Fragment, null, initialized ? accessGranted ? children : /* @__PURE__ */ React2.createElement(FlexGrowCol, {
107
- gap: 2,
108
- ...props
109
- }, /* @__PURE__ */ React2.createElement(FlexGrowRow, {
110
- gap: 2,
111
- alignItems: "start"
112
- }, /* @__PURE__ */ React2.createElement(FormControl, null, /* @__PURE__ */ React2.createElement(CodeTextField, {
113
- codeInput,
114
- disabled,
115
- label: "Enter Access Code",
116
- setCodeInput,
117
- validCode,
118
- onEnter
119
- })), /* @__PURE__ */ React2.createElement(FormControl, null, /* @__PURE__ */ React2.createElement(ButtonEx, {
120
- disabled,
121
- onClick: onEnter,
122
- variant: "contained"
123
- }, "Enter")))) : null);
124
- }, "AccessCodeGateFlexbox");
103
+ }, [onAccessCodeSuccess, userAccessCodes, validateCode]);
104
+ return /* @__PURE__ */ jsx2(Fragment, { children: initialized ? accessGranted ? children : /* @__PURE__ */ jsx2(FlexGrowCol, { gap: 2, ...props, children: /* @__PURE__ */ jsxs2(FlexGrowRow, { gap: 2, alignItems: "start", children: [
105
+ /* @__PURE__ */ jsx2(FormControl, { children: /* @__PURE__ */ jsx2(
106
+ CodeTextField,
107
+ {
108
+ codeInput,
109
+ disabled,
110
+ label: "Enter Access Code",
111
+ setCodeInput,
112
+ validCode,
113
+ onEnter
114
+ }
115
+ ) }),
116
+ /* @__PURE__ */ jsx2(FormControl, { children: /* @__PURE__ */ jsx2(ButtonEx, { disabled, onClick: onEnter, variant: "contained", children: "Enter" }) })
117
+ ] }) }) : null });
118
+ };
125
119
 
126
120
  // src/hooks/useAccessCodes.ts
127
121
  import { useMemo, useState as useState2 } from "react";
128
- var useAccessCodes = /* @__PURE__ */ __name((localStorageKey, validCodeLength = 6) => {
122
+ var useAccessCodes = (localStorageKey, validCodeLength = 6) => {
129
123
  const [validated, setValidated] = useState2(false);
130
124
  const [codeInput, setCodeInput] = useState2("");
131
- const onAccessCodeSuccess = /* @__PURE__ */ __name(() => {
125
+ const onAccessCodeSuccess = () => {
132
126
  if (codeInput) {
133
- localStorage.setItem(localStorageKey, JSON.stringify([
134
- codeInput
135
- ]));
127
+ localStorage.setItem(localStorageKey, JSON.stringify([codeInput]));
136
128
  setValidated(true);
137
129
  } else {
138
130
  setValidated(true);
139
131
  }
140
- }, "onAccessCodeSuccess");
141
- const validateCodeInput = /* @__PURE__ */ __name((code) => {
132
+ };
133
+ const validateCodeInput = (code) => {
142
134
  return code?.length === validCodeLength;
143
- }, "validateCodeInput");
144
- const onCodeInputChange = /* @__PURE__ */ __name((code) => {
135
+ };
136
+ const onCodeInputChange = (code) => {
145
137
  setCodeInput(code ?? "");
146
- }, "onCodeInputChange");
138
+ };
147
139
  const userAccessCodes = useMemo(() => {
148
140
  const storedCodes = localStorage.getItem(localStorageKey);
149
141
  if (storedCodes) {
@@ -159,7 +151,7 @@ var useAccessCodes = /* @__PURE__ */ __name((localStorageKey, validCodeLength =
159
151
  onCodeInputChange,
160
152
  validateCodeInput
161
153
  };
162
- }, "useAccessCodes");
154
+ };
163
155
  export {
164
156
  AccessCodeGateFlexbox,
165
157
  useAccessCodes
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/AccessCodeGateFlexbox.tsx","../../src/components/CodeTextField.tsx","../../src/hooks/useAccessCodes.ts"],"sourcesContent":["/* eslint-disable @eslint-react/hooks-extra/no-direct-set-state-in-use-effect */\nimport { FormControl } from '@mui/material'\nimport { ButtonEx } from '@xylabs/react-button'\nimport type { FlexBoxProps } from '@xylabs/react-flexbox'\nimport { FlexGrowCol, FlexGrowRow } from '@xylabs/react-flexbox'\nimport type { PropsWithChildren } from 'react'\nimport React, {\n useCallback, useEffect, useState,\n} from 'react'\n\nimport { CodeTextField } from './CodeTextField.tsx'\n\nexport interface AccessCodeGateFlexbox extends PropsWithChildren, FlexBoxProps {\n onAccessCodeSuccess?: (code?: string) => void\n onCodeInputChange?: (codeInput?: string) => void\n successRedirectDelay?: number\n textFieldHelperText?: string\n userAccessCodes?: string[]\n validAccessCodes?: string[]\n validateFunction?: (codeInput?: string) => boolean\n}\n\nexport const AccessCodeGateFlexbox: React.FC<AccessCodeGateFlexbox> = ({\n children,\n onCodeInputChange,\n onAccessCodeSuccess,\n successRedirectDelay = 1500,\n userAccessCodes,\n validAccessCodes,\n validateFunction,\n ...props\n}) => {\n const [initialized, setInitialized] = useState(false)\n const [accessGranted, setAccessGranted] = useState(false)\n const [codeInput, setCodeInput] = useState<string>()\n const [validCode, setValidCode] = useState<boolean | null>(null)\n\n const disabled = validateFunction ? !validateFunction(codeInput) : !codeInput\n const validateCode = useCallback((accessCode: string) => (accessCode ? validAccessCodes?.includes(accessCode) : false), [validAccessCodes])\n\n // keep the parent informed of the code input\n useEffect(() => {\n if (onCodeInputChange) {\n onCodeInputChange(codeInput)\n }\n }, [codeInput, onCodeInputChange])\n\n const onEnter = () => {\n onCodeInputChange?.(codeInput)\n if (codeInput) {\n const granted = validateCode(codeInput)\n if (granted) {\n setValidCode(true)\n // delay success callback to ensure the ui shows success before next action\n setTimeout(() => {\n setAccessGranted(granted)\n onAccessCodeSuccess?.(codeInput)\n }, successRedirectDelay)\n } else {\n setValidCode(false)\n }\n }\n }\n\n useEffect(() => {\n // whenever a code changes, reset the success/failure warning\n setValidCode(null)\n }, [codeInput])\n\n useEffect(() => {\n if (userAccessCodes) {\n const granted = userAccessCodes.some(code => validateCode(code))\n setAccessGranted(granted)\n if (granted) {\n onAccessCodeSuccess?.()\n }\n }\n setInitialized(true)\n }, [onAccessCodeSuccess, userAccessCodes, validateCode])\n\n return (\n <>\n {initialized\n ? accessGranted\n ? children\n : (\n <FlexGrowCol gap={2} {...props}>\n <FlexGrowRow gap={2} alignItems=\"start\">\n <FormControl>\n <CodeTextField\n codeInput={codeInput}\n disabled={disabled}\n label=\"Enter Access Code\"\n setCodeInput={setCodeInput}\n validCode={validCode}\n onEnter={onEnter}\n />\n </FormControl>\n <FormControl>\n <ButtonEx disabled={disabled} onClick={onEnter} variant=\"contained\">\n Enter\n </ButtonEx>\n </FormControl>\n </FlexGrowRow>\n </FlexGrowCol>\n )\n\n : null}\n </>\n )\n}\n","import { CheckCircleOutline, ErrorOutline } from '@mui/icons-material'\nimport type { TextFieldProps } from '@mui/material'\nimport {\n InputAdornment, styled, TextField,\n} from '@mui/material'\nimport type { Dispatch, SetStateAction } from 'react'\nimport React from 'react'\n\nexport type CodeTextFieldProps = TextFieldProps & {\n codeInput?: string\n disabled?: boolean\n onEnter?: () => void\n setCodeInput?: Dispatch<SetStateAction<string | undefined>>\n validCode?: boolean | null\n}\n\nexport const CodeTextField: React.FC<CodeTextFieldProps> = ({\n codeInput, disabled, onEnter, setCodeInput, validCode, ...props\n}) => (\n <StyledTextField\n InputProps={{\n endAdornment: (\n <InputAdornment position=\"start\">\n {/* Having a display block element for all 3 states (null, false, true) means the icon coming in and out\n does not affect the overall width */}\n <CheckCircleOutline sx={{ display: validCode === null ? 'block' : 'hidden', visibility: 'hidden' }} />\n <CheckCircleOutline\n color=\"success\"\n fontSize=\"medium\"\n sx={{ position: 'absolute', visibility: validCode === true ? 'visible' : 'hidden' }}\n />\n <ErrorOutline color=\"error\" fontSize=\"medium\" sx={{ position: 'absolute', visibility: validCode === false ? 'visible' : 'hidden' }} />\n </InputAdornment>\n ),\n }}\n onKeyUp={event => (event.key === 'Enter' && !disabled ? onEnter?.() : null)}\n autoFocus\n size=\"small\"\n value={codeInput ?? ''}\n onChange={event => setCodeInput?.(event.target.value)}\n {...props}\n />\n)\n\nconst StyledTextField = styled(TextField, { name: 'StyledTextField' })(() => ({ '& .MuiInputBase-root': { paddingRight: 0 } }))\n","import { useMemo, useState } from 'react'\n\nexport const useAccessCodes = (localStorageKey: string, validCodeLength = 6) => {\n const [validated, setValidated] = useState(false)\n const [codeInput, setCodeInput] = useState('')\n\n const onAccessCodeSuccess = () => {\n // Save the access code to local storage\n if (codeInput) {\n localStorage.setItem(localStorageKey, JSON.stringify([codeInput]))\n setValidated(true)\n } else {\n // If the codeInput is empty, but we have success, do nothing since the successful code is already saved\n setValidated(true)\n }\n }\n const validateCodeInput = (code?: string) => {\n return code?.length === validCodeLength\n }\n const onCodeInputChange = (code?: string) => {\n setCodeInput(code ?? '')\n }\n const userAccessCodes = useMemo(() => {\n const storedCodes = localStorage.getItem(localStorageKey)\n if (storedCodes) {\n const parsedResult = JSON.parse(storedCodes ?? '')\n if (Array.isArray(parsedResult)) return parsedResult\n }\n }, [])\n\n return {\n codeInput, validated, userAccessCodes, onAccessCodeSuccess, onCodeInputChange, validateCodeInput,\n }\n}\n"],"mappings":"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","names":["FormControl","ButtonEx","FlexGrowCol","FlexGrowRow","React","useCallback","useEffect","useState","CheckCircleOutline","ErrorOutline","InputAdornment","styled","TextField","React","CodeTextField","codeInput","disabled","onEnter","setCodeInput","validCode","props","StyledTextField","InputProps","endAdornment","InputAdornment","position","CheckCircleOutline","sx","display","visibility","color","fontSize","ErrorOutline","onKeyUp","event","key","autoFocus","size","value","onChange","target","styled","TextField","name","paddingRight","AccessCodeGateFlexbox","children","onCodeInputChange","onAccessCodeSuccess","successRedirectDelay","userAccessCodes","validAccessCodes","validateFunction","props","initialized","setInitialized","useState","accessGranted","setAccessGranted","codeInput","setCodeInput","validCode","setValidCode","disabled","validateCode","useCallback","accessCode","includes","useEffect","onEnter","granted","setTimeout","some","code","React","FlexGrowCol","gap","FlexGrowRow","alignItems","FormControl","CodeTextField","label","ButtonEx","onClick","variant","useMemo","useState","useAccessCodes","localStorageKey","validCodeLength","validated","setValidated","useState","codeInput","setCodeInput","onAccessCodeSuccess","localStorage","setItem","JSON","stringify","validateCodeInput","code","length","onCodeInputChange","userAccessCodes","useMemo","storedCodes","getItem","parsedResult","parse","Array","isArray"]}
1
+ {"version":3,"sources":["../../src/components/AccessCodeGateFlexbox.tsx","../../src/components/CodeTextField.tsx","../../src/hooks/useAccessCodes.ts"],"sourcesContent":["/* eslint-disable @eslint-react/hooks-extra/no-direct-set-state-in-use-effect */\nimport { FormControl } from '@mui/material'\nimport { ButtonEx } from '@xylabs/react-button'\nimport type { FlexBoxProps } from '@xylabs/react-flexbox'\nimport { FlexGrowCol, FlexGrowRow } from '@xylabs/react-flexbox'\nimport type { PropsWithChildren } from 'react'\nimport React, {\n useCallback, useEffect, useState,\n} from 'react'\n\nimport { CodeTextField } from './CodeTextField.tsx'\n\nexport interface AccessCodeGateFlexbox extends PropsWithChildren, FlexBoxProps {\n onAccessCodeSuccess?: (code?: string) => void\n onCodeInputChange?: (codeInput?: string) => void\n successRedirectDelay?: number\n textFieldHelperText?: string\n userAccessCodes?: string[]\n validAccessCodes?: string[]\n validateFunction?: (codeInput?: string) => boolean\n}\n\nexport const AccessCodeGateFlexbox: React.FC<AccessCodeGateFlexbox> = ({\n children,\n onCodeInputChange,\n onAccessCodeSuccess,\n successRedirectDelay = 1500,\n userAccessCodes,\n validAccessCodes,\n validateFunction,\n ...props\n}) => {\n const [initialized, setInitialized] = useState(false)\n const [accessGranted, setAccessGranted] = useState(false)\n const [codeInput, setCodeInput] = useState<string>()\n const [validCode, setValidCode] = useState<boolean | null>(null)\n\n const disabled = validateFunction ? !validateFunction(codeInput) : !codeInput\n const validateCode = useCallback((accessCode: string) => (accessCode ? validAccessCodes?.includes(accessCode) : false), [validAccessCodes])\n\n // keep the parent informed of the code input\n useEffect(() => {\n if (onCodeInputChange) {\n onCodeInputChange(codeInput)\n }\n }, [codeInput, onCodeInputChange])\n\n const onEnter = () => {\n onCodeInputChange?.(codeInput)\n if (codeInput) {\n const granted = validateCode(codeInput)\n if (granted) {\n setValidCode(true)\n // delay success callback to ensure the ui shows success before next action\n setTimeout(() => {\n setAccessGranted(granted)\n onAccessCodeSuccess?.(codeInput)\n }, successRedirectDelay)\n } else {\n setValidCode(false)\n }\n }\n }\n\n useEffect(() => {\n // whenever a code changes, reset the success/failure warning\n setValidCode(null)\n }, [codeInput])\n\n useEffect(() => {\n if (userAccessCodes) {\n const granted = userAccessCodes.some(code => validateCode(code))\n setAccessGranted(granted)\n if (granted) {\n onAccessCodeSuccess?.()\n }\n }\n setInitialized(true)\n }, [onAccessCodeSuccess, userAccessCodes, validateCode])\n\n return (\n <>\n {initialized\n ? accessGranted\n ? children\n : (\n <FlexGrowCol gap={2} {...props}>\n <FlexGrowRow gap={2} alignItems=\"start\">\n <FormControl>\n <CodeTextField\n codeInput={codeInput}\n disabled={disabled}\n label=\"Enter Access Code\"\n setCodeInput={setCodeInput}\n validCode={validCode}\n onEnter={onEnter}\n />\n </FormControl>\n <FormControl>\n <ButtonEx disabled={disabled} onClick={onEnter} variant=\"contained\">\n Enter\n </ButtonEx>\n </FormControl>\n </FlexGrowRow>\n </FlexGrowCol>\n )\n\n : null}\n </>\n )\n}\n","import { CheckCircleOutline, ErrorOutline } from '@mui/icons-material'\nimport type { TextFieldProps } from '@mui/material'\nimport {\n InputAdornment, styled, TextField,\n} from '@mui/material'\nimport type {\n Dispatch, KeyboardEvent, SetStateAction,\n} from 'react'\nimport React from 'react'\n\nexport type CodeTextFieldProps = TextFieldProps & {\n codeInput?: string\n disabled?: boolean\n onEnter?: () => void\n setCodeInput?: Dispatch<SetStateAction<string | undefined>>\n validCode?: boolean | null\n}\n\nexport const CodeTextField: React.FC<CodeTextFieldProps> = ({\n codeInput, disabled, onEnter, setCodeInput, validCode, ...props\n}) => (\n <StyledTextField\n InputProps={{\n endAdornment: (\n <InputAdornment position=\"start\">\n {/* Having a display block element for all 3 states (null, false, true) means the icon coming in and out\n does not affect the overall width */}\n <CheckCircleOutline sx={{ display: validCode === null ? 'block' : 'hidden', visibility: 'hidden' }} />\n <CheckCircleOutline\n color=\"success\"\n fontSize=\"medium\"\n sx={{ position: 'absolute', visibility: validCode === true ? 'visible' : 'hidden' }}\n />\n <ErrorOutline color=\"error\" fontSize=\"medium\" sx={{ position: 'absolute', visibility: validCode === false ? 'visible' : 'hidden' }} />\n </InputAdornment>\n ),\n }}\n onKeyUp={(event: KeyboardEvent) => (event.key === 'Enter' && !disabled ? onEnter?.() : null)}\n autoFocus\n size=\"small\"\n value={codeInput ?? ''}\n onChange={(event: React.ChangeEvent<HTMLInputElement>) => setCodeInput?.(event.target.value)}\n {...props}\n />\n)\n\nconst StyledTextField = styled(TextField, { name: 'StyledTextField' })(() => ({ '& .MuiInputBase-root': { paddingRight: 0 } }))\n","import { useMemo, useState } from 'react'\n\nexport const useAccessCodes = (localStorageKey: string, validCodeLength = 6) => {\n const [validated, setValidated] = useState(false)\n const [codeInput, setCodeInput] = useState('')\n\n const onAccessCodeSuccess = () => {\n // Save the access code to local storage\n if (codeInput) {\n localStorage.setItem(localStorageKey, JSON.stringify([codeInput]))\n setValidated(true)\n } else {\n // If the codeInput is empty, but we have success, do nothing since the successful code is already saved\n setValidated(true)\n }\n }\n const validateCodeInput = (code?: string) => {\n return code?.length === validCodeLength\n }\n const onCodeInputChange = (code?: string) => {\n setCodeInput(code ?? '')\n }\n const userAccessCodes = useMemo(() => {\n const storedCodes = localStorage.getItem(localStorageKey)\n if (storedCodes) {\n const parsedResult = JSON.parse(storedCodes ?? '')\n if (Array.isArray(parsedResult)) return parsedResult\n }\n }, [])\n\n return {\n codeInput, validated, userAccessCodes, onAccessCodeSuccess, onCodeInputChange, validateCodeInput,\n }\n}\n"],"mappings":"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","names":["jsx","jsxs","useState"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xyo-network/react-access-gate",
3
- "version": "7.0.0",
3
+ "version": "7.0.2",
4
4
  "description": "Common React library for all XYO projects that use React",
5
5
  "keywords": [
6
6
  "xyo",
@@ -43,26 +43,29 @@
43
43
  "src"
44
44
  ],
45
45
  "dependencies": {
46
- "@xylabs/react-button": "^7.0.0",
47
- "@xylabs/react-flexbox": "^7.0.0"
46
+ "@xylabs/react-button": "~7.0.4",
47
+ "@xylabs/react-flexbox": "~7.0.4"
48
48
  },
49
49
  "devDependencies": {
50
- "@mui/icons-material": "^7.2.0",
51
- "@mui/material": "^7.2.0",
52
- "@storybook/react-vite": "^9.0.18",
53
- "@types/react": "^19.1.9",
54
- "@xylabs/ts-scripts-yarn3": "^7.0.2",
55
- "@xylabs/tsconfig-react": "^7.0.2",
56
- "react": "^19.1.1",
57
- "react-dom": "^19.1.1",
58
- "storybook": "^9.0.18",
59
- "typescript": "^5.8.3"
50
+ "@mui/icons-material": "~7.3.1",
51
+ "@mui/material": "~7.3.1",
52
+ "@storybook/react-vite": "~9.1.3",
53
+ "@types/react": "~19.1.11",
54
+ "@xylabs/ts-scripts-yarn3": "~7.1.7",
55
+ "@xylabs/tsconfig": "~7.1.7",
56
+ "@xylabs/tsconfig-dom": "~7.1.7",
57
+ "@xylabs/tsconfig-react": "~7.1.7",
58
+ "react": "~19.1.1",
59
+ "react-dom": "~19.1.1",
60
+ "storybook": "~9.1.3",
61
+ "typescript": "~5.9.2",
62
+ "vite": "~7.1.3"
60
63
  },
61
64
  "peerDependencies": {
62
65
  "@mui/icons-material": ">=6 <8",
63
66
  "@mui/material": ">=6 <8",
64
- "react": "^19",
65
- "react-dom": "^19"
67
+ "react": "~19",
68
+ "react-dom": "~19"
66
69
  },
67
70
  "publishConfig": {
68
71
  "access": "public"
@@ -3,7 +3,9 @@ import type { TextFieldProps } from '@mui/material'
3
3
  import {
4
4
  InputAdornment, styled, TextField,
5
5
  } from '@mui/material'
6
- import type { Dispatch, SetStateAction } from 'react'
6
+ import type {
7
+ Dispatch, KeyboardEvent, SetStateAction,
8
+ } from 'react'
7
9
  import React from 'react'
8
10
 
9
11
  export type CodeTextFieldProps = TextFieldProps & {
@@ -33,11 +35,11 @@ export const CodeTextField: React.FC<CodeTextFieldProps> = ({
33
35
  </InputAdornment>
34
36
  ),
35
37
  }}
36
- onKeyUp={event => (event.key === 'Enter' && !disabled ? onEnter?.() : null)}
38
+ onKeyUp={(event: KeyboardEvent) => (event.key === 'Enter' && !disabled ? onEnter?.() : null)}
37
39
  autoFocus
38
40
  size="small"
39
41
  value={codeInput ?? ''}
40
- onChange={event => setCodeInput?.(event.target.value)}
42
+ onChange={(event: React.ChangeEvent<HTMLInputElement>) => setCodeInput?.(event.target.value)}
41
43
  {...props}
42
44
  />
43
45
  )