diff --git a/.storybook/preview.ts b/.storybook/preview.ts
index 56ca0421e..37517c17a 100644
--- a/.storybook/preview.ts
+++ b/.storybook/preview.ts
@@ -1,6 +1,6 @@
///
-import { html } from 'lit';
+import { type CSSResult, html } from 'lit';
import { configureTheme } from '../src/theming/config';
import type { Decorator } from '@storybook/web-components';
import { withActions } from '@storybook/addon-actions/decorator';
@@ -11,21 +11,24 @@ configureActions({
limit: 5,
});
-type ThemeImport = { default: string };
+type ThemeImport = { styles: CSSResult };
-const themes = import.meta.glob('../src/styles/themes/**/*.scss', {
- query: '?inline',
-});
-
-const getTheme = async ({ theme, variant }) => {
- const matcher = `../src/styles/themes/${variant}/${theme}.scss`;
+const themes = import.meta.glob(
+ '../src/styles/themes/**/*.css.ts',
+ {
+ eager: true,
+ import: 'styles',
+ }
+);
- const [_, resolver] = Object.entries(themes).find(([path]) => {
- return path.match(matcher);
- })!;
+const getTheme = ({ theme, variant }) => {
+ const matcher = `../src/styles/themes/${variant}/${theme}.css.ts`;
- const stylesheet = await resolver();
- return stylesheet.default;
+ for (const [path, styles] of Object.entries(themes)) {
+ if (path === matcher) {
+ return styles;
+ }
+ }
};
const getSize = (size: 'small' | 'medium' | 'large' | 'default') => {
@@ -81,22 +84,10 @@ export const globalTypes = {
},
};
-const parser = new DOMParser();
-
export const parameters = {
backgrounds: {
disable: true,
},
- docs: {
- source: {
- // Strip theme styles and wrapping container from the code preview
- transform: (code: string) =>
- parser.parseFromString(code, 'text/html').querySelector('#igc-story')
- ?.innerHTML,
- format: 'html',
- language: 'html',
- },
- },
};
export const loaders = [
diff --git a/scripts/build-styles.mjs b/scripts/build-styles.mjs
index 09ac21954..b1af8cf39 100644
--- a/scripts/build-styles.mjs
+++ b/scripts/build-styles.mjs
@@ -1,65 +1,3 @@
-import { mkdirSync as makeDir } from 'node:fs';
-import { writeFile } from 'node:fs/promises';
-import path from 'node:path';
-import { fileURLToPath } from 'node:url';
-import { globby } from 'globby';
-import * as sass from 'sass-embedded';
-import report from './report.mjs';
-import { compileSass, fromTemplate } from './sass.mjs';
+import { buildComponents, buildThemes } from './sass.mjs';
-const __dirname = path.dirname(fileURLToPath(import.meta.url));
-const DEST_DIR = path.join.bind(null, path.resolve(__dirname, '../dist'));
-
-export async function buildThemes() {
- const compiler = await sass.initAsyncCompiler();
- const paths = await globby('src/styles/themes/{light,dark}/*.scss');
-
- for (const sassFile of paths) {
- const css = await compileSass(sassFile, compiler);
-
- const outputFile = DEST_DIR(
- sassFile.replace(/\.scss$/, '.css').replace('src/styles/', '')
- );
- makeDir(path.dirname(outputFile), { recursive: true });
- await writeFile(outputFile, css, 'utf-8');
- }
-
- await compiler.dispose();
-}
-
-(async () => {
- const compiler = await sass.initAsyncCompiler();
- const start = performance.now();
-
- const paths = await globby([
- 'src/components/**/*.base.scss',
- 'src/components/**/*.common.scss',
- 'src/components/**/*.shared.scss',
- 'src/components/**/*.material.scss',
- 'src/components/**/*.bootstrap.scss',
- 'src/components/**/*.indigo.scss',
- 'src/components/**/*.fluent.scss',
- ]);
-
- try {
- await Promise.all(
- paths.map(async (path) => {
- writeFile(
- path.replace(/\.scss$/, '.css.ts'),
- fromTemplate(await compileSass(path, compiler)),
- 'utf8'
- );
- })
- );
- } catch (err) {
- await compiler.dispose();
- report.error(err);
- process.exit(1);
- }
-
- await compiler.dispose();
-
- report.success(
- `Styles generated in ${((performance.now() - start) / 1000).toFixed(2)}s`
- );
-})();
+await Promise.all([buildThemes(), buildComponents()]);
diff --git a/scripts/build.mjs b/scripts/build.mjs
index 0fc99f2c2..cd93d29a9 100644
--- a/scripts/build.mjs
+++ b/scripts/build.mjs
@@ -9,8 +9,8 @@ import {
getVsCodeHtmlCustomData,
} from 'custom-element-vs-code-integration';
import customElements from '../custom-elements.json' assert { type: 'json' };
-import { buildThemes } from './build-styles.mjs';
import report from './report.mjs';
+import { buildComponents, buildThemes } from './sass.mjs';
const exec = promisify(_exec);
@@ -39,7 +39,8 @@ async function runTask(tag, cmd) {
(async () => {
await runTask('Clean up', () => exec('npm run clean'));
- await runTask('Styles', () => exec('npm run build:styles'));
+ await runTask('Component styles', () => buildComponents(true));
+ await runTask('Themes', () => buildThemes(true));
// https://github.com/microsoft/TypeScript/issues/14619
await runTask('Components', () =>
@@ -48,8 +49,6 @@ async function runTask(tag, cmd) {
)
);
- await runTask('Themes', buildThemes);
-
await runTask('Copying release files', () =>
Promise.all([
copyFile('scripts/_package.json', DEST_DIR('package.json')),
diff --git a/scripts/sass.mjs b/scripts/sass.mjs
index dabacf9de..7632c0e5b 100644
--- a/scripts/sass.mjs
+++ b/scripts/sass.mjs
@@ -1,7 +1,17 @@
-import { readFile } from 'node:fs/promises';
+import { mkdir, readFile, writeFile } from 'node:fs/promises';
+import path from 'node:path';
import { resolve } from 'node:path';
+import { fileURLToPath } from 'node:url';
import autoprefixer from 'autoprefixer';
+import { globby } from 'globby';
import postcss from 'postcss';
+import * as sass from 'sass-embedded';
+import report from './report.mjs';
+
+const toDist = path.join.bind(
+ null,
+ path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../dist')
+);
const stripComments = () => {
return {
@@ -32,3 +42,87 @@ export async function compileSass(src, compiler) {
const out = _postProcessor.process(compiled.css).css;
return out.charCodeAt(0) === 0xfeff ? out.slice(1) : out;
}
+
+export async function buildThemes(isProduction = false) {
+ const start = performance.now();
+
+ const [compiler, paths] = await Promise.all([
+ sass.initAsyncCompiler(),
+ globby('src/styles/themes/{light,dark}/*.scss'),
+ ]);
+
+ try {
+ await Promise.all(
+ paths.map(async (sassFile) => {
+ const outputFile = isProduction
+ ? toDist(
+ sassFile.replace(/\.scss$/, '.css').replace('src/styles/', '')
+ )
+ : sassFile.replace(/\.scss$/, '.css.ts');
+
+ if (isProduction) {
+ await mkdir(path.dirname(outputFile), { recursive: true });
+ writeFile(outputFile, await compileSass(sassFile, compiler), 'utf-8');
+ } else {
+ writeFile(
+ outputFile,
+ fromTemplate(await compileSass(sassFile, compiler)),
+ 'utf-8'
+ );
+ }
+ })
+ );
+ } catch (err) {
+ await compiler.dispose();
+ report.error(err);
+ process.exit(1);
+ }
+
+ await compiler.dispose();
+
+ if (!isProduction) {
+ report.success(
+ `Themes generated in ${((performance.now() - start) / 1000).toFixed(2)}s`
+ );
+ }
+}
+
+export async function buildComponents(isProduction = false) {
+ const start = performance.now();
+ const [compiler, paths] = await Promise.all([
+ sass.initAsyncCompiler(),
+ globby([
+ 'src/components/**/*.base.scss',
+ 'src/components/**/*.common.scss',
+ 'src/components/**/*.shared.scss',
+ 'src/components/**/*.material.scss',
+ 'src/components/**/*.bootstrap.scss',
+ 'src/components/**/*.indigo.scss',
+ 'src/components/**/*.fluent.scss',
+ ]),
+ ]);
+
+ try {
+ await Promise.all(
+ paths.map(async (path) =>
+ writeFile(
+ path.replace(/\.scss$/, '.css.ts'),
+ fromTemplate(await compileSass(path, compiler)),
+ 'utf-8'
+ )
+ )
+ );
+ } catch (err) {
+ await compiler.dispose();
+ report.error(err);
+ process.exit(1);
+ }
+
+ await compiler.dispose();
+
+ if (!isProduction) {
+ report.success(
+ `Component styles generated in ${((performance.now() - start) / 1000).toFixed(2)}s`
+ );
+ }
+}