@micha.bigler/ui-core-micha 2.33.1 → 2.34.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/WORK_ORDERS.md +4 -2
- package/dist/auth/ReauthModal.js +3 -1
- package/dist/components/AccessCodeManager.js +16 -14
- package/dist/components/AccessCodeSingleUseToggle.js +2 -1
- package/dist/components/AllowedEmailDomainsManager.js +3 -1
- package/dist/components/AuthFactorRequirementCard.js +2 -1
- package/dist/components/BulkInviteCsvTab.js +7 -7
- package/dist/components/LoginForm.js +2 -1
- package/dist/components/MFAComponent.js +11 -5
- package/dist/components/MfaLoginComponent.js +4 -1
- package/dist/components/PasskeysComponent.js +4 -2
- package/dist/components/QrSignupManager.js +2 -1
- package/dist/components/QrSignupValidityManager.js +4 -1
- package/dist/components/RegistrationMethodsManager.js +3 -1
- package/dist/components/SecurityComponent.js +3 -1
- package/dist/components/SupportRecoveryRequestsTab.js +4 -1
- package/dist/components/UserInviteComponent.js +8 -8
- package/dist/components/UserListComponent.js +8 -4
- package/dist/components/charts/ChartFrame.js +5 -2
- package/dist/components/charts/TimeSeriesChart.js +7 -4
- package/dist/index.js +1 -1
- package/dist/layout/PageLayout.js +3 -2
- package/dist/messaging/AttachmentList.js +6 -1
- package/dist/messaging/Composer.js +2 -1
- package/dist/messaging/DirectMessageLauncher.js +2 -1
- package/dist/messaging/MessageBubble.js +29 -8
- package/dist/messaging/PollCard.js +6 -4
- package/dist/messaging/Thread.js +2 -1
- package/dist/notifications/NotificationSettings.js +17 -3
- package/dist/notifications/PopupSurface.js +2 -1
- package/dist/onboarding/steps/BrowserPushStep.js +2 -1
- package/dist/pages/AccountPage.js +2 -1
- package/dist/pages/LoginPage.js +2 -1
- package/dist/pages/SignUpPage.js +2 -1
- package/dist/pages/SignupConfirmPage.js +2 -1
- package/dist/theme/index.js +2 -1
- package/dist/theme/kitSxRegistry.js +187 -0
- package/dist/theme/themeCompleteness.js +218 -0
- package/dist/theme/tokens.js +1 -0
- package/package.json +1 -1
- package/src/auth/ReauthModal.jsx +5 -2
- package/src/components/AccessCodeManager.jsx +22 -20
- package/src/components/AccessCodeSingleUseToggle.jsx +4 -2
- package/src/components/AllowedEmailDomainsManager.jsx +6 -3
- package/src/components/AuthFactorRequirementCard.jsx +4 -2
- package/src/components/BulkInviteCsvTab.jsx +11 -10
- package/src/components/LoginForm.jsx +5 -3
- package/src/components/MFAComponent.jsx +14 -7
- package/src/components/MfaLoginComponent.jsx +9 -5
- package/src/components/PasskeysComponent.jsx +7 -4
- package/src/components/QrSignupManager.jsx +6 -4
- package/src/components/QrSignupValidityManager.jsx +8 -4
- package/src/components/RegistrationMethodsManager.jsx +7 -4
- package/src/components/SecurityComponent.jsx +10 -7
- package/src/components/SupportRecoveryRequestsTab.jsx +8 -4
- package/src/components/UserInviteComponent.jsx +10 -10
- package/src/components/UserListComponent.jsx +12 -7
- package/src/components/charts/ChartFrame.jsx +6 -2
- package/src/components/charts/TimeSeriesChart.jsx +8 -4
- package/src/index.js +3 -0
- package/src/layout/PageLayout.jsx +4 -2
- package/src/messaging/AttachmentList.jsx +9 -3
- package/src/messaging/Composer.jsx +3 -1
- package/src/messaging/DirectMessageLauncher.jsx +3 -1
- package/src/messaging/MessageBubble.jsx +31 -9
- package/src/messaging/PollCard.jsx +8 -6
- package/src/messaging/Thread.jsx +3 -1
- package/src/notifications/NotificationSettings.jsx +24 -9
- package/src/notifications/PopupSurface.jsx +3 -1
- package/src/onboarding/steps/BrowserPushStep.jsx +3 -1
- package/src/pages/AccountPage.jsx +11 -9
- package/src/pages/LoginPage.jsx +6 -4
- package/src/pages/SignUpPage.jsx +4 -2
- package/src/pages/SignupConfirmPage.jsx +4 -2
- package/src/theme/index.js +3 -0
- package/src/theme/kitSxRegistry.js +246 -0
- package/src/theme/themeCompleteness.js +228 -0
- package/src/theme/tokens.js +1 -0
- package/tests/createAppTheme.test.js +1 -0
- package/tests/themeCompleteness.test.js +214 -0
- package/work-orders/THEME-3.md +210 -0
- package/work-orders/THEME-4.md +271 -0
package/dist/pages/SignUpPage.js
CHANGED
|
@@ -8,6 +8,7 @@ import { NarrowPage } from '../layout/PageLayout';
|
|
|
8
8
|
import { AuthContext } from '../auth/AuthContext';
|
|
9
9
|
import { submitRegistrationRequest } from '../auth/authApi';
|
|
10
10
|
import { TurnstileWidget } from '../components/TurnstileWidget';
|
|
11
|
+
export const SIGN_UP_PAGE_ALERT_SX = { mb: 2 };
|
|
11
12
|
const TURNSTILE_SIGNUP_MODES = new Set([
|
|
12
13
|
'self_signup_open',
|
|
13
14
|
'self_signup_email_domain',
|
|
@@ -116,7 +117,7 @@ export function SignUpPage() {
|
|
|
116
117
|
const handleGoToLogin = () => {
|
|
117
118
|
navigate('/login');
|
|
118
119
|
};
|
|
119
|
-
return (_jsxs(NarrowPage, { title: t('Auth.LOGIN_SIGNUP_BUTTON'), subtitle: pageSubtitle, children: [_jsx(Helmet, { children: _jsxs("title", { children: [t('App.NAME'), " \u2013 ", t('Auth.LOGIN_SIGNUP_BUTTON')] }) }), successKey && (_jsx(Alert, { severity: "success", sx:
|
|
120
|
+
return (_jsxs(NarrowPage, { title: t('Auth.LOGIN_SIGNUP_BUTTON'), subtitle: pageSubtitle, children: [_jsx(Helmet, { children: _jsxs("title", { children: [t('App.NAME'), " \u2013 ", t('Auth.LOGIN_SIGNUP_BUTTON')] }) }), successKey && (_jsx(Alert, { severity: "success", sx: SIGN_UP_PAGE_ALERT_SX, children: t(successKey, { email }) })), errorKey && (_jsx(Alert, { severity: "error", sx: SIGN_UP_PAGE_ALERT_SX, children: t(errorKey, t('Auth.INVITE_FAILED', 'Could not complete signup.')) })), signupModes.length > 1 && (_jsx(Stack, { spacing: 1, sx: { mb: 2 }, children: _jsx(Stack, { spacing: 1, children: signupModes.map((entry) => (_jsx(Button, { variant: mode === entry ? 'contained' : 'outlined', onClick: () => setMode(entry), disabled: submitting, fullWidth: true, children: t(MODE_LABELS[entry] || entry, entry) }, entry))) }) })), _jsxs(Box, { component: "form", onSubmit: handleSubmit, sx: { display: 'flex', flexDirection: 'column', gap: 2 }, children: [_jsx(TextField, { label: t('Auth.EMAIL_LABEL'), type: "email", required: true, fullWidth: true, value: email, onChange: (e) => setEmail(e.target.value), disabled: submitting }), mode === 'self_signup_access_code' && (_jsx(TextField, { label: t('Auth.ACCESS_CODE_LABEL'), type: "text", required: true, fullWidth: true, value: accessCode, onChange: (e) => setAccessCode(e.target.value), disabled: submitting })), turnstileRequired && (_jsx(TurnstileWidget, { ref: turnstileWidgetRef, siteKey: authMethods.turnstile_site_key, onToken: setTurnstileToken })), _jsx(Button, { type: "submit", variant: "contained", disabled: submitting || signupModes.length === 0 || (turnstileRequired && !turnstileToken), children: submitting
|
|
120
121
|
? t('Auth.SIGNUP_SUBMITTING')
|
|
121
122
|
: t('Auth.SIGNUP_SUBMIT') })] }), _jsx(Box, { sx: { mt: 3 }, children: _jsxs(Typography, { variant: "body2", children: [t('Auth.SIGNUP_ALREADY_HAVE_ACCOUNT'), ' ', _jsx(Button, { onClick: handleGoToLogin, variant: "text", size: "small", children: t('Auth.SIGNUP_GO_TO_LOGIN') })] }) })] }));
|
|
122
123
|
}
|
|
@@ -13,6 +13,7 @@ import { Helmet } from 'react-helmet';
|
|
|
13
13
|
import { useTranslation } from 'react-i18next';
|
|
14
14
|
import { NarrowPage } from '../layout/PageLayout';
|
|
15
15
|
import { confirmRegistration } from '../auth/authApi';
|
|
16
|
+
export const SIGNUP_CONFIRM_PAGE_ALERT_SX = { mb: 2 };
|
|
16
17
|
export function SignupConfirmPage() {
|
|
17
18
|
const { t } = useTranslation();
|
|
18
19
|
const location = useLocation();
|
|
@@ -57,7 +58,7 @@ export function SignupConfirmPage() {
|
|
|
57
58
|
}
|
|
58
59
|
};
|
|
59
60
|
const tokenMissing = !tokenFromUrl;
|
|
60
|
-
return (_jsxs(NarrowPage, { title: t('Auth.SIGNUP_CONFIRM_TITLE', 'Confirm your registration'), subtitle: t('Auth.SIGNUP_CONFIRM_SUBTITLE', 'Choose a password to finish creating your account.'), children: [_jsx(Helmet, { children: _jsxs("title", { children: [t('App.NAME'), " \u2013 ", t('Auth.SIGNUP_CONFIRM_TITLE', 'Confirm your registration')] }) }), tokenMissing ? (_jsxs(_Fragment, { children: [_jsx(Alert, { severity: "error", sx:
|
|
61
|
+
return (_jsxs(NarrowPage, { title: t('Auth.SIGNUP_CONFIRM_TITLE', 'Confirm your registration'), subtitle: t('Auth.SIGNUP_CONFIRM_SUBTITLE', 'Choose a password to finish creating your account.'), children: [_jsx(Helmet, { children: _jsxs("title", { children: [t('App.NAME'), " \u2013 ", t('Auth.SIGNUP_CONFIRM_TITLE', 'Confirm your registration')] }) }), tokenMissing ? (_jsxs(_Fragment, { children: [_jsx(Alert, { severity: "error", sx: SIGNUP_CONFIRM_PAGE_ALERT_SX, children: t('Auth.PENDING_TOKEN_INVALID', 'This confirmation link is invalid or expired.') }), _jsxs(Stack, { direction: "row", spacing: 1, sx: { mt: 1 }, children: [_jsx(Button, { onClick: () => navigate('/signup'), variant: "contained", children: t('Auth.SIGNUP_REQUEST_NEW', 'Request a new invitation') }), _jsx(Button, { onClick: () => navigate('/login'), variant: "text", children: t('Auth.SIGNUP_GO_TO_LOGIN', 'Go to login') })] })] })) : (_jsxs(_Fragment, { children: [errorKey && (_jsx(Alert, { severity: "error", sx: SIGNUP_CONFIRM_PAGE_ALERT_SX, children: t(errorKey, t('Auth.PENDING_TOKEN_INVALID', 'Could not confirm registration.')) })), _jsxs(Box, { component: "form", onSubmit: handleSubmit, sx: { display: 'flex', flexDirection: 'column', gap: 2 }, children: [_jsx(TextField, { label: t('Auth.NEW_PASSWORD_LABEL', 'New password'), type: "password", required: true, fullWidth: true, value: password, onChange: (e) => setPassword(e.target.value), disabled: submitting, autoComplete: "new-password" }), _jsx(TextField, { label: t('Auth.PASSWORD_CONFIRM_LABEL', 'Confirm new password'), type: "password", required: true, fullWidth: true, value: confirmPassword, onChange: (e) => setConfirmPassword(e.target.value), disabled: submitting, autoComplete: "new-password" }), _jsx(Button, { type: "submit", variant: "contained", disabled: submitting, children: submitting
|
|
61
62
|
? t('Auth.SIGNUP_CONFIRM_SUBMITTING', 'Confirming…')
|
|
62
63
|
: t('Auth.SIGNUP_CONFIRM_SUBMIT', 'Confirm registration') })] }), _jsxs(Stack, { direction: "row", spacing: 1, sx: { mt: 3 }, children: [_jsx(Typography, { variant: "body2", children: t('Auth.SIGNUP_ALREADY_HAVE_ACCOUNT', 'Already have an account?') }), _jsx(Button, { onClick: () => navigate('/login'), variant: "text", size: "small", children: t('Auth.SIGNUP_GO_TO_LOGIN', 'Go to login') })] })] }))] }));
|
|
63
64
|
}
|
package/dist/theme/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { createAppTheme } from './createAppTheme';
|
|
2
|
-
export { assertThemeComplete, calculateContrastRatio, reportThemeAdoption, THEME_COMPLETENESS_SURFACES, } from './themeCompleteness';
|
|
2
|
+
export { assertThemeComplete, assertKitSxDisjoint, calculateContrastRatio, reportKitSxBypasses, reportThemeAdoption, THEME_COMPLETENESS_SURFACES, } from './themeCompleteness';
|
|
3
|
+
export { KIT_COMPONENT_SX_REGISTRY } from './kitSxRegistry';
|
|
3
4
|
export { formatShortTime, formatShortDate, formatShortMonth, formatShortYear, } from '../components/charts/chartLabels';
|
|
4
5
|
export { yearTickInterval } from '../components/charts/yearTickInterval';
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { ACCESS_CODE_ACTION_SX, ACCESS_CODE_ALERT_SX, ACCESS_CODE_PRIMARY_ACTION_SX, ACCESS_CODE_VALUE_FIELD_SX, } from '../components/AccessCodeManager';
|
|
2
|
+
import { ACCESS_CODE_SINGLE_USE_ALERT_SX } from '../components/AccessCodeSingleUseToggle';
|
|
3
|
+
import { ALLOWED_EMAIL_DOMAINS_ALERT_SX, ALLOWED_EMAIL_DOMAINS_BUTTON_SX, } from '../components/AllowedEmailDomainsManager';
|
|
4
|
+
import { AUTH_FACTOR_REQUIREMENT_ALERT_SX } from '../components/AuthFactorRequirementCard';
|
|
5
|
+
import { BULK_INVITE_ACTION_SX, BULK_INVITE_ALERT_SX } from '../components/BulkInviteCsvTab';
|
|
6
|
+
import { LOGIN_FORM_DIVIDER_SX } from '../components/LoginForm';
|
|
7
|
+
import { MFA_ACTIVE_CARD_SX, MFA_ALERT_SX, MFA_CARD_SX, MFA_DIVIDER_SX, MFA_RECOVERY_BUTTON_SX, MFA_TEXT_FIELD_SX, } from '../components/MFAComponent';
|
|
8
|
+
import { MFA_LOGIN_ALERT_SX, MFA_LOGIN_DIVIDER_SX, MFA_LOGIN_TEXT_FIELD_SX, } from '../components/MfaLoginComponent';
|
|
9
|
+
import { MOBILE_BOTTOM_NAV_ACTION_SX, MOBILE_BOTTOM_NAV_ROOT_SX, } from '../components/MobileBottomNav';
|
|
10
|
+
import { PASSKEYS_ALERT_SX, PASSKEYS_DIVIDER_SX } from '../components/PasskeysComponent';
|
|
11
|
+
import { QR_SIGNUP_MANAGER_ALERT_SX } from '../components/QrSignupManager';
|
|
12
|
+
import { QR_SIGNUP_VALIDITY_ALERT_SX, QR_SIGNUP_VALIDITY_BUTTON_SX, QR_SIGNUP_VALIDITY_FIELD_SX, } from '../components/QrSignupValidityManager';
|
|
13
|
+
import { REGISTRATION_METHODS_ALERT_SX, REGISTRATION_METHODS_INFO_SX, } from '../components/RegistrationMethodsManager';
|
|
14
|
+
import { SECURITY_ALERT_SX, SECURITY_DIVIDER_SX } from '../components/SecurityComponent';
|
|
15
|
+
import { SUPPORT_RECOVERY_AGENT_BUTTON_SX, SUPPORT_RECOVERY_AGENT_PAPER_SX, SUPPORT_RECOVERY_ALERT_SX, } from '../components/SupportRecoveryRequestsTab';
|
|
16
|
+
import { USER_INVITE_ACTION_SX, USER_INVITE_ALERT_SX } from '../components/UserInviteComponent';
|
|
17
|
+
import { USER_LIST_ACTION_SX, USER_LIST_ALERT_SX, USER_LIST_BODY_CELL_SX, USER_LIST_EMPTY_CELL_SX, USER_LIST_HEADER_CELL_SX, } from '../components/UserListComponent';
|
|
18
|
+
import { CHART_FRAME_ALERT_SX, CHART_FRAME_ROOT_SX } from '../components/charts/ChartFrame';
|
|
19
|
+
import { PAGE_LAYOUT_CONTAINER_SX } from '../layout/PageLayout';
|
|
20
|
+
import { ATTACHMENT_LIST_ALERT_SX, ATTACHMENT_LIST_LIGHTBOX_ACTION_SX, } from '../messaging/AttachmentList';
|
|
21
|
+
import { COMPOSER_EMOJI_BUTTON_SX } from '../messaging/Composer';
|
|
22
|
+
import { DIRECT_MESSAGE_LAUNCHER_ALERT_SX } from '../messaging/DirectMessageLauncher';
|
|
23
|
+
import { MESSAGE_BUBBLE_ACTION_SX, MESSAGE_BUBBLE_ROOT_SX } from '../messaging/MessageBubble';
|
|
24
|
+
import { POLL_CARD_CHECKBOX_SX, POLL_CARD_FORM_CONTROL_SX, POLL_CARD_ROOT_SX, } from '../messaging/PollCard';
|
|
25
|
+
import { THREAD_DAY_SEPARATOR_SX } from '../messaging/Thread';
|
|
26
|
+
import { NOTIFICATION_SETTINGS_ALERT_SX, NOTIFICATION_SETTINGS_CATEGORY_CONTROL_SX, NOTIFICATION_SETTINGS_FORM_CONTROL_SX, NOTIFICATION_SETTINGS_HINT_ALERT_SX, NOTIFICATION_SETTINGS_PUSH_CONTROL_SX, NOTIFICATION_SETTINGS_REACH_ALERT_SX, } from '../notifications/NotificationSettings';
|
|
27
|
+
import { POPUP_SURFACE_DISMISS_BUTTON_SX } from '../notifications/PopupSurface';
|
|
28
|
+
import { BROWSER_PUSH_FORM_CONTROL_LABEL_SX } from '../onboarding/steps/BrowserPushStep';
|
|
29
|
+
import { ACCOUNT_PAGE_SECTION_PAPER_SX } from '../pages/AccountPage';
|
|
30
|
+
import { LOGIN_PAGE_ALERT_SX } from '../pages/LoginPage';
|
|
31
|
+
import { SIGN_UP_PAGE_ALERT_SX } from '../pages/SignUpPage';
|
|
32
|
+
import { SIGNUP_CONFIRM_PAGE_ALERT_SX } from '../pages/SignupConfirmPage';
|
|
33
|
+
import { REAUTH_MODAL_ALERT_SX, REAUTH_MODAL_TEXT_FIELD_SX } from '../auth/ReauthModal';
|
|
34
|
+
const SX_EXPORTS = {
|
|
35
|
+
ACCESS_CODE_ACTION_SX,
|
|
36
|
+
ACCESS_CODE_ALERT_SX,
|
|
37
|
+
ACCESS_CODE_PRIMARY_ACTION_SX,
|
|
38
|
+
ACCESS_CODE_SINGLE_USE_ALERT_SX,
|
|
39
|
+
ACCESS_CODE_VALUE_FIELD_SX,
|
|
40
|
+
ACCOUNT_PAGE_SECTION_PAPER_SX,
|
|
41
|
+
ALLOWED_EMAIL_DOMAINS_ALERT_SX,
|
|
42
|
+
ALLOWED_EMAIL_DOMAINS_BUTTON_SX,
|
|
43
|
+
ATTACHMENT_LIST_ALERT_SX,
|
|
44
|
+
ATTACHMENT_LIST_LIGHTBOX_ACTION_SX,
|
|
45
|
+
AUTH_FACTOR_REQUIREMENT_ALERT_SX,
|
|
46
|
+
BROWSER_PUSH_FORM_CONTROL_LABEL_SX,
|
|
47
|
+
BULK_INVITE_ACTION_SX,
|
|
48
|
+
BULK_INVITE_ALERT_SX,
|
|
49
|
+
CHART_FRAME_ALERT_SX,
|
|
50
|
+
CHART_FRAME_ROOT_SX,
|
|
51
|
+
COMPOSER_EMOJI_BUTTON_SX,
|
|
52
|
+
DIRECT_MESSAGE_LAUNCHER_ALERT_SX,
|
|
53
|
+
LOGIN_FORM_DIVIDER_SX,
|
|
54
|
+
LOGIN_PAGE_ALERT_SX,
|
|
55
|
+
MESSAGE_BUBBLE_ACTION_SX,
|
|
56
|
+
MESSAGE_BUBBLE_ROOT_SX,
|
|
57
|
+
MFA_ACTIVE_CARD_SX,
|
|
58
|
+
MFA_ALERT_SX,
|
|
59
|
+
MFA_CARD_SX,
|
|
60
|
+
MFA_DIVIDER_SX,
|
|
61
|
+
MFA_LOGIN_ALERT_SX,
|
|
62
|
+
MFA_LOGIN_DIVIDER_SX,
|
|
63
|
+
MFA_LOGIN_TEXT_FIELD_SX,
|
|
64
|
+
MFA_RECOVERY_BUTTON_SX,
|
|
65
|
+
MFA_TEXT_FIELD_SX,
|
|
66
|
+
MOBILE_BOTTOM_NAV_ACTION_SX,
|
|
67
|
+
MOBILE_BOTTOM_NAV_ROOT_SX,
|
|
68
|
+
NOTIFICATION_SETTINGS_ALERT_SX,
|
|
69
|
+
NOTIFICATION_SETTINGS_CATEGORY_CONTROL_SX,
|
|
70
|
+
NOTIFICATION_SETTINGS_FORM_CONTROL_SX,
|
|
71
|
+
NOTIFICATION_SETTINGS_HINT_ALERT_SX,
|
|
72
|
+
NOTIFICATION_SETTINGS_PUSH_CONTROL_SX,
|
|
73
|
+
NOTIFICATION_SETTINGS_REACH_ALERT_SX,
|
|
74
|
+
PAGE_LAYOUT_CONTAINER_SX,
|
|
75
|
+
PASSKEYS_ALERT_SX,
|
|
76
|
+
PASSKEYS_DIVIDER_SX,
|
|
77
|
+
POLL_CARD_CHECKBOX_SX,
|
|
78
|
+
POLL_CARD_FORM_CONTROL_SX,
|
|
79
|
+
POLL_CARD_ROOT_SX,
|
|
80
|
+
POPUP_SURFACE_DISMISS_BUTTON_SX,
|
|
81
|
+
QR_SIGNUP_MANAGER_ALERT_SX,
|
|
82
|
+
QR_SIGNUP_VALIDITY_ALERT_SX,
|
|
83
|
+
QR_SIGNUP_VALIDITY_BUTTON_SX,
|
|
84
|
+
QR_SIGNUP_VALIDITY_FIELD_SX,
|
|
85
|
+
REAUTH_MODAL_ALERT_SX,
|
|
86
|
+
REAUTH_MODAL_TEXT_FIELD_SX,
|
|
87
|
+
REGISTRATION_METHODS_ALERT_SX,
|
|
88
|
+
REGISTRATION_METHODS_INFO_SX,
|
|
89
|
+
SECURITY_ALERT_SX,
|
|
90
|
+
SECURITY_DIVIDER_SX,
|
|
91
|
+
SIGNUP_CONFIRM_PAGE_ALERT_SX,
|
|
92
|
+
SIGN_UP_PAGE_ALERT_SX,
|
|
93
|
+
SUPPORT_RECOVERY_AGENT_BUTTON_SX,
|
|
94
|
+
SUPPORT_RECOVERY_AGENT_PAPER_SX,
|
|
95
|
+
SUPPORT_RECOVERY_ALERT_SX,
|
|
96
|
+
THREAD_DAY_SEPARATOR_SX,
|
|
97
|
+
USER_INVITE_ACTION_SX,
|
|
98
|
+
USER_INVITE_ALERT_SX,
|
|
99
|
+
USER_LIST_ACTION_SX,
|
|
100
|
+
USER_LIST_ALERT_SX,
|
|
101
|
+
USER_LIST_BODY_CELL_SX,
|
|
102
|
+
USER_LIST_EMPTY_CELL_SX,
|
|
103
|
+
USER_LIST_HEADER_CELL_SX,
|
|
104
|
+
};
|
|
105
|
+
const SX_EXPORT_NAMES = new Map(Object.entries(SX_EXPORTS).map(([name, sx]) => [sx, name]));
|
|
106
|
+
const entry = (component, muiComponent, sx) => ({
|
|
107
|
+
component,
|
|
108
|
+
muiComponent,
|
|
109
|
+
sx,
|
|
110
|
+
exportName: SX_EXPORT_NAMES.get(sx),
|
|
111
|
+
});
|
|
112
|
+
/**
|
|
113
|
+
* Kit-owned, top-level sx objects paired with the baseline-styled MUI key they
|
|
114
|
+
* target. Conditional and nested sx remain a documented lower bound in the
|
|
115
|
+
* checks rather than being represented here as if they were fully inspected.
|
|
116
|
+
*/
|
|
117
|
+
export const KIT_COMPONENT_SX_REGISTRY = [
|
|
118
|
+
entry('AccessCodeManager.action', 'MuiButton', ACCESS_CODE_ACTION_SX),
|
|
119
|
+
entry('AccessCodeManager.primaryAction', 'MuiButton', ACCESS_CODE_PRIMARY_ACTION_SX),
|
|
120
|
+
entry('AccessCodeManager.alert', 'MuiAlert', ACCESS_CODE_ALERT_SX),
|
|
121
|
+
entry('AccessCodeManager.valueField', 'MuiTextField', ACCESS_CODE_VALUE_FIELD_SX),
|
|
122
|
+
entry('AccessCodeSingleUseToggle.alert', 'MuiAlert', ACCESS_CODE_SINGLE_USE_ALERT_SX),
|
|
123
|
+
entry('AllowedEmailDomainsManager.alert', 'MuiAlert', ALLOWED_EMAIL_DOMAINS_ALERT_SX),
|
|
124
|
+
entry('AllowedEmailDomainsManager.action', 'MuiButton', ALLOWED_EMAIL_DOMAINS_BUTTON_SX),
|
|
125
|
+
entry('AuthFactorRequirementCard.alert', 'MuiAlert', AUTH_FACTOR_REQUIREMENT_ALERT_SX),
|
|
126
|
+
entry('BulkInviteCsvTab.action', 'MuiButton', BULK_INVITE_ACTION_SX),
|
|
127
|
+
entry('BulkInviteCsvTab.alert', 'MuiAlert', BULK_INVITE_ALERT_SX),
|
|
128
|
+
entry('LoginForm.divider', 'MuiDivider', LOGIN_FORM_DIVIDER_SX),
|
|
129
|
+
entry('MFAComponent.alert', 'MuiAlert', MFA_ALERT_SX),
|
|
130
|
+
entry('MFAComponent.card', 'MuiCard', MFA_CARD_SX),
|
|
131
|
+
entry('MFAComponent.activeCard', 'MuiCard', MFA_ACTIVE_CARD_SX),
|
|
132
|
+
entry('MFAComponent.field', 'MuiTextField', MFA_TEXT_FIELD_SX),
|
|
133
|
+
entry('MFAComponent.divider', 'MuiDivider', MFA_DIVIDER_SX),
|
|
134
|
+
entry('MFAComponent.recoveryAction', 'MuiButton', MFA_RECOVERY_BUTTON_SX),
|
|
135
|
+
entry('MfaLoginComponent.alert', 'MuiAlert', MFA_LOGIN_ALERT_SX),
|
|
136
|
+
entry('MfaLoginComponent.divider', 'MuiDivider', MFA_LOGIN_DIVIDER_SX),
|
|
137
|
+
entry('MfaLoginComponent.field', 'MuiTextField', MFA_LOGIN_TEXT_FIELD_SX),
|
|
138
|
+
entry('MobileBottomNav.root', 'MuiBottomNavigation', MOBILE_BOTTOM_NAV_ROOT_SX),
|
|
139
|
+
entry('MobileBottomNav.action', 'MuiBottomNavigationAction', MOBILE_BOTTOM_NAV_ACTION_SX),
|
|
140
|
+
entry('PasskeysComponent.alert', 'MuiAlert', PASSKEYS_ALERT_SX),
|
|
141
|
+
entry('PasskeysComponent.divider', 'MuiDivider', PASSKEYS_DIVIDER_SX),
|
|
142
|
+
entry('QrSignupManager.alert', 'MuiAlert', QR_SIGNUP_MANAGER_ALERT_SX),
|
|
143
|
+
entry('QrSignupValidityManager.alert', 'MuiAlert', QR_SIGNUP_VALIDITY_ALERT_SX),
|
|
144
|
+
entry('QrSignupValidityManager.field', 'MuiTextField', QR_SIGNUP_VALIDITY_FIELD_SX),
|
|
145
|
+
entry('QrSignupValidityManager.action', 'MuiButton', QR_SIGNUP_VALIDITY_BUTTON_SX),
|
|
146
|
+
entry('RegistrationMethodsManager.alert', 'MuiAlert', REGISTRATION_METHODS_ALERT_SX),
|
|
147
|
+
entry('RegistrationMethodsManager.info', 'MuiAlert', REGISTRATION_METHODS_INFO_SX),
|
|
148
|
+
entry('SecurityComponent.alert', 'MuiAlert', SECURITY_ALERT_SX),
|
|
149
|
+
entry('SecurityComponent.divider', 'MuiDivider', SECURITY_DIVIDER_SX),
|
|
150
|
+
entry('SupportRecoveryRequestsTab.agentPaper', 'MuiPaper', SUPPORT_RECOVERY_AGENT_PAPER_SX),
|
|
151
|
+
entry('SupportRecoveryRequestsTab.alert', 'MuiAlert', SUPPORT_RECOVERY_ALERT_SX),
|
|
152
|
+
entry('SupportRecoveryRequestsTab.agentAction', 'MuiButton', SUPPORT_RECOVERY_AGENT_BUTTON_SX),
|
|
153
|
+
entry('UserInviteComponent.action', 'MuiButton', USER_INVITE_ACTION_SX),
|
|
154
|
+
entry('UserInviteComponent.alert', 'MuiAlert', USER_INVITE_ALERT_SX),
|
|
155
|
+
entry('UserListComponent.action', 'MuiButton', USER_LIST_ACTION_SX),
|
|
156
|
+
entry('UserListComponent.alert', 'MuiAlert', USER_LIST_ALERT_SX),
|
|
157
|
+
entry('UserListComponent.headerCell', 'MuiTableCell', USER_LIST_HEADER_CELL_SX),
|
|
158
|
+
entry('UserListComponent.emptyCell', 'MuiTableCell', USER_LIST_EMPTY_CELL_SX),
|
|
159
|
+
entry('UserListComponent.bodyCell', 'MuiTableCell', USER_LIST_BODY_CELL_SX),
|
|
160
|
+
entry('ChartFrame.root', 'MuiPaper', CHART_FRAME_ROOT_SX),
|
|
161
|
+
entry('ChartFrame.alert', 'MuiAlert', CHART_FRAME_ALERT_SX),
|
|
162
|
+
entry('PageLayout.container', 'MuiContainer', PAGE_LAYOUT_CONTAINER_SX),
|
|
163
|
+
entry('AttachmentList.lightboxAction', 'MuiIconButton', ATTACHMENT_LIST_LIGHTBOX_ACTION_SX),
|
|
164
|
+
entry('AttachmentList.alert', 'MuiAlert', ATTACHMENT_LIST_ALERT_SX),
|
|
165
|
+
entry('Composer.emojiAction', 'MuiIconButton', COMPOSER_EMOJI_BUTTON_SX),
|
|
166
|
+
entry('DirectMessageLauncher.alert', 'MuiAlert', DIRECT_MESSAGE_LAUNCHER_ALERT_SX),
|
|
167
|
+
entry('MessageBubble.root', 'MuiPaper', MESSAGE_BUBBLE_ROOT_SX),
|
|
168
|
+
entry('MessageBubble.action', 'MuiIconButton', MESSAGE_BUBBLE_ACTION_SX),
|
|
169
|
+
entry('PollCard.root', 'MuiPaper', POLL_CARD_ROOT_SX),
|
|
170
|
+
entry('PollCard.formControl', 'MuiFormControlLabel', POLL_CARD_FORM_CONTROL_SX),
|
|
171
|
+
entry('PollCard.checkbox', 'MuiCheckbox', POLL_CARD_CHECKBOX_SX),
|
|
172
|
+
entry('Thread.daySeparator', 'MuiDivider', THREAD_DAY_SEPARATOR_SX),
|
|
173
|
+
entry('NotificationSettings.alert', 'MuiAlert', NOTIFICATION_SETTINGS_ALERT_SX),
|
|
174
|
+
entry('NotificationSettings.hintAlert', 'MuiAlert', NOTIFICATION_SETTINGS_HINT_ALERT_SX),
|
|
175
|
+
entry('NotificationSettings.reachAlert', 'MuiAlert', NOTIFICATION_SETTINGS_REACH_ALERT_SX),
|
|
176
|
+
entry('NotificationSettings.formControl', 'MuiFormControlLabel', NOTIFICATION_SETTINGS_FORM_CONTROL_SX),
|
|
177
|
+
entry('NotificationSettings.pushControl', 'MuiFormControlLabel', NOTIFICATION_SETTINGS_PUSH_CONTROL_SX),
|
|
178
|
+
entry('NotificationSettings.categoryControl', 'MuiFormControlLabel', NOTIFICATION_SETTINGS_CATEGORY_CONTROL_SX),
|
|
179
|
+
entry('PopupSurface.dismissAction', 'MuiButton', POPUP_SURFACE_DISMISS_BUTTON_SX),
|
|
180
|
+
entry('BrowserPushStep.formControl', 'MuiFormControlLabel', BROWSER_PUSH_FORM_CONTROL_LABEL_SX),
|
|
181
|
+
entry('AccountPage.sectionPaper', 'MuiPaper', ACCOUNT_PAGE_SECTION_PAPER_SX),
|
|
182
|
+
entry('LoginPage.alert', 'MuiAlert', LOGIN_PAGE_ALERT_SX),
|
|
183
|
+
entry('SignUpPage.alert', 'MuiAlert', SIGN_UP_PAGE_ALERT_SX),
|
|
184
|
+
entry('SignupConfirmPage.alert', 'MuiAlert', SIGNUP_CONFIRM_PAGE_ALERT_SX),
|
|
185
|
+
entry('ReauthModal.alert', 'MuiAlert', REAUTH_MODAL_ALERT_SX),
|
|
186
|
+
entry('ReauthModal.field', 'MuiTextField', REAUTH_MODAL_TEXT_FIELD_SX),
|
|
187
|
+
];
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createTheme, getContrastRatio as getMuiContrastRatio } from '@mui/material/styles';
|
|
2
2
|
import { STATUS_KEYS, TYPOGRAPHY_VARIANTS } from './tokens';
|
|
3
|
+
import { KIT_COMPONENT_SX_REGISTRY } from './kitSxRegistry';
|
|
3
4
|
const MUI_DEFAULT_THEME = createTheme();
|
|
4
5
|
function getPath(value, path) {
|
|
5
6
|
return path.split('.').reduce((current, key) => current === null || current === void 0 ? void 0 : current[key], value);
|
|
@@ -134,6 +135,7 @@ export const THEME_COMPLETENESS_SURFACES = [
|
|
|
134
135
|
pathSurface('palette.ink.muted'),
|
|
135
136
|
pathSurface('palette.background.default'),
|
|
136
137
|
pathSurface('palette.background.paper'),
|
|
138
|
+
pathSurface('palette.background.subtle'),
|
|
137
139
|
pathSurface('palette.divider'),
|
|
138
140
|
pathSurface('palette.controlBorder.main'),
|
|
139
141
|
pathSurface('palette.controlBorder.hover'),
|
|
@@ -335,6 +337,222 @@ export function assertThemeComplete(theme, { exemptions = [] } = {}) {
|
|
|
335
337
|
findings.push(...contrastFindings(theme));
|
|
336
338
|
return { findings };
|
|
337
339
|
}
|
|
340
|
+
const SAME_ROOT_STYLE_OVERRIDE_SLOTS = {
|
|
341
|
+
MuiAlert: ['standardSuccess', 'standardWarning', 'standardError', 'standardInfo'],
|
|
342
|
+
MuiButton: ['root', 'contained', 'outlined'],
|
|
343
|
+
MuiChip: ['root', 'outlined'],
|
|
344
|
+
};
|
|
345
|
+
// MUI's sx prop accepts CSS spacing shorthands (`py`, `px`, `pt`, ...) that
|
|
346
|
+
// styleOverrides' plain CSS-in-JS objects do not -- a baseline `padding`
|
|
347
|
+
// default and a component's own `sx={{ py: 1 }}` collide on the vertical
|
|
348
|
+
// axis even though the two key strings never match literally. Each key is
|
|
349
|
+
// expanded to the canonical longhand properties it can affect so the
|
|
350
|
+
// disjointness check compares axes, not raw key spellings; a property
|
|
351
|
+
// outside this table expands to itself.
|
|
352
|
+
const SPACING_SHORTHAND_LONGHANDS = {
|
|
353
|
+
p: ['paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft'],
|
|
354
|
+
padding: ['paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft'],
|
|
355
|
+
px: ['paddingLeft', 'paddingRight'],
|
|
356
|
+
py: ['paddingTop', 'paddingBottom'],
|
|
357
|
+
pt: ['paddingTop'],
|
|
358
|
+
pr: ['paddingRight'],
|
|
359
|
+
pb: ['paddingBottom'],
|
|
360
|
+
pl: ['paddingLeft'],
|
|
361
|
+
m: ['marginTop', 'marginRight', 'marginBottom', 'marginLeft'],
|
|
362
|
+
margin: ['marginTop', 'marginRight', 'marginBottom', 'marginLeft'],
|
|
363
|
+
mx: ['marginLeft', 'marginRight'],
|
|
364
|
+
my: ['marginTop', 'marginBottom'],
|
|
365
|
+
mt: ['marginTop'],
|
|
366
|
+
mr: ['marginRight'],
|
|
367
|
+
mb: ['marginBottom'],
|
|
368
|
+
ml: ['marginLeft'],
|
|
369
|
+
};
|
|
370
|
+
function expandShorthandProperty(property) {
|
|
371
|
+
return SPACING_SHORTHAND_LONGHANDS[property] || [property];
|
|
372
|
+
}
|
|
373
|
+
function styleOverrideKeys(componentConfig, slots = ['root']) {
|
|
374
|
+
var _a;
|
|
375
|
+
const keys = new Set();
|
|
376
|
+
for (const slot of slots) {
|
|
377
|
+
const slotStyles = (_a = componentConfig === null || componentConfig === void 0 ? void 0 : componentConfig.styleOverrides) === null || _a === void 0 ? void 0 : _a[slot];
|
|
378
|
+
if (!slotStyles || typeof slotStyles !== 'object' || Array.isArray(slotStyles))
|
|
379
|
+
continue;
|
|
380
|
+
Object.keys(slotStyles).forEach((key) => expandShorthandProperty(key).forEach((longhand) => keys.add(longhand)));
|
|
381
|
+
}
|
|
382
|
+
return keys;
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Reports top-level property collisions between registered kit sx objects and
|
|
386
|
+
* the baseline MUI component they target. Spacing shorthands (`py`/`px`/...)
|
|
387
|
+
* are compared by the longhand axis they affect, not by literal key name --
|
|
388
|
+
* see `SPACING_SHORTHAND_LONGHANDS`.
|
|
389
|
+
*
|
|
390
|
+
* This is deliberately a lower bound on shadowing: conditional sx, nested sx,
|
|
391
|
+
* callback results, and nested selector properties are not inspected. A clean
|
|
392
|
+
* result therefore proves only that the registered top-level key sets are
|
|
393
|
+
* disjoint; it is not proof that no component can shadow the baseline.
|
|
394
|
+
*/
|
|
395
|
+
export function assertKitSxDisjoint(theme, { registry = KIT_COMPONENT_SX_REGISTRY, exemptions = [] } = {}) {
|
|
396
|
+
var _a, _b, _c;
|
|
397
|
+
const declaredExemptions = [
|
|
398
|
+
...(((_a = theme === null || theme === void 0 ? void 0 : theme.themeCompleteness) === null || _a === void 0 ? void 0 : _a.exemptions) || []),
|
|
399
|
+
...exemptions,
|
|
400
|
+
];
|
|
401
|
+
const validExemptions = new Set();
|
|
402
|
+
const findings = [];
|
|
403
|
+
for (const exemption of declaredExemptions) {
|
|
404
|
+
if (!(exemption === null || exemption === void 0 ? void 0 : exemption.surface) || !((_b = exemption === null || exemption === void 0 ? void 0 : exemption.reason) === null || _b === void 0 ? void 0 : _b.trim())) {
|
|
405
|
+
findings.push({
|
|
406
|
+
surface: `exemption.${(exemption === null || exemption === void 0 ? void 0 : exemption.surface) || 'unknown'}`,
|
|
407
|
+
reason: 'A completeness exemption must name a surface and include a reason.',
|
|
408
|
+
});
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
411
|
+
validExemptions.add(exemption.surface);
|
|
412
|
+
}
|
|
413
|
+
for (const entry of registry) {
|
|
414
|
+
const baselineKeys = styleOverrideKeys((_c = theme === null || theme === void 0 ? void 0 : theme.components) === null || _c === void 0 ? void 0 : _c[entry.muiComponent], entry.slots || SAME_ROOT_STYLE_OVERRIDE_SLOTS[entry.muiComponent]);
|
|
415
|
+
for (const property of Object.keys(entry.sx || {})) {
|
|
416
|
+
const surface = `${entry.component}.${entry.muiComponent}.${property}`;
|
|
417
|
+
const collides = expandShorthandProperty(property).some((longhand) => baselineKeys.has(longhand));
|
|
418
|
+
if (collides && !validExemptions.has(surface)) {
|
|
419
|
+
findings.push({
|
|
420
|
+
surface,
|
|
421
|
+
reason: `${entry.component} sx shadows ${entry.muiComponent} styleOverrides property "${property}".`,
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
return { findings };
|
|
427
|
+
}
|
|
428
|
+
const BASELINE_STYLED_MUI_COMPONENTS = [
|
|
429
|
+
'Alert',
|
|
430
|
+
'BottomNavigation',
|
|
431
|
+
'BottomNavigationAction',
|
|
432
|
+
'Button',
|
|
433
|
+
'Card',
|
|
434
|
+
'Checkbox',
|
|
435
|
+
'Chip',
|
|
436
|
+
'Container',
|
|
437
|
+
'CssBaseline',
|
|
438
|
+
'Dialog',
|
|
439
|
+
'Divider',
|
|
440
|
+
'Drawer',
|
|
441
|
+
'FilledInput',
|
|
442
|
+
'FormControlLabel',
|
|
443
|
+
'IconButton',
|
|
444
|
+
'Input',
|
|
445
|
+
'Menu',
|
|
446
|
+
'OutlinedInput',
|
|
447
|
+
'Paper',
|
|
448
|
+
'Select',
|
|
449
|
+
'TableCell',
|
|
450
|
+
'TextField',
|
|
451
|
+
'Tooltip',
|
|
452
|
+
];
|
|
453
|
+
function jsxOpeningTag(source, start) {
|
|
454
|
+
let braces = 0;
|
|
455
|
+
let quote = null;
|
|
456
|
+
for (let index = start; index < source.length; index += 1) {
|
|
457
|
+
const character = source[index];
|
|
458
|
+
if (quote) {
|
|
459
|
+
if (character === quote && source[index - 1] !== '\\')
|
|
460
|
+
quote = null;
|
|
461
|
+
continue;
|
|
462
|
+
}
|
|
463
|
+
if (character === '"' || character === "'" || character === '`') {
|
|
464
|
+
quote = character;
|
|
465
|
+
}
|
|
466
|
+
else if (character === '{') {
|
|
467
|
+
braces += 1;
|
|
468
|
+
}
|
|
469
|
+
else if (character === '}') {
|
|
470
|
+
braces = Math.max(0, braces - 1);
|
|
471
|
+
}
|
|
472
|
+
else if (character === '>' && braces === 0) {
|
|
473
|
+
return source.slice(start, index + 1);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
return source.slice(start);
|
|
477
|
+
}
|
|
478
|
+
function topLevelSxValue(tag) {
|
|
479
|
+
var _a;
|
|
480
|
+
let braces = 0;
|
|
481
|
+
let quote = null;
|
|
482
|
+
for (let index = 0; index < tag.length; index += 1) {
|
|
483
|
+
const character = tag[index];
|
|
484
|
+
if (quote) {
|
|
485
|
+
if (character === quote && tag[index - 1] !== '\\')
|
|
486
|
+
quote = null;
|
|
487
|
+
continue;
|
|
488
|
+
}
|
|
489
|
+
if (character === '"' || character === "'" || character === '`') {
|
|
490
|
+
quote = character;
|
|
491
|
+
continue;
|
|
492
|
+
}
|
|
493
|
+
if (braces === 0 && (index === 0 || /\s/.test(tag[index - 1]))) {
|
|
494
|
+
const attribute = (_a = tag.slice(index).match(/^sx\b\s*=\s*/)) === null || _a === void 0 ? void 0 : _a[0];
|
|
495
|
+
if (attribute)
|
|
496
|
+
return tag.slice(index + attribute.length);
|
|
497
|
+
}
|
|
498
|
+
if (character === '{')
|
|
499
|
+
braces += 1;
|
|
500
|
+
if (character === '}')
|
|
501
|
+
braces = Math.max(0, braces - 1);
|
|
502
|
+
}
|
|
503
|
+
return '';
|
|
504
|
+
}
|
|
505
|
+
/**
|
|
506
|
+
* Reports baseline-styled MUI tags that bypass the exported-object convention.
|
|
507
|
+
* Like assertKitSxDisjoint, this is a documented lower bound: conditional,
|
|
508
|
+
* array, callback, and otherwise nested sx expressions are not inspected.
|
|
509
|
+
*/
|
|
510
|
+
export function reportKitSxBypasses(sources = [], { registry } = {}) {
|
|
511
|
+
var _a, _b;
|
|
512
|
+
const normalized = sources.map((entry, index) => typeof entry === 'string'
|
|
513
|
+
? { path: `source-${index + 1}`, source: entry }
|
|
514
|
+
: { path: entry.path || `source-${index + 1}`, source: entry.source || '' });
|
|
515
|
+
const findings = [];
|
|
516
|
+
const registeredTargets = registry
|
|
517
|
+
? registry.reduce((targets, { exportName, muiComponent }) => {
|
|
518
|
+
if (!exportName || !muiComponent)
|
|
519
|
+
return targets;
|
|
520
|
+
if (!targets.has(exportName))
|
|
521
|
+
targets.set(exportName, new Set());
|
|
522
|
+
targets.get(exportName).add(muiComponent);
|
|
523
|
+
return targets;
|
|
524
|
+
}, new Map())
|
|
525
|
+
: null;
|
|
526
|
+
const componentPattern = BASELINE_STYLED_MUI_COMPONENTS.join('|');
|
|
527
|
+
const tagPattern = new RegExp(`<(${componentPattern})\\b`, 'g');
|
|
528
|
+
for (const { path, source } of normalized) {
|
|
529
|
+
const exportedObjects = new Set([...source.matchAll(/\bexport\s+const\s+([A-Za-z_$][\w$]*)\s*=\s*\{/g)]
|
|
530
|
+
.map((match) => match[1]));
|
|
531
|
+
for (const match of source.matchAll(tagPattern)) {
|
|
532
|
+
const tag = jsxOpeningTag(source, match.index);
|
|
533
|
+
const sxValue = topLevelSxValue(tag);
|
|
534
|
+
const inline = /^\{\s*\{/.test(sxValue);
|
|
535
|
+
const identifier = (_a = sxValue.match(/^\{\s*([A-Za-z_$][\w$]*)\s*\}/)) === null || _a === void 0 ? void 0 : _a[1];
|
|
536
|
+
const exported = identifier && exportedObjects.has(identifier);
|
|
537
|
+
const muiComponent = `Mui${match[1]}`;
|
|
538
|
+
const unregistered = exported
|
|
539
|
+
&& registeredTargets
|
|
540
|
+
&& !((_b = registeredTargets.get(identifier)) === null || _b === void 0 ? void 0 : _b.has(muiComponent));
|
|
541
|
+
if (!inline && (!identifier || (exported && !unregistered)))
|
|
542
|
+
continue;
|
|
543
|
+
const line = source.slice(0, match.index).split(/\r?\n/).length;
|
|
544
|
+
findings.push({
|
|
545
|
+
surface: `${path}:${line}.Mui${match[1]}.sx`,
|
|
546
|
+
reason: inline
|
|
547
|
+
? `${match[1]} uses an inline sx object instead of a top-level exported object.`
|
|
548
|
+
: unregistered
|
|
549
|
+
? `${match[1]} uses exported sx object "${identifier}" without a ${muiComponent} registry entry.`
|
|
550
|
+
: `${match[1]} uses non-exported sx object "${identifier}".`,
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
return { findings };
|
|
555
|
+
}
|
|
338
556
|
/** Reports adoption signals as numbers; it never changes completeness. */
|
|
339
557
|
export function reportThemeAdoption(sources = []) {
|
|
340
558
|
const normalized = sources.map((entry, index) => typeof entry === 'string'
|
package/dist/theme/tokens.js
CHANGED
package/package.json
CHANGED
package/src/auth/ReauthModal.jsx
CHANGED
|
@@ -13,6 +13,9 @@ import apiClient from './apiClient';
|
|
|
13
13
|
import { HEADLESS_BASE } from './authConfig';
|
|
14
14
|
import { rejectReauth, resolveReauth, subscribe } from './reauth';
|
|
15
15
|
|
|
16
|
+
export const REAUTH_MODAL_ALERT_SX = { mb: 2 };
|
|
17
|
+
export const REAUTH_MODAL_TEXT_FIELD_SX = { mt: 1 };
|
|
18
|
+
|
|
16
19
|
export function ReauthModal() {
|
|
17
20
|
const { t } = useTranslation();
|
|
18
21
|
const [open, setOpen] = useState(false);
|
|
@@ -53,7 +56,7 @@ export function ReauthModal() {
|
|
|
53
56
|
<form onSubmit={handleSubmit}>
|
|
54
57
|
<DialogTitle>{t('Auth.REAUTH_TITLE')}</DialogTitle>
|
|
55
58
|
<DialogContent>
|
|
56
|
-
{error && <Alert severity="error" sx={
|
|
59
|
+
{error && <Alert severity="error" sx={REAUTH_MODAL_ALERT_SX}>{error}</Alert>}
|
|
57
60
|
<TextField
|
|
58
61
|
autoFocus
|
|
59
62
|
fullWidth
|
|
@@ -62,7 +65,7 @@ export function ReauthModal() {
|
|
|
62
65
|
value={password}
|
|
63
66
|
onChange={(e) => setPassword(e.target.value)}
|
|
64
67
|
disabled={loading}
|
|
65
|
-
sx={
|
|
68
|
+
sx={REAUTH_MODAL_TEXT_FIELD_SX}
|
|
66
69
|
/>
|
|
67
70
|
</DialogContent>
|
|
68
71
|
<DialogActions>
|
|
@@ -21,15 +21,22 @@ import {
|
|
|
21
21
|
deleteAccessCode,
|
|
22
22
|
} from '../auth/authApi';
|
|
23
23
|
|
|
24
|
+
export const ACCESS_CODE_ACTION_SX = {
|
|
25
|
+
minWidth: 120,
|
|
26
|
+
height: 40,
|
|
27
|
+
whiteSpace: 'nowrap',
|
|
28
|
+
};
|
|
29
|
+
export const ACCESS_CODE_PRIMARY_ACTION_SX = { ...ACCESS_CODE_ACTION_SX, mt: 1 };
|
|
30
|
+
export const ACCESS_CODE_ALERT_SX = { mb: 2 };
|
|
31
|
+
export const ACCESS_CODE_VALUE_FIELD_SX = {
|
|
32
|
+
'& .MuiInputBase-input': {
|
|
33
|
+
fontFamily: 'monospace',
|
|
34
|
+
letterSpacing: '0.04em',
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
|
|
24
38
|
export function AccessCodeManager() {
|
|
25
39
|
const { t } = useTranslation();
|
|
26
|
-
const actionButtonSx = {
|
|
27
|
-
minWidth: 120,
|
|
28
|
-
height: 40,
|
|
29
|
-
textTransform: 'none',
|
|
30
|
-
whiteSpace: 'nowrap',
|
|
31
|
-
};
|
|
32
|
-
|
|
33
40
|
const [codes, setCodes] = useState([]);
|
|
34
41
|
const [loading, setLoading] = useState(true);
|
|
35
42
|
const [submitting, setSubmitting] = useState(false);
|
|
@@ -142,17 +149,17 @@ export function AccessCodeManager() {
|
|
|
142
149
|
return (
|
|
143
150
|
<Box>
|
|
144
151
|
{errorKey && (
|
|
145
|
-
<Alert severity="error" sx={
|
|
152
|
+
<Alert severity="error" sx={ACCESS_CODE_ALERT_SX}>
|
|
146
153
|
{t(errorKey)}
|
|
147
154
|
</Alert>
|
|
148
155
|
)}
|
|
149
156
|
{successKey && (
|
|
150
|
-
<Alert severity="success" sx={
|
|
157
|
+
<Alert severity="success" sx={ACCESS_CODE_ALERT_SX}>
|
|
151
158
|
{t(successKey)}
|
|
152
159
|
</Alert>
|
|
153
160
|
)}
|
|
154
161
|
{copyNotice && (
|
|
155
|
-
<Alert severity="info" sx={
|
|
162
|
+
<Alert severity="info" sx={ACCESS_CODE_ALERT_SX}>
|
|
156
163
|
{copyNotice}
|
|
157
164
|
</Alert>
|
|
158
165
|
)}
|
|
@@ -190,19 +197,14 @@ export function AccessCodeManager() {
|
|
|
190
197
|
onFocus: (event) => event.target.select(),
|
|
191
198
|
},
|
|
192
199
|
}}
|
|
193
|
-
sx={
|
|
194
|
-
'& .MuiInputBase-input': {
|
|
195
|
-
fontFamily: 'monospace',
|
|
196
|
-
letterSpacing: '0.04em',
|
|
197
|
-
},
|
|
198
|
-
}}
|
|
200
|
+
sx={ACCESS_CODE_VALUE_FIELD_SX}
|
|
199
201
|
/>
|
|
200
202
|
<Button
|
|
201
203
|
variant="outlined"
|
|
202
204
|
size="small"
|
|
203
205
|
onClick={() => handleCopyCode(code.code)}
|
|
204
206
|
startIcon={<ContentCopyIcon fontSize="small" />}
|
|
205
|
-
sx={
|
|
207
|
+
sx={ACCESS_CODE_ACTION_SX}
|
|
206
208
|
>
|
|
207
209
|
{t('Auth.ACCESS_CODE_COPY_BUTTON', t('Auth.MFA_RECOVERY_COPY_TOOLTIP', 'Kopieren'))}
|
|
208
210
|
</Button>
|
|
@@ -212,7 +214,7 @@ export function AccessCodeManager() {
|
|
|
212
214
|
size="small"
|
|
213
215
|
onClick={() => handleDelete(code.id)}
|
|
214
216
|
startIcon={<DeleteIcon fontSize="small" />}
|
|
215
|
-
sx={
|
|
217
|
+
sx={ACCESS_CODE_ACTION_SX}
|
|
216
218
|
>
|
|
217
219
|
{t('Common.DELETE', 'Löschen')}
|
|
218
220
|
</Button>
|
|
@@ -246,7 +248,7 @@ export function AccessCodeManager() {
|
|
|
246
248
|
<Button
|
|
247
249
|
variant="contained"
|
|
248
250
|
size="small"
|
|
249
|
-
sx={
|
|
251
|
+
sx={ACCESS_CODE_PRIMARY_ACTION_SX}
|
|
250
252
|
onClick={handleGenerateClick}
|
|
251
253
|
disabled={submitting}
|
|
252
254
|
>
|
|
@@ -275,7 +277,7 @@ export function AccessCodeManager() {
|
|
|
275
277
|
size="small"
|
|
276
278
|
onClick={handleAddManual}
|
|
277
279
|
disabled={submitting}
|
|
278
|
-
sx={
|
|
280
|
+
sx={ACCESS_CODE_ACTION_SX}
|
|
279
281
|
>
|
|
280
282
|
{t('Auth.ACCESS_CODE_ADD_BUTTON')}
|
|
281
283
|
</Button>
|
|
@@ -9,6 +9,8 @@ import {
|
|
|
9
9
|
import { useTranslation } from 'react-i18next';
|
|
10
10
|
import { fetchAuthPolicy, updateAuthPolicy } from '../auth/authApi';
|
|
11
11
|
|
|
12
|
+
export const ACCESS_CODE_SINGLE_USE_ALERT_SX = { mb: 2 };
|
|
13
|
+
|
|
12
14
|
export function AccessCodeSingleUseToggle({ canEdit = true, policy = null, onPolicyChange = null }) {
|
|
13
15
|
const { t } = useTranslation();
|
|
14
16
|
const [value, setValue] = useState(false);
|
|
@@ -72,8 +74,8 @@ export function AccessCodeSingleUseToggle({ canEdit = true, policy = null, onPol
|
|
|
72
74
|
'When enabled, each access code can be redeemed only once. Recommended.',
|
|
73
75
|
)}
|
|
74
76
|
</Typography>
|
|
75
|
-
{error && <Alert severity="error" sx={
|
|
76
|
-
{success && <Alert severity="success" sx={
|
|
77
|
+
{error && <Alert severity="error" sx={ACCESS_CODE_SINGLE_USE_ALERT_SX}>{error}</Alert>}
|
|
78
|
+
{success && <Alert severity="success" sx={ACCESS_CODE_SINGLE_USE_ALERT_SX}>{success}</Alert>}
|
|
77
79
|
<FormControlLabel
|
|
78
80
|
control={
|
|
79
81
|
<Switch
|