@xyo-network/react-access-gate 7.5.8 → 7.5.11

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.
@@ -1 +1 @@
1
- {"version":3,"file":"AccessCodeGateFlexbox.d.ts","sourceRoot":"","sources":["../../../src/components/AccessCodeGateFlexbox.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAEzD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAA;AAC9C,OAAO,KAEN,MAAM,OAAO,CAAA;AAId,MAAM,WAAW,qBAAsB,SAAQ,iBAAiB,EAAE,YAAY;IAC5E,mBAAmB,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IAC7C,iBAAiB,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IAChD,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;IAC1B,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC3B,gBAAgB,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,KAAK,OAAO,CAAA;CACnD;AAED,eAAO,MAAM,qBAAqB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAwFjE,CAAA"}
1
+ {"version":3,"file":"AccessCodeGateFlexbox.d.ts","sourceRoot":"","sources":["../../../src/components/AccessCodeGateFlexbox.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAEzD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAA;AAC9C,OAAO,KAEN,MAAM,OAAO,CAAA;AAId,MAAM,WAAW,qBAAsB,SAAQ,iBAAiB,EAAE,YAAY;IAC5E,mBAAmB,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IAC7C,iBAAiB,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IAChD,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;IAC1B,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC3B,gBAAgB,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,KAAK,OAAO,CAAA;CACnD;AAED,eAAO,MAAM,qBAAqB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CA4FjE,CAAA"}
@@ -1,77 +1,81 @@
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
- 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"),
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,
46
25
  ...props
47
- }), "CodeTextField");
48
- var StyledTextField = styled(TextField, {
49
- name: "StyledTextField"
50
- })(() => ({
51
- "& .MuiInputBase-root": {
52
- paddingRight: 0
26
+ }) => /* @__PURE__ */ jsx(
27
+ StyledTextField,
28
+ {
29
+ slotProps: {
30
+ input: {
31
+ endAdornment: /* @__PURE__ */ jsxs(InputAdornment, { position: "start", children: [
32
+ /* @__PURE__ */ jsx(CheckCircleOutline, { sx: { display: validCode === null ? "block" : "hidden", visibility: "hidden" } }),
33
+ /* @__PURE__ */ jsx(
34
+ CheckCircleOutline,
35
+ {
36
+ color: "success",
37
+ fontSize: "medium",
38
+ sx: { position: "absolute", visibility: validCode === true ? "visible" : "hidden" }
39
+ }
40
+ ),
41
+ /* @__PURE__ */ jsx(ErrorOutline, { color: "error", fontSize: "medium", sx: { position: "absolute", visibility: validCode === false ? "visible" : "hidden" } })
42
+ ] })
43
+ }
44
+ },
45
+ onKeyUp: (event) => event.key === "Enter" && !disabled ? onEnter?.() : null,
46
+ autoFocus: true,
47
+ size: "small",
48
+ value: codeInput ?? "",
49
+ onChange: (event) => setCodeInput?.(event.target.value),
50
+ ...props
53
51
  }
54
- }));
52
+ );
53
+ var StyledTextField = styled(TextField, { name: "StyledTextField" })(() => ({ "& .MuiInputBase-root": { paddingRight: 0 } }));
55
54
 
56
55
  // src/components/AccessCodeGateFlexbox.tsx
57
- var AccessCodeGateFlexbox = /* @__PURE__ */ __name(({ children, onCodeInputChange, onAccessCodeSuccess, successRedirectDelay = 1500, userAccessCodes, validAccessCodes, validateFunction, ...props }) => {
56
+ import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
57
+ var AccessCodeGateFlexbox = ({
58
+ children,
59
+ onCodeInputChange,
60
+ onAccessCodeSuccess,
61
+ successRedirectDelay = 1500,
62
+ userAccessCodes,
63
+ validAccessCodes,
64
+ validateFunction,
65
+ ...props
66
+ }) => {
58
67
  const [initialized, setInitialized] = useState(false);
59
68
  const [accessGranted, setAccessGranted] = useState(false);
60
69
  const [codeInput, setCodeInput] = useState();
61
70
  const [validCode, setValidCode] = useState(null);
62
71
  const disabled = validateFunction ? !validateFunction(codeInput) : !codeInput;
63
- const validateCode = useCallback((accessCode) => accessCode ? validAccessCodes?.includes(accessCode) : false, [
64
- validAccessCodes
65
- ]);
72
+ const validateCode = useCallback((accessCode) => accessCode ? validAccessCodes?.includes(accessCode) : false, [validAccessCodes]);
66
73
  useEffect(() => {
67
74
  if (onCodeInputChange) {
68
75
  onCodeInputChange(codeInput);
69
76
  }
70
- }, [
71
- codeInput,
72
- onCodeInputChange
73
- ]);
74
- const onEnter = /* @__PURE__ */ __name(() => {
77
+ }, [codeInput, onCodeInputChange]);
78
+ const onEnter = () => {
75
79
  onCodeInputChange?.(codeInput);
76
80
  if (codeInput) {
77
81
  const granted = validateCode(codeInput);
@@ -85,76 +89,62 @@ var AccessCodeGateFlexbox = /* @__PURE__ */ __name(({ children, onCodeInputChang
85
89
  setValidCode(false);
86
90
  }
87
91
  }
88
- }, "onEnter");
92
+ };
89
93
  useEffect(() => {
90
94
  setValidCode(null);
91
- }, [
92
- codeInput
93
- ]);
95
+ }, [codeInput]);
94
96
  useEffect(() => {
95
97
  if (userAccessCodes) {
96
98
  const granted = userAccessCodes.some((code) => validateCode(code));
97
- setAccessGranted(granted);
98
99
  if (granted) {
100
+ setAccessGranted(true);
99
101
  onAccessCodeSuccess?.();
100
102
  }
101
103
  }
102
104
  setInitialized(true);
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");
105
+ }, [userAccessCodes, validateCode]);
106
+ return /* @__PURE__ */ jsx2(Fragment, { children: initialized ? accessGranted ? children : /* @__PURE__ */ jsx2(FlexGrowCol, { gap: 2, ...props, children: /* @__PURE__ */ jsxs2(FlexGrowRow, { gap: 2, alignItems: "start", children: [
107
+ /* @__PURE__ */ jsx2(FormControl, { children: /* @__PURE__ */ jsx2(
108
+ CodeTextField,
109
+ {
110
+ codeInput,
111
+ disabled,
112
+ label: "Enter Access Code",
113
+ setCodeInput,
114
+ validCode,
115
+ onEnter
116
+ }
117
+ ) }),
118
+ /* @__PURE__ */ jsx2(FormControl, { children: /* @__PURE__ */ jsx2(ButtonEx, { disabled, onClick: onEnter, variant: "contained", children: "Enter" }) })
119
+ ] }) }) : null });
120
+ };
127
121
 
128
122
  // src/hooks/useAccessCodes.ts
129
123
  import { useMemo, useState as useState2 } from "react";
130
- var useAccessCodes = /* @__PURE__ */ __name((localStorageKey, validCodeLength = 6) => {
124
+ var useAccessCodes = (localStorageKey, validCodeLength = 6) => {
131
125
  const [validated, setValidated] = useState2(false);
132
126
  const [codeInput, setCodeInput] = useState2("");
133
- const onAccessCodeSuccess = /* @__PURE__ */ __name(() => {
127
+ const onAccessCodeSuccess = () => {
134
128
  if (codeInput) {
135
- localStorage.setItem(localStorageKey, JSON.stringify([
136
- codeInput
137
- ]));
129
+ localStorage.setItem(localStorageKey, JSON.stringify([codeInput]));
138
130
  setValidated(true);
139
131
  } else {
140
132
  setValidated(true);
141
133
  }
142
- }, "onAccessCodeSuccess");
143
- const validateCodeInput = /* @__PURE__ */ __name((code) => {
134
+ };
135
+ const validateCodeInput = (code) => {
144
136
  return code?.length === validCodeLength;
145
- }, "validateCodeInput");
146
- const onCodeInputChange = /* @__PURE__ */ __name((code) => {
137
+ };
138
+ const onCodeInputChange = (code) => {
147
139
  setCodeInput(code ?? "");
148
- }, "onCodeInputChange");
140
+ };
149
141
  const userAccessCodes = useMemo(() => {
150
142
  const storedCodes = localStorage.getItem(localStorageKey);
151
143
  if (storedCodes) {
152
144
  const parsedResult = JSON.parse(storedCodes ?? "");
153
145
  if (Array.isArray(parsedResult)) return parsedResult;
154
146
  }
155
- }, [
156
- localStorageKey
157
- ]);
147
+ }, [localStorageKey]);
158
148
  return {
159
149
  codeInput,
160
150
  validated,
@@ -163,7 +153,7 @@ var useAccessCodes = /* @__PURE__ */ __name((localStorageKey, validCodeLength =
163
153
  onCodeInputChange,
164
154
  validateCodeInput
165
155
  };
166
- }, "useAccessCodes");
156
+ };
167
157
  export {
168
158
  AccessCodeGateFlexbox,
169
159
  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 { 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 }, [localStorageKey])\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"]}
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 // eslint-disable-next-line react-hooks/set-state-in-effect, react-x/set-state-in-effect\n setValidCode(null)\n }, [codeInput])\n\n useEffect(() => {\n if (userAccessCodes) {\n const granted = userAccessCodes.some(code => validateCode(code))\n if (granted) {\n // eslint-disable-next-line react-hooks/set-state-in-effect, react-x/set-state-in-effect\n setAccessGranted(true)\n onAccessCodeSuccess?.()\n }\n }\n // eslint-disable-next-line react-x/set-state-in-effect\n setInitialized(true)\n // eslint-disable-next-line react-hooks/exhaustive-deps, react-x/exhaustive-deps\n }, [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 }, [localStorageKey])\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.5.8",
3
+ "version": "7.5.11",
4
4
  "description": "Common React library for all XYO projects that use React",
5
5
  "keywords": [
6
6
  "xyo",
@@ -36,44 +36,72 @@
36
36
  },
37
37
  "./package.json": "./package.json"
38
38
  },
39
- "module": "dist/browser/index.mjs",
40
- "types": "dist/browser/index.d.ts",
41
39
  "files": [
42
40
  "dist",
43
- "src"
41
+ "README.md"
44
42
  ],
45
- "dependencies": {
46
- "@xylabs/react-button": "~7.1.17",
47
- "@xylabs/react-flexbox": "~7.1.17"
48
- },
49
43
  "devDependencies": {
50
- "@mui/icons-material": "~7.3.9",
51
- "@mui/material": "~7.3.9",
52
- "@storybook/react-vite": "~10.3.3",
44
+ "@mui/icons-material": "^7.3.10",
45
+ "@mui/material": "^7.3.10",
46
+ "@opentelemetry/api": "^1.9.1",
47
+ "@opentelemetry/sdk-trace-base": "^2.7.0",
48
+ "@storybook/react-vite": "~10.3.5",
49
+ "@types/node": "~25.6.0",
53
50
  "@types/react": "^19.2.14",
54
- "@xylabs/ts-scripts-common": "~7.5.6",
55
- "@xylabs/ts-scripts-yarn3": "~7.5.6",
56
- "@xylabs/tsconfig": "~7.5.6",
57
- "@xylabs/tsconfig-dom": "~7.5.6",
58
- "@xylabs/tsconfig-react": "~7.5.6",
59
- "react": "^19.2.4",
60
- "react-dom": "^19.2.4",
61
- "react-router-dom": "^7.13.2",
62
- "storybook": "~10.3.3",
51
+ "@xylabs/react-async-effect": "~7.1.20",
52
+ "@xylabs/react-button": "~7.1.20",
53
+ "@xylabs/react-flexbox": "~7.1.20",
54
+ "@xylabs/react-promise": "~7.1.20",
55
+ "@xylabs/toolchain": "~7.11.9",
56
+ "@xylabs/tsconfig": "^7.11.9",
57
+ "@xylabs/tsconfig-dom": "^7.11.9",
58
+ "@xylabs/tsconfig-react": "~7.11.9",
59
+ "@xylabs/zod": "~5.0.100",
60
+ "async-mutex": "^0.5.0",
61
+ "axios": "^1.15.2",
62
+ "bn.js": "^5.2.3",
63
+ "bowser": "^2.14.1",
64
+ "buffer": "^6.0.3",
65
+ "chalk": "^5.6.2",
66
+ "esbuild": "~0.28.0",
67
+ "eslint": "^10.2.1",
68
+ "ethers": "^6.16.0",
69
+ "fast-deep-equal": "~3.1.3",
70
+ "js-cookie": "~3.0.5",
71
+ "pako": "^2.1.0",
72
+ "react": "^19.2.5",
73
+ "react-dom": "^19.2.5",
74
+ "spark-md5": "~3.0.2",
75
+ "storybook": "^10.3.5",
63
76
  "typescript": "^5.9.3",
64
- "vite": "~8.0.3",
77
+ "vite": "^8.0.10",
65
78
  "zod": "^4.3.6"
66
79
  },
67
80
  "peerDependencies": {
68
- "@mui/icons-material": ">=6 <8",
69
- "@mui/material": ">=6 <8",
70
- "react": "^19",
71
- "react-dom": "^19",
72
- "react-router-dom": "^7",
73
- "zod": "^4"
81
+ "@mui/icons-material": "^7.3.10",
82
+ "@mui/material": "^7.3.10",
83
+ "@opentelemetry/sdk-trace-base": "^2.7.0",
84
+ "@types/react": "^19.2.14",
85
+ "@xylabs/react-async-effect": "~7.1.20",
86
+ "@xylabs/react-button": "~7.1.20",
87
+ "@xylabs/react-flexbox": "~7.1.20",
88
+ "@xylabs/zod": "~5.0.100",
89
+ "async-mutex": "^0.5.0",
90
+ "bn.js": "^5.2.3",
91
+ "bowser": "^2.14.1",
92
+ "buffer": "^6.0.3",
93
+ "chalk": "^5.6.2",
94
+ "ethers": "^6.16.0",
95
+ "fast-deep-equal": "~3.1.3",
96
+ "js-cookie": "~3.0.5",
97
+ "pako": "^2.1.0",
98
+ "react": "^19.2.5",
99
+ "react-dom": "^19.2.5",
100
+ "spark-md5": "~3.0.2",
101
+ "zod": "^4.3.6"
74
102
  },
75
103
  "publishConfig": {
76
104
  "access": "public"
77
105
  },
78
106
  "docs": "dist/docs.json"
79
- }
107
+ }
@@ -1,51 +0,0 @@
1
- import { Alert, Typography } from '@mui/material'
2
- import type { Meta, StoryFn } from '@storybook/react-vite'
3
- import { FlexCol } from '@xylabs/react-flexbox'
4
- import React from 'react'
5
-
6
- import { useAccessCodes } from '../hooks/index.ts'
7
- import { AccessCodeGateFlexbox } from './AccessCodeGateFlexbox.tsx'
8
-
9
- const ValidAccessCodes = ['100519']
10
-
11
- export default {
12
- component: AccessCodeGateFlexbox,
13
- title: 'access/AccessCodeGateFlexbox',
14
- } as Meta
15
-
16
- const Template: StoryFn<typeof AccessCodeGateFlexbox> = args => (
17
- <AccessCodeGateFlexbox {...args} />
18
- )
19
-
20
- const TemplateWithAccessCodes: StoryFn<typeof AccessCodeGateFlexbox> = (args) => {
21
- const {
22
- codeInput, validated, onAccessCodeSuccess, onCodeInputChange, validateCodeInput,
23
- } = useAccessCodes('storybook-access-codes-test')
24
-
25
- return validated
26
- ? <Alert severity="success">Success!</Alert>
27
- : (
28
- <FlexCol gap={2}>
29
- <AccessCodeGateFlexbox
30
- onAccessCodeSuccess={onAccessCodeSuccess}
31
- onCodeInputChange={onCodeInputChange}
32
- validAccessCodes={ValidAccessCodes}
33
- validateFunction={validateCodeInput}
34
- {...args}
35
- />
36
- <Typography variant="caption" gutterBottom>
37
- Hint:
38
- {ValidAccessCodes[0]}
39
- </Typography>
40
- <Typography variant="caption">
41
- Code Input in Parent:
42
- {codeInput}
43
- </Typography>
44
- </FlexCol>
45
- )
46
- }
47
-
48
- const Default = Template.bind({})
49
- const WithAccessCodes = TemplateWithAccessCodes.bind({})
50
-
51
- export { Default, WithAccessCodes }
@@ -1,110 +0,0 @@
1
- import { FormControl } from '@mui/material'
2
- import { ButtonEx } from '@xylabs/react-button'
3
- import type { FlexBoxProps } from '@xylabs/react-flexbox'
4
- import { FlexGrowCol, FlexGrowRow } from '@xylabs/react-flexbox'
5
- import type { PropsWithChildren } from 'react'
6
- import React, {
7
- useCallback, useEffect, useState,
8
- } from 'react'
9
-
10
- import { CodeTextField } from './CodeTextField.tsx'
11
-
12
- export interface AccessCodeGateFlexbox extends PropsWithChildren, FlexBoxProps {
13
- onAccessCodeSuccess?: (code?: string) => void
14
- onCodeInputChange?: (codeInput?: string) => void
15
- successRedirectDelay?: number
16
- textFieldHelperText?: string
17
- userAccessCodes?: string[]
18
- validAccessCodes?: string[]
19
- validateFunction?: (codeInput?: string) => boolean
20
- }
21
-
22
- export const AccessCodeGateFlexbox: React.FC<AccessCodeGateFlexbox> = ({
23
- children,
24
- onCodeInputChange,
25
- onAccessCodeSuccess,
26
- successRedirectDelay = 1500,
27
- userAccessCodes,
28
- validAccessCodes,
29
- validateFunction,
30
- ...props
31
- }) => {
32
- const [initialized, setInitialized] = useState(false)
33
- const [accessGranted, setAccessGranted] = useState(false)
34
- const [codeInput, setCodeInput] = useState<string>()
35
- const [validCode, setValidCode] = useState<boolean | null>(null)
36
-
37
- const disabled = validateFunction ? !validateFunction(codeInput) : !codeInput
38
- const validateCode = useCallback((accessCode: string) => (accessCode ? validAccessCodes?.includes(accessCode) : false), [validAccessCodes])
39
-
40
- // keep the parent informed of the code input
41
- useEffect(() => {
42
- if (onCodeInputChange) {
43
- onCodeInputChange(codeInput)
44
- }
45
- }, [codeInput, onCodeInputChange])
46
-
47
- const onEnter = () => {
48
- onCodeInputChange?.(codeInput)
49
- if (codeInput) {
50
- const granted = validateCode(codeInput)
51
- if (granted) {
52
- setValidCode(true)
53
- // delay success callback to ensure the ui shows success before next action
54
- setTimeout(() => {
55
- setAccessGranted(granted)
56
- onAccessCodeSuccess?.(codeInput)
57
- }, successRedirectDelay)
58
- } else {
59
- setValidCode(false)
60
- }
61
- }
62
- }
63
-
64
- useEffect(() => {
65
- // whenever a code changes, reset the success/failure warning
66
- setValidCode(null)
67
- }, [codeInput])
68
-
69
- useEffect(() => {
70
- if (userAccessCodes) {
71
- const granted = userAccessCodes.some(code => validateCode(code))
72
- setAccessGranted(granted)
73
- if (granted) {
74
- onAccessCodeSuccess?.()
75
- }
76
- }
77
- setInitialized(true)
78
- }, [onAccessCodeSuccess, userAccessCodes, validateCode])
79
-
80
- return (
81
- <>
82
- {initialized
83
- ? accessGranted
84
- ? children
85
- : (
86
- <FlexGrowCol gap={2} {...props}>
87
- <FlexGrowRow gap={2} alignItems="start">
88
- <FormControl>
89
- <CodeTextField
90
- codeInput={codeInput}
91
- disabled={disabled}
92
- label="Enter Access Code"
93
- setCodeInput={setCodeInput}
94
- validCode={validCode}
95
- onEnter={onEnter}
96
- />
97
- </FormControl>
98
- <FormControl>
99
- <ButtonEx disabled={disabled} onClick={onEnter} variant="contained">
100
- Enter
101
- </ButtonEx>
102
- </FormControl>
103
- </FlexGrowRow>
104
- </FlexGrowCol>
105
- )
106
-
107
- : null}
108
- </>
109
- )
110
- }
@@ -1,47 +0,0 @@
1
- import { CheckCircleOutline, ErrorOutline } from '@mui/icons-material'
2
- import type { TextFieldProps } from '@mui/material'
3
- import {
4
- InputAdornment, styled, TextField,
5
- } from '@mui/material'
6
- import type { KeyboardEvent } from 'react'
7
- import React from 'react'
8
-
9
- export type CodeTextFieldProps = TextFieldProps & {
10
- codeInput?: string
11
- disabled?: boolean
12
- onEnter?: () => void
13
- setCodeInput?: (code?: string) => void
14
- validCode?: boolean | null
15
- }
16
-
17
- export const CodeTextField: React.FC<CodeTextFieldProps> = ({
18
- codeInput, disabled, onEnter, setCodeInput, validCode, ...props
19
- }) => (
20
- <StyledTextField
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
- }}
38
- onKeyUp={(event: KeyboardEvent) => (event.key === 'Enter' && !disabled ? onEnter?.() : null)}
39
- autoFocus
40
- size="small"
41
- value={codeInput ?? ''}
42
- onChange={(event: React.ChangeEvent<HTMLInputElement>) => setCodeInput?.(event.target.value)}
43
- {...props}
44
- />
45
- )
46
-
47
- const StyledTextField = styled(TextField, { name: 'StyledTextField' })(() => ({ '& .MuiInputBase-root': { paddingRight: 0 } }))
@@ -1 +0,0 @@
1
- export * from './AccessCodeGateFlexbox.tsx'
@@ -1 +0,0 @@
1
- export * from './useAccessCodes.ts'
@@ -1,34 +0,0 @@
1
- import { useMemo, useState } from 'react'
2
-
3
- export const useAccessCodes = (localStorageKey: string, validCodeLength = 6) => {
4
- const [validated, setValidated] = useState(false)
5
- const [codeInput, setCodeInput] = useState('')
6
-
7
- const onAccessCodeSuccess = () => {
8
- // Save the access code to local storage
9
- if (codeInput) {
10
- localStorage.setItem(localStorageKey, JSON.stringify([codeInput]))
11
- setValidated(true)
12
- } else {
13
- // If the codeInput is empty, but we have success, do nothing since the successful code is already saved
14
- setValidated(true)
15
- }
16
- }
17
- const validateCodeInput = (code?: string) => {
18
- return code?.length === validCodeLength
19
- }
20
- const onCodeInputChange = (code?: string) => {
21
- setCodeInput(code ?? '')
22
- }
23
- const userAccessCodes = useMemo(() => {
24
- const storedCodes = localStorage.getItem(localStorageKey)
25
- if (storedCodes) {
26
- const parsedResult = JSON.parse(storedCodes ?? '')
27
- if (Array.isArray(parsedResult)) return parsedResult
28
- }
29
- }, [localStorageKey])
30
-
31
- return {
32
- codeInput, validated, userAccessCodes, onAccessCodeSuccess, onCodeInputChange, validateCodeInput,
33
- }
34
- }
package/src/index.ts DELETED
@@ -1,2 +0,0 @@
1
- export * from './components/index.ts'
2
- export * from './hooks/index.ts'
@@ -1,5 +0,0 @@
1
- declare module '*.png'
2
- declare module '*.jpg'
3
- declare module '*.svg'
4
- declare module '*.gif'
5
- declare module '*.webp'