@emulsify/core 3.4.1 → 3.5.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/.storybook/_drupal.js +5 -5
- package/.storybook/emulsifyTheme.js +1 -1
- package/.storybook/main.js +79 -18
- package/.storybook/manager.js +4 -4
- package/.storybook/polyfills/twig-include.js +10 -6
- package/.storybook/polyfills/twig-resolver.js +25 -23
- package/.storybook/polyfills/twig-source.js +20 -9
- package/.storybook/preview.js +90 -12
- package/.storybook/utils.js +17 -11
- package/.storybook/webpack.config.js +145 -69
- package/config/babel.config.js +11 -1
- package/config/eslint.config.js +0 -25
- package/config/webpack/optimizers.js +10 -1
- package/config/webpack/webpack.common.js +4 -0
- package/package.json +26 -35
- package/release.config.cjs +1 -1
package/.storybook/_drupal.js
CHANGED
|
@@ -32,14 +32,14 @@ window.Drupal = { behaviors: {} };
|
|
|
32
32
|
Drupal.attachBehaviors = function (context, settings) {
|
|
33
33
|
context = context || document;
|
|
34
34
|
settings = settings || drupalSettings;
|
|
35
|
-
/** @type {
|
|
36
|
-
const behaviors = Drupal.behaviors;
|
|
35
|
+
/** @type {Array<{attach?: Function}>} */
|
|
36
|
+
const behaviors = Object.values(Drupal.behaviors);
|
|
37
37
|
|
|
38
38
|
// Iterate through each behavior and invoke its attach method if defined.
|
|
39
|
-
|
|
40
|
-
if (typeof
|
|
39
|
+
behaviors.forEach(function (behavior) {
|
|
40
|
+
if (typeof behavior.attach === 'function') {
|
|
41
41
|
try {
|
|
42
|
-
|
|
42
|
+
behavior.attach(context, settings);
|
|
43
43
|
} catch (e) {
|
|
44
44
|
Drupal.throwError(e);
|
|
45
45
|
}
|
package/.storybook/main.js
CHANGED
|
@@ -11,7 +11,10 @@ import { resolve } from 'path';
|
|
|
11
11
|
import fs from 'fs';
|
|
12
12
|
import path from 'path';
|
|
13
13
|
import { fileURLToPath } from 'url';
|
|
14
|
-
import
|
|
14
|
+
import { createRequire } from 'module';
|
|
15
|
+
import extendWebpackConfig from './webpack.config.js';
|
|
16
|
+
|
|
17
|
+
const require = createRequire(import.meta.url);
|
|
15
18
|
|
|
16
19
|
/**
|
|
17
20
|
* The full path to the current file (ESM compatible).
|
|
@@ -23,26 +26,70 @@ const _filename = fileURLToPath(import.meta.url);
|
|
|
23
26
|
* The directory name of the current module file.
|
|
24
27
|
* @type {string}
|
|
25
28
|
*/
|
|
26
|
-
const _dirname
|
|
29
|
+
const _dirname = path.dirname(_filename);
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Migrate the consumer Storybook theme import from "@storybook/theming" to
|
|
33
|
+
* "storybook/theming" when needed.
|
|
34
|
+
*
|
|
35
|
+
* This runs opportunistically during startup and never throws so Storybook
|
|
36
|
+
* startup is resilient across all projects.
|
|
37
|
+
*/
|
|
38
|
+
const migrateConsumerThemeImport = () => {
|
|
39
|
+
try {
|
|
40
|
+
const themeConfigPath = resolve(
|
|
41
|
+
_dirname,
|
|
42
|
+
'../../../../config/emulsify-core/storybook/theme.js',
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
if (!fs.existsSync(themeConfigPath)) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const originalThemeConfig = fs.readFileSync(themeConfigPath, 'utf8');
|
|
50
|
+
|
|
51
|
+
if (!originalThemeConfig.includes('@storybook/theming')) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const migratedThemeConfig = originalThemeConfig.replace(
|
|
56
|
+
/(['"])@storybook\/theming\1/g,
|
|
57
|
+
'$1storybook/theming$1',
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
if (migratedThemeConfig !== originalThemeConfig) {
|
|
61
|
+
fs.writeFileSync(themeConfigPath, migratedThemeConfig, 'utf8');
|
|
62
|
+
}
|
|
63
|
+
} catch {
|
|
64
|
+
// Ignore migration failures so Storybook startup is never blocked.
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
migrateConsumerThemeImport();
|
|
27
69
|
|
|
28
70
|
/**
|
|
29
71
|
* Safely apply any user-provided overrides or fall back to an empty object.
|
|
30
72
|
* @type {object}
|
|
31
73
|
*/
|
|
32
|
-
const safeConfigOverrides =
|
|
74
|
+
const safeConfigOverrides = (() => {
|
|
75
|
+
try {
|
|
76
|
+
const overridesModule = require('../../../../config/emulsify-core/storybook/main.js');
|
|
77
|
+
return overridesModule.default || overridesModule || {};
|
|
78
|
+
} catch {
|
|
79
|
+
return {};
|
|
80
|
+
}
|
|
81
|
+
})();
|
|
33
82
|
|
|
34
83
|
/**
|
|
35
84
|
* Primary Storybook configuration object.
|
|
36
|
-
* @type {import('
|
|
85
|
+
* @type {import('storybook/internal/types').StorybookConfig}
|
|
37
86
|
*/
|
|
38
87
|
const config = {
|
|
39
88
|
/**
|
|
40
89
|
* Patterns for locating story files under src or components directories.
|
|
41
90
|
* @type {string[]}
|
|
42
91
|
*/
|
|
43
|
-
stories: [
|
|
44
|
-
'../../../../(src|components)/**/*.stories.@(js|jsx|ts|tsx)',
|
|
45
|
-
],
|
|
92
|
+
stories: ['../../../../@(src|components)/**/*.stories.@(js|jsx|ts|tsx)'],
|
|
46
93
|
|
|
47
94
|
/**
|
|
48
95
|
* Directories to serve as static assets in the Storybook build.
|
|
@@ -52,6 +99,7 @@ const config = {
|
|
|
52
99
|
'../../../../assets/images',
|
|
53
100
|
'../../../../assets/icons',
|
|
54
101
|
'../../../../dist',
|
|
102
|
+
'../../../../assets/videos',
|
|
55
103
|
],
|
|
56
104
|
|
|
57
105
|
/**
|
|
@@ -59,28 +107,31 @@ const config = {
|
|
|
59
107
|
* @type {string[]}
|
|
60
108
|
*/
|
|
61
109
|
addons: [
|
|
62
|
-
'
|
|
63
|
-
'
|
|
64
|
-
'
|
|
65
|
-
'
|
|
66
|
-
'../../../@storybook/addon-styling-webpack',
|
|
110
|
+
'@storybook/addon-a11y',
|
|
111
|
+
'@storybook/addon-links',
|
|
112
|
+
'@storybook/addon-themes',
|
|
113
|
+
'@storybook/addon-styling-webpack',
|
|
67
114
|
],
|
|
68
115
|
|
|
69
116
|
/**
|
|
70
117
|
* Core builder configuration for Storybook.
|
|
71
|
-
*
|
|
118
|
+
* Storybook 9 splits the HTML renderer from the webpack builder, so the
|
|
119
|
+
* builder must be declared explicitly instead of relying on html-webpack5.
|
|
120
|
+
* @type {{builder: {name: string}, disableTelemetry: boolean}}
|
|
72
121
|
*/
|
|
73
122
|
core: {
|
|
74
|
-
builder:
|
|
123
|
+
builder: {
|
|
124
|
+
name: '@storybook/builder-webpack5',
|
|
125
|
+
},
|
|
75
126
|
disableTelemetry: true,
|
|
76
127
|
},
|
|
77
128
|
|
|
78
129
|
/**
|
|
79
|
-
* Framework specification for Storybook
|
|
130
|
+
* Framework specification for Storybook's HTML renderer.
|
|
80
131
|
* @type {{name: string, options: object}}
|
|
81
132
|
*/
|
|
82
133
|
framework: {
|
|
83
|
-
name: '@storybook/
|
|
134
|
+
name: '@storybook/server-webpack5',
|
|
84
135
|
options: {},
|
|
85
136
|
},
|
|
86
137
|
|
|
@@ -205,7 +256,7 @@ const config = {
|
|
|
205
256
|
// load external manager-head.html if present
|
|
206
257
|
const externalManagerHeadPath = resolve(
|
|
207
258
|
_dirname,
|
|
208
|
-
'../../../../config/emulsify-core/storybook/manager-head.html'
|
|
259
|
+
'../../../../config/emulsify-core/storybook/manager-head.html',
|
|
209
260
|
);
|
|
210
261
|
let externalManagerHtml = '';
|
|
211
262
|
if (fs.existsSync(externalManagerHeadPath)) {
|
|
@@ -225,7 +276,7 @@ ${externalManagerHtml}`;
|
|
|
225
276
|
previewHead: (head) => {
|
|
226
277
|
const externalHeadPath = resolve(
|
|
227
278
|
_dirname,
|
|
228
|
-
'../../../../config/emulsify-core/storybook/preview-head.html'
|
|
279
|
+
'../../../../config/emulsify-core/storybook/preview-head.html',
|
|
229
280
|
);
|
|
230
281
|
|
|
231
282
|
let externalHtml = '';
|
|
@@ -237,6 +288,16 @@ ${externalManagerHtml}`;
|
|
|
237
288
|
${externalHtml}`;
|
|
238
289
|
},
|
|
239
290
|
|
|
291
|
+
/**
|
|
292
|
+
* Forward Storybook 9's webpack hook to the existing shared webpack helper so
|
|
293
|
+
* custom Twig, Sass, YAML, and resolver behavior still applies.
|
|
294
|
+
* @param {object} storybookConfig - Storybook's generated webpack config.
|
|
295
|
+
* @param {object} options - Storybook webpack hook options.
|
|
296
|
+
* @returns {Promise<object>} The merged webpack config.
|
|
297
|
+
*/
|
|
298
|
+
webpackFinal: async (storybookConfig, options) =>
|
|
299
|
+
extendWebpackConfig({ config: storybookConfig, ...options }),
|
|
300
|
+
|
|
240
301
|
// Merge in user overrides without modifying original logic
|
|
241
302
|
...safeConfigOverrides,
|
|
242
303
|
};
|
package/.storybook/manager.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// .storybook/manager.js
|
|
2
2
|
|
|
3
|
-
import { addons } from '
|
|
4
|
-
import emulsifyTheme from './emulsifyTheme';
|
|
3
|
+
import { addons } from 'storybook/manager-api';
|
|
4
|
+
import emulsifyTheme from './emulsifyTheme.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Dynamically import the user-provided Storybook theme override.
|
|
@@ -19,7 +19,8 @@ import('../../../../config/emulsify-core/storybook/theme')
|
|
|
19
19
|
*/
|
|
20
20
|
const isEmptyObject =
|
|
21
21
|
!customTheme ||
|
|
22
|
-
(typeof customTheme === 'object' &&
|
|
22
|
+
(typeof customTheme === 'object' &&
|
|
23
|
+
Object.keys(customTheme).length === 0);
|
|
23
24
|
|
|
24
25
|
/**
|
|
25
26
|
* Apply the chosen theme to Storybook’s manager UI configuration.
|
|
@@ -42,4 +43,3 @@ import('../../../../config/emulsify-core/storybook/theme')
|
|
|
42
43
|
theme: emulsifyTheme,
|
|
43
44
|
});
|
|
44
45
|
});
|
|
45
|
-
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
import resolveTemplate from './twig-resolver.js';
|
|
3
2
|
|
|
4
3
|
/**
|
|
@@ -12,7 +11,11 @@ import resolveTemplate from './twig-resolver.js';
|
|
|
12
11
|
function twigInclude(Twig) {
|
|
13
12
|
Twig.extendFunction('include', (...args) => {
|
|
14
13
|
let [templateName, variables = {}, withContext = false] = args;
|
|
15
|
-
if (
|
|
14
|
+
if (
|
|
15
|
+
typeof withContext !== 'boolean' &&
|
|
16
|
+
variables &&
|
|
17
|
+
typeof variables.with_context !== 'undefined'
|
|
18
|
+
) {
|
|
16
19
|
withContext = variables.with_context;
|
|
17
20
|
delete variables.with_context;
|
|
18
21
|
}
|
|
@@ -21,9 +24,10 @@ function twigInclude(Twig) {
|
|
|
21
24
|
const templateFn = resolveTemplate(templateName);
|
|
22
25
|
if (!templateFn) return '';
|
|
23
26
|
|
|
24
|
-
const finalContext =
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
const finalContext =
|
|
28
|
+
withContext && typeof this === 'object'
|
|
29
|
+
? { ...(this.context || {}), ...variables }
|
|
30
|
+
: variables;
|
|
27
31
|
|
|
28
32
|
return templateFn(finalContext);
|
|
29
33
|
} catch (err) {
|
|
@@ -31,6 +35,6 @@ function twigInclude(Twig) {
|
|
|
31
35
|
return '';
|
|
32
36
|
}
|
|
33
37
|
});
|
|
34
|
-
}
|
|
38
|
+
}
|
|
35
39
|
|
|
36
40
|
export default twigInclude;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { getProjectMachineName } from '../utils';
|
|
1
|
+
import { getProjectMachineName } from '../utils.js';
|
|
2
2
|
|
|
3
3
|
const namespace = getProjectMachineName();
|
|
4
4
|
|
|
5
5
|
const twigComponents = require.context(
|
|
6
6
|
'../../../../../src/components/',
|
|
7
7
|
true,
|
|
8
|
-
/\.twig
|
|
8
|
+
/\.twig$/,
|
|
9
9
|
);
|
|
10
10
|
|
|
11
11
|
/**
|
|
@@ -17,15 +17,14 @@ const twigComponents = require.context(
|
|
|
17
17
|
function resolveTemplate(name) {
|
|
18
18
|
// namespace:icon, @namespace/icon.twig
|
|
19
19
|
if (name.startsWith(`${namespace}:`) || name.startsWith(`@${namespace}/`)) {
|
|
20
|
-
const part = name.startsWith(`${namespace}:`)
|
|
20
|
+
const part = name.startsWith(`${namespace}:`)
|
|
21
|
+
? name.split(':')[1]
|
|
22
|
+
: name.replace(`${namespace}/`, '').replace('.twig', '');
|
|
21
23
|
const path = `./${part}/${part}.twig`;
|
|
22
24
|
try {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
} catch (e) {
|
|
28
|
-
// eslint-disable-next-line no-console
|
|
25
|
+
const mod = twigComponents(path);
|
|
26
|
+
return mod && mod.default ? mod.default : mod;
|
|
27
|
+
} catch {
|
|
29
28
|
console.error(`Cannot resolve Twig component for '${name}' at '${path}'`);
|
|
30
29
|
}
|
|
31
30
|
}
|
|
@@ -36,33 +35,36 @@ function resolveTemplate(name) {
|
|
|
36
35
|
const path = `./${part}/${part}.twig`;
|
|
37
36
|
try {
|
|
38
37
|
return twigComponents(path).default || twigComponents(path);
|
|
39
|
-
} catch
|
|
40
|
-
console.error(
|
|
38
|
+
} catch {
|
|
39
|
+
console.error(
|
|
40
|
+
`Cannot resolve Twig shorthand template '${name}' at '${path}'`,
|
|
41
|
+
);
|
|
41
42
|
}
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
// namespace/icon.twig via webpack alias
|
|
45
46
|
if (name.startsWith(`${namespace}/`)) {
|
|
46
|
-
const part = name.
|
|
47
|
+
const part = name.slice(namespace.length + 1).replace('.twig', '');
|
|
47
48
|
const path = `./${part}/${part}.twig`;
|
|
48
49
|
try {
|
|
49
50
|
return twigComponents(path).default || twigComponents(path);
|
|
50
|
-
} catch
|
|
51
|
-
console.error(
|
|
51
|
+
} catch {
|
|
52
|
+
console.error(
|
|
53
|
+
`Cannot resolve Twig alias template '${name}' at '${path}'`,
|
|
54
|
+
);
|
|
52
55
|
}
|
|
53
56
|
}
|
|
54
57
|
|
|
55
58
|
try {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
} catch (
|
|
62
|
-
|
|
63
|
-
console.error(`Cannot resolve Twig template '${name}'`, e);
|
|
59
|
+
// Storybook resolves runtime Twig requests through webpack, so this
|
|
60
|
+
// fallback intentionally loads a module path determined at render time.
|
|
61
|
+
// eslint-disable-next-line security/detect-non-literal-require
|
|
62
|
+
const mod = require(name);
|
|
63
|
+
return mod && mod.default ? mod.default : mod;
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.error(`Cannot resolve Twig template '${name}'`, error);
|
|
64
66
|
return () => '';
|
|
65
67
|
}
|
|
66
|
-
}
|
|
68
|
+
}
|
|
67
69
|
|
|
68
70
|
export default resolveTemplate;
|
|
@@ -1,14 +1,27 @@
|
|
|
1
|
-
import { getProjectMachineName } from '../utils';
|
|
1
|
+
import { getProjectMachineName } from '../utils.js';
|
|
2
2
|
|
|
3
3
|
const namespace = getProjectMachineName();
|
|
4
4
|
|
|
5
5
|
// Constants used by the `source()` polyfill.
|
|
6
|
-
const PUBLIC_ASSET_BASE =
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
const PUBLIC_ASSET_BASE =
|
|
7
|
+
typeof window !== 'undefined' &&
|
|
8
|
+
window.location &&
|
|
9
|
+
window.location.hostname &&
|
|
10
|
+
window.location.hostname.endsWith('github.io')
|
|
11
|
+
? `/${namespace}/assets/`
|
|
12
|
+
: '/assets/';
|
|
9
13
|
|
|
10
|
-
const INLINE_ASSET_EXTS = new Set([
|
|
11
|
-
|
|
14
|
+
const INLINE_ASSET_EXTS = new Set([
|
|
15
|
+
'svg',
|
|
16
|
+
'html',
|
|
17
|
+
'twig',
|
|
18
|
+
'css',
|
|
19
|
+
'js',
|
|
20
|
+
'json',
|
|
21
|
+
'txt',
|
|
22
|
+
'md',
|
|
23
|
+
]);
|
|
24
|
+
const IMAGE_ASSET_EXTS = new Set(['png', 'jpg', 'jpeg', 'gif', 'webp', 'avif']);
|
|
12
25
|
|
|
13
26
|
/**
|
|
14
27
|
* Twig `source()` polyfill.
|
|
@@ -33,10 +46,8 @@ function twigSource(Twig) {
|
|
|
33
46
|
if (xhr.status >= 200 && xhr.status < 300) {
|
|
34
47
|
return xhr.responseText;
|
|
35
48
|
}
|
|
36
|
-
// eslint-disable-next-line no-console
|
|
37
49
|
console.error(`source(): ${xhr.status} while fetching ${relPath}`);
|
|
38
50
|
} catch (err) {
|
|
39
|
-
// eslint-disable-next-line no-console
|
|
40
51
|
console.error(`source(): failed to fetch ${relPath}`, err);
|
|
41
52
|
}
|
|
42
53
|
}
|
|
@@ -49,6 +60,6 @@ function twigSource(Twig) {
|
|
|
49
60
|
// Fallback: return public URL.
|
|
50
61
|
return `${PUBLIC_ASSET_BASE}${relPath}`;
|
|
51
62
|
});
|
|
52
|
-
}
|
|
63
|
+
}
|
|
53
64
|
|
|
54
65
|
export default twigSource;
|
package/.storybook/preview.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// .storybook/preview.js
|
|
2
|
-
import { useEffect } from '
|
|
2
|
+
import { useEffect } from 'storybook/preview-api';
|
|
3
3
|
import Twig from 'twig';
|
|
4
4
|
import { setupTwig, fetchCSSFiles } from './utils.js';
|
|
5
5
|
import { getRules } from 'axe-core';
|
|
@@ -8,7 +8,7 @@ import { getRules } from 'axe-core';
|
|
|
8
8
|
* External override parameters loaded from project config file, if present.
|
|
9
9
|
* @type {object}
|
|
10
10
|
*/
|
|
11
|
-
let externalOverrides
|
|
11
|
+
let externalOverrides;
|
|
12
12
|
|
|
13
13
|
// Load the preview.js from the project config overrides.
|
|
14
14
|
try {
|
|
@@ -16,10 +16,9 @@ try {
|
|
|
16
16
|
* Dynamically require external preview overrides.
|
|
17
17
|
* @module '../../../../config/emulsify-core/storybook/preview.js'
|
|
18
18
|
*/
|
|
19
|
-
externalOverrides =
|
|
20
|
-
'../../../../config/emulsify-core/storybook/preview.js'
|
|
21
|
-
|
|
22
|
-
} catch (err) {
|
|
19
|
+
externalOverrides =
|
|
20
|
+
require('../../../../config/emulsify-core/storybook/preview.js').default;
|
|
21
|
+
} catch {
|
|
23
22
|
// no override file? swallow the error and use {}
|
|
24
23
|
externalOverrides = {};
|
|
25
24
|
}
|
|
@@ -34,10 +33,10 @@ import './_drupal.js';
|
|
|
34
33
|
*/
|
|
35
34
|
function enableRulesByTag(tags = []) {
|
|
36
35
|
const allRules = getRules();
|
|
37
|
-
return allRules.map(rule =>
|
|
38
|
-
tags.some(t => rule.tags.includes(t))
|
|
36
|
+
return allRules.map((rule) =>
|
|
37
|
+
tags.some((t) => rule.tags.includes(t))
|
|
39
38
|
? { id: rule.ruleId, enabled: true }
|
|
40
|
-
: { id: rule.ruleId, enabled: false }
|
|
39
|
+
: { id: rule.ruleId, enabled: false },
|
|
41
40
|
);
|
|
42
41
|
}
|
|
43
42
|
|
|
@@ -54,13 +53,81 @@ const AxeRules = enableRulesByTag([
|
|
|
54
53
|
'best-practice',
|
|
55
54
|
]);
|
|
56
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Cache of rendered story output keyed by story id.
|
|
58
|
+
* Storybook server renderer calls `storyFn()` before `fetchStoryHtml`, so
|
|
59
|
+
* decorators can stash markup here and fetch can read it without re-rendering.
|
|
60
|
+
*
|
|
61
|
+
* @type {Map<string, unknown>}
|
|
62
|
+
*/
|
|
63
|
+
const renderedStoryCache = new Map();
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Converts a rendered story return value into an HTML string.
|
|
67
|
+
*
|
|
68
|
+
* @param {unknown} rendered
|
|
69
|
+
* The rendered story result.
|
|
70
|
+
*
|
|
71
|
+
* @returns {string}
|
|
72
|
+
* Normalized HTML string.
|
|
73
|
+
*/
|
|
74
|
+
function toHtmlString(rendered) {
|
|
75
|
+
if (typeof rendered === 'string') {
|
|
76
|
+
return rendered;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (rendered && typeof rendered === 'object') {
|
|
80
|
+
if (typeof rendered.outerHTML === 'string') {
|
|
81
|
+
return rendered.outerHTML;
|
|
82
|
+
}
|
|
83
|
+
if (typeof rendered.html === 'string') {
|
|
84
|
+
return rendered.html;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return '';
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Default server renderer adapter for Storybook 9 server-webpack5.
|
|
93
|
+
* Falls back to local story functions so projects do not need a remote
|
|
94
|
+
* `parameters.server.url` endpoint for basic HTML/Twig stories.
|
|
95
|
+
*
|
|
96
|
+
* @param {string} _url
|
|
97
|
+
* Unused URL from server parameters.
|
|
98
|
+
* @param {string} _path
|
|
99
|
+
* Unused story path/id from server parameters.
|
|
100
|
+
* @param {object} _params
|
|
101
|
+
* Unused merged server params.
|
|
102
|
+
* @param {object} storyContext
|
|
103
|
+
* Story context from Storybook.
|
|
104
|
+
*
|
|
105
|
+
* @returns {Promise<string>}
|
|
106
|
+
* Story markup as an HTML string.
|
|
107
|
+
*/
|
|
108
|
+
async function fetchStoryHtmlFromStoryContext(
|
|
109
|
+
_url,
|
|
110
|
+
_path,
|
|
111
|
+
_params,
|
|
112
|
+
storyContext,
|
|
113
|
+
) {
|
|
114
|
+
const storyId = storyContext?.id || _path;
|
|
115
|
+
if (!storyId || !renderedStoryCache.has(storyId)) {
|
|
116
|
+
return '';
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const rendered = await Promise.resolve(renderedStoryCache.get(storyId));
|
|
120
|
+
return toHtmlString(rendered);
|
|
121
|
+
}
|
|
122
|
+
|
|
57
123
|
// Initialize Twig and load any CSS that your stories need.
|
|
58
124
|
setupTwig(Twig);
|
|
59
125
|
fetchCSSFiles();
|
|
60
126
|
|
|
61
127
|
/**
|
|
62
128
|
* Storybook decorators to apply Drupal behaviors before rendering each story.
|
|
63
|
-
*
|
|
129
|
+
* The HTML renderer still uses the generic Storybook decorator signature.
|
|
130
|
+
* @type {Function[]}
|
|
64
131
|
*/
|
|
65
132
|
export const decorators = [
|
|
66
133
|
/**
|
|
@@ -69,11 +136,17 @@ export const decorators = [
|
|
|
69
136
|
* @param {object} context Story context including args.
|
|
70
137
|
* @returns {Function} Rendered story.
|
|
71
138
|
*/
|
|
72
|
-
(Story,
|
|
139
|
+
(Story, context) => {
|
|
140
|
+
const { args, id } = context;
|
|
73
141
|
useEffect(() => {
|
|
74
142
|
Drupal.attachBehaviors();
|
|
75
143
|
}, [args]);
|
|
76
|
-
|
|
144
|
+
|
|
145
|
+
const rendered = Story();
|
|
146
|
+
if (id) {
|
|
147
|
+
renderedStoryCache.set(id, rendered);
|
|
148
|
+
}
|
|
149
|
+
return rendered;
|
|
77
150
|
},
|
|
78
151
|
];
|
|
79
152
|
|
|
@@ -91,6 +164,11 @@ const defaultParams = {
|
|
|
91
164
|
},
|
|
92
165
|
},
|
|
93
166
|
layout: 'fullscreen',
|
|
167
|
+
server: {
|
|
168
|
+
url: '',
|
|
169
|
+
fetchStoryHtml: fetchStoryHtmlFromStoryContext,
|
|
170
|
+
params: {},
|
|
171
|
+
},
|
|
94
172
|
};
|
|
95
173
|
|
|
96
174
|
/**
|
package/.storybook/utils.js
CHANGED
|
@@ -3,8 +3,8 @@ import twigDrupal from 'twig-drupal-filters';
|
|
|
3
3
|
import twigBEM from 'bem-twig-extension';
|
|
4
4
|
import twigAddAttributes from 'add-attributes-twig-extension';
|
|
5
5
|
import emulsifyConfig from '../../../../project.emulsify.json' with { type: 'json' };
|
|
6
|
-
import twigInclude from './polyfills/twig-include';
|
|
7
|
-
import twigSource from './polyfills/twig-source';
|
|
6
|
+
import twigInclude from './polyfills/twig-include.js';
|
|
7
|
+
import twigSource from './polyfills/twig-source.js';
|
|
8
8
|
|
|
9
9
|
// Create __filename from import.meta.url without fileURLToPath
|
|
10
10
|
let _filename = decodeURIComponent(new URL(import.meta.url).pathname);
|
|
@@ -25,7 +25,7 @@ const _dirname = dirname(_filename);
|
|
|
25
25
|
const fetchVariantConfig = () => {
|
|
26
26
|
try {
|
|
27
27
|
return emulsifyConfig.variant.structureImplementations;
|
|
28
|
-
} catch
|
|
28
|
+
} catch {
|
|
29
29
|
return [
|
|
30
30
|
{
|
|
31
31
|
name: 'components',
|
|
@@ -49,10 +49,14 @@ const fetchCSSFiles = () => {
|
|
|
49
49
|
|
|
50
50
|
// Load all CSS files from 'components' for 'drupal' platform.
|
|
51
51
|
if (emulsifyConfig.project.platform === 'drupal') {
|
|
52
|
-
const drupalCSSFiles = require.context(
|
|
52
|
+
const drupalCSSFiles = require.context(
|
|
53
|
+
'../../../../components',
|
|
54
|
+
true,
|
|
55
|
+
/\.css$/,
|
|
56
|
+
);
|
|
53
57
|
drupalCSSFiles.keys().forEach((file) => drupalCSSFiles(file));
|
|
54
58
|
}
|
|
55
|
-
} catch
|
|
59
|
+
} catch {
|
|
56
60
|
return undefined;
|
|
57
61
|
}
|
|
58
62
|
};
|
|
@@ -66,16 +70,18 @@ const fetchCSSFiles = () => {
|
|
|
66
70
|
export function getProjectMachineName() {
|
|
67
71
|
try {
|
|
68
72
|
return emulsifyConfig.project.machineName;
|
|
69
|
-
} catch
|
|
73
|
+
} catch {
|
|
70
74
|
return undefined;
|
|
71
75
|
}
|
|
72
|
-
}
|
|
76
|
+
}
|
|
73
77
|
|
|
74
78
|
// Build namespaces mapping.
|
|
75
|
-
export const namespaces =
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
+
export const namespaces = Object.fromEntries(
|
|
80
|
+
fetchVariantConfig().map(({ name, directory }) => [
|
|
81
|
+
name,
|
|
82
|
+
resolve(_dirname, '../../../../', directory),
|
|
83
|
+
]),
|
|
84
|
+
);
|
|
79
85
|
|
|
80
86
|
/**
|
|
81
87
|
* Configures and extends a standard Twig object.
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { dirname, resolve } from 'path';
|
|
2
|
+
import { createRequire } from 'module';
|
|
2
3
|
import globImporter from 'node-sass-glob-importer';
|
|
3
4
|
import _StyleLintPlugin from 'stylelint-webpack-plugin';
|
|
4
|
-
import
|
|
5
|
+
import webpack from 'webpack';
|
|
5
6
|
import resolves from '../config/webpack/resolves.js';
|
|
6
7
|
import emulsifyConfig from '../../../../project.emulsify.json' with { type: 'json' };
|
|
7
8
|
|
|
9
|
+
const require = createRequire(import.meta.url);
|
|
10
|
+
|
|
8
11
|
// Create __filename from import.meta.url without fileURLToPath
|
|
9
12
|
let _filename = decodeURIComponent(new URL(import.meta.url).pathname);
|
|
10
13
|
|
|
@@ -54,13 +57,10 @@ class ProjectNameResolverPlugin {
|
|
|
54
57
|
(request, resolveContext, callback) => {
|
|
55
58
|
const requestPath = request.request;
|
|
56
59
|
|
|
57
|
-
if (
|
|
58
|
-
requestPath &&
|
|
59
|
-
requestPath.startsWith(`${this.prefix}:`)
|
|
60
|
-
) {
|
|
60
|
+
if (requestPath && requestPath.startsWith(`${this.prefix}:`)) {
|
|
61
61
|
const newRequestPath = requestPath.replace(
|
|
62
62
|
`${this.prefix}:`,
|
|
63
|
-
`${this.prefix}
|
|
63
|
+
`${this.prefix}/`,
|
|
64
64
|
);
|
|
65
65
|
const newRequest = {
|
|
66
66
|
...request,
|
|
@@ -70,14 +70,14 @@ class ProjectNameResolverPlugin {
|
|
|
70
70
|
resolver.doResolve(
|
|
71
71
|
target,
|
|
72
72
|
newRequest,
|
|
73
|
-
`Resolved ${this.prefix} URI
|
|
73
|
+
`Resolved ${this.prefix} URI`,
|
|
74
74
|
resolveContext,
|
|
75
|
-
callback
|
|
75
|
+
callback,
|
|
76
76
|
);
|
|
77
77
|
} else {
|
|
78
78
|
callback();
|
|
79
79
|
}
|
|
80
|
-
}
|
|
80
|
+
},
|
|
81
81
|
);
|
|
82
82
|
}
|
|
83
83
|
}
|
|
@@ -89,77 +89,138 @@ class ProjectNameResolverPlugin {
|
|
|
89
89
|
* @returns {object} The updated webpack config.
|
|
90
90
|
*/
|
|
91
91
|
export default async function ({ config }) {
|
|
92
|
+
config.resolve = config.resolve || {};
|
|
93
|
+
config.plugins = config.plugins || [];
|
|
94
|
+
|
|
95
|
+
config.module = config.module || {};
|
|
96
|
+
config.module.rules = config.module.rules || [];
|
|
97
|
+
|
|
98
|
+
const hasLoader = (rule, loaderName) => {
|
|
99
|
+
if (!rule) {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (typeof rule.loader === 'string' && rule.loader.includes(loaderName)) {
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const use = rule.use;
|
|
108
|
+
if (typeof use === 'string') {
|
|
109
|
+
return use.includes(loaderName);
|
|
110
|
+
}
|
|
111
|
+
if (Array.isArray(use)) {
|
|
112
|
+
return use.some((entry) => {
|
|
113
|
+
if (typeof entry === 'string') {
|
|
114
|
+
return entry.includes(loaderName);
|
|
115
|
+
}
|
|
116
|
+
return (
|
|
117
|
+
entry &&
|
|
118
|
+
typeof entry.loader === 'string' &&
|
|
119
|
+
entry.loader.includes(loaderName)
|
|
120
|
+
);
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return false;
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const hasRule = (testRegex, loaderName) =>
|
|
128
|
+
config.module.rules.some(
|
|
129
|
+
(rule) =>
|
|
130
|
+
rule &&
|
|
131
|
+
rule.test &&
|
|
132
|
+
String(rule.test) === String(testRegex) &&
|
|
133
|
+
hasLoader(rule, loaderName),
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
const pushRuleOnce = (rule, loaderName) => {
|
|
137
|
+
if (!hasRule(rule.test, loaderName)) {
|
|
138
|
+
config.module.rules.push(rule);
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
|
|
92
142
|
// Alias
|
|
93
143
|
Object.assign(config.resolve.alias, resolves.TwigResolve.alias);
|
|
94
144
|
|
|
95
145
|
// Twig loader
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
* Custom loader for svg/spritemap integration.
|
|
105
|
-
* @type {string}
|
|
106
|
-
*/
|
|
107
|
-
loader: resolve(_dirname, '../config/webpack/sdc-loader.js'),
|
|
108
|
-
options: {
|
|
146
|
+
pushRuleOnce(
|
|
147
|
+
{
|
|
148
|
+
/**
|
|
149
|
+
* @type {RegExp}
|
|
150
|
+
*/
|
|
151
|
+
test: /\.twig$/,
|
|
152
|
+
use: [
|
|
153
|
+
{
|
|
109
154
|
/**
|
|
110
|
-
*
|
|
155
|
+
* Custom loader for svg/spritemap integration.
|
|
111
156
|
* @type {string}
|
|
112
157
|
*/
|
|
113
|
-
|
|
158
|
+
loader: resolve(_dirname, '../config/webpack/sdc-loader.js'),
|
|
159
|
+
options: {
|
|
160
|
+
/**
|
|
161
|
+
* Name of the Emulsify project for resolving.
|
|
162
|
+
* @type {string}
|
|
163
|
+
*/
|
|
164
|
+
projectName: emulsifyConfig.project.name,
|
|
165
|
+
},
|
|
114
166
|
},
|
|
115
|
-
|
|
116
|
-
{
|
|
117
|
-
/**
|
|
118
|
-
* Standard Twig JS loader.
|
|
119
|
-
* @type {string}
|
|
120
|
-
*/
|
|
121
|
-
loader: 'twigjs-loader',
|
|
122
|
-
},
|
|
123
|
-
],
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
// SCSS Loader configuration
|
|
127
|
-
config.module.rules.push({
|
|
128
|
-
test: /\.s[ac]ss$/i,
|
|
129
|
-
use: [
|
|
130
|
-
'style-loader',
|
|
131
|
-
{
|
|
132
|
-
loader: 'css-loader',
|
|
133
|
-
options: {
|
|
167
|
+
{
|
|
134
168
|
/**
|
|
135
|
-
*
|
|
136
|
-
* @type {
|
|
169
|
+
* Standard Twig JS loader.
|
|
170
|
+
* @type {string}
|
|
137
171
|
*/
|
|
138
|
-
|
|
172
|
+
loader: 'twigjs-loader',
|
|
139
173
|
},
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
174
|
+
],
|
|
175
|
+
},
|
|
176
|
+
'twigjs-loader',
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
// SCSS Loader configuration
|
|
180
|
+
pushRuleOnce(
|
|
181
|
+
{
|
|
182
|
+
test: /\.s[ac]ss$/i,
|
|
183
|
+
use: [
|
|
184
|
+
'style-loader',
|
|
185
|
+
{
|
|
186
|
+
loader: 'css-loader',
|
|
187
|
+
options: {
|
|
188
|
+
/**
|
|
189
|
+
* Enable source maps for CSS.
|
|
190
|
+
* @type {boolean}
|
|
191
|
+
*/
|
|
192
|
+
sourceMap: true,
|
|
147
193
|
},
|
|
148
194
|
},
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
195
|
+
{
|
|
196
|
+
loader: 'sass-loader',
|
|
197
|
+
options: {
|
|
198
|
+
sourceMap: true,
|
|
199
|
+
sassOptions: {
|
|
200
|
+
importer: globImporter(),
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
],
|
|
205
|
+
},
|
|
206
|
+
'sass-loader',
|
|
207
|
+
);
|
|
152
208
|
|
|
153
209
|
// YAML loader
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
210
|
+
pushRuleOnce(
|
|
211
|
+
{
|
|
212
|
+
/**
|
|
213
|
+
* @type {RegExp}
|
|
214
|
+
*/
|
|
215
|
+
test: /\.ya?ml$/,
|
|
216
|
+
loader: 'js-yaml-loader',
|
|
217
|
+
},
|
|
218
|
+
'js-yaml-loader',
|
|
219
|
+
);
|
|
161
220
|
|
|
162
|
-
//
|
|
221
|
+
// Keep style linting in the Storybook webpack build. ESLint runs via the
|
|
222
|
+
// dedicated npm scripts instead, which avoids coupling Storybook to a
|
|
223
|
+
// specific ESLint major version.
|
|
163
224
|
config.plugins.push(
|
|
164
225
|
new _StyleLintPlugin({
|
|
165
226
|
configFile: resolve(projectDir, '../', '.stylelintrc.json'),
|
|
@@ -168,10 +229,6 @@ export default async function ({ config }) {
|
|
|
168
229
|
failOnError: false,
|
|
169
230
|
quiet: false,
|
|
170
231
|
}),
|
|
171
|
-
new ESLintPlugin({
|
|
172
|
-
context: resolve(projectDir, '../', 'src'),
|
|
173
|
-
extensions: ['js'],
|
|
174
|
-
}),
|
|
175
232
|
);
|
|
176
233
|
|
|
177
234
|
// Custom resolver plugin for namespaced imports
|
|
@@ -181,13 +238,32 @@ export default async function ({ config }) {
|
|
|
181
238
|
}),
|
|
182
239
|
];
|
|
183
240
|
|
|
184
|
-
//
|
|
241
|
+
// Merge fallbacks so we do not clobber Storybook defaults.
|
|
185
242
|
config.resolve.fallback = {
|
|
243
|
+
...(config.resolve.fallback || {}),
|
|
244
|
+
process: require.resolve('process/browser'),
|
|
186
245
|
/**
|
|
187
246
|
* Prevent resolution of components directory if missing.
|
|
188
247
|
*/
|
|
189
248
|
'../../../../components': false,
|
|
190
249
|
};
|
|
191
250
|
|
|
251
|
+
// Provide global `process` for browser bundles that pull in node-style libs.
|
|
252
|
+
const hasProcessProvidePlugin = config.plugins.some(
|
|
253
|
+
(plugin) =>
|
|
254
|
+
plugin &&
|
|
255
|
+
plugin.constructor &&
|
|
256
|
+
plugin.constructor.name === 'ProvidePlugin' &&
|
|
257
|
+
plugin.definitions &&
|
|
258
|
+
Object.prototype.hasOwnProperty.call(plugin.definitions, 'process'),
|
|
259
|
+
);
|
|
260
|
+
if (!hasProcessProvidePlugin) {
|
|
261
|
+
config.plugins.push(
|
|
262
|
+
new webpack.ProvidePlugin({
|
|
263
|
+
process: 'process/browser',
|
|
264
|
+
}),
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
|
|
192
268
|
return config;
|
|
193
269
|
}
|
package/config/babel.config.js
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
export default (api) => {
|
|
2
2
|
api.cache(true);
|
|
3
3
|
|
|
4
|
-
const presets = [
|
|
4
|
+
const presets = [
|
|
5
|
+
[
|
|
6
|
+
'minify',
|
|
7
|
+
{
|
|
8
|
+
builtIns: false,
|
|
9
|
+
mangle: {
|
|
10
|
+
reserved: ['Drupal', 'drupalSettings', 'once'],
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
],
|
|
14
|
+
];
|
|
5
15
|
const comments = false;
|
|
6
16
|
|
|
7
17
|
return { presets, comments };
|
package/config/eslint.config.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
// Import ESLint Flat Config and required plugins
|
|
2
2
|
import js from '@eslint/js';
|
|
3
|
-
import babelParser from '@babel/eslint-parser';
|
|
4
|
-
import importPlugin from 'eslint-plugin-import';
|
|
5
3
|
import pluginSecurity from 'eslint-plugin-security';
|
|
6
4
|
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
|
|
7
5
|
|
|
@@ -10,21 +8,12 @@ export default [
|
|
|
10
8
|
js.configs.recommended,
|
|
11
9
|
|
|
12
10
|
// Plugin configurations
|
|
13
|
-
importPlugin.flatConfigs.recommended,
|
|
14
11
|
pluginSecurity.configs.recommended,
|
|
15
12
|
eslintPluginPrettierRecommended,
|
|
16
13
|
|
|
17
14
|
{
|
|
18
15
|
name: 'emulsify-core-config',
|
|
19
16
|
languageOptions: {
|
|
20
|
-
parser: babelParser,
|
|
21
|
-
parserOptions: {
|
|
22
|
-
requireConfigFile: false,
|
|
23
|
-
babelOptions: {
|
|
24
|
-
babelrc: false,
|
|
25
|
-
configFile: false,
|
|
26
|
-
},
|
|
27
|
-
},
|
|
28
17
|
sourceType: 'module',
|
|
29
18
|
ecmaVersion: 'latest',
|
|
30
19
|
globals: {
|
|
@@ -43,10 +32,6 @@ export default [
|
|
|
43
32
|
'consistent-return': 'off',
|
|
44
33
|
'no-underscore-dangle': 'off',
|
|
45
34
|
'max-nested-callbacks': ['warn', 3],
|
|
46
|
-
'import/extensions': 'off',
|
|
47
|
-
'import/no-unresolved': 'off',
|
|
48
|
-
'import/no-extraneous-dependencies': 'warn',
|
|
49
|
-
'import/no-mutable-exports': 'warn',
|
|
50
35
|
'no-plusplus': ['warn', { allowForLoopAfterthoughts: true }],
|
|
51
36
|
'no-param-reassign': 'off',
|
|
52
37
|
'no-prototype-builtins': 'off',
|
|
@@ -60,15 +45,5 @@ export default [
|
|
|
60
45
|
],
|
|
61
46
|
quotes: ['error', 'single'],
|
|
62
47
|
},
|
|
63
|
-
|
|
64
|
-
settings: {
|
|
65
|
-
'import/ignore': ['\\.(scss|less|css)$'],
|
|
66
|
-
'import/resolver': {
|
|
67
|
-
node: {
|
|
68
|
-
extensions: ['.js', '.jsx'],
|
|
69
|
-
moduleDirectory: ['src', 'node_modules'],
|
|
70
|
-
},
|
|
71
|
-
},
|
|
72
|
-
},
|
|
73
48
|
},
|
|
74
49
|
];
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import ImageMinimizerPlugin from 'image-minimizer-webpack-plugin';
|
|
2
|
+
import TerserPlugin from 'terser-webpack-plugin';
|
|
2
3
|
|
|
3
4
|
const ImageMinimizer = new ImageMinimizerPlugin({
|
|
4
5
|
minimizer: {
|
|
@@ -12,6 +13,14 @@ const ImageMinimizer = new ImageMinimizerPlugin({
|
|
|
12
13
|
},
|
|
13
14
|
});
|
|
14
15
|
|
|
16
|
+
const TerserMinimizer = new TerserPlugin({
|
|
17
|
+
terserOptions: {
|
|
18
|
+
mangle: {
|
|
19
|
+
reserved: ['Drupal', 'drupalSettings', 'once'],
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
|
|
15
24
|
export default {
|
|
16
|
-
minimizer: [ImageMinimizer],
|
|
25
|
+
minimizer: [ImageMinimizer, TerserMinimizer],
|
|
17
26
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@emulsify/core",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.5.0",
|
|
4
4
|
"description": "Bundled tooling for Storybook development + Webpack Build",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"component library",
|
|
@@ -37,35 +37,29 @@
|
|
|
37
37
|
"husky:pre-commit": "npm run lint",
|
|
38
38
|
"lint": "npm run lint-js",
|
|
39
39
|
"lint-fix": "npm run lint-js -- --fix",
|
|
40
|
-
"lint-js": "eslint --config config/eslint.config.js --no-error-on-unmatched-pattern ./config
|
|
40
|
+
"lint-js": "eslint --config config/eslint.config.js --no-error-on-unmatched-pattern ./config ./.storybook",
|
|
41
41
|
"lint-staged": "lint-staged",
|
|
42
42
|
"prepare": "[ -d '.git' ] && (husky install) || true",
|
|
43
43
|
"prettier": "prettier --config config/prettierrc.json --ignore-unknown \"**/*.{js,yml,scss,md}\"",
|
|
44
44
|
"prettier-fix": "prettier --config config/prettierrc.json --write --ignore-unknown \"**/*.{js,yml,scss,md}\"",
|
|
45
45
|
"semantic-release": "semantic-release --config ./release.config.cjs",
|
|
46
|
-
"storybook": "NODE_OPTIONS=--no-deprecation storybook dev --ci -
|
|
47
|
-
"storybook-build": "storybook build -
|
|
46
|
+
"storybook": "NODE_OPTIONS=--no-deprecation storybook dev --ci -p 6006",
|
|
47
|
+
"storybook-build": "storybook build -o .out",
|
|
48
48
|
"storybook-deploy": "storybook-to-ghpages -o .out",
|
|
49
49
|
"test": "jest --coverage --config ./config/jest.config.js",
|
|
50
50
|
"twatch": "jest --no-coverage --watch --verbose"
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
53
|
"@babel/core": "^7.28.5",
|
|
54
|
-
"@babel/eslint-parser": "^7.28.5",
|
|
55
54
|
"@babel/preset-env": "^7.28.5",
|
|
56
55
|
"@emulsify/cli": "^1.11.4",
|
|
57
|
-
"@eslint/js": "^
|
|
58
|
-
"@storybook/addon-a11y": "^
|
|
59
|
-
"@storybook/addon-
|
|
60
|
-
"@storybook/addon-
|
|
61
|
-
"@storybook/addon-
|
|
62
|
-
"@storybook/
|
|
63
|
-
"@storybook/
|
|
64
|
-
"@storybook/html": "^8.6.14",
|
|
65
|
-
"@storybook/html-webpack5": "^8.6.14",
|
|
66
|
-
"@storybook/manager-api": "^8.6.14",
|
|
67
|
-
"@storybook/preview-api": "^8.6.14",
|
|
68
|
-
"@storybook/theming": "^8.6.14",
|
|
56
|
+
"@eslint/js": "^10.0.1",
|
|
57
|
+
"@storybook/addon-a11y": "^9.1.20",
|
|
58
|
+
"@storybook/addon-links": "^9.1.20",
|
|
59
|
+
"@storybook/addon-styling-webpack": "^2.0.0",
|
|
60
|
+
"@storybook/addon-themes": "^9.1.20",
|
|
61
|
+
"@storybook/builder-webpack5": "^9.1.20",
|
|
62
|
+
"@storybook/server-webpack5": "^9.1.20",
|
|
69
63
|
"add-attributes-twig-extension": "^0.1.0",
|
|
70
64
|
"autoprefixer": "^10.4.21",
|
|
71
65
|
"babel-loader": "^10.0.0",
|
|
@@ -74,22 +68,19 @@
|
|
|
74
68
|
"breakpoint-sass": "^3.0.0",
|
|
75
69
|
"clean-webpack-plugin": "^4.0.0",
|
|
76
70
|
"concurrently": "^9.2.1",
|
|
77
|
-
"copy-webpack-plugin": "^
|
|
71
|
+
"copy-webpack-plugin": "^14.0.0",
|
|
78
72
|
"css-loader": "^7.1.1",
|
|
79
|
-
"eslint": "^
|
|
73
|
+
"eslint": "^10.1.0",
|
|
80
74
|
"eslint-config-prettier": "^10.1.8",
|
|
81
|
-
"eslint-plugin-
|
|
82
|
-
"eslint-plugin-jest": "^29.0.1",
|
|
75
|
+
"eslint-plugin-jest": "^29.15.1",
|
|
83
76
|
"eslint-plugin-prettier": "^5.5.4",
|
|
84
|
-
"eslint-plugin-security": "^
|
|
85
|
-
"eslint-plugin-storybook": "^0.12.0",
|
|
86
|
-
"eslint-webpack-plugin": "^5.0.2",
|
|
77
|
+
"eslint-plugin-security": "^4.0.0",
|
|
87
78
|
"file-loader": "^6.2.0",
|
|
88
79
|
"fs-extra": "^11.3.2",
|
|
89
|
-
"glob": "^
|
|
80
|
+
"glob": "^13.0.6",
|
|
90
81
|
"graceful-fs": "^4.2.11",
|
|
91
82
|
"html-webpack-plugin": "^5.6.4",
|
|
92
|
-
"image-minimizer-webpack-plugin": "^
|
|
83
|
+
"image-minimizer-webpack-plugin": "^5.0.0",
|
|
93
84
|
"imagemin": "^9.0.1",
|
|
94
85
|
"imagemin-jpegtran": "^8.0.0",
|
|
95
86
|
"imagemin-optipng": "^8.0.0",
|
|
@@ -100,7 +91,7 @@
|
|
|
100
91
|
"mini-css-extract-plugin": "^2.9.4",
|
|
101
92
|
"node-sass-glob-importer": "^5.3.3",
|
|
102
93
|
"normalize.css": "^8.0.1",
|
|
103
|
-
"open-cli": "^
|
|
94
|
+
"open-cli": "^9.0.0",
|
|
104
95
|
"pa11y": "^9.0.1",
|
|
105
96
|
"postcss": "^8.5.6",
|
|
106
97
|
"postcss-loader": "^8.2.0",
|
|
@@ -109,20 +100,20 @@
|
|
|
109
100
|
"regenerator-runtime": "^0.14.1",
|
|
110
101
|
"sass": "^1.93.2",
|
|
111
102
|
"sass-loader": "^16.0.6",
|
|
112
|
-
"storybook": "^
|
|
103
|
+
"storybook": "^9.1.20",
|
|
113
104
|
"style-dictionary": "^5.1.1",
|
|
114
|
-
"stylelint": "^
|
|
115
|
-
"stylelint-config-standard-scss": "^
|
|
105
|
+
"stylelint": "^17.7.0",
|
|
106
|
+
"stylelint-config-standard-scss": "^17.0.0",
|
|
116
107
|
"stylelint-prettier": "^5.0.3",
|
|
117
|
-
"stylelint-selector-bem-pattern": "^4.0.1",
|
|
118
108
|
"stylelint-webpack-plugin": "^5.0.1",
|
|
119
109
|
"svg-spritemap-webpack-plugin": "^5.0.3",
|
|
110
|
+
"terser-webpack-plugin": "^5.3.9",
|
|
120
111
|
"token-transformer": "^0.0.33",
|
|
121
112
|
"twig-drupal-filters": "^3.2.0",
|
|
122
113
|
"twig-testing-library": "^1.2.0",
|
|
123
114
|
"twigjs-loader": "^1.0.3",
|
|
124
115
|
"webpack": "^5.102.1",
|
|
125
|
-
"webpack-cli": "^
|
|
116
|
+
"webpack-cli": "^7.0.2",
|
|
126
117
|
"webpack-merge": "^6.0.1",
|
|
127
118
|
"webpack-remove-empty-scripts": "^1.1.1",
|
|
128
119
|
"yaml": "^2.8.1"
|
|
@@ -133,17 +124,17 @@
|
|
|
133
124
|
"@semantic-release/changelog": "^6.0.2",
|
|
134
125
|
"@semantic-release/commit-analyzer": "^13.0.1",
|
|
135
126
|
"@semantic-release/git": "^10.0.1",
|
|
136
|
-
"@semantic-release/github": "^
|
|
127
|
+
"@semantic-release/github": "^12.0.6",
|
|
137
128
|
"@semantic-release/release-notes-generator": "^14.1.0",
|
|
138
129
|
"all-contributors-cli": "^6.26.1",
|
|
139
130
|
"husky": "^9.1.7",
|
|
140
131
|
"lint-staged": "^16.2.6",
|
|
141
|
-
"semantic-release": "^
|
|
132
|
+
"semantic-release": "^25.0.3"
|
|
142
133
|
},
|
|
143
134
|
"overrides": {
|
|
144
135
|
"inflight": "^1.0.7",
|
|
145
136
|
"graceful-fs": "^4.2.11",
|
|
146
|
-
"glob": "^
|
|
137
|
+
"glob": "^13.0.6",
|
|
147
138
|
"rimraf": "^4.3.0",
|
|
148
139
|
"source-map-url": "^0.4.1",
|
|
149
140
|
"source-map-resolve": "^0.6.0",
|