From e417105f7a159e62b06537fd465571c7243840cc Mon Sep 17 00:00:00 2001 From: Younes ENNAJI Date: Sun, 1 Mar 2026 21:34:50 +0000 Subject: [PATCH] refactor(themes): create shared utilities and design tokens MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This refactoring improves code quality and reduces duplication: ## New Files - `themes/shared/icons.ts` - Centralized SVG icons (getIcon, getCloseIcon) - `themes/shared/accessibility.ts` - A11y helpers (getA11yString, getCloseButtonA11y) - `themes/shared/constants.ts` - Standard class names and default titles ## Design Tokens Added (index.scss) - Spacing scale: --fl-spacing-xs through --fl-spacing-2xl - Typography scale: --fl-font-size-xs through --fl-font-size-xl - Close button sizes: --fl-close-sm, --fl-close-md, --fl-close-lg - Border radius: --fl-radius-sm through --fl-radius-full - Shadow tokens: --fl-shadow-sm through --fl-shadow-lg - Animation: --fl-duration-*, --fl-easing-*, --fl-slide-* ## Mixins Updated - Added `close-button-sized($size)` with sm/md/lg support - Added `close-button-circular($size)` variant - Added `close-button-text` for text-style buttons - Updated existing mixins to use design tokens ## All 17 Themes Refactored Each theme now uses shared utilities instead of duplicating code: - Icon code: 20+ lines → 1 function call - Accessibility: 3 lines → 1 function call - Class names: via CLASS_NAMES constants Backwards compatible - no breaking changes. --- .../Resources/assets/themes/amazon/amazon.ts | 58 +++----- .../Resources/assets/themes/amber/amber.ts | 22 ++- .../Resources/assets/themes/aurora/aurora.ts | 18 ++- .../assets/themes/crystal/crystal.ts | 20 ++- .../assets/themes/emerald/emerald.ts | 14 +- .../assets/themes/facebook/facebook.ts | 31 +++-- .../assets/themes/flasher/flasher.ts | 24 ++-- .../Resources/assets/themes/google/google.ts | 53 ++------ src/Prime/Resources/assets/themes/index.scss | 47 ++++++- src/Prime/Resources/assets/themes/ios/ios.ts | 55 +++----- .../Resources/assets/themes/jade/jade.ts | 18 ++- .../assets/themes/material/material.ts | 24 ++-- .../assets/themes/minimal/minimal.ts | 18 ++- src/Prime/Resources/assets/themes/mixins.scss | 106 ++++++++++++++- .../Resources/assets/themes/neon/neon.ts | 18 ++- .../Resources/assets/themes/onyx/onyx.ts | 20 ++- .../Resources/assets/themes/ruby/ruby.ts | 22 ++- .../assets/themes/sapphire/sapphire.ts | 16 +-- .../assets/themes/shared/accessibility.ts | 25 ++++ .../assets/themes/shared/constants.ts | 45 +++++++ .../Resources/assets/themes/shared/icons.ts | 51 +++++++ .../Resources/assets/themes/shared/index.ts | 13 ++ .../Resources/assets/themes/slack/slack.ts | 40 +++--- src/Prime/Resources/dist/flasher.esm.js | 69 ++++++++-- src/Prime/Resources/dist/flasher.js | 69 ++++++++-- src/Prime/Resources/dist/flasher.min.css | 4 +- src/Prime/Resources/dist/flasher.min.js | 2 +- .../dist/themes/amazon/amazon.esm.js | 126 ++++++++++++------ .../Resources/dist/themes/amazon/amazon.js | 126 ++++++++++++------ .../dist/themes/amazon/amazon.min.js | 2 +- .../Resources/dist/themes/amber/amber.esm.js | 55 ++++++-- .../Resources/dist/themes/amber/amber.js | 55 ++++++-- .../Resources/dist/themes/amber/amber.min.js | 2 +- .../dist/themes/aurora/aurora.esm.js | 51 +++++-- .../Resources/dist/themes/aurora/aurora.js | 51 +++++-- .../dist/themes/aurora/aurora.min.js | 2 +- .../dist/themes/crystal/crystal.esm.js | 53 ++++++-- .../Resources/dist/themes/crystal/crystal.js | 53 ++++++-- .../dist/themes/crystal/crystal.min.js | 2 +- .../dist/themes/emerald/emerald.esm.js | 47 ++++++- .../Resources/dist/themes/emerald/emerald.js | 47 ++++++- .../dist/themes/emerald/emerald.min.js | 2 +- .../dist/themes/facebook/facebook.esm.js | 84 ++++++++++-- .../dist/themes/facebook/facebook.js | 84 ++++++++++-- .../dist/themes/facebook/facebook.min.js | 2 +- .../dist/themes/flasher/flasher.esm.js | 69 ++++++++-- .../Resources/dist/themes/flasher/flasher.js | 69 ++++++++-- .../dist/themes/flasher/flasher.min.css | 2 +- .../dist/themes/flasher/flasher.min.js | 2 +- .../dist/themes/google/google.esm.js | 114 +++++++++++----- .../Resources/dist/themes/google/google.js | 114 +++++++++++----- .../dist/themes/google/google.min.js | 2 +- .../Resources/dist/themes/ios/ios.esm.js | 111 ++++++++++----- src/Prime/Resources/dist/themes/ios/ios.js | 111 ++++++++++----- .../Resources/dist/themes/ios/ios.min.js | 2 +- .../Resources/dist/themes/jade/jade.esm.js | 51 +++++-- src/Prime/Resources/dist/themes/jade/jade.js | 51 +++++-- .../Resources/dist/themes/jade/jade.min.js | 2 +- .../dist/themes/material/material.esm.js | 58 ++++++-- .../dist/themes/material/material.js | 58 ++++++-- .../dist/themes/material/material.min.js | 2 +- .../dist/themes/minimal/minimal.esm.js | 51 +++++-- .../Resources/dist/themes/minimal/minimal.js | 51 +++++-- .../dist/themes/minimal/minimal.min.js | 2 +- .../Resources/dist/themes/neon/neon.esm.js | 51 +++++-- src/Prime/Resources/dist/themes/neon/neon.js | 51 +++++-- .../Resources/dist/themes/neon/neon.min.js | 2 +- .../Resources/dist/themes/onyx/onyx.esm.js | 53 ++++++-- src/Prime/Resources/dist/themes/onyx/onyx.js | 53 ++++++-- .../Resources/dist/themes/onyx/onyx.min.js | 2 +- .../Resources/dist/themes/ruby/ruby.esm.js | 55 ++++++-- src/Prime/Resources/dist/themes/ruby/ruby.js | 55 ++++++-- .../Resources/dist/themes/ruby/ruby.min.js | 2 +- .../dist/themes/sapphire/sapphire.esm.js | 46 +++++-- .../dist/themes/sapphire/sapphire.js | 46 +++++-- .../dist/themes/sapphire/sapphire.min.js | 2 +- .../dist/themes/shared/accessibility.d.ts | 9 ++ .../dist/themes/shared/constants.d.ts | 26 ++++ .../Resources/dist/themes/shared/icons.d.ts | 9 ++ .../Resources/dist/themes/shared/index.d.ts | 5 + .../dist/themes/shared/shared.esm.js | 90 +++++++++++++ .../Resources/dist/themes/shared/shared.js | 108 +++++++++++++++ .../dist/themes/shared/shared.min.js | 1 + .../Resources/dist/themes/slack/slack.esm.js | 94 +++++++++---- .../Resources/dist/themes/slack/slack.js | 94 +++++++++---- .../Resources/dist/themes/slack/slack.min.js | 2 +- src/Prime/Resources/public/flasher.min.css | 4 +- src/Prime/Resources/public/flasher.min.js | 2 +- .../public/themes/amazon/amazon.min.js | 2 +- .../public/themes/amber/amber.min.js | 2 +- .../public/themes/aurora/aurora.min.js | 2 +- .../public/themes/crystal/crystal.min.js | 2 +- .../public/themes/emerald/emerald.min.js | 2 +- .../public/themes/facebook/facebook.min.js | 2 +- .../public/themes/flasher/flasher.min.css | 2 +- .../public/themes/flasher/flasher.min.js | 2 +- .../public/themes/google/google.min.js | 2 +- .../Resources/public/themes/ios/ios.min.js | 2 +- .../Resources/public/themes/jade/jade.min.js | 2 +- .../public/themes/material/material.min.js | 2 +- .../public/themes/minimal/minimal.min.js | 2 +- .../Resources/public/themes/neon/neon.min.js | 2 +- .../Resources/public/themes/onyx/onyx.min.js | 2 +- .../Resources/public/themes/ruby/ruby.min.js | 2 +- .../public/themes/sapphire/sapphire.min.js | 2 +- .../public/themes/shared/shared.min.js | 1 + .../public/themes/slack/slack.min.js | 2 +- 107 files changed, 2678 insertions(+), 889 deletions(-) create mode 100644 src/Prime/Resources/assets/themes/shared/accessibility.ts create mode 100644 src/Prime/Resources/assets/themes/shared/constants.ts create mode 100644 src/Prime/Resources/assets/themes/shared/icons.ts create mode 100644 src/Prime/Resources/assets/themes/shared/index.ts create mode 100644 src/Prime/Resources/dist/themes/shared/accessibility.d.ts create mode 100644 src/Prime/Resources/dist/themes/shared/constants.d.ts create mode 100644 src/Prime/Resources/dist/themes/shared/icons.d.ts create mode 100644 src/Prime/Resources/dist/themes/shared/index.d.ts create mode 100644 src/Prime/Resources/dist/themes/shared/shared.esm.js create mode 100644 src/Prime/Resources/dist/themes/shared/shared.js create mode 100644 src/Prime/Resources/dist/themes/shared/shared.min.js create mode 100644 src/Prime/Resources/public/themes/shared/shared.min.js diff --git a/src/Prime/Resources/assets/themes/amazon/amazon.ts b/src/Prime/Resources/assets/themes/amazon/amazon.ts index af7179a7..c98aedfa 100644 --- a/src/Prime/Resources/assets/themes/amazon/amazon.ts +++ b/src/Prime/Resources/assets/themes/amazon/amazon.ts @@ -1,63 +1,37 @@ import './amazon.scss' import type { Envelope } from '../../types' +import { getTypeIcon, getCloseIcon } from '../shared/icons' +import { getA11yString, getCloseButtonA11y } from '../shared/accessibility' +import { CLASS_NAMES, DEFAULT_TITLES } from '../shared/constants' + +const AMAZON_TITLES: Record = { + success: 'Success!', + error: 'Problem', + warning: 'Warning', + info: 'Information', +} export const amazonTheme = { render: (envelope: Envelope): string => { const { type, message } = envelope - const isAlert = type === 'error' || type === 'warning' - const role = isAlert ? 'alert' : 'status' - const ariaLive = isAlert ? 'assertive' : 'polite' - - const getAlertIcon = () => { - switch (type) { - case 'success': - return ` - - ` - case 'error': - return ` - - ` - case 'warning': - return ` - - ` - case 'info': - return ` - - ` - } - return '' - } - - const getAlertTitle = () => { - switch (type) { - case 'success': return 'Success!' - case 'error': return 'Problem' - case 'warning': return 'Warning' - case 'info': return 'Information' - default: return 'Alert' - } - } + const alertTitle = AMAZON_TITLES[type] || DEFAULT_TITLES[type] || 'Alert' return ` -
+
- ${getAlertIcon()} + ${getTypeIcon(type, { size: 'lg' })}
-
${getAlertTitle()}
+
${alertTitle}
${message}
-
diff --git a/src/Prime/Resources/assets/themes/amber/amber.ts b/src/Prime/Resources/assets/themes/amber/amber.ts index 05f54a23..f2bad839 100644 --- a/src/Prime/Resources/assets/themes/amber/amber.ts +++ b/src/Prime/Resources/assets/themes/amber/amber.ts @@ -1,25 +1,23 @@ import './amber.scss' import type { Envelope } from '../../types' +import { getA11yString, getCloseButtonA11y } from '../shared/accessibility' +import { CLASS_NAMES } from '../shared/constants' export const amberTheme = { render: (envelope: Envelope): string => { const { type, message } = envelope - const isAlert = type === 'error' || type === 'warning' - const role = isAlert ? 'alert' : 'status' - const ariaLive = isAlert ? 'assertive' : 'polite' - return ` -
-
-
-
-
${message}
+
+
+
+
+
${message}
- +
-
-
+
+
` }, diff --git a/src/Prime/Resources/assets/themes/aurora/aurora.ts b/src/Prime/Resources/assets/themes/aurora/aurora.ts index 3b498e09..e69965b1 100644 --- a/src/Prime/Resources/assets/themes/aurora/aurora.ts +++ b/src/Prime/Resources/assets/themes/aurora/aurora.ts @@ -1,22 +1,20 @@ import './aurora.scss' import type { Envelope } from '../../types' +import { getA11yString, getCloseButtonA11y } from '../shared/accessibility' +import { CLASS_NAMES } from '../shared/constants' export const auroraTheme = { render: (envelope: Envelope): string => { const { type, message } = envelope - const isAlert = type === 'error' || type === 'warning' - const role = isAlert ? 'alert' : 'status' - const ariaLive = isAlert ? 'assertive' : 'polite' - return ` -
-
-
${message}
- +
+
+
${message}
+
-
-
+
+
` }, diff --git a/src/Prime/Resources/assets/themes/crystal/crystal.ts b/src/Prime/Resources/assets/themes/crystal/crystal.ts index 81b8879f..d244de45 100644 --- a/src/Prime/Resources/assets/themes/crystal/crystal.ts +++ b/src/Prime/Resources/assets/themes/crystal/crystal.ts @@ -1,24 +1,22 @@ import './crystal.scss' import type { Envelope } from '../../types' +import { getA11yString, getCloseButtonA11y } from '../shared/accessibility' +import { CLASS_NAMES } from '../shared/constants' export const crystalTheme = { render: (envelope: Envelope): string => { const { type, message } = envelope - const isAlert = type === 'error' || type === 'warning' - const role = isAlert ? 'alert' : 'status' - const ariaLive = isAlert ? 'assertive' : 'polite' - return ` -
-
-
-

${message}

+
+
+
+

${message}

- +
-
-
+
+
` }, diff --git a/src/Prime/Resources/assets/themes/emerald/emerald.ts b/src/Prime/Resources/assets/themes/emerald/emerald.ts index 87156d65..fccd8be7 100644 --- a/src/Prime/Resources/assets/themes/emerald/emerald.ts +++ b/src/Prime/Resources/assets/themes/emerald/emerald.ts @@ -1,19 +1,17 @@ import './emerald.scss' import type { Envelope } from '../../types' +import { getA11yString, getCloseButtonA11y } from '../shared/accessibility' +import { CLASS_NAMES } from '../shared/constants' export const emeraldTheme = { render: (envelope: Envelope): string => { const { type, message } = envelope - const isAlert = type === 'error' || type === 'warning' - const role = isAlert ? 'alert' : 'status' - const ariaLive = isAlert ? 'assertive' : 'polite' - return ` -
-
-
${message}
- +
+
+
${message}
+
` }, diff --git a/src/Prime/Resources/assets/themes/facebook/facebook.ts b/src/Prime/Resources/assets/themes/facebook/facebook.ts index b23630f7..060e5919 100644 --- a/src/Prime/Resources/assets/themes/facebook/facebook.ts +++ b/src/Prime/Resources/assets/themes/facebook/facebook.ts @@ -1,17 +1,18 @@ import './facebook.scss' import type { Envelope } from '../../types' +import { getCloseIcon } from '../shared/icons' +import { getA11yString, getCloseButtonA11y } from '../shared/accessibility' +import { CLASS_NAMES } from '../shared/constants' + +function getTimeString(): string { + const now = new Date() + return now.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' }) +} export const facebookTheme = { render: (envelope: Envelope): string => { const { type, message } = envelope - const isAlert = type === 'error' || type === 'warning' - const role = isAlert ? 'alert' : 'status' - const ariaLive = isAlert ? 'assertive' : 'polite' - - const now = new Date() - const timeString = now.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' }) - const getNotificationIcon = () => { switch (type) { case 'success': @@ -43,25 +44,23 @@ export const facebookTheme = { } return ` -