strapi-plugin-magic-link-v5 5.5.9 → 6.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/CHANGELOG.md +733 -0
- package/README.md +662 -928
- package/dist/admin/LicenseGuard-BgLA9go3.mjs +495 -0
- package/dist/admin/LicenseGuard-ewCjpc17.js +513 -0
- package/dist/admin/de-B1FNErPH.mjs +673 -0
- package/dist/admin/de-e75OECdq.js +673 -0
- package/dist/admin/en-CABKGbxH.js +673 -0
- package/dist/admin/en-HqDOFBCc.mjs +673 -0
- package/dist/admin/es-DpWl0Fax.js +673 -0
- package/dist/admin/es-jb94jqPR.mjs +673 -0
- package/dist/admin/fr-BQhLPvYw.js +673 -0
- package/dist/admin/fr-BseH1wrr.mjs +673 -0
- package/dist/admin/index-6ot9j1cN.js +5268 -0
- package/dist/admin/index-B390rccl.js +622 -0
- package/dist/admin/index-BPGKtruf.mjs +5266 -0
- package/dist/admin/index-BaTIQtnA.js +3869 -0
- package/dist/admin/index-CmG-93yx.js +141 -0
- package/dist/admin/index-DXe_ge4v.mjs +620 -0
- package/dist/admin/index-Dv5PVT1E.mjs +3867 -0
- package/dist/admin/index-k240ls6p.mjs +142 -0
- package/dist/admin/index.js +3 -3
- package/dist/admin/index.mjs +1 -2
- package/dist/admin/pt-CPkaveti.js +673 -0
- package/dist/admin/pt-DhlSCJn2.mjs +673 -0
- package/dist/admin/useUnsavedChangesGuard-BVZ4Mg4E.js +225 -0
- package/dist/admin/useUnsavedChangesGuard-QnkiZTLP.mjs +224 -0
- package/dist/server/i18n/de.json +32 -1
- package/dist/server/i18n/en.json +32 -1
- package/dist/server/i18n/es.json +32 -1
- package/dist/server/i18n/fr.json +32 -1
- package/dist/server/i18n/pt.json +32 -1
- package/dist/server/index.js +7092 -5971
- package/dist/server/index.mjs +7115 -5972
- package/package.json +42 -41
- package/strapi-admin.js +3 -1
- package/strapi-server.js +3 -2
- package/dist/_chunks/LicenseGuard-CiyjFnrw.js +0 -54
- package/dist/_chunks/LicenseGuard-DJ5fq2UZ.mjs +0 -55
- package/dist/_chunks/de-BSOk5suQ.js +0 -454
- package/dist/_chunks/de-CwhYs3O3.mjs +0 -454
- package/dist/_chunks/en-DnvSpXvu.js +0 -454
- package/dist/_chunks/en-gXXgGDV1.mjs +0 -454
- package/dist/_chunks/es-B-tnwByt.js +0 -407
- package/dist/_chunks/es-DG5gW3RZ.mjs +0 -407
- package/dist/_chunks/fr-BKo8t7Fx.js +0 -407
- package/dist/_chunks/fr-BQn1OHOR.mjs +0 -407
- package/dist/_chunks/index-01GHNxSr.js +0 -307
- package/dist/_chunks/index-5jsDgD-q.mjs +0 -330
- package/dist/_chunks/index-BWuj-5WE.js +0 -5068
- package/dist/_chunks/index-Bj3H_Z4B.js +0 -142
- package/dist/_chunks/index-CC4Eu9Dm.js +0 -332
- package/dist/_chunks/index-Csyi13vd.mjs +0 -2891
- package/dist/_chunks/index-DJqXiiP1.js +0 -2893
- package/dist/_chunks/index-DQUYFsLT.mjs +0 -143
- package/dist/_chunks/index-Dufv-daf.mjs +0 -305
- package/dist/_chunks/index-szeYJKpN.mjs +0 -5066
- package/dist/_chunks/pt-CjEkXBAz.js +0 -407
- package/dist/_chunks/pt-trziAOzT.mjs +0 -407
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
import { jsx, Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { Typography } from "@strapi/design-system";
|
|
3
|
+
import * as strapiAdmin from "@strapi/strapi/admin";
|
|
4
|
+
import { Page, useNotification } from "@strapi/strapi/admin";
|
|
5
|
+
import styled, { css } from "styled-components";
|
|
6
|
+
import { g as getTranslation, p as pluginPermissions } from "./index-k240ls6p.mjs";
|
|
7
|
+
import { useCallback, useMemo, useContext, useState, createContext } from "react";
|
|
8
|
+
import { useIntl, IntlContext, IntlProvider } from "react-intl";
|
|
9
|
+
import enTranslations from "./en-HqDOFBCc.mjs";
|
|
10
|
+
import deTranslations from "./de-B1FNErPH.mjs";
|
|
11
|
+
import frTranslations from "./fr-BseH1wrr.mjs";
|
|
12
|
+
import esTranslations from "./es-jb94jqPR.mjs";
|
|
13
|
+
import ptTranslations from "./pt-DhlSCJn2.mjs";
|
|
14
|
+
const useMagicLinkIntl = () => {
|
|
15
|
+
const intl = useIntl();
|
|
16
|
+
const t = useCallback(
|
|
17
|
+
(key, defaultMessage, values) => intl.formatMessage({ id: getTranslation(key), defaultMessage }, values),
|
|
18
|
+
[intl]
|
|
19
|
+
);
|
|
20
|
+
return { t, formatMessage: intl.formatMessage, locale: intl.locale };
|
|
21
|
+
};
|
|
22
|
+
const PluginPageTitle = ({ children }) => {
|
|
23
|
+
const { t } = useMagicLinkIntl();
|
|
24
|
+
return /* @__PURE__ */ jsx(Page.Title, { children: t("common.pageTitle", "{page} | Magic Link", { page: children }) });
|
|
25
|
+
};
|
|
26
|
+
styled(Typography).attrs((props) => ({
|
|
27
|
+
tag: props.tag ?? "h2",
|
|
28
|
+
variant: props.variant ?? "delta",
|
|
29
|
+
textColor: props.textColor ?? "neutral800"
|
|
30
|
+
}))``;
|
|
31
|
+
const SubsectionHeading = styled(Typography).attrs((props) => ({
|
|
32
|
+
tag: props.tag ?? "h3",
|
|
33
|
+
variant: props.variant ?? "omega",
|
|
34
|
+
fontWeight: props.fontWeight ?? "bold",
|
|
35
|
+
textColor: props.textColor ?? "neutral800"
|
|
36
|
+
}))``;
|
|
37
|
+
const PLUGIN_CAPABILITIES = [...pluginPermissions.read, ...pluginPermissions.manage];
|
|
38
|
+
const SETTINGS_CAPABILITIES = [
|
|
39
|
+
...pluginPermissions.settingsRead,
|
|
40
|
+
...pluginPermissions.settingsUpdate
|
|
41
|
+
];
|
|
42
|
+
const grantedActions = (permissions) => new Set(
|
|
43
|
+
(Array.isArray(permissions) ? permissions : []).filter(
|
|
44
|
+
(permission) => typeof permission?.action === "string" && (!Array.isArray(permission.conditions) || permission.conditions.length === 0)
|
|
45
|
+
).map((permission) => permission.action)
|
|
46
|
+
);
|
|
47
|
+
const resolveCapabilities = (plugin = {}, settings = {}, auth = {}) => {
|
|
48
|
+
const isLoading = Boolean(plugin.isLoading || settings.isLoading || auth.isLoading);
|
|
49
|
+
const error = plugin.error ?? settings.error;
|
|
50
|
+
const settled = !isLoading && !error;
|
|
51
|
+
const granted = grantedActions(auth.permissions);
|
|
52
|
+
const allowed = (result, key, uid) => settled && (result.allowedActions?.[key] === true || granted.has(uid));
|
|
53
|
+
const canRead = allowed(plugin, "canRead", "plugin::magic-link.read");
|
|
54
|
+
const canManage = allowed(plugin, "canManage", "plugin::magic-link.manage");
|
|
55
|
+
const canReadSettings = allowed(settings, "canRead", "plugin::magic-link.settings.read");
|
|
56
|
+
const canUpdateSettings = allowed(settings, "canUpdate", "plugin::magic-link.settings.update");
|
|
57
|
+
return {
|
|
58
|
+
canRead,
|
|
59
|
+
canManage,
|
|
60
|
+
canReadSettings,
|
|
61
|
+
canUpdateSettings,
|
|
62
|
+
isReadOnly: canRead && !canManage,
|
|
63
|
+
isSettingsReadOnly: canReadSettings && !canUpdateSettings,
|
|
64
|
+
isLoading,
|
|
65
|
+
error
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
const useAdminPermissions = typeof strapiAdmin.useAuth === "function" ? () => {
|
|
69
|
+
const permissions = strapiAdmin.useAuth("MagicLinkRBAC", (state) => state.permissions);
|
|
70
|
+
const isLoading = strapiAdmin.useAuth("MagicLinkRBAC", (state) => state.isLoading);
|
|
71
|
+
return { permissions, isLoading };
|
|
72
|
+
} : () => EMPTY_AUTH;
|
|
73
|
+
const EMPTY_AUTH = Object.freeze({});
|
|
74
|
+
const useMagicLinkRBAC = () => {
|
|
75
|
+
const plugin = strapiAdmin.useRBAC(PLUGIN_CAPABILITIES) ?? {};
|
|
76
|
+
const settings = strapiAdmin.useRBAC(SETTINGS_CAPABILITIES) ?? {};
|
|
77
|
+
const auth = useAdminPermissions();
|
|
78
|
+
return { ...resolveCapabilities(plugin, settings, auth), permissions: pluginPermissions };
|
|
79
|
+
};
|
|
80
|
+
const LIGHT_FALLBACK_COLORS = Object.freeze({
|
|
81
|
+
alternative100: "#f6ecfc",
|
|
82
|
+
alternative200: "#e0c1f4",
|
|
83
|
+
alternative500: "#ac73e6",
|
|
84
|
+
alternative600: "#9736e8",
|
|
85
|
+
alternative700: "#8312d1",
|
|
86
|
+
neutral0: "#ffffff",
|
|
87
|
+
neutral100: "#f6f6f9",
|
|
88
|
+
neutral150: "#eaeaef",
|
|
89
|
+
neutral200: "#dcdce4",
|
|
90
|
+
neutral300: "#c0c0cf",
|
|
91
|
+
neutral400: "#a5a5ba",
|
|
92
|
+
neutral500: "#8e8ea9",
|
|
93
|
+
neutral600: "#666687",
|
|
94
|
+
neutral700: "#4a4a6a",
|
|
95
|
+
neutral800: "#32324d",
|
|
96
|
+
neutral900: "#212134",
|
|
97
|
+
neutral1000: "#181826",
|
|
98
|
+
primary100: "#f0f0ff",
|
|
99
|
+
primary200: "#d9d8ff",
|
|
100
|
+
primary500: "#7b79ff",
|
|
101
|
+
primary600: "#4945ff",
|
|
102
|
+
primary700: "#271fe0",
|
|
103
|
+
secondary100: "#eaf5ff",
|
|
104
|
+
secondary200: "#b8e1ff",
|
|
105
|
+
secondary500: "#66b7f1",
|
|
106
|
+
secondary600: "#0c75af",
|
|
107
|
+
secondary700: "#006096",
|
|
108
|
+
success100: "#eafbe7",
|
|
109
|
+
success200: "#c6f0c2",
|
|
110
|
+
success500: "#5cb176",
|
|
111
|
+
success600: "#328048",
|
|
112
|
+
success700: "#2f6846",
|
|
113
|
+
warning100: "#fdf4dc",
|
|
114
|
+
warning200: "#fae7b9",
|
|
115
|
+
warning500: "#f29d41",
|
|
116
|
+
warning600: "#d9822f",
|
|
117
|
+
warning700: "#be5d01",
|
|
118
|
+
danger100: "#fcecea",
|
|
119
|
+
danger200: "#f5c0b8",
|
|
120
|
+
danger500: "#ee5e52",
|
|
121
|
+
danger600: "#d02b20",
|
|
122
|
+
danger700: "#b72b1a"
|
|
123
|
+
});
|
|
124
|
+
const FONT_SIZE_FALLBACK = Object.freeze([
|
|
125
|
+
"1.1rem",
|
|
126
|
+
// 0 -> 11px (sigma, uppercase table headers only)
|
|
127
|
+
"1.2rem",
|
|
128
|
+
// 1 -> 12px (pi, the minimum for helper text)
|
|
129
|
+
"1.4rem",
|
|
130
|
+
// 2 -> 14px (omega, body)
|
|
131
|
+
"1.6rem",
|
|
132
|
+
// 3 -> 16px
|
|
133
|
+
"1.8rem",
|
|
134
|
+
// 4 -> 18px
|
|
135
|
+
"2rem",
|
|
136
|
+
// 5 -> 20px
|
|
137
|
+
"2.8rem",
|
|
138
|
+
// 6 -> 28px
|
|
139
|
+
"3.2rem"
|
|
140
|
+
// 7 -> 32px
|
|
141
|
+
]);
|
|
142
|
+
const SPACE_FALLBACK = Object.freeze([
|
|
143
|
+
"0px",
|
|
144
|
+
"4px",
|
|
145
|
+
"8px",
|
|
146
|
+
"12px",
|
|
147
|
+
"16px",
|
|
148
|
+
"20px",
|
|
149
|
+
"24px",
|
|
150
|
+
"32px",
|
|
151
|
+
"40px",
|
|
152
|
+
"48px",
|
|
153
|
+
"56px",
|
|
154
|
+
"64px"
|
|
155
|
+
]);
|
|
156
|
+
const color = (token) => (props) => props?.theme?.colors?.[token] ?? LIGHT_FALLBACK_COLORS[token];
|
|
157
|
+
const fontSize = (step) => (props) => props?.theme?.fontSizes?.[step] ?? FONT_SIZE_FALLBACK[step];
|
|
158
|
+
const space = (step) => (props) => props?.theme?.spaces?.[step] ?? SPACE_FALLBACK[step];
|
|
159
|
+
const isDarkTheme = (themeObject) => themeObject?.colorScheme === "dark";
|
|
160
|
+
const byScheme = (light, dark) => (props) => isDarkTheme(props?.theme) ? dark : light;
|
|
161
|
+
const brand = Object.freeze({
|
|
162
|
+
primary: "#0369A1",
|
|
163
|
+
primaryHover: "#075985",
|
|
164
|
+
secondary: "#9333EA",
|
|
165
|
+
secondaryHover: "#7E22CE",
|
|
166
|
+
success: "#15803D",
|
|
167
|
+
successHover: "#166534",
|
|
168
|
+
warning: "#B45309",
|
|
169
|
+
warningHover: "#92400E",
|
|
170
|
+
danger: "#DC2626",
|
|
171
|
+
dangerHover: "#B91C1C",
|
|
172
|
+
gradient: "linear-gradient(135deg, #0369A1 0%, #9333EA 100%)",
|
|
173
|
+
gradientHover: "linear-gradient(135deg, #075985 0%, #7E22CE 100%)",
|
|
174
|
+
successGradient: "linear-gradient(135deg, #15803D 0%, #166534 100%)",
|
|
175
|
+
violetGradient: "linear-gradient(135deg, #667EEA 0%, #764BA2 100%)",
|
|
176
|
+
violetHeroGradient: "linear-gradient(rgba(15, 23, 42, 0.25), rgba(15, 23, 42, 0.25)), linear-gradient(135deg, #667EEA 0%, #764BA2 100%)",
|
|
177
|
+
onFill: "#FFFFFF"
|
|
178
|
+
});
|
|
179
|
+
const ACCENT_VALUES = Object.freeze({
|
|
180
|
+
primary: ["#0369A1", "#7DD3FC"],
|
|
181
|
+
secondary: ["#7E22CE", "#D8B4FE"],
|
|
182
|
+
success: ["#15803D", "#86EFAC"],
|
|
183
|
+
warning: ["#B45309", "#FCD34D"],
|
|
184
|
+
danger: ["#B91C1C", "#FCA5A5"]
|
|
185
|
+
});
|
|
186
|
+
const accent = Object.freeze(
|
|
187
|
+
Object.fromEntries(
|
|
188
|
+
Object.entries(ACCENT_VALUES).map(([name, [light, dark]]) => [name, byScheme(light, dark)])
|
|
189
|
+
)
|
|
190
|
+
);
|
|
191
|
+
const TINT_VALUES = Object.freeze({
|
|
192
|
+
primary: { bg: ["#F0F9FF", "rgba(14, 165, 233, 0.12)"], border: ["#BAE6FD", "#0C4A6E"] },
|
|
193
|
+
success: { bg: ["#F0FDF4", "rgba(34, 197, 94, 0.12)"], border: ["#BBF7D0", "#14532D"] },
|
|
194
|
+
warning: { bg: ["#FFFBEB", "rgba(245, 158, 11, 0.12)"], border: ["#FDE68A", "#78350F"] },
|
|
195
|
+
danger: { bg: ["#FEF2F2", "rgba(239, 68, 68, 0.12)"], border: ["#FECACA", "#7F1D1D"] }
|
|
196
|
+
});
|
|
197
|
+
const tint = Object.freeze(
|
|
198
|
+
Object.fromEntries(
|
|
199
|
+
Object.entries(TINT_VALUES).map(([name, values]) => [
|
|
200
|
+
name,
|
|
201
|
+
Object.freeze({
|
|
202
|
+
bg: byScheme(...values.bg),
|
|
203
|
+
border: byScheme(...values.border),
|
|
204
|
+
fg: accent[name]
|
|
205
|
+
})
|
|
206
|
+
])
|
|
207
|
+
)
|
|
208
|
+
);
|
|
209
|
+
const breakpoints = Object.freeze({
|
|
210
|
+
mobile: "768px",
|
|
211
|
+
tablet: "1024px",
|
|
212
|
+
statsThreeTwo: "960px",
|
|
213
|
+
tableCompact: "1199px",
|
|
214
|
+
compact: "520px"
|
|
215
|
+
});
|
|
216
|
+
const theme = Object.freeze({
|
|
217
|
+
spacing: Object.freeze({
|
|
218
|
+
xs: "4px",
|
|
219
|
+
sm: "8px",
|
|
220
|
+
smd: "12px",
|
|
221
|
+
md: "16px",
|
|
222
|
+
lg: "24px",
|
|
223
|
+
xl: "32px",
|
|
224
|
+
"2xl": "48px"
|
|
225
|
+
}),
|
|
226
|
+
borderRadius: Object.freeze({ sm: "4px", md: "8px", lg: "12px", xl: "16px", full: "9999px" }),
|
|
227
|
+
shadows: Object.freeze({
|
|
228
|
+
sm: "0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1)",
|
|
229
|
+
md: "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)",
|
|
230
|
+
lg: "0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1)",
|
|
231
|
+
xl: "0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1)"
|
|
232
|
+
}),
|
|
233
|
+
transitions: Object.freeze({
|
|
234
|
+
fast: "150ms cubic-bezier(0.4, 0, 0.2, 1)",
|
|
235
|
+
normal: "300ms cubic-bezier(0.4, 0, 0.2, 1)"
|
|
236
|
+
}),
|
|
237
|
+
/**
|
|
238
|
+
* DS 2.2.4 button heights at >= 768px (theme.sizes.button). Below 768px DS
|
|
239
|
+
* grows them to 40/44/48px. Use one size per row and match custom controls
|
|
240
|
+
* to it.
|
|
241
|
+
*/
|
|
242
|
+
controlHeight: Object.freeze({ S: "32px", M: "36px", L: "40px" })
|
|
243
|
+
});
|
|
244
|
+
const reducedMotion = css`
|
|
245
|
+
@media (prefers-reduced-motion: reduce) {
|
|
246
|
+
animation: none !important;
|
|
247
|
+
transition: none !important;
|
|
248
|
+
|
|
249
|
+
&::before,
|
|
250
|
+
&::after {
|
|
251
|
+
animation: none !important;
|
|
252
|
+
transition: none !important;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
&:hover,
|
|
256
|
+
&:active,
|
|
257
|
+
&:focus-visible {
|
|
258
|
+
transform: none !important;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
`;
|
|
262
|
+
const motionSafe = (block) => css`
|
|
263
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
264
|
+
${block}
|
|
265
|
+
}
|
|
266
|
+
`;
|
|
267
|
+
const EMPTY_VALUE = "-";
|
|
268
|
+
const DATE_TIME_FORMAT = Object.freeze({ dateStyle: "medium", timeStyle: "short" });
|
|
269
|
+
const DATE_FORMAT = Object.freeze({ dateStyle: "medium" });
|
|
270
|
+
const toValidDate = (value) => {
|
|
271
|
+
if (value === null || value === void 0 || value === "") return null;
|
|
272
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
273
|
+
return Number.isNaN(date.getTime()) ? null : date;
|
|
274
|
+
};
|
|
275
|
+
const createFormatters = (intl) => {
|
|
276
|
+
const formatDateTime = (value, options = DATE_TIME_FORMAT, fallback = EMPTY_VALUE) => {
|
|
277
|
+
const date = toValidDate(value);
|
|
278
|
+
return date ? intl.formatDate(date, options) : fallback;
|
|
279
|
+
};
|
|
280
|
+
const formatDateOnly = (value, options = DATE_FORMAT, fallback = EMPTY_VALUE) => {
|
|
281
|
+
const date = toValidDate(value);
|
|
282
|
+
return date ? intl.formatDate(date, options) : fallback;
|
|
283
|
+
};
|
|
284
|
+
const formatCount = (value, options, fallback = EMPTY_VALUE) => {
|
|
285
|
+
const number = typeof value === "number" ? value : Number(value);
|
|
286
|
+
return value === null || value === void 0 || value === "" || !Number.isFinite(number) ? fallback : intl.formatNumber(number, options);
|
|
287
|
+
};
|
|
288
|
+
const formatPercent = (value, fractionDigits = 1, fallback = EMPTY_VALUE) => {
|
|
289
|
+
if (value === null || value === void 0 || value === "") return fallback;
|
|
290
|
+
const number = Number(value);
|
|
291
|
+
return Number.isFinite(number) ? intl.formatNumber(number / 100, { style: "percent", maximumFractionDigits: fractionDigits }) : fallback;
|
|
292
|
+
};
|
|
293
|
+
const formatRelative = (value, now = /* @__PURE__ */ new Date(), fallback = EMPTY_VALUE) => {
|
|
294
|
+
const date = toValidDate(value);
|
|
295
|
+
if (!date || typeof intl.formatRelativeTime !== "function") {
|
|
296
|
+
return date ? formatDateTime(date) : fallback;
|
|
297
|
+
}
|
|
298
|
+
const seconds = Math.round((date.getTime() - now.getTime()) / 1e3);
|
|
299
|
+
const abs = Math.abs(seconds);
|
|
300
|
+
if (abs < 60) return intl.formatRelativeTime(seconds, "second", { numeric: "auto" });
|
|
301
|
+
if (abs < 3600)
|
|
302
|
+
return intl.formatRelativeTime(Math.round(seconds / 60), "minute", { numeric: "auto" });
|
|
303
|
+
if (abs < 86400)
|
|
304
|
+
return intl.formatRelativeTime(Math.round(seconds / 3600), "hour", { numeric: "auto" });
|
|
305
|
+
if (abs < 86400 * 30)
|
|
306
|
+
return intl.formatRelativeTime(Math.round(seconds / 86400), "day", { numeric: "auto" });
|
|
307
|
+
return formatDateOnly(date);
|
|
308
|
+
};
|
|
309
|
+
return {
|
|
310
|
+
formatDateTime,
|
|
311
|
+
formatDate: formatDateOnly,
|
|
312
|
+
formatNumber: formatCount,
|
|
313
|
+
formatPercent,
|
|
314
|
+
formatRelative
|
|
315
|
+
};
|
|
316
|
+
};
|
|
317
|
+
const useFormatters = () => {
|
|
318
|
+
const intl = useIntl();
|
|
319
|
+
return useMemo(() => createFormatters(intl), [intl]);
|
|
320
|
+
};
|
|
321
|
+
const copyToClipboard = async (text, env = {}) => {
|
|
322
|
+
if (typeof text !== "string" || text.length === 0) return false;
|
|
323
|
+
const win = env.window ?? (typeof window === "undefined" ? void 0 : window);
|
|
324
|
+
const nav = env.navigator ?? win?.navigator ?? (typeof navigator === "undefined" ? void 0 : navigator);
|
|
325
|
+
const doc = env.document ?? win?.document ?? (typeof document === "undefined" ? void 0 : document);
|
|
326
|
+
const secure = win?.isSecureContext !== false;
|
|
327
|
+
if (secure && typeof nav?.clipboard?.writeText === "function") {
|
|
328
|
+
try {
|
|
329
|
+
await nav.clipboard.writeText(text);
|
|
330
|
+
return true;
|
|
331
|
+
} catch {
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return legacyCopy(text, doc);
|
|
335
|
+
};
|
|
336
|
+
const legacyCopy = (text, doc) => {
|
|
337
|
+
if (!doc?.body || typeof doc.createElement !== "function" || typeof doc.execCommand !== "function") {
|
|
338
|
+
return false;
|
|
339
|
+
}
|
|
340
|
+
const textarea = doc.createElement("textarea");
|
|
341
|
+
textarea.value = text;
|
|
342
|
+
textarea.setAttribute("readonly", "");
|
|
343
|
+
textarea.setAttribute("aria-hidden", "true");
|
|
344
|
+
textarea.style.position = "fixed";
|
|
345
|
+
textarea.style.top = "0";
|
|
346
|
+
textarea.style.left = "-9999px";
|
|
347
|
+
textarea.style.opacity = "0";
|
|
348
|
+
const activeElement = doc.activeElement;
|
|
349
|
+
doc.body.appendChild(textarea);
|
|
350
|
+
try {
|
|
351
|
+
textarea.select();
|
|
352
|
+
return doc.execCommand("copy") === true;
|
|
353
|
+
} catch {
|
|
354
|
+
return false;
|
|
355
|
+
} finally {
|
|
356
|
+
doc.body.removeChild(textarea);
|
|
357
|
+
if (activeElement && typeof activeElement.focus === "function") {
|
|
358
|
+
try {
|
|
359
|
+
activeElement.focus();
|
|
360
|
+
} catch {
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
};
|
|
365
|
+
const useCopyToClipboard = () => {
|
|
366
|
+
const { toggleNotification } = useNotification();
|
|
367
|
+
const { t } = useMagicLinkIntl();
|
|
368
|
+
return useCallback(
|
|
369
|
+
async (text, messages = {}) => {
|
|
370
|
+
const copied = await copyToClipboard(text);
|
|
371
|
+
toggleNotification({
|
|
372
|
+
type: copied ? "success" : "warning",
|
|
373
|
+
message: copied ? messages.success ?? t("common.clipboard.copied", "Copied to clipboard") : messages.failure ?? t("common.clipboard.failed", "Copy failed. Select the text and copy it manually.")
|
|
374
|
+
});
|
|
375
|
+
return copied;
|
|
376
|
+
},
|
|
377
|
+
[t, toggleNotification]
|
|
378
|
+
);
|
|
379
|
+
};
|
|
380
|
+
const STORAGE_KEY = "magic-link-language";
|
|
381
|
+
const SUPPORTED_LANGUAGES = Object.freeze(["en", "de", "fr", "es", "pt"]);
|
|
382
|
+
const translations = Object.freeze({
|
|
383
|
+
en: enTranslations,
|
|
384
|
+
de: deTranslations,
|
|
385
|
+
fr: frTranslations,
|
|
386
|
+
es: esTranslations,
|
|
387
|
+
pt: ptTranslations
|
|
388
|
+
});
|
|
389
|
+
const toSupportedLanguage = (locale) => {
|
|
390
|
+
if (typeof locale !== "string" || !locale) return null;
|
|
391
|
+
const base = locale.toLowerCase().split(/[-_]/)[0];
|
|
392
|
+
return SUPPORTED_LANGUAGES.includes(base) ? base : null;
|
|
393
|
+
};
|
|
394
|
+
const readStoredLanguage = (storage = safeLocalStorage()) => {
|
|
395
|
+
try {
|
|
396
|
+
return toSupportedLanguage(storage?.getItem(STORAGE_KEY));
|
|
397
|
+
} catch {
|
|
398
|
+
return null;
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
const writeStoredLanguage = (language, storage = safeLocalStorage()) => {
|
|
402
|
+
try {
|
|
403
|
+
if (language) storage?.setItem(STORAGE_KEY, language);
|
|
404
|
+
else storage?.removeItem(STORAGE_KEY);
|
|
405
|
+
} catch {
|
|
406
|
+
}
|
|
407
|
+
};
|
|
408
|
+
function safeLocalStorage() {
|
|
409
|
+
try {
|
|
410
|
+
return typeof window === "undefined" ? void 0 : window.localStorage;
|
|
411
|
+
} catch {
|
|
412
|
+
return void 0;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
const buildMessages = (adminMessages, language) => ({
|
|
416
|
+
...adminMessages ?? {},
|
|
417
|
+
...translations.en,
|
|
418
|
+
...translations[language] ?? {}
|
|
419
|
+
});
|
|
420
|
+
const createIntlErrorHandler = (parentOnError) => (error) => {
|
|
421
|
+
if (error?.code === "MISSING_TRANSLATION") return;
|
|
422
|
+
if (typeof parentOnError === "function") parentOnError(error);
|
|
423
|
+
};
|
|
424
|
+
const LanguageContext = createContext(null);
|
|
425
|
+
const usePluginLanguage = () => {
|
|
426
|
+
const context = useContext(LanguageContext);
|
|
427
|
+
if (!context) {
|
|
428
|
+
throw new Error("usePluginLanguage must be used within LanguageProvider");
|
|
429
|
+
}
|
|
430
|
+
return context;
|
|
431
|
+
};
|
|
432
|
+
const LanguageProvider = ({ children }) => {
|
|
433
|
+
const parentIntl = useContext(IntlContext);
|
|
434
|
+
const adminLanguage = toSupportedLanguage(parentIntl?.locale) ?? "en";
|
|
435
|
+
const [override, setOverride] = useState(() => readStoredLanguage());
|
|
436
|
+
const language = override ?? adminLanguage;
|
|
437
|
+
const changeLanguage = useCallback((next) => {
|
|
438
|
+
const supported = toSupportedLanguage(next);
|
|
439
|
+
setOverride(supported);
|
|
440
|
+
writeStoredLanguage(supported);
|
|
441
|
+
}, []);
|
|
442
|
+
const messages = useMemo(
|
|
443
|
+
() => buildMessages(parentIntl?.messages, language),
|
|
444
|
+
[parentIntl?.messages, language]
|
|
445
|
+
);
|
|
446
|
+
const parentOnError = parentIntl?.onError;
|
|
447
|
+
const onError = useMemo(() => createIntlErrorHandler(parentOnError), [parentOnError]);
|
|
448
|
+
const value = useMemo(
|
|
449
|
+
() => ({
|
|
450
|
+
language,
|
|
451
|
+
adminLanguage,
|
|
452
|
+
isFollowingAdmin: override === null,
|
|
453
|
+
languages: SUPPORTED_LANGUAGES,
|
|
454
|
+
changeLanguage,
|
|
455
|
+
/** @deprecated use `useMagicLinkIntl().t(key, defaultMessage)` */
|
|
456
|
+
t: (key) => messages[key] ?? key
|
|
457
|
+
}),
|
|
458
|
+
[language, adminLanguage, override, changeLanguage, messages]
|
|
459
|
+
);
|
|
460
|
+
const locale = parentIntl?.locale && toSupportedLanguage(parentIntl.locale) === language ? parentIntl.locale : language;
|
|
461
|
+
return /* @__PURE__ */ jsx(LanguageContext.Provider, { value, children: /* @__PURE__ */ jsx(
|
|
462
|
+
IntlProvider,
|
|
463
|
+
{
|
|
464
|
+
locale,
|
|
465
|
+
messages,
|
|
466
|
+
defaultLocale: "en",
|
|
467
|
+
timeZone: parentIntl?.timeZone,
|
|
468
|
+
onError,
|
|
469
|
+
children
|
|
470
|
+
}
|
|
471
|
+
) });
|
|
472
|
+
};
|
|
473
|
+
const LicenseGuard = ({ children }) => /* @__PURE__ */ jsx(Fragment, { children });
|
|
474
|
+
export {
|
|
475
|
+
LicenseGuard as L,
|
|
476
|
+
PluginPageTitle as P,
|
|
477
|
+
SubsectionHeading as S,
|
|
478
|
+
brand as a,
|
|
479
|
+
breakpoints as b,
|
|
480
|
+
color as c,
|
|
481
|
+
accent as d,
|
|
482
|
+
tint as e,
|
|
483
|
+
fontSize as f,
|
|
484
|
+
byScheme as g,
|
|
485
|
+
useFormatters as h,
|
|
486
|
+
useMagicLinkRBAC as i,
|
|
487
|
+
useCopyToClipboard as j,
|
|
488
|
+
LanguageProvider as k,
|
|
489
|
+
usePluginLanguage as l,
|
|
490
|
+
motionSafe as m,
|
|
491
|
+
reducedMotion as r,
|
|
492
|
+
space as s,
|
|
493
|
+
theme as t,
|
|
494
|
+
useMagicLinkIntl as u
|
|
495
|
+
};
|