@emulsify/core 2.7.1 → 3.0.1
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/.github/workflows/semantic-release.yml +3 -3
- package/.nvmrc +1 -1
- package/.storybook/_drupal.js +22 -0
- package/.storybook/emulsifyTheme.js +1 -2
- package/.storybook/main.js +116 -31
- package/.storybook/manager.js +40 -9
- package/.storybook/preview.js +71 -19
- package/.storybook/utils.js +29 -19
- package/.storybook/webpack.config.js +95 -26
- package/commitlint.config.js +4 -2
- package/config/babel.config.js +1 -2
- package/config/eslint.config.js +74 -0
- package/config/postcss.config.js +2 -2
- package/config/webpack/loaders.js +21 -12
- package/config/webpack/optimizers.js +2 -2
- package/config/webpack/plugins.js +37 -33
- package/config/webpack/resolves.js +42 -35
- package/config/webpack/sdc-loader.js +10 -2
- package/config/webpack/webpack.common.js +103 -95
- package/config/webpack/webpack.dev.js +3 -3
- package/config/webpack/webpack.prod.js +3 -3
- package/package.json +45 -36
- package/release.config.cjs +30 -0
- package/.eslintignore +0 -2
- package/config/eslintrc.config.json +0 -76
- package/config/webpack/svgSprite.js +0 -5
- package/release.config.js +0 -11
|
@@ -8,13 +8,13 @@ jobs:
|
|
|
8
8
|
runs-on: ubuntu-latest
|
|
9
9
|
steps:
|
|
10
10
|
- name: Checkout
|
|
11
|
-
uses: actions/checkout@
|
|
11
|
+
uses: actions/checkout@v4
|
|
12
12
|
with:
|
|
13
13
|
fetch-depth: 0
|
|
14
14
|
- name: Install Node.js
|
|
15
|
-
uses: actions/setup-node@
|
|
15
|
+
uses: actions/setup-node@v4
|
|
16
16
|
with:
|
|
17
|
-
node-version:
|
|
17
|
+
node-version: "24.x"
|
|
18
18
|
- name: Install
|
|
19
19
|
run: npm install
|
|
20
20
|
- name: Release
|
package/.nvmrc
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
24
|
package/.storybook/_drupal.js
CHANGED
|
@@ -1,19 +1,41 @@
|
|
|
1
1
|
// Simple Drupal.behaviors usage for Storybook
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Global Drupal namespace stub for Storybook environment.
|
|
5
|
+
* @namespace Drupal
|
|
6
|
+
*/
|
|
3
7
|
window.Drupal = { behaviors: {} };
|
|
4
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Immediately-Invoked Function Expression to scope Drupal behavior attachment logic.
|
|
11
|
+
* @param {Object} Drupal - The Drupal global namespace object.
|
|
12
|
+
* @param {Object} drupalSettings - Global Drupal settings object stub.
|
|
13
|
+
*/
|
|
5
14
|
(function (Drupal, drupalSettings) {
|
|
15
|
+
/**
|
|
16
|
+
* Throws an error asynchronously to avoid interrupting execution flow.
|
|
17
|
+
* @param {Error} error - The error object to throw.
|
|
18
|
+
* @returns {void}
|
|
19
|
+
*/
|
|
6
20
|
Drupal.throwError = function (error) {
|
|
7
21
|
setTimeout(function () {
|
|
8
22
|
throw error;
|
|
9
23
|
}, 0);
|
|
10
24
|
};
|
|
11
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Attaches all registered Drupal behaviors.
|
|
28
|
+
* @param {HTMLElement|Document} [context=document] - DOM context to attach behaviors to.
|
|
29
|
+
* @param {Object} [settings=drupalSettings] - Drupal settings to pass to behaviors.
|
|
30
|
+
* @returns {void}
|
|
31
|
+
*/
|
|
12
32
|
Drupal.attachBehaviors = function (context, settings) {
|
|
13
33
|
context = context || document;
|
|
14
34
|
settings = settings || drupalSettings;
|
|
35
|
+
/** @type {Object.<string, {attach: Function}>} */
|
|
15
36
|
const behaviors = Drupal.behaviors;
|
|
16
37
|
|
|
38
|
+
// Iterate through each behavior and invoke its attach method if defined.
|
|
17
39
|
Object.keys(behaviors).forEach(function (i) {
|
|
18
40
|
if (typeof behaviors[i].attach === 'function') {
|
|
19
41
|
try {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
// Documentation on theming Storybook: https://storybook.js.org/docs/configurations/theming/
|
|
2
|
-
|
|
3
2
|
import { create } from '@storybook/theming';
|
|
4
3
|
|
|
5
4
|
export default create({
|
|
@@ -34,5 +33,5 @@ export default create({
|
|
|
34
33
|
brandTitle: 'Emulsify',
|
|
35
34
|
brandUrl: 'https://emulsify.info',
|
|
36
35
|
brandImage:
|
|
37
|
-
'https://raw.githubusercontent.com/fourkitchens/emulsify-core/main/assets/images/emulsify-logo-sb.svg
|
|
36
|
+
'https://raw.githubusercontent.com/fourkitchens/emulsify-core/main/assets/images/emulsify-logo-sb.svg',
|
|
38
37
|
});
|
package/.storybook/main.js
CHANGED
|
@@ -1,36 +1,107 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
// .storybook/main.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Storybook main configuration file.
|
|
5
|
+
* This configures stories, static directories, addons, core builder,
|
|
6
|
+
* framework, documentation settings, manager head styles, and overrides.
|
|
7
|
+
* @module .storybook/main
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { resolve } from 'path';
|
|
11
|
+
import fs from 'fs';
|
|
12
|
+
import path from 'path';
|
|
13
|
+
import { fileURLToPath } from 'url';
|
|
14
|
+
import configOverrides from '../../../../config/emulsify-core/storybook/main.js';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The full path to the current file (ESM compatible).
|
|
18
|
+
* @type {string}
|
|
19
|
+
*/
|
|
20
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The directory name of the current module file.
|
|
24
|
+
* @type {string}
|
|
25
|
+
*/
|
|
26
|
+
const __dirname = path.dirname(__filename);
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Safely apply any user-provided overrides or fall back to an empty object.
|
|
30
|
+
* @type {object}
|
|
31
|
+
*/
|
|
3
32
|
const safeConfigOverrides = configOverrides || {};
|
|
4
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Primary Storybook configuration object.
|
|
36
|
+
* @type {import('@storybook/core-common').StorybookConfig}
|
|
37
|
+
*/
|
|
5
38
|
const config = {
|
|
39
|
+
/**
|
|
40
|
+
* Patterns for locating story files under src or components directories.
|
|
41
|
+
* @type {string[]}
|
|
42
|
+
*/
|
|
6
43
|
stories: [
|
|
7
44
|
'../../../../(src|components)/**/*.stories.@(js|jsx|ts|tsx)',
|
|
8
45
|
],
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Directories to serve as static assets in the Storybook build.
|
|
49
|
+
* @type {string[]}
|
|
50
|
+
*/
|
|
9
51
|
staticDirs: [
|
|
10
52
|
'../../../../assets/images',
|
|
11
53
|
'../../../../assets/icons',
|
|
12
54
|
'../../../../dist',
|
|
13
55
|
],
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* List of Storybook addons to enable various features.
|
|
59
|
+
* @type {string[]}
|
|
60
|
+
*/
|
|
14
61
|
addons: [
|
|
15
62
|
'../../../@storybook/addon-a11y',
|
|
16
63
|
'../../../@storybook/addon-links',
|
|
17
64
|
'../../../@storybook/addon-essentials',
|
|
18
65
|
'../../../@storybook/addon-themes',
|
|
19
|
-
'../../../@storybook/addon-styling-webpack'
|
|
66
|
+
'../../../@storybook/addon-styling-webpack',
|
|
20
67
|
],
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Core builder configuration for Storybook.
|
|
71
|
+
* @type {{builder: string, disableTelemetry: boolean}}
|
|
72
|
+
*/
|
|
21
73
|
core: {
|
|
22
74
|
builder: 'webpack5',
|
|
75
|
+
disableTelemetry: true,
|
|
23
76
|
},
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Framework specification for Storybook (HTML + Webpack5).
|
|
80
|
+
* @type {{name: string, options: object}}
|
|
81
|
+
*/
|
|
24
82
|
framework: {
|
|
25
83
|
name: '@storybook/html-webpack5',
|
|
26
84
|
options: {},
|
|
27
85
|
},
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Documentation settings for Storybook autodocs.
|
|
89
|
+
* @type {{autodocs: boolean}}
|
|
90
|
+
*/
|
|
28
91
|
docs: {
|
|
29
92
|
autodocs: false,
|
|
30
93
|
},
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Custom styles injected into the Storybook manager (sidebar) head,
|
|
97
|
+
* plus any external manager-head.html snippet.
|
|
98
|
+
* @param {string} head - Existing head HTML.
|
|
99
|
+
* @returns {string} Modified head HTML.
|
|
100
|
+
*/
|
|
101
|
+
managerHead: (head) => {
|
|
102
|
+
// inline theme styles
|
|
103
|
+
const inlineStyles = `
|
|
104
|
+
<style>
|
|
34
105
|
:root {
|
|
35
106
|
--colors-emulsify-blue-100: #e6f5fc;
|
|
36
107
|
--colors-emulsify-blue-200: #CCECFA;
|
|
@@ -44,41 +115,33 @@ const config = {
|
|
|
44
115
|
--colors-emulsify-blue-1000: #00202e;
|
|
45
116
|
--colors-purple: #8B1E7E;
|
|
46
117
|
}
|
|
47
|
-
|
|
48
118
|
.sidebar-container {
|
|
49
119
|
background: url('https://raw.githubusercontent.com/fourkitchens/emulsify-core/main/assets/images/corner-bkg.png?token=GHSAT0AAAAAACIEXLVDMX56QK3ZIZWHWHTEZNYFYIA') no-repeat top left;
|
|
50
120
|
}
|
|
51
|
-
|
|
52
121
|
.sidebar-container .sidebar-subheading {
|
|
53
122
|
color: var(--colors-emulsify-blue-200);
|
|
54
123
|
font-size: 13px;
|
|
55
124
|
letter-spacing: 0.15em;
|
|
56
125
|
}
|
|
57
|
-
|
|
58
126
|
.sidebar-container .sidebar-subheading button:focus {
|
|
59
127
|
color: var(--colors-emulsify-blue-300);
|
|
60
128
|
}
|
|
61
|
-
|
|
62
129
|
/** Triangle icon **/
|
|
63
130
|
.sidebar-container .sidebar-subheading button span {
|
|
64
131
|
color: var(--colors-emulsify-blue-300);
|
|
65
132
|
}
|
|
66
|
-
|
|
67
133
|
.sidebar-container .search-field input {
|
|
68
134
|
border-color: var(--colors-emulsify-blue-700);
|
|
69
135
|
}
|
|
70
|
-
|
|
71
136
|
.sidebar-container .search-field input:active {
|
|
72
137
|
border-color: var(--colors-emulsify-blue-700);
|
|
73
138
|
}
|
|
74
|
-
|
|
75
139
|
.sidebar-container .search-result-recentlyOpened,
|
|
76
140
|
.sidebar-container .search-result-back,
|
|
77
141
|
.sidebar-container .search-result-clearHistory {
|
|
78
142
|
color: var(--colors-emulsify-blue-300) !important;
|
|
79
143
|
letter-spacing: 0.15em;
|
|
80
144
|
}
|
|
81
|
-
|
|
82
145
|
.sidebar-container .search-result-back span,
|
|
83
146
|
.sidebar-container .search-result-back svg,
|
|
84
147
|
.sidebar-container .search-result-clearHistory span,
|
|
@@ -86,74 +149,96 @@ const config = {
|
|
|
86
149
|
letter-spacing: normal;
|
|
87
150
|
color: white;
|
|
88
151
|
}
|
|
89
|
-
|
|
90
152
|
.sidebar-container .sidebar-item svg {
|
|
91
153
|
margin-top: 1px;
|
|
92
154
|
}
|
|
93
|
-
|
|
94
155
|
.sidebar-container .sidebar-item span {
|
|
95
156
|
margin-top: 4px;
|
|
96
157
|
}
|
|
97
|
-
|
|
98
158
|
.sidebar-container .sidebar-subheading-action svg {
|
|
99
159
|
color: var(--colors-emulsify-blue-400);
|
|
100
160
|
}
|
|
101
|
-
|
|
102
161
|
.sidebar-container .sidebar-subheading-action:hover svg {
|
|
103
162
|
color: var(--colors-emulsify-blue-300);
|
|
104
163
|
}
|
|
105
|
-
|
|
106
164
|
.sidebar-header button[title="Shortcuts"] {
|
|
107
165
|
box-shadow: none;
|
|
108
166
|
border: 1px solid var(--colors-emulsify-blue-700);
|
|
109
167
|
}
|
|
110
|
-
|
|
111
168
|
.sidebar-header button[title="Shortcuts"]:active {
|
|
112
169
|
border: 1px solid var(--colors-emulsify-blue-500);
|
|
113
170
|
}
|
|
114
|
-
|
|
115
171
|
.sidebar-header button[title="Shortcuts"]:focus {
|
|
116
172
|
background: transparent;
|
|
117
173
|
}
|
|
118
|
-
|
|
119
174
|
#shortcuts {
|
|
120
175
|
border-bottom-color: var(--colors-emulsify-blue-900) !important;
|
|
121
176
|
}
|
|
122
|
-
|
|
123
177
|
[role="main"]:not(:nth-child(3)) {
|
|
124
178
|
top: 1rem !important;
|
|
125
179
|
height: calc(100vh - 2rem) !important;
|
|
126
180
|
}
|
|
127
|
-
|
|
128
181
|
[role="main"] .os-host .os-content button:hover {
|
|
129
182
|
background: var(--colors-emulsify-blue-100);
|
|
130
183
|
}
|
|
131
|
-
|
|
132
184
|
[role="main"] .os-host .os-content button:hover svg {
|
|
133
185
|
color: var(--colors-emulsify-blue-900);
|
|
134
186
|
}
|
|
135
|
-
|
|
136
187
|
#panel-tab-content,
|
|
137
188
|
#panel-tab-content>* {
|
|
138
189
|
color: var(--colors-emulsify-blue-100) !important;
|
|
139
190
|
}
|
|
140
|
-
|
|
141
191
|
#panel-tab-content a,
|
|
142
192
|
#panel-tab-content a span,
|
|
143
193
|
#panel-tab-content a span svg {
|
|
144
194
|
color: var(--colors-emulsify-blue-800);
|
|
145
195
|
}
|
|
146
|
-
|
|
147
196
|
#panel-tab-content>div>div>div>div>div>div {
|
|
148
197
|
background: transparent;
|
|
149
198
|
}
|
|
150
|
-
|
|
151
199
|
#panel-tab-content>div>div>div>div>div>div>div {
|
|
152
200
|
color: var(--colors-emulsify-blue-1000) !important;
|
|
153
201
|
}
|
|
154
202
|
</style>
|
|
155
|
-
|
|
203
|
+
`;
|
|
204
|
+
|
|
205
|
+
// load external manager-head.html if present
|
|
206
|
+
const externalManagerHeadPath = resolve(
|
|
207
|
+
__dirname,
|
|
208
|
+
'../../../../config/emulsify-core/storybook/manager-head.html'
|
|
209
|
+
);
|
|
210
|
+
let externalManagerHtml = '';
|
|
211
|
+
if (fs.existsSync(externalManagerHeadPath)) {
|
|
212
|
+
externalManagerHtml = fs.readFileSync(externalManagerHeadPath, 'utf8');
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return `${head}
|
|
216
|
+
${inlineStyles}
|
|
217
|
+
${externalManagerHtml}`;
|
|
218
|
+
},
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Function to load and append an external preview-head.html into the preview iframe.
|
|
222
|
+
* @param {string} head - Existing preview head HTML.
|
|
223
|
+
* @returns {string} Combined head HTML including external snippet if present.
|
|
224
|
+
*/
|
|
225
|
+
previewHead: (head) => {
|
|
226
|
+
const externalHeadPath = resolve(
|
|
227
|
+
__dirname,
|
|
228
|
+
'../../../../config/emulsify-core/storybook/preview-head.html'
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
let externalHtml = '';
|
|
232
|
+
if (fs.existsSync(externalHeadPath)) {
|
|
233
|
+
externalHtml = fs.readFileSync(externalHeadPath, 'utf8');
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return `${head}
|
|
237
|
+
${externalHtml}`;
|
|
238
|
+
},
|
|
239
|
+
|
|
240
|
+
// Merge in user overrides without modifying original logic
|
|
156
241
|
...safeConfigOverrides,
|
|
157
242
|
};
|
|
158
243
|
|
|
159
|
-
|
|
244
|
+
export default config;
|
package/.storybook/manager.js
CHANGED
|
@@ -1,14 +1,45 @@
|
|
|
1
|
+
// .storybook/manager.js
|
|
2
|
+
|
|
1
3
|
import { addons } from '@storybook/manager-api';
|
|
2
4
|
import emulsifyTheme from './emulsifyTheme';
|
|
3
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Dynamically import the user-provided Storybook theme override.
|
|
8
|
+
* Falls back to the default Emulsify theme if the import fails or is empty.
|
|
9
|
+
*/
|
|
4
10
|
import('../../../../config/emulsify-core/storybook/theme')
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
})
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Handle successful dynamic import of the theme module.
|
|
13
|
+
* @param {{ default: object }} module - The imported theme module.
|
|
14
|
+
*/
|
|
15
|
+
.then(({ default: customTheme }) => {
|
|
16
|
+
/**
|
|
17
|
+
* Determine if the imported theme object is empty or not.
|
|
18
|
+
* @type {boolean}
|
|
19
|
+
*/
|
|
20
|
+
const isEmptyObject =
|
|
21
|
+
!customTheme ||
|
|
22
|
+
(typeof customTheme === 'object' && Object.keys(customTheme).length === 0);
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Apply the chosen theme to Storybook’s manager UI configuration.
|
|
26
|
+
* @type {{ theme: object }}
|
|
27
|
+
*/
|
|
28
|
+
addons.setConfig({
|
|
29
|
+
theme: isEmptyObject ? emulsifyTheme : customTheme,
|
|
30
|
+
});
|
|
31
|
+
})
|
|
32
|
+
/**
|
|
33
|
+
* Handle failure of the dynamic import (e.g., file not found).
|
|
34
|
+
* @returns {void}
|
|
35
|
+
*/
|
|
36
|
+
.catch(() => {
|
|
37
|
+
addons.setConfig({
|
|
38
|
+
/**
|
|
39
|
+
* Fallback to the default Emulsify theme on import error.
|
|
40
|
+
* @type {{ theme: object }}
|
|
41
|
+
*/
|
|
42
|
+
theme: emulsifyTheme,
|
|
43
|
+
});
|
|
13
44
|
});
|
|
14
|
-
|
|
45
|
+
|
package/.storybook/preview.js
CHANGED
|
@@ -1,32 +1,75 @@
|
|
|
1
|
+
// .storybook/preview.js
|
|
1
2
|
import { useEffect } from '@storybook/preview-api';
|
|
2
3
|
import Twig from 'twig';
|
|
3
4
|
import { setupTwig, fetchCSSFiles } from './utils.js';
|
|
4
|
-
import { getRules } from
|
|
5
|
+
import { getRules } from 'axe-core';
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
/**
|
|
8
|
+
* External override parameters loaded from project config file, if present.
|
|
9
|
+
* @type {object}
|
|
10
|
+
*/
|
|
11
|
+
let externalOverrides = {};
|
|
12
|
+
|
|
13
|
+
// Load the preview.js from the project config overrides.
|
|
14
|
+
try {
|
|
15
|
+
/**
|
|
16
|
+
* Dynamically require external preview overrides.
|
|
17
|
+
* @module '../../../../config/emulsify-core/storybook/preview.js'
|
|
18
|
+
*/
|
|
19
|
+
externalOverrides = require(
|
|
20
|
+
'../../../../config/emulsify-core/storybook/preview.js'
|
|
21
|
+
).default;
|
|
22
|
+
} catch (err) {
|
|
23
|
+
// no override file? swallow the error and use {}
|
|
24
|
+
externalOverrides = {};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Import Drupal behaviors for rich JavaScript integration.
|
|
7
28
|
import './_drupal.js';
|
|
8
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Filters accessibility rules by matching tags.
|
|
32
|
+
* @param {string[]} [tags=[]] List of WCAG rule tags to enable.
|
|
33
|
+
* @returns {{id: string, enabled: boolean}[]} Array of rule configurations.
|
|
34
|
+
*/
|
|
9
35
|
function enableRulesByTag(tags = []) {
|
|
10
36
|
const allRules = getRules();
|
|
11
37
|
return allRules.map(rule =>
|
|
12
|
-
tags.some(t => rule.tags.includes(t))
|
|
38
|
+
tags.some(t => rule.tags.includes(t))
|
|
39
|
+
? { id: rule.ruleId, enabled: true }
|
|
40
|
+
: { id: rule.ruleId, enabled: false }
|
|
13
41
|
);
|
|
14
42
|
}
|
|
15
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Precomputed Axe accessibility rules enabled by default.
|
|
46
|
+
* @type {{id: string, enabled: boolean}[]}
|
|
47
|
+
*/
|
|
16
48
|
const AxeRules = enableRulesByTag([
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
49
|
+
'wcag2a',
|
|
50
|
+
'wcag2aa',
|
|
51
|
+
'wcag21a',
|
|
52
|
+
'wcag21aa',
|
|
53
|
+
'wcag22aa',
|
|
54
|
+
'best-practice',
|
|
23
55
|
]);
|
|
24
56
|
|
|
57
|
+
// Initialize Twig and load any CSS that your stories need.
|
|
58
|
+
setupTwig(Twig);
|
|
59
|
+
fetchCSSFiles();
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Storybook decorators to apply Drupal behaviors before rendering each story.
|
|
63
|
+
* @type {Array<import('@storybook/react').Decorator>}
|
|
64
|
+
*/
|
|
25
65
|
export const decorators = [
|
|
66
|
+
/**
|
|
67
|
+
* Decorator that attaches Drupal behaviors on story mount.
|
|
68
|
+
* @param {Function} Story The story component to render.
|
|
69
|
+
* @param {object} context Story context including args.
|
|
70
|
+
* @returns {Function} Rendered story.
|
|
71
|
+
*/
|
|
26
72
|
(Story, { args }) => {
|
|
27
|
-
const { renderAs } = args || {};
|
|
28
|
-
|
|
29
|
-
// Usual emulsify hack to add Drupal behaviors.
|
|
30
73
|
useEffect(() => {
|
|
31
74
|
Drupal.attachBehaviors();
|
|
32
75
|
}, [args]);
|
|
@@ -34,18 +77,27 @@ export const decorators = [
|
|
|
34
77
|
},
|
|
35
78
|
];
|
|
36
79
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
80
|
+
/**
|
|
81
|
+
* Default Storybook parameters before applying overrides.
|
|
82
|
+
* @type {object}
|
|
83
|
+
*/
|
|
84
|
+
const defaultParams = {
|
|
41
85
|
actions: { argTypesRegex: '^on[A-Z].*' },
|
|
42
86
|
a11y: {
|
|
43
87
|
config: {
|
|
44
88
|
detailedReport: true,
|
|
45
|
-
detailedReportOptions: {
|
|
46
|
-
html: true,
|
|
47
|
-
},
|
|
89
|
+
detailedReportOptions: { html: true },
|
|
48
90
|
rules: AxeRules,
|
|
49
91
|
},
|
|
50
92
|
},
|
|
93
|
+
layout: 'fullscreen',
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Merged Storybook parameters including external overrides.
|
|
98
|
+
* @type {object}
|
|
99
|
+
*/
|
|
100
|
+
export const parameters = {
|
|
101
|
+
...defaultParams,
|
|
102
|
+
...externalOverrides,
|
|
51
103
|
};
|
package/.storybook/utils.js
CHANGED
|
@@ -1,17 +1,28 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { resolve, dirname } from 'path';
|
|
2
|
+
import twigDrupal from 'twig-drupal-filters';
|
|
3
|
+
import twigBEM from 'bem-twig-extension';
|
|
4
|
+
import twigAddAttributes from 'add-attributes-twig-extension';
|
|
5
|
+
import emulsifyConfig from '../../../../project.emulsify.json' with { type: 'json' };
|
|
6
|
+
|
|
7
|
+
// Create __filename from import.meta.url without fileURLToPath
|
|
8
|
+
let _filename = decodeURIComponent(new URL(import.meta.url).pathname);
|
|
9
|
+
|
|
10
|
+
// On Windows, remove the leading slash (e.g. "/C:/path" -> "C:/path")
|
|
11
|
+
if (process.platform === 'win32' && _filename.startsWith('/')) {
|
|
12
|
+
_filename = _filename.slice(1);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const _dirname = dirname(_filename);
|
|
5
16
|
|
|
6
17
|
/**
|
|
7
18
|
* Fetches project-based variant configuration. If no such configuration
|
|
8
19
|
* exists, returns default values as a flat component structure.
|
|
9
20
|
*
|
|
10
|
-
* @returns project-based variant configuration, or default config.
|
|
21
|
+
* @returns {Array} project-based variant configuration, or default config.
|
|
11
22
|
*/
|
|
12
23
|
const fetchVariantConfig = () => {
|
|
13
24
|
try {
|
|
14
|
-
return
|
|
25
|
+
return emulsifyConfig.variant.structureImplementations;
|
|
15
26
|
} catch (e) {
|
|
16
27
|
return [
|
|
17
28
|
{
|
|
@@ -32,38 +43,37 @@ const fetchCSSFiles = () => {
|
|
|
32
43
|
try {
|
|
33
44
|
// Load all CSS files from 'dist'.
|
|
34
45
|
const cssFiles = require.context('../../../../dist', true, /\.css$/);
|
|
35
|
-
cssFiles.keys().forEach(file => cssFiles(file));
|
|
46
|
+
cssFiles.keys().forEach((file) => cssFiles(file));
|
|
36
47
|
|
|
37
48
|
// Load all CSS files from 'components' for 'drupal' platform.
|
|
38
|
-
const emulsifyConfig = require('../../../../project.emulsify.json');
|
|
39
49
|
if (emulsifyConfig.project.platform === 'drupal') {
|
|
40
50
|
const drupalCSSFiles = require.context('../../../../components', true, /\.css$/);
|
|
41
|
-
drupalCSSFiles.keys().forEach(file => drupalCSSFiles(file));
|
|
51
|
+
drupalCSSFiles.keys().forEach((file) => drupalCSSFiles(file));
|
|
42
52
|
}
|
|
43
53
|
} catch (e) {
|
|
44
54
|
return undefined;
|
|
45
55
|
}
|
|
46
56
|
};
|
|
47
57
|
|
|
48
|
-
|
|
58
|
+
// Build namespaces mapping.
|
|
59
|
+
export const namespaces = {};
|
|
49
60
|
for (const { name, directory } of fetchVariantConfig()) {
|
|
50
|
-
|
|
61
|
+
namespaces[name] = resolve(_dirname, '../../../../', directory);
|
|
51
62
|
}
|
|
52
63
|
|
|
53
64
|
/**
|
|
54
|
-
* Configures and extends a standard
|
|
65
|
+
* Configures and extends a standard Twig object.
|
|
55
66
|
*
|
|
56
|
-
* @param {
|
|
57
|
-
*
|
|
58
|
-
* @returns {Twig} configured twig object.
|
|
67
|
+
* @param {Object} twig - Twig object that should be configured and extended.
|
|
68
|
+
* @returns {Object} Configured Twig object.
|
|
59
69
|
*/
|
|
60
|
-
|
|
70
|
+
export function setupTwig(twig) {
|
|
61
71
|
twig.cache();
|
|
62
72
|
twigDrupal(twig);
|
|
63
73
|
twigBEM(twig);
|
|
64
74
|
twigAddAttributes(twig);
|
|
65
75
|
return twig;
|
|
66
|
-
}
|
|
76
|
+
}
|
|
67
77
|
|
|
68
|
-
// Export the fetchCSSFiles function
|
|
69
|
-
|
|
78
|
+
// Export the fetchCSSFiles function.
|
|
79
|
+
export { fetchCSSFiles };
|