@xyo-network/react-access-gate 7.4.2 → 7.5.1
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/browser/components/AccessCodeGateFlexbox.stories.d.ts +2 -2
- package/dist/browser/components/AccessCodeGateFlexbox.stories.d.ts.map +1 -1
- package/dist/browser/components/CodeTextField.d.ts +1 -2
- package/dist/browser/components/CodeTextField.d.ts.map +1 -1
- package/dist/browser/index.mjs +93 -83
- package/dist/browser/index.mjs.map +1 -1
- package/package.json +20 -18
- package/src/components/CodeTextField.tsx +18 -18
|
@@ -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("
|
|
6
|
-
declare const WithAccessCodes: import("
|
|
5
|
+
declare const Default: import("storybook/internal/csf").AnnotatedStoryFn<import("@storybook/react").ReactRenderer, AccessCodeGateFlexbox>;
|
|
6
|
+
declare const WithAccessCodes: import("storybook/internal/csf").AnnotatedStoryFn<import("@storybook/react").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,
|
|
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,oHAAoB,CAAA;AACjC,QAAA,MAAM,eAAe,oHAAmC,CAAA;AAExD,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,CAAA"}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import type { TextFieldProps } from '@mui/material';
|
|
2
|
-
import type { Dispatch, SetStateAction } from 'react';
|
|
3
2
|
import React from 'react';
|
|
4
3
|
export type CodeTextFieldProps = TextFieldProps & {
|
|
5
4
|
codeInput?: string;
|
|
6
5
|
disabled?: boolean;
|
|
7
6
|
onEnter?: () => void;
|
|
8
|
-
setCodeInput?:
|
|
7
|
+
setCodeInput?: (code?: string) => void;
|
|
9
8
|
validCode?: boolean | null;
|
|
10
9
|
};
|
|
11
10
|
export declare const CodeTextField: React.FC<CodeTextFieldProps>;
|
|
@@ -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;
|
|
1
|
+
{"version":3,"file":"CodeTextField.d.ts","sourceRoot":"","sources":["../../../src/components/CodeTextField.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAKnD,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,CAAC,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IACtC,SAAS,CAAC,EAAE,OAAO,GAAG,IAAI,CAAA;CAC3B,CAAA;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA4BtD,CAAA"}
|
package/dist/browser/index.mjs
CHANGED
|
@@ -1,79 +1,77 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
|
+
|
|
1
4
|
// src/components/AccessCodeGateFlexbox.tsx
|
|
2
5
|
import { FormControl } from "@mui/material";
|
|
3
6
|
import { ButtonEx } from "@xylabs/react-button";
|
|
4
7
|
import { FlexGrowCol, FlexGrowRow } from "@xylabs/react-flexbox";
|
|
5
|
-
import {
|
|
6
|
-
useCallback,
|
|
7
|
-
useEffect,
|
|
8
|
-
useState
|
|
9
|
-
} from "react";
|
|
8
|
+
import React2, { useCallback, useEffect, useState } from "react";
|
|
10
9
|
|
|
11
10
|
// src/components/CodeTextField.tsx
|
|
12
11
|
import { CheckCircleOutline, ErrorOutline } from "@mui/icons-material";
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
+
slotProps: {
|
|
16
|
+
input: {
|
|
17
|
+
endAdornment: /* @__PURE__ */ React.createElement(InputAdornment, {
|
|
18
|
+
position: "start"
|
|
19
|
+
}, /* @__PURE__ */ React.createElement(CheckCircleOutline, {
|
|
20
|
+
sx: {
|
|
21
|
+
display: validCode === null ? "block" : "hidden",
|
|
22
|
+
visibility: "hidden"
|
|
23
|
+
}
|
|
24
|
+
}), /* @__PURE__ */ React.createElement(CheckCircleOutline, {
|
|
25
|
+
color: "success",
|
|
26
|
+
fontSize: "medium",
|
|
27
|
+
sx: {
|
|
28
|
+
position: "absolute",
|
|
29
|
+
visibility: validCode === true ? "visible" : "hidden"
|
|
30
|
+
}
|
|
31
|
+
}), /* @__PURE__ */ React.createElement(ErrorOutline, {
|
|
32
|
+
color: "error",
|
|
33
|
+
fontSize: "medium",
|
|
34
|
+
sx: {
|
|
35
|
+
position: "absolute",
|
|
36
|
+
visibility: validCode === false ? "visible" : "hidden"
|
|
37
|
+
}
|
|
38
|
+
}))
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
onKeyUp: /* @__PURE__ */ __name((event) => event.key === "Enter" && !disabled ? onEnter?.() : null, "onKeyUp"),
|
|
42
|
+
autoFocus: true,
|
|
43
|
+
size: "small",
|
|
44
|
+
value: codeInput ?? "",
|
|
45
|
+
onChange: /* @__PURE__ */ __name((event) => setCodeInput?.(event.target.value), "onChange"),
|
|
25
46
|
...props
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
|
47
|
+
}), "CodeTextField");
|
|
48
|
+
var StyledTextField = styled(TextField, {
|
|
49
|
+
name: "StyledTextField"
|
|
50
|
+
})(() => ({
|
|
51
|
+
"& .MuiInputBase-root": {
|
|
52
|
+
paddingRight: 0
|
|
49
53
|
}
|
|
50
|
-
);
|
|
51
|
-
var StyledTextField = styled(TextField, { name: "StyledTextField" })(() => ({ "& .MuiInputBase-root": { paddingRight: 0 } }));
|
|
54
|
+
}));
|
|
52
55
|
|
|
53
56
|
// src/components/AccessCodeGateFlexbox.tsx
|
|
54
|
-
|
|
55
|
-
var AccessCodeGateFlexbox = ({
|
|
56
|
-
children,
|
|
57
|
-
onCodeInputChange,
|
|
58
|
-
onAccessCodeSuccess,
|
|
59
|
-
successRedirectDelay = 1500,
|
|
60
|
-
userAccessCodes,
|
|
61
|
-
validAccessCodes,
|
|
62
|
-
validateFunction,
|
|
63
|
-
...props
|
|
64
|
-
}) => {
|
|
57
|
+
var AccessCodeGateFlexbox = /* @__PURE__ */ __name(({ children, onCodeInputChange, onAccessCodeSuccess, successRedirectDelay = 1500, userAccessCodes, validAccessCodes, validateFunction, ...props }) => {
|
|
65
58
|
const [initialized, setInitialized] = useState(false);
|
|
66
59
|
const [accessGranted, setAccessGranted] = useState(false);
|
|
67
60
|
const [codeInput, setCodeInput] = useState();
|
|
68
61
|
const [validCode, setValidCode] = useState(null);
|
|
69
62
|
const disabled = validateFunction ? !validateFunction(codeInput) : !codeInput;
|
|
70
|
-
const validateCode = useCallback((accessCode) => accessCode ? validAccessCodes?.includes(accessCode) : false, [
|
|
63
|
+
const validateCode = useCallback((accessCode) => accessCode ? validAccessCodes?.includes(accessCode) : false, [
|
|
64
|
+
validAccessCodes
|
|
65
|
+
]);
|
|
71
66
|
useEffect(() => {
|
|
72
67
|
if (onCodeInputChange) {
|
|
73
68
|
onCodeInputChange(codeInput);
|
|
74
69
|
}
|
|
75
|
-
}, [
|
|
76
|
-
|
|
70
|
+
}, [
|
|
71
|
+
codeInput,
|
|
72
|
+
onCodeInputChange
|
|
73
|
+
]);
|
|
74
|
+
const onEnter = /* @__PURE__ */ __name(() => {
|
|
77
75
|
onCodeInputChange?.(codeInput);
|
|
78
76
|
if (codeInput) {
|
|
79
77
|
const granted = validateCode(codeInput);
|
|
@@ -87,10 +85,12 @@ var AccessCodeGateFlexbox = ({
|
|
|
87
85
|
setValidCode(false);
|
|
88
86
|
}
|
|
89
87
|
}
|
|
90
|
-
};
|
|
88
|
+
}, "onEnter");
|
|
91
89
|
useEffect(() => {
|
|
92
90
|
setValidCode(null);
|
|
93
|
-
}, [
|
|
91
|
+
}, [
|
|
92
|
+
codeInput
|
|
93
|
+
]);
|
|
94
94
|
useEffect(() => {
|
|
95
95
|
if (userAccessCodes) {
|
|
96
96
|
const granted = userAccessCodes.some((code) => validateCode(code));
|
|
@@ -100,42 +100,52 @@ var AccessCodeGateFlexbox = ({
|
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
102
|
setInitialized(true);
|
|
103
|
-
}, [
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
103
|
+
}, [
|
|
104
|
+
onAccessCodeSuccess,
|
|
105
|
+
userAccessCodes,
|
|
106
|
+
validateCode
|
|
107
|
+
]);
|
|
108
|
+
return /* @__PURE__ */ React2.createElement(React2.Fragment, null, initialized ? accessGranted ? children : /* @__PURE__ */ React2.createElement(FlexGrowCol, {
|
|
109
|
+
gap: 2,
|
|
110
|
+
...props
|
|
111
|
+
}, /* @__PURE__ */ React2.createElement(FlexGrowRow, {
|
|
112
|
+
gap: 2,
|
|
113
|
+
alignItems: "start"
|
|
114
|
+
}, /* @__PURE__ */ React2.createElement(FormControl, null, /* @__PURE__ */ React2.createElement(CodeTextField, {
|
|
115
|
+
codeInput,
|
|
116
|
+
disabled,
|
|
117
|
+
label: "Enter Access Code",
|
|
118
|
+
setCodeInput,
|
|
119
|
+
validCode,
|
|
120
|
+
onEnter
|
|
121
|
+
})), /* @__PURE__ */ React2.createElement(FormControl, null, /* @__PURE__ */ React2.createElement(ButtonEx, {
|
|
122
|
+
disabled,
|
|
123
|
+
onClick: onEnter,
|
|
124
|
+
variant: "contained"
|
|
125
|
+
}, "Enter")))) : null);
|
|
126
|
+
}, "AccessCodeGateFlexbox");
|
|
119
127
|
|
|
120
128
|
// src/hooks/useAccessCodes.ts
|
|
121
129
|
import { useMemo, useState as useState2 } from "react";
|
|
122
|
-
var useAccessCodes = (localStorageKey, validCodeLength = 6) => {
|
|
130
|
+
var useAccessCodes = /* @__PURE__ */ __name((localStorageKey, validCodeLength = 6) => {
|
|
123
131
|
const [validated, setValidated] = useState2(false);
|
|
124
132
|
const [codeInput, setCodeInput] = useState2("");
|
|
125
|
-
const onAccessCodeSuccess = () => {
|
|
133
|
+
const onAccessCodeSuccess = /* @__PURE__ */ __name(() => {
|
|
126
134
|
if (codeInput) {
|
|
127
|
-
localStorage.setItem(localStorageKey, JSON.stringify([
|
|
135
|
+
localStorage.setItem(localStorageKey, JSON.stringify([
|
|
136
|
+
codeInput
|
|
137
|
+
]));
|
|
128
138
|
setValidated(true);
|
|
129
139
|
} else {
|
|
130
140
|
setValidated(true);
|
|
131
141
|
}
|
|
132
|
-
};
|
|
133
|
-
const validateCodeInput = (code) => {
|
|
142
|
+
}, "onAccessCodeSuccess");
|
|
143
|
+
const validateCodeInput = /* @__PURE__ */ __name((code) => {
|
|
134
144
|
return code?.length === validCodeLength;
|
|
135
|
-
};
|
|
136
|
-
const onCodeInputChange = (code) => {
|
|
145
|
+
}, "validateCodeInput");
|
|
146
|
+
const onCodeInputChange = /* @__PURE__ */ __name((code) => {
|
|
137
147
|
setCodeInput(code ?? "");
|
|
138
|
-
};
|
|
148
|
+
}, "onCodeInputChange");
|
|
139
149
|
const userAccessCodes = useMemo(() => {
|
|
140
150
|
const storedCodes = localStorage.getItem(localStorageKey);
|
|
141
151
|
if (storedCodes) {
|
|
@@ -151,7 +161,7 @@ var useAccessCodes = (localStorageKey, validCodeLength = 6) => {
|
|
|
151
161
|
onCodeInputChange,
|
|
152
162
|
validateCodeInput
|
|
153
163
|
};
|
|
154
|
-
};
|
|
164
|
+
}, "useAccessCodes");
|
|
155
165
|
export {
|
|
156
166
|
AccessCodeGateFlexbox,
|
|
157
167
|
useAccessCodes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/AccessCodeGateFlexbox.tsx","../../src/components/CodeTextField.tsx","../../src/hooks/useAccessCodes.ts"],"sourcesContent":["import { 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"]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/AccessCodeGateFlexbox.tsx","../../src/components/CodeTextField.tsx","../../src/hooks/useAccessCodes.ts"],"sourcesContent":["import { 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 { KeyboardEvent } from 'react'\nimport React from 'react'\n\nexport type CodeTextFieldProps = TextFieldProps & {\n codeInput?: string\n disabled?: boolean\n onEnter?: () => void\n setCodeInput?: (code?: string) => void\n validCode?: boolean | null\n}\n\nexport const CodeTextField: React.FC<CodeTextFieldProps> = ({\n codeInput, disabled, onEnter, setCodeInput, validCode, ...props\n}) => (\n <StyledTextField\n slotProps={{\n input: {\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 }}\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":["FormControl","ButtonEx","FlexGrowCol","FlexGrowRow","React","useCallback","useEffect","useState","CheckCircleOutline","ErrorOutline","InputAdornment","styled","TextField","React","CodeTextField","codeInput","disabled","onEnter","setCodeInput","validCode","props","StyledTextField","slotProps","input","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"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xyo-network/react-access-gate",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.5.1",
|
|
4
4
|
"description": "Common React library for all XYO projects that use React",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"xyo",
|
|
@@ -43,34 +43,36 @@
|
|
|
43
43
|
"src"
|
|
44
44
|
],
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@xylabs/react-button": "~7.1.
|
|
47
|
-
"@xylabs/react-flexbox": "~7.1.
|
|
46
|
+
"@xylabs/react-button": "~7.1.12",
|
|
47
|
+
"@xylabs/react-flexbox": "~7.1.12"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@mui/icons-material": "~7.3.
|
|
51
|
-
"@mui/material": "~7.3.
|
|
52
|
-
"@storybook/react-vite": "~10.1
|
|
53
|
-
"@types/react": "^19.2.
|
|
54
|
-
"@xylabs/ts-scripts-yarn3": "~7.2
|
|
55
|
-
"@xylabs/tsconfig": "~7.2
|
|
56
|
-
"@xylabs/tsconfig-dom": "~7.2
|
|
57
|
-
"@xylabs/tsconfig-react": "~7.2
|
|
58
|
-
"react": "^19.2.
|
|
59
|
-
"react-dom": "^19.2.
|
|
60
|
-
"react-router-dom": "^7.
|
|
61
|
-
"storybook": "~10.1
|
|
50
|
+
"@mui/icons-material": "~7.3.7",
|
|
51
|
+
"@mui/material": "~7.3.7",
|
|
52
|
+
"@storybook/react-vite": "~10.2.1",
|
|
53
|
+
"@types/react": "^19.2.10",
|
|
54
|
+
"@xylabs/ts-scripts-yarn3": "~7.3.2",
|
|
55
|
+
"@xylabs/tsconfig": "~7.3.2",
|
|
56
|
+
"@xylabs/tsconfig-dom": "~7.3.2",
|
|
57
|
+
"@xylabs/tsconfig-react": "~7.3.2",
|
|
58
|
+
"react": "^19.2.4",
|
|
59
|
+
"react-dom": "^19.2.4",
|
|
60
|
+
"react-router-dom": "^7.13.0",
|
|
61
|
+
"storybook": "~10.2.1",
|
|
62
62
|
"typescript": "^5.9.3",
|
|
63
|
-
"vite": "~7.
|
|
63
|
+
"vite": "~7.3.1",
|
|
64
|
+
"zod": "^4.3.6"
|
|
64
65
|
},
|
|
65
66
|
"peerDependencies": {
|
|
66
67
|
"@mui/icons-material": ">=6 <8",
|
|
67
68
|
"@mui/material": ">=6 <8",
|
|
68
69
|
"react": "^19",
|
|
69
70
|
"react-dom": "^19",
|
|
70
|
-
"react-router-dom": "^7"
|
|
71
|
+
"react-router-dom": "^7",
|
|
72
|
+
"zod": "^4"
|
|
71
73
|
},
|
|
72
74
|
"publishConfig": {
|
|
73
75
|
"access": "public"
|
|
74
76
|
},
|
|
75
77
|
"docs": "dist/docs.json"
|
|
76
|
-
}
|
|
78
|
+
}
|
|
@@ -3,16 +3,14 @@ import type { TextFieldProps } from '@mui/material'
|
|
|
3
3
|
import {
|
|
4
4
|
InputAdornment, styled, TextField,
|
|
5
5
|
} from '@mui/material'
|
|
6
|
-
import type {
|
|
7
|
-
Dispatch, KeyboardEvent, SetStateAction,
|
|
8
|
-
} from 'react'
|
|
6
|
+
import type { KeyboardEvent } from 'react'
|
|
9
7
|
import React from 'react'
|
|
10
8
|
|
|
11
9
|
export type CodeTextFieldProps = TextFieldProps & {
|
|
12
10
|
codeInput?: string
|
|
13
11
|
disabled?: boolean
|
|
14
12
|
onEnter?: () => void
|
|
15
|
-
setCodeInput?:
|
|
13
|
+
setCodeInput?: (code?: string) => void
|
|
16
14
|
validCode?: boolean | null
|
|
17
15
|
}
|
|
18
16
|
|
|
@@ -20,20 +18,22 @@ export const CodeTextField: React.FC<CodeTextFieldProps> = ({
|
|
|
20
18
|
codeInput, disabled, onEnter, setCodeInput, validCode, ...props
|
|
21
19
|
}) => (
|
|
22
20
|
<StyledTextField
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
21
|
+
slotProps={{
|
|
22
|
+
input: {
|
|
23
|
+
endAdornment: (
|
|
24
|
+
<InputAdornment position="start">
|
|
25
|
+
{/* Having a display block element for all 3 states (null, false, true) means the icon coming in and out
|
|
26
|
+
does not affect the overall width */}
|
|
27
|
+
<CheckCircleOutline sx={{ display: validCode === null ? 'block' : 'hidden', visibility: 'hidden' }} />
|
|
28
|
+
<CheckCircleOutline
|
|
29
|
+
color="success"
|
|
30
|
+
fontSize="medium"
|
|
31
|
+
sx={{ position: 'absolute', visibility: validCode === true ? 'visible' : 'hidden' }}
|
|
32
|
+
/>
|
|
33
|
+
<ErrorOutline color="error" fontSize="medium" sx={{ position: 'absolute', visibility: validCode === false ? 'visible' : 'hidden' }} />
|
|
34
|
+
</InputAdornment>
|
|
35
|
+
),
|
|
36
|
+
},
|
|
37
37
|
}}
|
|
38
38
|
onKeyUp={(event: KeyboardEvent) => (event.key === 'Enter' && !disabled ? onEnter?.() : null)}
|
|
39
39
|
autoFocus
|