@smart-cloud/ai-kit-ui 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/.gitattributes +8 -0
- package/dist/ai-kit-ui.css +201 -0
- package/dist/index.cjs +14 -0
- package/dist/index.d.cts +87 -0
- package/dist/index.d.ts +87 -0
- package/dist/index.js +14 -0
- package/eslint.config.js +18 -0
- package/package.json +75 -0
- package/src/ShadowBoundary.tsx +266 -0
- package/src/ai-feature/AiFeature.tsx +1824 -0
- package/src/ai-feature/AiFeatureBorder.tsx +22 -0
- package/src/ai-feature/ProofreadDiff.tsx +118 -0
- package/src/ai-feature/index.tsx +2 -0
- package/src/ai-feature/utils.tsx +20 -0
- package/src/i18n/ar.ts +156 -0
- package/src/i18n/de.ts +157 -0
- package/src/i18n/en.ts +156 -0
- package/src/i18n/es.ts +157 -0
- package/src/i18n/fr.ts +158 -0
- package/src/i18n/he.ts +156 -0
- package/src/i18n/hi.ts +157 -0
- package/src/i18n/hu.ts +156 -0
- package/src/i18n/id.ts +157 -0
- package/src/i18n/index.ts +47 -0
- package/src/i18n/it.ts +159 -0
- package/src/i18n/ja.ts +157 -0
- package/src/i18n/ko.ts +155 -0
- package/src/i18n/nb.ts +156 -0
- package/src/i18n/nl.ts +157 -0
- package/src/i18n/pl.ts +158 -0
- package/src/i18n/pt.ts +155 -0
- package/src/i18n/ru.ts +157 -0
- package/src/i18n/sv.ts +156 -0
- package/src/i18n/th.ts +154 -0
- package/src/i18n/tr.ts +158 -0
- package/src/i18n/ua.ts +159 -0
- package/src/i18n/zh.ts +151 -0
- package/src/index.tsx +4 -0
- package/src/styles/ai-kit-ui.css +201 -0
- package/src/useAiRun.ts +177 -0
- package/src/withAiKitShell.tsx +208 -0
- package/tsconfig.json +32 -0
- package/tsconfig.node.json +13 -0
- package/tsup.config.ts +21 -0
package/src/useAiRun.ts
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AiKitLanguageCode,
|
|
3
|
+
AiKitPlugin,
|
|
4
|
+
AiKitSettings,
|
|
5
|
+
getAiKitPlugin,
|
|
6
|
+
getStoreSelect,
|
|
7
|
+
type AiKitConfig,
|
|
8
|
+
type AiKitStatusEvent,
|
|
9
|
+
} from "@smart-cloud/ai-kit-core";
|
|
10
|
+
import { getWpSuite } from "@smart-cloud/wpsuite-core";
|
|
11
|
+
import { useCallback, useRef, useState } from "react";
|
|
12
|
+
|
|
13
|
+
export type AiRunState<T> = {
|
|
14
|
+
busy: boolean;
|
|
15
|
+
error: string | null;
|
|
16
|
+
statusEvent: AiKitStatusEvent | null;
|
|
17
|
+
result: T | null;
|
|
18
|
+
isCancelled: boolean;
|
|
19
|
+
/** Last known execution source (best-effort). */
|
|
20
|
+
lastSource: "on-device" | "backend" | null;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type AiFeatureFunction<T> = (args: {
|
|
24
|
+
signal: AbortSignal;
|
|
25
|
+
onStatus: (e: AiKitStatusEvent) => void;
|
|
26
|
+
}) => Promise<T>;
|
|
27
|
+
|
|
28
|
+
export type UseAiRunResult<T> = AiRunState<T> & {
|
|
29
|
+
run: (func: AiFeatureFunction<T>) => Promise<T | null>;
|
|
30
|
+
cancel: () => void;
|
|
31
|
+
reset: () => void;
|
|
32
|
+
/** Current AbortSignal, if a run is in-flight. */
|
|
33
|
+
signal: AbortSignal | null;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
function getErrorMessage(err: unknown): string {
|
|
37
|
+
if (err instanceof Error) return err.message;
|
|
38
|
+
if (typeof err === "string") return err;
|
|
39
|
+
try {
|
|
40
|
+
return JSON.stringify(err);
|
|
41
|
+
} catch {
|
|
42
|
+
return "Unknown error";
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Returns true if backend routing is configured in the current AiKit settings.
|
|
48
|
+
*
|
|
49
|
+
* This is intentionally conservative: it only checks *configuration*, not reachability.
|
|
50
|
+
*/
|
|
51
|
+
export async function isBackendConfigured(): Promise<boolean> {
|
|
52
|
+
const store = await getAiKitPlugin().features.store;
|
|
53
|
+
if (!store) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
const s: AiKitConfig = getStoreSelect(store).getConfig() ?? {};
|
|
57
|
+
if (s.backendTransport === "gatey") {
|
|
58
|
+
return Boolean(s.backendApiName);
|
|
59
|
+
}
|
|
60
|
+
if (s.backendTransport === "fetch") {
|
|
61
|
+
return Boolean(s.backendBaseUrl);
|
|
62
|
+
}
|
|
63
|
+
// Unknown/undefined transport: treat as not configured.
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function readDefaultOutputLanguage(): AiKitLanguageCode {
|
|
68
|
+
const aiKit = getWpSuite()?.plugins?.aiKit as AiKitPlugin | undefined;
|
|
69
|
+
return (
|
|
70
|
+
((aiKit?.settings ?? {}) as AiKitSettings).defaultOutputLanguage ?? "en"
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Removes a single surrounding Markdown code fence.
|
|
76
|
+
*
|
|
77
|
+
* Handles common model outputs like:
|
|
78
|
+
* ```json
|
|
79
|
+
* {"a":1}
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
export function stripCodeFence(text: string): string {
|
|
83
|
+
const fence = /^\s*```(?:json)?\s*([\s\S]*?)\s*```\s*$/i;
|
|
84
|
+
const m = text.match(fence);
|
|
85
|
+
return m ? m[1] : text;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function useAiRun<T>(): UseAiRunResult<T> {
|
|
89
|
+
const ctrlRef = useRef<AbortController | null>(null);
|
|
90
|
+
const lastSourceRef = useRef<"on-device" | "backend" | null>(null);
|
|
91
|
+
|
|
92
|
+
const [busy, setBusy] = useState(false);
|
|
93
|
+
const [error, setError] = useState<string | null>(null);
|
|
94
|
+
const [statusEvent, setStatusEvent] = useState<AiKitStatusEvent | null>(null);
|
|
95
|
+
const [result, setResult] = useState<T | null>(null);
|
|
96
|
+
const [isCancelled, setIsCancelled] = useState(false);
|
|
97
|
+
const [lastSource, setLastSource] = useState<"on-device" | "backend" | null>(
|
|
98
|
+
null,
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
const cancel = useCallback(() => {
|
|
102
|
+
ctrlRef.current?.abort();
|
|
103
|
+
}, []);
|
|
104
|
+
|
|
105
|
+
const reset = useCallback(() => {
|
|
106
|
+
ctrlRef.current?.abort();
|
|
107
|
+
ctrlRef.current = null;
|
|
108
|
+
setBusy(false);
|
|
109
|
+
setError(null);
|
|
110
|
+
setStatusEvent(null);
|
|
111
|
+
setResult(null);
|
|
112
|
+
setIsCancelled(false);
|
|
113
|
+
lastSourceRef.current = null;
|
|
114
|
+
setLastSource(null);
|
|
115
|
+
}, []);
|
|
116
|
+
|
|
117
|
+
const run = useCallback(
|
|
118
|
+
async (func: AiFeatureFunction<T>): Promise<T | null> => {
|
|
119
|
+
// Cancel any ongoing run
|
|
120
|
+
ctrlRef.current?.abort();
|
|
121
|
+
|
|
122
|
+
const ctrl = new AbortController();
|
|
123
|
+
ctrlRef.current = ctrl;
|
|
124
|
+
|
|
125
|
+
setBusy(true);
|
|
126
|
+
setError(null);
|
|
127
|
+
setStatusEvent(null);
|
|
128
|
+
setResult(null);
|
|
129
|
+
setIsCancelled(false);
|
|
130
|
+
lastSourceRef.current = null;
|
|
131
|
+
setLastSource(null);
|
|
132
|
+
|
|
133
|
+
try {
|
|
134
|
+
const value = await func({
|
|
135
|
+
signal: ctrl.signal,
|
|
136
|
+
onStatus: (e) => {
|
|
137
|
+
setStatusEvent(e);
|
|
138
|
+
if (e.source === "on-device" || e.source === "backend") {
|
|
139
|
+
lastSourceRef.current = e.source;
|
|
140
|
+
setLastSource(e.source);
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
setResult(value);
|
|
145
|
+
return value;
|
|
146
|
+
} catch (err) {
|
|
147
|
+
if (ctrl.signal.aborted) {
|
|
148
|
+
setIsCancelled(true);
|
|
149
|
+
setError(null);
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
setError(getErrorMessage(err));
|
|
153
|
+
return null;
|
|
154
|
+
} finally {
|
|
155
|
+
setBusy(false);
|
|
156
|
+
setStatusEvent(null);
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
[],
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
// NOTE: do not memoize; ctrlRef changes don't trigger rerender.
|
|
163
|
+
const signal = ctrlRef.current?.signal ?? null;
|
|
164
|
+
|
|
165
|
+
return {
|
|
166
|
+
busy,
|
|
167
|
+
error,
|
|
168
|
+
statusEvent,
|
|
169
|
+
result,
|
|
170
|
+
isCancelled,
|
|
171
|
+
lastSource,
|
|
172
|
+
run,
|
|
173
|
+
cancel,
|
|
174
|
+
reset,
|
|
175
|
+
signal,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import {
|
|
2
|
+
colorsTuple,
|
|
3
|
+
createTheme,
|
|
4
|
+
DEFAULT_THEME,
|
|
5
|
+
DirectionProvider,
|
|
6
|
+
MantineColorsTuple,
|
|
7
|
+
MantineProvider,
|
|
8
|
+
} from "@mantine/core";
|
|
9
|
+
import {
|
|
10
|
+
AiWorkerProps,
|
|
11
|
+
CustomTranslations,
|
|
12
|
+
getStoreSelect,
|
|
13
|
+
} from "@smart-cloud/ai-kit-core";
|
|
14
|
+
import { useSelect } from "@wordpress/data";
|
|
15
|
+
import { I18n } from "aws-amplify/utils";
|
|
16
|
+
import { type ComponentType, useMemo, useState } from "react";
|
|
17
|
+
import { ShadowBoundary } from "./ShadowBoundary";
|
|
18
|
+
|
|
19
|
+
export type AiKitShellInjectedProps = {
|
|
20
|
+
language?: string;
|
|
21
|
+
rootElement: HTMLElement;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export function withAiKitShell<P extends object>(
|
|
25
|
+
RootComponent: ComponentType<P & AiKitShellInjectedProps>,
|
|
26
|
+
propOverrides?: Partial<AiWorkerProps>,
|
|
27
|
+
) {
|
|
28
|
+
const Wrapped: React.FC<P & Partial<AiWorkerProps>> = (props) => {
|
|
29
|
+
// Duck-typing merge: supports both explicit shell props or defaults.
|
|
30
|
+
const {
|
|
31
|
+
store,
|
|
32
|
+
variation,
|
|
33
|
+
showOpenButton,
|
|
34
|
+
colors,
|
|
35
|
+
colorMode,
|
|
36
|
+
primaryColor,
|
|
37
|
+
primaryShade,
|
|
38
|
+
className,
|
|
39
|
+
styleText,
|
|
40
|
+
language,
|
|
41
|
+
direction,
|
|
42
|
+
} = { ...props, ...propOverrides } as AiWorkerProps & P;
|
|
43
|
+
|
|
44
|
+
const languageInStore: string | undefined | null = useSelect(() =>
|
|
45
|
+
getStoreSelect(store).getLanguage(),
|
|
46
|
+
);
|
|
47
|
+
const directionInStore: "ltr" | "rtl" | "auto" | undefined | null =
|
|
48
|
+
useSelect(() => getStoreSelect(store).getDirection());
|
|
49
|
+
const customTranslations: CustomTranslations | undefined | null = useSelect(
|
|
50
|
+
() => getStoreSelect(store).getCustomTranslations(),
|
|
51
|
+
);
|
|
52
|
+
const [languageOverride] = useState<string>(
|
|
53
|
+
new URLSearchParams(window.location.search).get("language") ?? "",
|
|
54
|
+
);
|
|
55
|
+
const [directionOverride] = useState<string>(
|
|
56
|
+
new URLSearchParams(window.location.search).get("direction") ?? "",
|
|
57
|
+
);
|
|
58
|
+
const currentLanguage = useMemo(() => {
|
|
59
|
+
I18n.putVocabularies(customTranslations || {});
|
|
60
|
+
const lang = languageInStore || languageOverride || language;
|
|
61
|
+
if (!lang || lang === "system") {
|
|
62
|
+
I18n.setLanguage("");
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
I18n.setLanguage(lang);
|
|
66
|
+
return lang;
|
|
67
|
+
}, [language, languageOverride, languageInStore, customTranslations]);
|
|
68
|
+
|
|
69
|
+
const currentDirection = useMemo(() => {
|
|
70
|
+
const dir = directionInStore || directionOverride || direction;
|
|
71
|
+
if (!dir || dir === "auto") {
|
|
72
|
+
return currentLanguage === "ar" || currentLanguage === "he"
|
|
73
|
+
? "rtl"
|
|
74
|
+
: "ltr";
|
|
75
|
+
}
|
|
76
|
+
return dir as "ltr" | "rtl";
|
|
77
|
+
}, [currentLanguage, direction, directionInStore, directionOverride]);
|
|
78
|
+
|
|
79
|
+
const stylesheets = useMemo(
|
|
80
|
+
() => [
|
|
81
|
+
(
|
|
82
|
+
WpSuite as never as {
|
|
83
|
+
constants: { aiKit: { mantineCssHref: string } };
|
|
84
|
+
}
|
|
85
|
+
)?.constants?.aiKit?.mantineCssHref,
|
|
86
|
+
(
|
|
87
|
+
WpSuite as never as {
|
|
88
|
+
constants: { aiKit: { aiKitUiCssHref: string } };
|
|
89
|
+
}
|
|
90
|
+
)?.constants?.aiKit?.aiKitUiCssHref,
|
|
91
|
+
],
|
|
92
|
+
[WpSuite],
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
let customColors: Record<string, MantineColorsTuple> | undefined;
|
|
96
|
+
if (colors) {
|
|
97
|
+
customColors = {};
|
|
98
|
+
Object.keys(colors).forEach((c) => {
|
|
99
|
+
customColors![c] = colorsTuple(colors[c]);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const theme = createTheme({
|
|
104
|
+
respectReducedMotion: true,
|
|
105
|
+
...(customColors && { colors: customColors }),
|
|
106
|
+
...(primaryColor &&
|
|
107
|
+
[
|
|
108
|
+
...Object.keys(DEFAULT_THEME.colors),
|
|
109
|
+
...Object.keys(customColors || {}),
|
|
110
|
+
].includes(primaryColor) && { primaryColor }),
|
|
111
|
+
...(primaryShade &&
|
|
112
|
+
Object.keys(primaryShade).length > 0 && {
|
|
113
|
+
primaryShade: {
|
|
114
|
+
light:
|
|
115
|
+
primaryShade.light ??
|
|
116
|
+
(typeof DEFAULT_THEME.primaryShade === "object"
|
|
117
|
+
? DEFAULT_THEME.primaryShade.light
|
|
118
|
+
: (DEFAULT_THEME.primaryShade ?? 6)),
|
|
119
|
+
dark:
|
|
120
|
+
primaryShade.dark ??
|
|
121
|
+
(typeof DEFAULT_THEME.primaryShade === "object"
|
|
122
|
+
? DEFAULT_THEME.primaryShade.dark
|
|
123
|
+
: (DEFAULT_THEME.primaryShade ?? 6)),
|
|
124
|
+
},
|
|
125
|
+
}),
|
|
126
|
+
components: {
|
|
127
|
+
Button: {
|
|
128
|
+
styles: { root: { borderRadius: "inherit" } },
|
|
129
|
+
},
|
|
130
|
+
Tooltip: {
|
|
131
|
+
defaultProps: {
|
|
132
|
+
withinPortal: false,
|
|
133
|
+
zIndex: 100002,
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
Modal: {
|
|
137
|
+
defaultProps: {
|
|
138
|
+
withinPortal: false,
|
|
139
|
+
zIndex: 100002,
|
|
140
|
+
},
|
|
141
|
+
styles: {
|
|
142
|
+
body: {
|
|
143
|
+
overflow: "visible",
|
|
144
|
+
position: "relative",
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
Select: {
|
|
149
|
+
defaultProps: {
|
|
150
|
+
comboboxProps: {
|
|
151
|
+
withinPortal: false,
|
|
152
|
+
floatingStrategy: "fixed",
|
|
153
|
+
positionDependencies: [],
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
return (
|
|
161
|
+
<ShadowBoundary
|
|
162
|
+
mode={variation === "modal" && !showOpenButton ? "overlay" : "local"}
|
|
163
|
+
overlayRootId="ai-kit-overlay-root"
|
|
164
|
+
stylesheets={stylesheets}
|
|
165
|
+
styleText={styleText}
|
|
166
|
+
className={className}
|
|
167
|
+
rootElementId={
|
|
168
|
+
variation === "modal" && !showOpenButton
|
|
169
|
+
? "ai-kit-portal-root"
|
|
170
|
+
: "ai-kit-inline-root"
|
|
171
|
+
}
|
|
172
|
+
>
|
|
173
|
+
{({ rootElement }) => {
|
|
174
|
+
rootElement.setAttribute(
|
|
175
|
+
"data-ai-kit-variation",
|
|
176
|
+
variation || "default",
|
|
177
|
+
);
|
|
178
|
+
rootElement.setAttribute("dir", currentDirection);
|
|
179
|
+
if (currentLanguage) {
|
|
180
|
+
rootElement.setAttribute("lang", currentLanguage);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return (
|
|
184
|
+
<DirectionProvider initialDirection={currentDirection}>
|
|
185
|
+
<MantineProvider
|
|
186
|
+
defaultColorScheme={colorMode}
|
|
187
|
+
theme={theme}
|
|
188
|
+
cssVariablesSelector={`#${rootElement.id}`}
|
|
189
|
+
getRootElement={() => rootElement as unknown as HTMLElement}
|
|
190
|
+
>
|
|
191
|
+
<RootComponent
|
|
192
|
+
{...props}
|
|
193
|
+
language={currentLanguage}
|
|
194
|
+
rootElement={rootElement}
|
|
195
|
+
/>
|
|
196
|
+
</MantineProvider>
|
|
197
|
+
</DirectionProvider>
|
|
198
|
+
);
|
|
199
|
+
}}
|
|
200
|
+
</ShadowBoundary>
|
|
201
|
+
);
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
Wrapped.displayName = `withAiKitShell(${
|
|
205
|
+
RootComponent.displayName ?? RootComponent.name ?? "Component"
|
|
206
|
+
})`;
|
|
207
|
+
return Wrapped;
|
|
208
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "esnext",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"lib": ["ESNext", "DOM", "DOM.Iterable"],
|
|
6
|
+
"module": "esnext",
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
|
|
9
|
+
/* Bundler mode */
|
|
10
|
+
"moduleResolution": "bundler",
|
|
11
|
+
"allowImportingTsExtensions": true,
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"isolatedModules": true,
|
|
14
|
+
"noEmit": true,
|
|
15
|
+
"jsx": "react-jsx",
|
|
16
|
+
|
|
17
|
+
/* Linting */
|
|
18
|
+
"strict": true,
|
|
19
|
+
"noUnusedLocals": true,
|
|
20
|
+
"noUnusedParameters": true,
|
|
21
|
+
"noFallthroughCasesInSwitch": true,
|
|
22
|
+
|
|
23
|
+
"types": ["jquery", "dom-chromium-ai"]
|
|
24
|
+
},
|
|
25
|
+
"include": ["src"],
|
|
26
|
+
"exclude": ["dist", "build", "node_modules"],
|
|
27
|
+
"references": [
|
|
28
|
+
{
|
|
29
|
+
"path": "./tsconfig.node.json"
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "esnext",
|
|
4
|
+
"module": "esnext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"composite": true,
|
|
7
|
+
"lib": ["ESNext"],
|
|
8
|
+
"allowSyntheticDefaultImports": true,
|
|
9
|
+
"types": ["node"]
|
|
10
|
+
},
|
|
11
|
+
"include": ["tsup.config.ts"],
|
|
12
|
+
"exclude": ["src/**", "dist/**", "node_modules/**"]
|
|
13
|
+
}
|
package/tsup.config.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { defineConfig } from "tsup";
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
// Copy non-hashed global CSS so consumers can import it (like Mantine styles)
|
|
5
|
+
onSuccess: "node -e \"const fs=require('fs'); const path=require('path'); fs.mkdirSync('dist',{recursive:true}); fs.copyFileSync(path.join('src','styles','ai-kit-ui.css'), path.join('dist','ai-kit-ui.css'));\"",
|
|
6
|
+
|
|
7
|
+
entry: ["src/index.tsx"],
|
|
8
|
+
format: ["cjs", "esm"],
|
|
9
|
+
dts: true,
|
|
10
|
+
splitting: false,
|
|
11
|
+
sourcemap: false,
|
|
12
|
+
clean: true,
|
|
13
|
+
external: [
|
|
14
|
+
"react",
|
|
15
|
+
"react-dom",
|
|
16
|
+
/^aws-amplify(\/.*)?$/,
|
|
17
|
+
/^@mantine\/.*?$/,
|
|
18
|
+
"jquery",
|
|
19
|
+
"@wordpress/data",
|
|
20
|
+
],
|
|
21
|
+
});
|