@spur.us/monocle-react 0.0.18 → 1.0.0
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/.turbo/turbo-build.log +22 -0
- package/CHANGELOG.md +25 -0
- package/LICENSE +21 -0
- package/README.md +32 -2
- package/dist/index.d.mts +16 -0
- package/dist/index.d.ts +16 -7
- package/dist/index.js +145 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +108 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +29 -78
- package/src/contexts/MonocleProvider.tsx +102 -0
- package/src/contexts/index.ts +1 -0
- package/src/global.d.ts +8 -0
- package/src/index.ts +1 -0
- package/src/utils/__tests__/useMaxAllowedInstancesGuard.test.tsx +117 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/useMaxAllowedInstancesGuard.tsx +77 -0
- package/tsconfig.declarations.json +11 -0
- package/tsconfig.json +20 -0
- package/tsup.config.ts +25 -0
- package/vitest.config.mts +11 -0
- package/vitest.setup.mts +8 -0
- package/dist/MonocleContext.d.ts +0 -2
- package/dist/MonocleContext.js +0 -9
- package/dist/MonocleContext.js.map +0 -1
- package/dist/MonocleProvider.d.ts +0 -8
- package/dist/MonocleProvider.js +0 -10
- package/dist/MonocleProvider.js.map +0 -1
- package/dist/hooks.d.ts +0 -2
- package/dist/hooks.js +0 -6
- package/dist/hooks.js.map +0 -1
- package/dist/index.test.d.ts +0 -1
- package/dist/index.test.js +0 -27
- package/dist/index.test.js.map +0 -1
- package/dist/withMonocle.d.ts +0 -7
- package/dist/withMonocle.js +0 -22
- package/dist/withMonocle.js.map +0 -1
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
|
|
2
|
+
> @spur.us/monocle-react@1.0.0 build /home/runner/work/javascript/javascript/packages/monocle-react
|
|
3
|
+
> tsup
|
|
4
|
+
|
|
5
|
+
[34mCLI[39m Building entry: {"index":"src/index.ts"}
|
|
6
|
+
[34mCLI[39m Using tsconfig: tsconfig.json
|
|
7
|
+
[34mCLI[39m tsup v8.4.0
|
|
8
|
+
[34mCLI[39m Using tsup config: /home/runner/work/javascript/javascript/packages/monocle-react/tsup.config.ts
|
|
9
|
+
[34mCLI[39m Target: es2019
|
|
10
|
+
[34mCLI[39m Cleaning output folder
|
|
11
|
+
[34mCJS[39m Build start
|
|
12
|
+
[34mESM[39m Build start
|
|
13
|
+
[32mCJS[39m [1mdist/index.js [22m[32m5.09 KB[39m
|
|
14
|
+
[32mCJS[39m [1mdist/index.js.map [22m[32m7.55 KB[39m
|
|
15
|
+
[32mCJS[39m ⚡️ Build success in 40ms
|
|
16
|
+
[32mESM[39m [1mdist/index.mjs [22m[32m3.29 KB[39m
|
|
17
|
+
[32mESM[39m [1mdist/index.mjs.map [22m[32m7.42 KB[39m
|
|
18
|
+
[32mESM[39m ⚡️ Build success in 40ms
|
|
19
|
+
[34mDTS[39m Build start
|
|
20
|
+
[32mDTS[39m ⚡️ Build success in 1853ms
|
|
21
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m432.00 B[39m
|
|
22
|
+
[32mDTS[39m [1mdist/index.d.mts [22m[32m432.00 B[39m
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# @spur.us/monocle-react
|
|
2
|
+
|
|
3
|
+
## 1.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- a2b3919: - Rename `bundle` to `assessment` in `useMonocle` hook
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- d377c8a: Remove 'use client' directive.
|
|
12
|
+
- Updated dependencies [a2b3919]
|
|
13
|
+
- Updated dependencies [d7071af]
|
|
14
|
+
- @spur.us/types@0.2.0
|
|
15
|
+
|
|
16
|
+
## 0.1.0
|
|
17
|
+
|
|
18
|
+
### Minor Changes
|
|
19
|
+
|
|
20
|
+
- 14d0ff0: Rename `token` prop to `publishableKey` in `MonocleProvider`.
|
|
21
|
+
|
|
22
|
+
### Patch Changes
|
|
23
|
+
|
|
24
|
+
- Updated dependencies [14d0ff0]
|
|
25
|
+
- @spur.us/types@0.1.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Spur Intelligence Corporation
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,33 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
<a href="https://spur.us">
|
|
3
|
+
<picture>
|
|
4
|
+
<source media="(prefers-color-scheme: dark)" srcset="../../docs/images/logo-dark-mode.svg">
|
|
5
|
+
<img alt="Spur logo" src="../../docs/images/logo-light-mode.svg" height="128">
|
|
6
|
+
</picture>
|
|
7
|
+
</a>
|
|
8
|
+
<br />
|
|
9
|
+
<h1>@spur.us/monocle-react</h1>
|
|
10
|
+
</div>
|
|
11
|
+
<br />
|
|
2
12
|
|
|
3
|
-
|
|
13
|
+
A React library for integrating Monocle into your React applications. This package provides a context provider and hooks for managing Monocle's functionality in your React components.
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @spur.us/monocle-react
|
|
19
|
+
# or
|
|
20
|
+
yarn add @spur.us/monocle-react
|
|
21
|
+
# or
|
|
22
|
+
pnpm add @spur.us/monocle-react
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Contributing
|
|
26
|
+
|
|
27
|
+
We welcome all contributors!
|
|
28
|
+
|
|
29
|
+
Please read our [contributing guidelines](https://github.com/spurintel/javascript/blob/main/docs/CONTRIBUTING.md) to learn how to submit issues or open pull requests.
|
|
30
|
+
|
|
31
|
+
## License
|
|
32
|
+
|
|
33
|
+
This project is licensed under the [MIT license](https://github.com/spurintel/javascript/blob/main/packages/monocle-react/LICENSE).
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
interface MonocleContextType {
|
|
4
|
+
assessment: string | undefined;
|
|
5
|
+
refresh: () => void;
|
|
6
|
+
isLoading: boolean;
|
|
7
|
+
error: Error | null;
|
|
8
|
+
}
|
|
9
|
+
interface MonocleProviderProps {
|
|
10
|
+
children: React.ReactNode;
|
|
11
|
+
publishableKey: string;
|
|
12
|
+
}
|
|
13
|
+
declare const MonocleProvider: React.ComponentType<MonocleProviderProps>;
|
|
14
|
+
declare const useMonocle: () => MonocleContextType;
|
|
15
|
+
|
|
16
|
+
export { MonocleProvider, useMonocle };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
interface MonocleContextType {
|
|
4
|
+
assessment: string | undefined;
|
|
5
|
+
refresh: () => void;
|
|
6
|
+
isLoading: boolean;
|
|
7
|
+
error: Error | null;
|
|
8
|
+
}
|
|
9
|
+
interface MonocleProviderProps {
|
|
10
|
+
children: React.ReactNode;
|
|
11
|
+
publishableKey: string;
|
|
12
|
+
}
|
|
13
|
+
declare const MonocleProvider: React.ComponentType<MonocleProviderProps>;
|
|
14
|
+
declare const useMonocle: () => MonocleContextType;
|
|
15
|
+
|
|
16
|
+
export { MonocleProvider, useMonocle };
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,146 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
var
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var src_exports = {};
|
|
32
|
+
__export(src_exports, {
|
|
33
|
+
MonocleProvider: () => MonocleProvider,
|
|
34
|
+
useMonocle: () => useMonocle
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(src_exports);
|
|
37
|
+
|
|
38
|
+
// src/contexts/MonocleProvider.tsx
|
|
39
|
+
var import_react2 = require("react");
|
|
40
|
+
|
|
41
|
+
// src/utils/useMaxAllowedInstancesGuard.tsx
|
|
42
|
+
var import_react = __toESM(require("react"));
|
|
43
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
44
|
+
var instanceCounter = /* @__PURE__ */ new Map();
|
|
45
|
+
function useMaxAllowedInstancesGuard(name, error, maxCount = 1) {
|
|
46
|
+
import_react.default.useEffect(() => {
|
|
47
|
+
const count = instanceCounter.get(name) || 0;
|
|
48
|
+
if (count === maxCount) {
|
|
49
|
+
throw new Error(error);
|
|
50
|
+
}
|
|
51
|
+
instanceCounter.set(name, count + 1);
|
|
52
|
+
return () => {
|
|
53
|
+
instanceCounter.set(name, (instanceCounter.get(name) || 1) - 1);
|
|
54
|
+
};
|
|
55
|
+
}, []);
|
|
56
|
+
}
|
|
57
|
+
function withMaxAllowedInstancesGuard(WrappedComponent, name, error) {
|
|
58
|
+
const displayName = WrappedComponent.displayName || WrappedComponent.name || name || "Component";
|
|
59
|
+
const Hoc = (props) => {
|
|
60
|
+
useMaxAllowedInstancesGuard(name, error);
|
|
61
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(WrappedComponent, { ...props });
|
|
62
|
+
};
|
|
63
|
+
Hoc.displayName = `withMaxAllowedInstancesGuard(${displayName})`;
|
|
64
|
+
return Hoc;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// src/contexts/MonocleProvider.tsx
|
|
68
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
69
|
+
var MonocleContext = (0, import_react2.createContext)(null);
|
|
70
|
+
var MonocleProviderComponent = ({
|
|
71
|
+
children,
|
|
72
|
+
publishableKey
|
|
73
|
+
}) => {
|
|
74
|
+
const [assessment, setAssessment] = (0, import_react2.useState)(void 0);
|
|
75
|
+
const [isLoading, setIsLoading] = (0, import_react2.useState)(true);
|
|
76
|
+
const [error, setError] = (0, import_react2.useState)(null);
|
|
77
|
+
const loadScript = () => {
|
|
78
|
+
return new Promise((resolve, reject) => {
|
|
79
|
+
const existingScript = document.getElementById("_mcl");
|
|
80
|
+
if (existingScript) {
|
|
81
|
+
if (!window.MCL) {
|
|
82
|
+
existingScript.onload = () => resolve();
|
|
83
|
+
existingScript.onerror = () => reject(new Error("Failed to load Monocle script"));
|
|
84
|
+
} else {
|
|
85
|
+
resolve();
|
|
86
|
+
}
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const script = document.createElement("script");
|
|
90
|
+
script.id = "_mcl";
|
|
91
|
+
script.async = true;
|
|
92
|
+
script.src = `https://mcl.spur.us/d/mcl.js?tk=${publishableKey}`;
|
|
93
|
+
script.onload = () => {
|
|
94
|
+
resolve();
|
|
95
|
+
};
|
|
96
|
+
script.onerror = (_e) => {
|
|
97
|
+
console.error("MonocleProvider: Script failed to load");
|
|
98
|
+
reject(new Error("Failed to load Monocle script"));
|
|
99
|
+
};
|
|
100
|
+
document.head.appendChild(script);
|
|
101
|
+
});
|
|
102
|
+
};
|
|
103
|
+
const refresh = async () => {
|
|
104
|
+
try {
|
|
105
|
+
setIsLoading(true);
|
|
106
|
+
setError(null);
|
|
107
|
+
await loadScript();
|
|
108
|
+
if (window.MCL) {
|
|
109
|
+
const newAssessment = window.MCL.getAssessment();
|
|
110
|
+
setAssessment(newAssessment);
|
|
111
|
+
} else {
|
|
112
|
+
throw new Error("MCL object not found on window");
|
|
113
|
+
}
|
|
114
|
+
} catch (err) {
|
|
115
|
+
setError(
|
|
116
|
+
err instanceof Error ? err : new Error("Unknown error occurred")
|
|
117
|
+
);
|
|
118
|
+
} finally {
|
|
119
|
+
setIsLoading(false);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
(0, import_react2.useEffect)(() => {
|
|
123
|
+
if (!assessment) {
|
|
124
|
+
refresh();
|
|
125
|
+
}
|
|
126
|
+
}, [publishableKey]);
|
|
127
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(MonocleContext.Provider, { value: { assessment, refresh, isLoading, error }, children });
|
|
128
|
+
};
|
|
129
|
+
var MonocleProvider = withMaxAllowedInstancesGuard(
|
|
130
|
+
MonocleProviderComponent,
|
|
131
|
+
"MonocleProvider",
|
|
132
|
+
"Only one instance of MonocleProvider is allowed"
|
|
133
|
+
);
|
|
134
|
+
var useMonocle = () => {
|
|
135
|
+
const context = (0, import_react2.useContext)(MonocleContext);
|
|
136
|
+
if (!context) {
|
|
137
|
+
throw new Error("useMonocle must be used within a MonocleProvider");
|
|
138
|
+
}
|
|
139
|
+
return context;
|
|
140
|
+
};
|
|
141
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
142
|
+
0 && (module.exports = {
|
|
143
|
+
MonocleProvider,
|
|
144
|
+
useMonocle
|
|
145
|
+
});
|
|
8
146
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/contexts/MonocleProvider.tsx","../src/utils/useMaxAllowedInstancesGuard.tsx"],"sourcesContent":["export * from './contexts';\n","import React, { createContext, useContext, useEffect, useState } from 'react';\nimport { withMaxAllowedInstancesGuard } from '../utils';\n\ninterface MonocleContextType {\n assessment: string | undefined;\n refresh: () => void;\n isLoading: boolean;\n error: Error | null;\n}\n\nconst MonocleContext = createContext<MonocleContextType | null>(null);\n\ninterface MonocleProviderProps {\n children: React.ReactNode;\n publishableKey: string;\n}\n\nconst MonocleProviderComponent: React.FC<MonocleProviderProps> = ({\n children,\n publishableKey,\n}) => {\n const [assessment, setAssessment] = useState<string | undefined>(undefined);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const loadScript = () => {\n return new Promise<void>((resolve, reject) => {\n const existingScript = document.getElementById('_mcl');\n if (existingScript) {\n // If script exists but hasn't loaded yet, wait for it\n if (!window.MCL) {\n existingScript.onload = () => resolve();\n existingScript.onerror = () =>\n reject(new Error('Failed to load Monocle script'));\n } else {\n resolve();\n }\n return;\n }\n\n const script = document.createElement('script');\n script.id = '_mcl';\n script.async = true;\n script.src = `https://mcl.spur.us/d/mcl.js?tk=${publishableKey}`;\n script.onload = () => {\n resolve();\n };\n script.onerror = (_e) => {\n console.error('MonocleProvider: Script failed to load');\n reject(new Error('Failed to load Monocle script'));\n };\n document.head.appendChild(script);\n });\n };\n\n const refresh = async () => {\n try {\n setIsLoading(true);\n setError(null);\n await loadScript();\n if (window.MCL) {\n const newAssessment = window.MCL.getAssessment();\n setAssessment(newAssessment);\n } else {\n throw new Error('MCL object not found on window');\n }\n } catch (err) {\n setError(\n err instanceof Error ? err : new Error('Unknown error occurred')\n );\n } finally {\n setIsLoading(false);\n }\n };\n\n useEffect(() => {\n // Only refresh if the publishableKey changes and we don't already have an assessment\n if (!assessment) {\n refresh();\n }\n }, [publishableKey]);\n\n return (\n <MonocleContext.Provider value={{ assessment, refresh, isLoading, error }}>\n {children}\n </MonocleContext.Provider>\n );\n};\n\nexport const MonocleProvider = withMaxAllowedInstancesGuard(\n MonocleProviderComponent,\n 'MonocleProvider',\n 'Only one instance of MonocleProvider is allowed'\n);\n\nexport const useMonocle = () => {\n const context = useContext(MonocleContext);\n if (!context) {\n throw new Error('useMonocle must be used within a MonocleProvider');\n }\n return context;\n};\n","import React from 'react';\n\nconst instanceCounter = new Map<string, number>();\n\n/**\n * A React hook that ensures a component is not instantiated more than a specified number of times.\n * Throws an error if the maximum number of instances is exceeded.\n *\n * @param name - A unique identifier for the component type\n * @param error - The error message to display if the maximum count is exceeded\n * @param maxCount - The maximum number of allowed instances (defaults to 1)\n * @throws Error when the maximum number of instances is exceeded\n *\n * @example\n * ```tsx\n * const MyComponent = () => {\n * useMaxAllowedInstancesGuard('MyComponent', 'Only one instance of MyComponent is allowed');\n * return <div>My Component</div>;\n * };\n * ```\n */\nexport function useMaxAllowedInstancesGuard(\n name: string,\n error: string,\n maxCount = 1\n): void {\n React.useEffect(() => {\n const count = instanceCounter.get(name) || 0;\n if (count === maxCount) {\n throw new Error(error);\n }\n instanceCounter.set(name, count + 1);\n\n return () => {\n instanceCounter.set(name, (instanceCounter.get(name) || 1) - 1);\n };\n }, []);\n}\n\n/**\n * A higher-order component that wraps a component with instance count protection.\n * This HOC ensures that the wrapped component cannot be instantiated more than once\n * (or a specified number of times) in the application.\n *\n * @param WrappedComponent - The component to wrap with instance count protection\n * @param name - A unique identifier for the component type\n * @param error - The error message to display if the maximum count is exceeded\n * @returns A new component with instance count protection\n *\n * @example\n * ```tsx\n * const ProtectedComponent = withMaxAllowedInstancesGuard(\n * MyComponent,\n * 'MyComponent',\n * 'Only one instance of MyComponent is allowed'\n * );\n * ```\n */\nexport function withMaxAllowedInstancesGuard<P extends object>(\n WrappedComponent: React.ComponentType<P>,\n name: string,\n error: string\n): React.ComponentType<P> {\n const displayName =\n WrappedComponent.displayName ||\n WrappedComponent.name ||\n name ||\n 'Component';\n\n const Hoc: React.FC<P> = (props) => {\n useMaxAllowedInstancesGuard(name, error);\n return <WrappedComponent {...props} />;\n };\n\n Hoc.displayName = `withMaxAllowedInstancesGuard(${displayName})`;\n return Hoc;\n}\n"],"mappings":"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","names":["import_react","React","import_jsx_runtime"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// src/contexts/MonocleProvider.tsx
|
|
2
|
+
import { createContext, useContext, useEffect, useState } from "react";
|
|
3
|
+
|
|
4
|
+
// src/utils/useMaxAllowedInstancesGuard.tsx
|
|
5
|
+
import React from "react";
|
|
6
|
+
import { jsx } from "react/jsx-runtime";
|
|
7
|
+
var instanceCounter = /* @__PURE__ */ new Map();
|
|
8
|
+
function useMaxAllowedInstancesGuard(name, error, maxCount = 1) {
|
|
9
|
+
React.useEffect(() => {
|
|
10
|
+
const count = instanceCounter.get(name) || 0;
|
|
11
|
+
if (count === maxCount) {
|
|
12
|
+
throw new Error(error);
|
|
13
|
+
}
|
|
14
|
+
instanceCounter.set(name, count + 1);
|
|
15
|
+
return () => {
|
|
16
|
+
instanceCounter.set(name, (instanceCounter.get(name) || 1) - 1);
|
|
17
|
+
};
|
|
18
|
+
}, []);
|
|
19
|
+
}
|
|
20
|
+
function withMaxAllowedInstancesGuard(WrappedComponent, name, error) {
|
|
21
|
+
const displayName = WrappedComponent.displayName || WrappedComponent.name || name || "Component";
|
|
22
|
+
const Hoc = (props) => {
|
|
23
|
+
useMaxAllowedInstancesGuard(name, error);
|
|
24
|
+
return /* @__PURE__ */ jsx(WrappedComponent, { ...props });
|
|
25
|
+
};
|
|
26
|
+
Hoc.displayName = `withMaxAllowedInstancesGuard(${displayName})`;
|
|
27
|
+
return Hoc;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// src/contexts/MonocleProvider.tsx
|
|
31
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
32
|
+
var MonocleContext = createContext(null);
|
|
33
|
+
var MonocleProviderComponent = ({
|
|
34
|
+
children,
|
|
35
|
+
publishableKey
|
|
36
|
+
}) => {
|
|
37
|
+
const [assessment, setAssessment] = useState(void 0);
|
|
38
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
39
|
+
const [error, setError] = useState(null);
|
|
40
|
+
const loadScript = () => {
|
|
41
|
+
return new Promise((resolve, reject) => {
|
|
42
|
+
const existingScript = document.getElementById("_mcl");
|
|
43
|
+
if (existingScript) {
|
|
44
|
+
if (!window.MCL) {
|
|
45
|
+
existingScript.onload = () => resolve();
|
|
46
|
+
existingScript.onerror = () => reject(new Error("Failed to load Monocle script"));
|
|
47
|
+
} else {
|
|
48
|
+
resolve();
|
|
49
|
+
}
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const script = document.createElement("script");
|
|
53
|
+
script.id = "_mcl";
|
|
54
|
+
script.async = true;
|
|
55
|
+
script.src = `https://mcl.spur.us/d/mcl.js?tk=${publishableKey}`;
|
|
56
|
+
script.onload = () => {
|
|
57
|
+
resolve();
|
|
58
|
+
};
|
|
59
|
+
script.onerror = (_e) => {
|
|
60
|
+
console.error("MonocleProvider: Script failed to load");
|
|
61
|
+
reject(new Error("Failed to load Monocle script"));
|
|
62
|
+
};
|
|
63
|
+
document.head.appendChild(script);
|
|
64
|
+
});
|
|
65
|
+
};
|
|
66
|
+
const refresh = async () => {
|
|
67
|
+
try {
|
|
68
|
+
setIsLoading(true);
|
|
69
|
+
setError(null);
|
|
70
|
+
await loadScript();
|
|
71
|
+
if (window.MCL) {
|
|
72
|
+
const newAssessment = window.MCL.getAssessment();
|
|
73
|
+
setAssessment(newAssessment);
|
|
74
|
+
} else {
|
|
75
|
+
throw new Error("MCL object not found on window");
|
|
76
|
+
}
|
|
77
|
+
} catch (err) {
|
|
78
|
+
setError(
|
|
79
|
+
err instanceof Error ? err : new Error("Unknown error occurred")
|
|
80
|
+
);
|
|
81
|
+
} finally {
|
|
82
|
+
setIsLoading(false);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
if (!assessment) {
|
|
87
|
+
refresh();
|
|
88
|
+
}
|
|
89
|
+
}, [publishableKey]);
|
|
90
|
+
return /* @__PURE__ */ jsx2(MonocleContext.Provider, { value: { assessment, refresh, isLoading, error }, children });
|
|
91
|
+
};
|
|
92
|
+
var MonocleProvider = withMaxAllowedInstancesGuard(
|
|
93
|
+
MonocleProviderComponent,
|
|
94
|
+
"MonocleProvider",
|
|
95
|
+
"Only one instance of MonocleProvider is allowed"
|
|
96
|
+
);
|
|
97
|
+
var useMonocle = () => {
|
|
98
|
+
const context = useContext(MonocleContext);
|
|
99
|
+
if (!context) {
|
|
100
|
+
throw new Error("useMonocle must be used within a MonocleProvider");
|
|
101
|
+
}
|
|
102
|
+
return context;
|
|
103
|
+
};
|
|
104
|
+
export {
|
|
105
|
+
MonocleProvider,
|
|
106
|
+
useMonocle
|
|
107
|
+
};
|
|
108
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/contexts/MonocleProvider.tsx","../src/utils/useMaxAllowedInstancesGuard.tsx"],"sourcesContent":["import React, { createContext, useContext, useEffect, useState } from 'react';\nimport { withMaxAllowedInstancesGuard } from '../utils';\n\ninterface MonocleContextType {\n assessment: string | undefined;\n refresh: () => void;\n isLoading: boolean;\n error: Error | null;\n}\n\nconst MonocleContext = createContext<MonocleContextType | null>(null);\n\ninterface MonocleProviderProps {\n children: React.ReactNode;\n publishableKey: string;\n}\n\nconst MonocleProviderComponent: React.FC<MonocleProviderProps> = ({\n children,\n publishableKey,\n}) => {\n const [assessment, setAssessment] = useState<string | undefined>(undefined);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const loadScript = () => {\n return new Promise<void>((resolve, reject) => {\n const existingScript = document.getElementById('_mcl');\n if (existingScript) {\n // If script exists but hasn't loaded yet, wait for it\n if (!window.MCL) {\n existingScript.onload = () => resolve();\n existingScript.onerror = () =>\n reject(new Error('Failed to load Monocle script'));\n } else {\n resolve();\n }\n return;\n }\n\n const script = document.createElement('script');\n script.id = '_mcl';\n script.async = true;\n script.src = `https://mcl.spur.us/d/mcl.js?tk=${publishableKey}`;\n script.onload = () => {\n resolve();\n };\n script.onerror = (_e) => {\n console.error('MonocleProvider: Script failed to load');\n reject(new Error('Failed to load Monocle script'));\n };\n document.head.appendChild(script);\n });\n };\n\n const refresh = async () => {\n try {\n setIsLoading(true);\n setError(null);\n await loadScript();\n if (window.MCL) {\n const newAssessment = window.MCL.getAssessment();\n setAssessment(newAssessment);\n } else {\n throw new Error('MCL object not found on window');\n }\n } catch (err) {\n setError(\n err instanceof Error ? err : new Error('Unknown error occurred')\n );\n } finally {\n setIsLoading(false);\n }\n };\n\n useEffect(() => {\n // Only refresh if the publishableKey changes and we don't already have an assessment\n if (!assessment) {\n refresh();\n }\n }, [publishableKey]);\n\n return (\n <MonocleContext.Provider value={{ assessment, refresh, isLoading, error }}>\n {children}\n </MonocleContext.Provider>\n );\n};\n\nexport const MonocleProvider = withMaxAllowedInstancesGuard(\n MonocleProviderComponent,\n 'MonocleProvider',\n 'Only one instance of MonocleProvider is allowed'\n);\n\nexport const useMonocle = () => {\n const context = useContext(MonocleContext);\n if (!context) {\n throw new Error('useMonocle must be used within a MonocleProvider');\n }\n return context;\n};\n","import React from 'react';\n\nconst instanceCounter = new Map<string, number>();\n\n/**\n * A React hook that ensures a component is not instantiated more than a specified number of times.\n * Throws an error if the maximum number of instances is exceeded.\n *\n * @param name - A unique identifier for the component type\n * @param error - The error message to display if the maximum count is exceeded\n * @param maxCount - The maximum number of allowed instances (defaults to 1)\n * @throws Error when the maximum number of instances is exceeded\n *\n * @example\n * ```tsx\n * const MyComponent = () => {\n * useMaxAllowedInstancesGuard('MyComponent', 'Only one instance of MyComponent is allowed');\n * return <div>My Component</div>;\n * };\n * ```\n */\nexport function useMaxAllowedInstancesGuard(\n name: string,\n error: string,\n maxCount = 1\n): void {\n React.useEffect(() => {\n const count = instanceCounter.get(name) || 0;\n if (count === maxCount) {\n throw new Error(error);\n }\n instanceCounter.set(name, count + 1);\n\n return () => {\n instanceCounter.set(name, (instanceCounter.get(name) || 1) - 1);\n };\n }, []);\n}\n\n/**\n * A higher-order component that wraps a component with instance count protection.\n * This HOC ensures that the wrapped component cannot be instantiated more than once\n * (or a specified number of times) in the application.\n *\n * @param WrappedComponent - The component to wrap with instance count protection\n * @param name - A unique identifier for the component type\n * @param error - The error message to display if the maximum count is exceeded\n * @returns A new component with instance count protection\n *\n * @example\n * ```tsx\n * const ProtectedComponent = withMaxAllowedInstancesGuard(\n * MyComponent,\n * 'MyComponent',\n * 'Only one instance of MyComponent is allowed'\n * );\n * ```\n */\nexport function withMaxAllowedInstancesGuard<P extends object>(\n WrappedComponent: React.ComponentType<P>,\n name: string,\n error: string\n): React.ComponentType<P> {\n const displayName =\n WrappedComponent.displayName ||\n WrappedComponent.name ||\n name ||\n 'Component';\n\n const Hoc: React.FC<P> = (props) => {\n useMaxAllowedInstancesGuard(name, error);\n return <WrappedComponent {...props} />;\n };\n\n Hoc.displayName = `withMaxAllowedInstancesGuard(${displayName})`;\n return Hoc;\n}\n"],"mappings":"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","names":["jsx"]}
|
package/package.json
CHANGED
|
@@ -1,87 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spur.us/monocle-react",
|
|
3
|
-
"version": "0.0
|
|
4
|
-
"description": "",
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"exports": {
|
|
10
|
-
".": {
|
|
11
|
-
"import": "./dist/index.js",
|
|
12
|
-
"default": "./dist/index.js"
|
|
13
|
-
},
|
|
14
|
-
"./package.json": "./package.json"
|
|
15
|
-
},
|
|
16
|
-
"files": [
|
|
17
|
-
"dist"
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Monocle React library",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"spur",
|
|
7
|
+
"monocle",
|
|
8
|
+
"react"
|
|
18
9
|
],
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"lint": "eslint ./src --ext .ts",
|
|
23
|
-
"test": "jest"
|
|
10
|
+
"homepage": "https://spur.us",
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/spurintel/javascript/issues"
|
|
24
13
|
},
|
|
25
|
-
"
|
|
26
|
-
"
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/spurintel/javascript.git",
|
|
17
|
+
"directory": "packages/monocle-react"
|
|
27
18
|
},
|
|
19
|
+
"main": "./dist/index.js",
|
|
20
|
+
"author": "Spur",
|
|
21
|
+
"license": "MIT",
|
|
28
22
|
"dependencies": {
|
|
29
|
-
"@spur.us/
|
|
30
|
-
"hoist-non-react-statics": "^3.3.2",
|
|
31
|
-
"tiny-invariant": "^1.2.0"
|
|
32
|
-
},
|
|
33
|
-
"devDependencies": {
|
|
34
|
-
"@types/hoist-non-react-statics": "^3.3.1",
|
|
35
|
-
"@types/react": "^17.0.37",
|
|
36
|
-
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
|
37
|
-
"@typescript-eslint/eslint-plugin-tslint": "^5.4.0",
|
|
38
|
-
"@typescript-eslint/parser": "^5.4.0",
|
|
39
|
-
"eslint": "^8.3.0",
|
|
40
|
-
"eslint-plugin-import": "^2.25.3",
|
|
41
|
-
"eslint-plugin-unused-imports": "^2.0.0",
|
|
42
|
-
"eslint-webpack-plugin": "^3.1.1",
|
|
43
|
-
"jest": "^27.5.1",
|
|
44
|
-
"terser-webpack-plugin": "^5.2.5",
|
|
45
|
-
"ts-jest": "^27.1.4",
|
|
46
|
-
"ts-loader": "^9.2.6",
|
|
47
|
-
"ts-node": "^10.4.0",
|
|
48
|
-
"typescript": "^4.5.2",
|
|
49
|
-
"webpack": "^5.64.2",
|
|
50
|
-
"webpack-cli": "^4.9.1"
|
|
23
|
+
"@spur.us/types": "^0.2.0"
|
|
51
24
|
},
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
|
|
55
|
-
"not dead",
|
|
56
|
-
"not op_mini all"
|
|
57
|
-
],
|
|
58
|
-
"development": [
|
|
59
|
-
"last 1 chrome version",
|
|
60
|
-
"last 1 firefox version",
|
|
61
|
-
"last 1 safari version"
|
|
62
|
-
]
|
|
25
|
+
"peerDependencies": {
|
|
26
|
+
"react": "^18.0.0 || ^19.0.0 || ^19.0.0-0",
|
|
27
|
+
"react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-0"
|
|
63
28
|
},
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
"transform": {
|
|
73
|
-
"^.+\\.ts?$": "ts-jest"
|
|
74
|
-
},
|
|
75
|
-
"testRegex": "(\\.test)\\.(jsx?|tsx?)$",
|
|
76
|
-
"testPathIgnorePatterns": [
|
|
77
|
-
"/node_modules/"
|
|
78
|
-
],
|
|
79
|
-
"moduleFileExtensions": [
|
|
80
|
-
"js",
|
|
81
|
-
"jsx",
|
|
82
|
-
"ts",
|
|
83
|
-
"tsx"
|
|
84
|
-
],
|
|
85
|
-
"collectCoverage": true
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "tsup",
|
|
31
|
+
"build:declarations": "tsc -p tsconfig.declarations.json",
|
|
32
|
+
"clean": "rimraf ./dist",
|
|
33
|
+
"dev": "tsup --watch",
|
|
34
|
+
"lint": "eslint src",
|
|
35
|
+
"publish:local": "pnpm yalc push --replace --sig",
|
|
36
|
+
"test": "vitest"
|
|
86
37
|
}
|
|
87
|
-
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import React, { createContext, useContext, useEffect, useState } from 'react';
|
|
2
|
+
import { withMaxAllowedInstancesGuard } from '../utils';
|
|
3
|
+
|
|
4
|
+
interface MonocleContextType {
|
|
5
|
+
assessment: string | undefined;
|
|
6
|
+
refresh: () => void;
|
|
7
|
+
isLoading: boolean;
|
|
8
|
+
error: Error | null;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const MonocleContext = createContext<MonocleContextType | null>(null);
|
|
12
|
+
|
|
13
|
+
interface MonocleProviderProps {
|
|
14
|
+
children: React.ReactNode;
|
|
15
|
+
publishableKey: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const MonocleProviderComponent: React.FC<MonocleProviderProps> = ({
|
|
19
|
+
children,
|
|
20
|
+
publishableKey,
|
|
21
|
+
}) => {
|
|
22
|
+
const [assessment, setAssessment] = useState<string | undefined>(undefined);
|
|
23
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
24
|
+
const [error, setError] = useState<Error | null>(null);
|
|
25
|
+
|
|
26
|
+
const loadScript = () => {
|
|
27
|
+
return new Promise<void>((resolve, reject) => {
|
|
28
|
+
const existingScript = document.getElementById('_mcl');
|
|
29
|
+
if (existingScript) {
|
|
30
|
+
// If script exists but hasn't loaded yet, wait for it
|
|
31
|
+
if (!window.MCL) {
|
|
32
|
+
existingScript.onload = () => resolve();
|
|
33
|
+
existingScript.onerror = () =>
|
|
34
|
+
reject(new Error('Failed to load Monocle script'));
|
|
35
|
+
} else {
|
|
36
|
+
resolve();
|
|
37
|
+
}
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const script = document.createElement('script');
|
|
42
|
+
script.id = '_mcl';
|
|
43
|
+
script.async = true;
|
|
44
|
+
script.src = `https://mcl.spur.us/d/mcl.js?tk=${publishableKey}`;
|
|
45
|
+
script.onload = () => {
|
|
46
|
+
resolve();
|
|
47
|
+
};
|
|
48
|
+
script.onerror = (_e) => {
|
|
49
|
+
console.error('MonocleProvider: Script failed to load');
|
|
50
|
+
reject(new Error('Failed to load Monocle script'));
|
|
51
|
+
};
|
|
52
|
+
document.head.appendChild(script);
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const refresh = async () => {
|
|
57
|
+
try {
|
|
58
|
+
setIsLoading(true);
|
|
59
|
+
setError(null);
|
|
60
|
+
await loadScript();
|
|
61
|
+
if (window.MCL) {
|
|
62
|
+
const newAssessment = window.MCL.getAssessment();
|
|
63
|
+
setAssessment(newAssessment);
|
|
64
|
+
} else {
|
|
65
|
+
throw new Error('MCL object not found on window');
|
|
66
|
+
}
|
|
67
|
+
} catch (err) {
|
|
68
|
+
setError(
|
|
69
|
+
err instanceof Error ? err : new Error('Unknown error occurred')
|
|
70
|
+
);
|
|
71
|
+
} finally {
|
|
72
|
+
setIsLoading(false);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
useEffect(() => {
|
|
77
|
+
// Only refresh if the publishableKey changes and we don't already have an assessment
|
|
78
|
+
if (!assessment) {
|
|
79
|
+
refresh();
|
|
80
|
+
}
|
|
81
|
+
}, [publishableKey]);
|
|
82
|
+
|
|
83
|
+
return (
|
|
84
|
+
<MonocleContext.Provider value={{ assessment, refresh, isLoading, error }}>
|
|
85
|
+
{children}
|
|
86
|
+
</MonocleContext.Provider>
|
|
87
|
+
);
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export const MonocleProvider = withMaxAllowedInstancesGuard(
|
|
91
|
+
MonocleProviderComponent,
|
|
92
|
+
'MonocleProvider',
|
|
93
|
+
'Only one instance of MonocleProvider is allowed'
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
export const useMonocle = () => {
|
|
97
|
+
const context = useContext(MonocleContext);
|
|
98
|
+
if (!context) {
|
|
99
|
+
throw new Error('useMonocle must be used within a MonocleProvider');
|
|
100
|
+
}
|
|
101
|
+
return context;
|
|
102
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './MonocleProvider';
|
package/src/global.d.ts
ADDED
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './contexts';
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import '@testing-library/jest-dom';
|
|
4
|
+
import {
|
|
5
|
+
useMaxAllowedInstancesGuard,
|
|
6
|
+
withMaxAllowedInstancesGuard,
|
|
7
|
+
} from '../useMaxAllowedInstancesGuard';
|
|
8
|
+
|
|
9
|
+
describe('useMaxAllowedInstancesGuard', () => {
|
|
10
|
+
it('should allow a single instance of a component', () => {
|
|
11
|
+
const TestComponent = () => {
|
|
12
|
+
useMaxAllowedInstancesGuard('TestComponent', 'Only one instance allowed');
|
|
13
|
+
return <div>Test Component</div>;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
expect(() => render(<TestComponent />)).not.toThrow();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should throw an error when exceeding max instances', () => {
|
|
20
|
+
const TestComponent = () => {
|
|
21
|
+
useMaxAllowedInstancesGuard('TestComponent', 'Only one instance allowed');
|
|
22
|
+
return <div>Test Component</div>;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// First instance should work
|
|
26
|
+
render(<TestComponent />);
|
|
27
|
+
|
|
28
|
+
// Second instance should throw
|
|
29
|
+
expect(() => render(<TestComponent />)).toThrow(
|
|
30
|
+
'Only one instance allowed'
|
|
31
|
+
);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should allow multiple instances when maxCount is greater than 1', () => {
|
|
35
|
+
const TestComponent = () => {
|
|
36
|
+
useMaxAllowedInstancesGuard(
|
|
37
|
+
'TestComponent',
|
|
38
|
+
'Only two instances allowed',
|
|
39
|
+
2
|
|
40
|
+
);
|
|
41
|
+
return <div>Test Component</div>;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// First instance
|
|
45
|
+
render(<TestComponent />);
|
|
46
|
+
|
|
47
|
+
// Second instance should work
|
|
48
|
+
expect(() => render(<TestComponent />)).not.toThrow();
|
|
49
|
+
|
|
50
|
+
// Third instance should throw
|
|
51
|
+
expect(() => render(<TestComponent />)).toThrow(
|
|
52
|
+
'Only two instances allowed'
|
|
53
|
+
);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('should decrement count when component unmounts', () => {
|
|
57
|
+
const TestComponent = () => {
|
|
58
|
+
useMaxAllowedInstancesGuard('TestComponent', 'Only one instance allowed');
|
|
59
|
+
return <div>Test Component</div>;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const { unmount } = render(<TestComponent />);
|
|
63
|
+
unmount();
|
|
64
|
+
|
|
65
|
+
// After unmounting, we should be able to render again
|
|
66
|
+
expect(() => render(<TestComponent />)).not.toThrow();
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe('withMaxAllowedInstancesGuard', () => {
|
|
71
|
+
interface TestComponentProps {
|
|
72
|
+
text: string;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const TestComponent: React.FC<TestComponentProps> = ({ text }) => (
|
|
76
|
+
<div>{text}</div>
|
|
77
|
+
);
|
|
78
|
+
TestComponent.displayName = 'TestComponent';
|
|
79
|
+
|
|
80
|
+
it('should wrap a component with instance count protection', () => {
|
|
81
|
+
const ProtectedComponent = withMaxAllowedInstancesGuard(
|
|
82
|
+
TestComponent,
|
|
83
|
+
'TestComponent',
|
|
84
|
+
'Only one instance allowed'
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
render(<ProtectedComponent text="First Instance" />);
|
|
88
|
+
expect(screen.getByText('First Instance')).toBeInTheDocument();
|
|
89
|
+
|
|
90
|
+
expect(() => render(<ProtectedComponent text="Second Instance" />)).toThrow(
|
|
91
|
+
'Only one instance allowed'
|
|
92
|
+
);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('should preserve component props', () => {
|
|
96
|
+
const ProtectedComponent = withMaxAllowedInstancesGuard(
|
|
97
|
+
TestComponent,
|
|
98
|
+
'TestComponent',
|
|
99
|
+
'Only one instance allowed'
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
render(<ProtectedComponent text="Test Text" />);
|
|
103
|
+
expect(screen.getByText('Test Text')).toBeInTheDocument();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('should use component displayName if available', () => {
|
|
107
|
+
const ProtectedComponent = withMaxAllowedInstancesGuard(
|
|
108
|
+
TestComponent,
|
|
109
|
+
'TestComponent',
|
|
110
|
+
'Only one instance allowed'
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
expect(ProtectedComponent.displayName).toBe(
|
|
114
|
+
'withMaxAllowedInstancesGuard(TestComponent)'
|
|
115
|
+
);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './useMaxAllowedInstancesGuard';
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
const instanceCounter = new Map<string, number>();
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A React hook that ensures a component is not instantiated more than a specified number of times.
|
|
7
|
+
* Throws an error if the maximum number of instances is exceeded.
|
|
8
|
+
*
|
|
9
|
+
* @param name - A unique identifier for the component type
|
|
10
|
+
* @param error - The error message to display if the maximum count is exceeded
|
|
11
|
+
* @param maxCount - The maximum number of allowed instances (defaults to 1)
|
|
12
|
+
* @throws Error when the maximum number of instances is exceeded
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```tsx
|
|
16
|
+
* const MyComponent = () => {
|
|
17
|
+
* useMaxAllowedInstancesGuard('MyComponent', 'Only one instance of MyComponent is allowed');
|
|
18
|
+
* return <div>My Component</div>;
|
|
19
|
+
* };
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export function useMaxAllowedInstancesGuard(
|
|
23
|
+
name: string,
|
|
24
|
+
error: string,
|
|
25
|
+
maxCount = 1
|
|
26
|
+
): void {
|
|
27
|
+
React.useEffect(() => {
|
|
28
|
+
const count = instanceCounter.get(name) || 0;
|
|
29
|
+
if (count === maxCount) {
|
|
30
|
+
throw new Error(error);
|
|
31
|
+
}
|
|
32
|
+
instanceCounter.set(name, count + 1);
|
|
33
|
+
|
|
34
|
+
return () => {
|
|
35
|
+
instanceCounter.set(name, (instanceCounter.get(name) || 1) - 1);
|
|
36
|
+
};
|
|
37
|
+
}, []);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* A higher-order component that wraps a component with instance count protection.
|
|
42
|
+
* This HOC ensures that the wrapped component cannot be instantiated more than once
|
|
43
|
+
* (or a specified number of times) in the application.
|
|
44
|
+
*
|
|
45
|
+
* @param WrappedComponent - The component to wrap with instance count protection
|
|
46
|
+
* @param name - A unique identifier for the component type
|
|
47
|
+
* @param error - The error message to display if the maximum count is exceeded
|
|
48
|
+
* @returns A new component with instance count protection
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```tsx
|
|
52
|
+
* const ProtectedComponent = withMaxAllowedInstancesGuard(
|
|
53
|
+
* MyComponent,
|
|
54
|
+
* 'MyComponent',
|
|
55
|
+
* 'Only one instance of MyComponent is allowed'
|
|
56
|
+
* );
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export function withMaxAllowedInstancesGuard<P extends object>(
|
|
60
|
+
WrappedComponent: React.ComponentType<P>,
|
|
61
|
+
name: string,
|
|
62
|
+
error: string
|
|
63
|
+
): React.ComponentType<P> {
|
|
64
|
+
const displayName =
|
|
65
|
+
WrappedComponent.displayName ||
|
|
66
|
+
WrappedComponent.name ||
|
|
67
|
+
name ||
|
|
68
|
+
'Component';
|
|
69
|
+
|
|
70
|
+
const Hoc: React.FC<P> = (props) => {
|
|
71
|
+
useMaxAllowedInstancesGuard(name, error);
|
|
72
|
+
return <WrappedComponent {...props} />;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
Hoc.displayName = `withMaxAllowedInstancesGuard(${displayName})`;
|
|
76
|
+
return Hoc;
|
|
77
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2019",
|
|
4
|
+
"lib": ["dom", "dom.iterable", "esnext"],
|
|
5
|
+
"allowJs": true,
|
|
6
|
+
"skipLibCheck": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"allowSyntheticDefaultImports": true,
|
|
9
|
+
"strict": true,
|
|
10
|
+
"forceConsistentCasingInFileNames": true,
|
|
11
|
+
"noFallthroughCasesInSwitch": true,
|
|
12
|
+
"module": "esnext",
|
|
13
|
+
"moduleResolution": "node",
|
|
14
|
+
"resolveJsonModule": true,
|
|
15
|
+
"isolatedModules": true,
|
|
16
|
+
"noEmit": true,
|
|
17
|
+
"jsx": "react-jsx"
|
|
18
|
+
},
|
|
19
|
+
"include": ["src"]
|
|
20
|
+
}
|
package/tsup.config.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { defineConfig } from 'tsup';
|
|
2
|
+
|
|
3
|
+
import { name, version } from './package.json';
|
|
4
|
+
|
|
5
|
+
export default defineConfig((overrideOptions) => {
|
|
6
|
+
const shouldPublish = !!overrideOptions.env?.publish;
|
|
7
|
+
|
|
8
|
+
return {
|
|
9
|
+
entry: {
|
|
10
|
+
index: 'src/index.ts',
|
|
11
|
+
},
|
|
12
|
+
dts: true,
|
|
13
|
+
onSuccess: shouldPublish ? 'pnpm publish:local' : undefined,
|
|
14
|
+
format: ['cjs', 'esm'],
|
|
15
|
+
bundle: true,
|
|
16
|
+
clean: true,
|
|
17
|
+
minify: false,
|
|
18
|
+
sourcemap: true,
|
|
19
|
+
external: ['react', 'react-dom'],
|
|
20
|
+
define: {
|
|
21
|
+
PACKAGE_NAME: `"${name}"`,
|
|
22
|
+
PACKAGE_VERSION: `"${version}"`,
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
});
|
package/vitest.setup.mts
ADDED
package/dist/MonocleContext.d.ts
DELETED
package/dist/MonocleContext.js
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { createContext } from "react";
|
|
2
|
-
var createNamedContext = function (name) {
|
|
3
|
-
var context = createContext({});
|
|
4
|
-
context.displayName = name;
|
|
5
|
-
return context;
|
|
6
|
-
};
|
|
7
|
-
var context = createNamedContext("monocle");
|
|
8
|
-
export default context;
|
|
9
|
-
//# sourceMappingURL=MonocleContext.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"MonocleContext.js","sourceRoot":"","sources":["../src/MonocleContext.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAEtC,IAAM,kBAAkB,GAAG,UAAC,IAAwB;IAClD,IAAM,OAAO,GAAG,aAAa,CAAC,EAAE,CAAC,CAAC;IAClC,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAC3B,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC;AAEF,IAAM,OAAO,GAAG,kBAAkB,CAAC,SAAS,CAAC,CAAC;AAC9C,eAAe,OAAO,CAAC"}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { Monocle } from "@spur.us/monocle-types";
|
|
3
|
-
interface MonocoleProviderProps {
|
|
4
|
-
children: React.ReactNode;
|
|
5
|
-
instance?: Monocle;
|
|
6
|
-
}
|
|
7
|
-
declare const MonocleProvider: ({ children, instance }: MonocoleProviderProps) => JSX.Element;
|
|
8
|
-
export default MonocleProvider;
|
package/dist/MonocleProvider.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import MonocleContext from "./MonocleContext";
|
|
3
|
-
import invariant from "tiny-invariant";
|
|
4
|
-
var MonocleProvider = function (_a) {
|
|
5
|
-
var children = _a.children, instance = _a.instance;
|
|
6
|
-
invariant(instance, "Monocle instance not provided to <MonocleProvider />");
|
|
7
|
-
return (React.createElement(MonocleContext.Provider, { value: instance, children: children || null }));
|
|
8
|
-
};
|
|
9
|
-
export default MonocleProvider;
|
|
10
|
-
//# sourceMappingURL=MonocleProvider.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"MonocleProvider.js","sourceRoot":"","sources":["../src/MonocleProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,cAAc,MAAM,kBAAkB,CAAC;AAC9C,OAAO,SAAS,MAAM,gBAAgB,CAAC;AAQvC,IAAM,eAAe,GAAG,UAAC,EAA6C;QAA3C,QAAQ,cAAA,EAAE,QAAQ,cAAA;IAC3C,SAAS,CAAC,QAAQ,EAAE,sDAAsD,CAAC,CAAC;IAC5E,OAAO,CACL,oBAAC,cAAc,CAAC,QAAQ,IAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,IAAI,IAAI,GAAI,CACzE,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,eAAe,CAAC"}
|
package/dist/hooks.d.ts
DELETED
package/dist/hooks.js
DELETED
package/dist/hooks.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAEnC,OAAO,cAAc,MAAM,kBAAkB,CAAC;AAE9C,MAAM,CAAC,IAAM,UAAU,GAAG;IACxB,OAAO,UAAU,CAAC,cAAc,CAAY,CAAC;AAC/C,CAAC,CAAC"}
|
package/dist/index.test.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/index.test.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test, it } from "@jest/globals";
|
|
2
|
-
import * as MonocleReact from "./index";
|
|
3
|
-
describe("Monocle React Library", function () {
|
|
4
|
-
test("Library is loadable", function () {
|
|
5
|
-
expect(MonocleReact).not.toBeUndefined();
|
|
6
|
-
});
|
|
7
|
-
test("Core library is exported when initialized", function () {
|
|
8
|
-
expect(MonocleReact.MonocleConsumer).toBeDefined();
|
|
9
|
-
expect(MonocleReact.MonocleContext).toBeDefined();
|
|
10
|
-
expect(MonocleReact.MonocleProvider).toBeDefined();
|
|
11
|
-
expect(MonocleReact.useMonocle).toBeDefined();
|
|
12
|
-
expect(MonocleReact.withMonocle).toBeDefined();
|
|
13
|
-
});
|
|
14
|
-
});
|
|
15
|
-
describe("Monocle React hooks", function () {
|
|
16
|
-
it.todo("useMonocle return null when unavailable");
|
|
17
|
-
it.todo("useMonocle should return our monocle instanace when available");
|
|
18
|
-
it.todo("withMonocle return null when unavailable");
|
|
19
|
-
it.todo("withMonocle should return our monocle instanace when available");
|
|
20
|
-
});
|
|
21
|
-
describe("Monocle React components", function () {
|
|
22
|
-
it.todo("MonocleContext should be loadable");
|
|
23
|
-
it.todo("MonocleContext should fail gracefully");
|
|
24
|
-
it.todo("MonocleProvider should be loadable");
|
|
25
|
-
it.todo("MonocleProvider should fail gracefully");
|
|
26
|
-
});
|
|
27
|
-
//# sourceMappingURL=index.test.js.map
|
package/dist/index.test.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,KAAK,YAAY,MAAM,SAAS,CAAC;AAExC,QAAQ,CAAC,uBAAuB,EAAE;IAChC,IAAI,CAAC,qBAAqB,EAAE;QAC1B,MAAM,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,2CAA2C,EAAE;QAChD,MAAM,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC,WAAW,EAAE,CAAC;QACnD,MAAM,CAAC,YAAY,CAAC,cAAc,CAAC,CAAC,WAAW,EAAE,CAAC;QAClD,MAAM,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC,WAAW,EAAE,CAAC;QACnD,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE,CAAC;QAC9C,MAAM,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC,WAAW,EAAE,CAAC;IACjD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,qBAAqB,EAAE;IAC9B,EAAE,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;IACnD,EAAE,CAAC,IAAI,CAAC,+DAA+D,CAAC,CAAC;IACzE,EAAE,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAC;IACpD,EAAE,CAAC,IAAI,CAAC,gEAAgE,CAAC,CAAC;AAC5E,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,0BAA0B,EAAE;IACnC,EAAE,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC;IAC7C,EAAE,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;IACjD,EAAE,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC;IAC9C,EAAE,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;AACpD,CAAC,CAAC,CAAC"}
|
package/dist/withMonocle.d.ts
DELETED
package/dist/withMonocle.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { __assign, __rest } from "tslib";
|
|
2
|
-
import React from "react";
|
|
3
|
-
import MonocleContext from "./MonocleContext";
|
|
4
|
-
import hoistStatics from "hoist-non-react-statics";
|
|
5
|
-
import invariant from "tiny-invariant";
|
|
6
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7
|
-
var withMonocle = function (Component) {
|
|
8
|
-
var displayName = "withMonocle(".concat(Component.displayName || Component.name, ")");
|
|
9
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
10
|
-
var C = function (props) {
|
|
11
|
-
var wrappedComponentRef = props.wrappedComponentRef, remainingProps = __rest(props, ["wrappedComponentRef"]);
|
|
12
|
-
return (React.createElement(MonocleContext.Consumer, null, function (context) {
|
|
13
|
-
invariant(context, "You should not use ".concat(displayName, " outside of a <MonocleProvider>"));
|
|
14
|
-
return (React.createElement(Component, __assign({}, remainingProps, { analytics: context, ref: wrappedComponentRef })));
|
|
15
|
-
}));
|
|
16
|
-
};
|
|
17
|
-
C.displayName = displayName;
|
|
18
|
-
C.WrappedComponent = Component;
|
|
19
|
-
return hoistStatics(C, Component);
|
|
20
|
-
};
|
|
21
|
-
export default withMonocle;
|
|
22
|
-
//# sourceMappingURL=withMonocle.js.map
|
package/dist/withMonocle.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"withMonocle.js","sourceRoot":"","sources":["../src/withMonocle.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,cAAc,MAAM,kBAAkB,CAAC;AAC9C,OAAO,YAAY,MAAM,yBAAyB,CAAC;AACnD,OAAO,SAAS,MAAM,gBAAgB,CAAC;AAEvC,8DAA8D;AAC9D,IAAM,WAAW,GAAG,UAAC,SAAc;IACjC,IAAM,WAAW,GAAG,sBAAe,SAAS,CAAC,WAAW,IAAI,SAAS,CAAC,IAAI,MAAG,CAAC;IAE9E,8DAA8D;IAC9D,IAAM,CAAC,GAAG,UAAC,KAAU;QACX,IAAA,mBAAmB,GAAwB,KAAK,oBAA7B,EAAK,cAAc,UAAK,KAAK,EAAlD,uBAA0C,CAAF,CAAW;QAEzD,OAAO,CACL,oBAAC,cAAc,CAAC,QAAQ,QACrB,UAAC,OAAO;YACP,SAAS,CACP,OAAO,EACP,6BAAsB,WAAW,oCAAiC,CACnE,CAAC;YAEF,OAAO,CACL,oBAAC,SAAS,eACJ,cAAc,IAClB,SAAS,EAAE,OAAO,EAClB,GAAG,EAAE,mBAAmB,IACxB,CACH,CAAC;QACJ,CAAC,CACuB,CAC3B,CAAC;IACJ,CAAC,CAAC;IAEF,CAAC,CAAC,WAAW,GAAG,WAAW,CAAC;IAC5B,CAAC,CAAC,gBAAgB,GAAG,SAAS,CAAC;IAC/B,OAAO,YAAY,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;AACpC,CAAC,CAAC;AAEF,eAAe,WAAW,CAAC"}
|