From 5a1b7010a0ef3e26d9a624bc2368419ad474ff93 Mon Sep 17 00:00:00 2001 From: rdlabo Date: Wed, 11 Nov 2026 10:41:28 +0900 Subject: [PATCH 1/5] feat: simplify MD3 theme setup with a preset --- README.md | 121 ++++---------------------------------- docs/configuration.md | 109 ++++++++++++++++++++++++++++++++++ docs/migration.md | 73 ++++++++++++++++++++++- docs/setup.md | 87 +++++++++++++++++++++++++++ package.json | 7 ++- scripts/build-presets.mjs | 9 +++ scripts/presets.test.mjs | 50 ++++++++++++++++ src/config.ts | 12 ++++ src/index.ts | 1 + 9 files changed, 356 insertions(+), 113 deletions(-) create mode 100644 docs/configuration.md create mode 100644 docs/setup.md create mode 100644 scripts/build-presets.mjs create mode 100644 scripts/presets.test.mjs create mode 100644 src/config.ts diff --git a/README.md b/README.md index b71182c2..6495759a 100644 --- a/README.md +++ b/README.md @@ -14,63 +14,13 @@ Designed for compatibility with `@rdlabo/ionic-theme-ios27`, so one markup tree ## Installation -In an existing Ionic project: +Use the [setup guide](docs/setup.md) to install the package, import +`@rdlabo/ionic-theme-md3/preset/default.css`, and pass `md3ThemeConfig()` to your +existing Ionic initializer. Ionic `>=8.8.0 <10` is supported. Apps on older Ionic +versions can use `@rdlabo/ionic-theme-md3@1.0.2`. -```bash -npm install @rdlabo/ionic-theme-md3 -``` - -Note: **If you use @ionic/core@ < 8.8.0**, use @rdlabo/ionic-theme-md3@1.0.2. - -Import the theme in your project's main CSS file (e.g., `src/styles.scss`) **after Ionic's core styles**. This order allows the MD default font to apply while preserving your application's `--ion-font-family` override. - -```css -@import '@rdlabo/ionic-theme-md3/dist/css/default-variables.css'; -@import '@rdlabo/ionic-theme-md3/dist/css/ionic-theme-md3.css'; -``` - -### Configure animations - -If you installed only the MD3 theme, configure its animation as follows. - -```ts -import { isPlatform } from '@ionic/core'; // or @ionic/angular (Ionic 9), @ionic/angular/standalone (Ionic 8), @ionic/react, @ionic/vue -import { mdTransitionAnimation } from '@rdlabo/ionic-theme-md3'; - -// Angular -provideIonicAngular({ - ... - navAnimation: isPlatform('ios') ? undefined: mdTransitionAnimation, -}); - -// React -setupIonicReact({ - ... - navAnimation: isPlatform('ios') ? undefined: mdTransitionAnimation, -}); - -// Vue -createApp(App) - .use(IonicVue, { - ... - navAnimation: isPlatform('ios') ? undefined: mdTransitionAnimation, -}) -``` - -### Check the theme - -Test on Android. When previewing on desktop, set Ionic mode to `md` in your existing framework initialization config (for example `mode: 'md'`). - -Use this markup to preview the inset grouped list look. For the list structure the theme expects, see [Using ion-item-group](https://docs.rdlabo.dev/projects/ionic-theme-md3/docs/using-ion-item-group). - -```html - - - Notifications - Appearance - - -``` +For existing apps, follow the [optional wrapper migration](docs/migration.md#optional-adopt-the-setup-wrappers). +For individual CSS files and animation settings, use [configuration](docs/configuration.md). ### Android Settings appearance @@ -86,69 +36,20 @@ for changes to toolbar, list and toggle dimensions. ### Optional: use the MD3 and iOS 27 themes together -Install the iOS 27 theme to style both Ionic modes from the same application. - -The current releases of both themes require `@ionic/core` 8.8.1 or later. Upgrade Ionic before using this setup if your application is on 8.8.0 or earlier. - -```bash -npm install @rdlabo/ionic-theme-ios27 -``` - -When your global stylesheet uses Sass, initialize the themes in this order: - -```scss -@use '@rdlabo/ionic-theme-ios27/src/styles/default-variables.scss' as ios27-vars; -@use '@rdlabo/ionic-theme-ios27/src/styles/ionic-theme-ios27.scss'; -@use '@rdlabo/ionic-theme-ios27/src/styles/ionic-theme-ios27-dark-class.scss'; -@use '@rdlabo/ionic-theme-ios27/src/styles/md-remove-ios-class-effect.scss'; -@use '@rdlabo/ionic-theme-md3/dist/css/default-variables.css' as md3-vars; -@use '@rdlabo/ionic-theme-md3/dist/css/ionic-theme-md3.css'; -``` - -The example uses Ionic's class-based dark mode. Your global stylesheet must also load Ionic's matching dark palette, such as `@ionic/angular/css/palettes/dark.class.css` for Angular. When using `dark-system` or `dark-always`, select the same variant for both Ionic's palette and the iOS 27 theme. See Ionic's [Dark Mode documentation](https://ionicframework.com/docs/theming/dark-mode). The explicit `ios27-vars` and `md3-vars` namespaces prevent the two variable modules from using the same default namespace. - -Configure both transition implementations when both themes are installed: - -```ts -import { isPlatform } from '@ionic/core'; // or @ionic/angular (Ionic 9), @ionic/angular/standalone (Ionic 8), @ionic/react, @ionic/vue -import { iosTransitionAnimation, popoverEnterAnimation, popoverLeaveAnimation } from '@rdlabo/ionic-theme-ios27'; -import { mdTransitionAnimation } from '@rdlabo/ionic-theme-md3'; - -// Angular -provideIonicAngular({ - ... - navAnimation: isPlatform('ios') ? iosTransitionAnimation : mdTransitionAnimation, - popoverEnter: isPlatform('ios') ? popoverEnterAnimation : undefined, - popoverLeave: isPlatform('ios') ? popoverLeaveAnimation : undefined, -}); - -// React -setupIonicReact({ - ... - navAnimation: isPlatform('ios') ? iosTransitionAnimation : mdTransitionAnimation, - popoverEnter: isPlatform('ios') ? popoverEnterAnimation : undefined, - popoverLeave: isPlatform('ios') ? popoverLeaveAnimation : undefined, -}); - -// Vue -createApp(App) - .use(IonicVue, { - ... - navAnimation: isPlatform('ios') ? iosTransitionAnimation : mdTransitionAnimation, - popoverEnter: isPlatform('ios') ? popoverEnterAnimation : undefined, - popoverLeave: isPlatform('ios') ? popoverLeaveAnimation : undefined, - }); -``` +Follow [combined theme configuration](docs/configuration.md#use-md3-and-ios-27-together) +for stylesheet ordering and platform-based animation selection. ## Documentation +- [Setup](docs/setup.md) — install and configure the theme with the preset and configuration helper. +- [Configuration](docs/configuration.md) — individual stylesheets, animations and existing mode selection. - [Android dynamic colors](docs/dynamic-colors.md) — opt-in Material You setup, light/dark appearance, lifecycle and role mapping. - [Color system](docs/color-system.md) — Ionic palette defaults, optional Material roles and component color assignments. - [Android Settings appearance](docs/android-settings.md) — default geometry, CSS font defaults and Ionic customization. - [Using ion-item-group](https://docs.rdlabo.dev/projects/ionic-theme-md3/docs/using-ion-item-group) — shared inset-list markup for iOS 27 and MD3. - [Special markup](https://docs.rdlabo.dev/projects/ionic-theme-md3/docs/special-markup) — opt-in component combinations used by the demo. - [ESLint](https://docs.rdlabo.dev/projects/ionic-theme-md3/docs/eslint) — check list structure with ESLint rules. -- [Migration](https://docs.rdlabo.dev/projects/ionic-theme-md3/docs/migration) — changes required when updating theme markup. +- [Migration](docs/migration.md) — optional wrapper adoption and version-specific upgrade steps. ## Related Projects diff --git a/docs/configuration.md b/docs/configuration.md new file mode 100644 index 00000000..2294c285 --- /dev/null +++ b/docs/configuration.md @@ -0,0 +1,109 @@ +--- +title: Theme configuration +--- + +# Theme configuration + +The [setup guide](setup.md) uses the combined MD3 CSS preset and `md3ThemeConfig()`. +The individual stylesheets and animation exports support custom composition. + +## Load individual stylesheets + +Place these imports after Ionic's core CSS and your chosen Ionic dark palette: + +```css +@import '@rdlabo/ionic-theme-md3/dist/css/default-variables.css'; +@import '@rdlabo/ionic-theme-md3/dist/css/ionic-theme-md3.css'; +``` + +These two files form `preset/default.css`. Use either the preset or the individual +imports. Put application CSS overrides after the theme. + +Ionic owns dark-palette selection. Choose `dark.system.css`, `dark.class.css` or +`dark.always.css` from `@ionic/core/css/palettes/` according to your app's appearance +policy. [Dynamic Colors](dynamic-colors.md) manages `ion-palette-dark` and uses +`dark.class.css`. + +## Configure animations directly + +Use the MD3 transition for Ionic's Material Design mode in your existing initializer: + +```ts +import { isPlatform } from '@ionic/core'; +import { mdTransitionAnimation } from '@rdlabo/ionic-theme-md3'; + +const ionicConfig = { + navAnimation: isPlatform('ios') ? undefined : mdTransitionAnimation, +}; +``` + +Pass this object to Angular's `provideIonicAngular(ionicConfig)`, React's +`setupIonicReact(ionicConfig)` or Vue's `app.use(IonicVue, ionicConfig)`. Angular +imports `provideIonicAngular` from `@ionic/angular` in Ionic 9 and from +`@ionic/angular/standalone` in Ionic 8. React imports `setupIonicReact` from +`@ionic/react`, and Vue imports `IonicVue` from `@ionic/vue`. + +[Combined theme configuration](#use-md3-and-ios-27-together) shows platform-based +transitions when both themes are installed. + +## Preserve existing mode selection with the helper + +`md3ThemeConfig()` defaults to Material Design mode. Pass an explicit mode to +retain an application's existing iOS-versus-Material-Design selection: + +```ts +import { isPlatform } from '@ionic/core'; +import { md3ThemeConfig } from '@rdlabo/ionic-theme-md3'; + +const ionicConfig = md3ThemeConfig({ + mode: isPlatform('ios') ? 'ios' : 'md', +}); +``` + +Existing options take precedence over helper defaults. A custom `navAnimation` +passed to the helper is retained, including an explicit `undefined` value when the +app wants Ionic's default transition. An explicit `mode: 'ios'` selects Ionic's iOS +animation defaults. See [migration](migration.md#optional-adopt-the-setup-wrappers) +for a before-and-after example. + +## Use MD3 and iOS 27 together + +Install the iOS 27 theme to style both Ionic modes from the same application. + +The current releases of both themes require `@ionic/core` 8.8.1 or later. Upgrade Ionic before using this setup if your application is on 8.8.0 or earlier. + +```bash +npm install @rdlabo/ionic-theme-ios27 +``` + +When your global stylesheet uses Sass, initialize the themes in this order: + +```scss +@use '@rdlabo/ionic-theme-ios27/src/styles/default-variables.scss' as ios27-vars; +@use '@rdlabo/ionic-theme-ios27/src/styles/ionic-theme-ios27.scss'; +@use '@rdlabo/ionic-theme-ios27/src/styles/ionic-theme-ios27-dark-class.scss'; +@use '@rdlabo/ionic-theme-ios27/src/styles/md-remove-ios-class-effect.scss'; +@use '@rdlabo/ionic-theme-md3/dist/css/default-variables.css' as md3-vars; +@use '@rdlabo/ionic-theme-md3/dist/css/ionic-theme-md3.css'; +``` + +The example uses Ionic's class-based dark mode. Your global stylesheet must also load Ionic's matching dark palette, such as `@ionic/angular/css/palettes/dark.class.css` for Angular. When using `dark-system` or `dark-always`, select the same variant for both Ionic's palette and the iOS 27 theme. See Ionic's [Dark Mode documentation](https://ionicframework.com/docs/theming/dark-mode). The explicit `ios27-vars` and `md3-vars` namespaces prevent the two variable modules from using the same default namespace. + +Configure both transition implementations when both themes are installed: + +```ts +import { isPlatform } from '@ionic/core'; +import { iosTransitionAnimation, popoverEnterAnimation, popoverLeaveAnimation } from '@rdlabo/ionic-theme-ios27'; +import { mdTransitionAnimation } from '@rdlabo/ionic-theme-md3'; + +const ios = isPlatform('ios'); +const ionicConfig = { + ...existingIonicConfig, + navAnimation: ios ? iosTransitionAnimation : mdTransitionAnimation, + popoverEnter: ios ? popoverEnterAnimation : undefined, + popoverLeave: ios ? popoverLeaveAnimation : undefined, +}; +``` + +Pass this object to your existing framework initializer using the imports described +in [Configure animations directly](#configure-animations-directly). diff --git a/docs/migration.md b/docs/migration.md index 22221cc8..a7b2fef6 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -6,7 +6,78 @@ title: Migration Review every section newer than the version currently installed, in ascending order. For example, when upgrading from 1.x to 9.0.0, complete the 2.0.0 migration steps before reviewing 9.0.0. -Each section lists only the changes that require application code or configuration updates. +Versioned sections list changes that require application code or configuration updates. The setup-wrapper migration below is optional. + +## Optional: adopt the setup wrappers + +The CSS preset and `md3ThemeConfig()` provide a shorter setup. Existing individual +stylesheet paths and animation exports remain supported. Applications can adopt +the CSS preset and configuration helper independently. + +### Replace the theme stylesheet imports + +Before: + +```css +@import '@ionic/core/css/palettes/dark.system.css'; +@import '@rdlabo/ionic-theme-md3/dist/css/default-variables.css'; +@import '@rdlabo/ionic-theme-md3/dist/css/ionic-theme-md3.css'; +``` + +After: + +```css +@import '@ionic/core/css/palettes/dark.system.css'; +@import '@rdlabo/ionic-theme-md3/preset/default.css'; +``` + +Keep the Ionic dark palette your application already selects. The example uses +system appearance; class-controlled and always-dark applications keep their +corresponding palette. Keep Ionic's base styles before these imports and +application overrides after them. MD3 provides one preset shared by these modes. + +### Replace animation wiring + +For an app already using Material Design mode, the manual setup: + +```ts +import { mdTransitionAnimation } from '@rdlabo/ionic-theme-md3'; + +const ionicConfig = { + mode: 'md' as const, + navAnimation: mdTransitionAnimation, +}; +``` + +becomes: + +```ts +import { md3ThemeConfig } from '@rdlabo/ionic-theme-md3'; + +const ionicConfig = md3ThemeConfig(); +``` + +Pass the result to your existing framework initializer. The helper defaults to +`mode: 'md'`. If the app uses Ionic's automatic platform-based mode selection, +make that selection explicit while adopting the helper: + +```ts +import { isPlatform } from '@ionic/core'; +import { md3ThemeConfig } from '@rdlabo/ionic-theme-md3'; + +const ionicConfig = md3ThemeConfig({ + ...existingIonicConfig, + mode: existingIonicConfig.mode ?? (isPlatform('ios') ? 'ios' : 'md'), +}); +``` + +Pass an application's explicit existing mode and other options through +`md3ThemeConfig(existingIonicConfig)`. Custom animations take precedence over the +helper defaults, including an explicit `navAnimation: undefined`. For a custom +transition, keep its function in the existing configuration. See +[setup](setup.md) for framework imports and [configuration](configuration.md) +for individual APIs and mode selection. Dynamic Colors continues to use Ionic's +[class-based palette](dynamic-colors.md). ## Migrating to 9.2.0: Android Settings alignment diff --git a/docs/setup.md b/docs/setup.md new file mode 100644 index 00000000..628270a0 --- /dev/null +++ b/docs/setup.md @@ -0,0 +1,87 @@ +--- +title: Set up the MD3 theme +--- + +# Set up the MD3 theme + +Use an existing Ionic Angular, React or Vue app with Ionic `>=8.8.0 <10`. + +## Install the theme + +```sh +npm install @rdlabo/ionic-theme-md3 +``` + +## Load the preset + +Add one import to your global stylesheet after Ionic's base CSS and your selected +Ionic dark palette: + +```css +@import '@rdlabo/ionic-theme-md3/preset/default.css'; +``` + +This preset combines the default variables and MD3 component styles. When adopting +it in an existing app, replace the individual MD3 stylesheet imports. Keep your +chosen Ionic dark-palette import, such as +`@ionic/core/css/palettes/dark.system.css`, and put application overrides after the +preset. MD3 has one preset for all appearance modes. For +[Dynamic Colors](dynamic-colors.md), select Ionic's `dark.class.css` palette. + +## Configure Ionic + +Pass `md3ThemeConfig()` to the Ionic initializer your app already calls, before +rendering components. Choose the example for your framework. + +### Angular + +```ts +import { provideIonicAngular } from '@ionic/angular'; // Ionic 9 +// Ionic 8: import { provideIonicAngular } from '@ionic/angular/standalone'; +import { md3ThemeConfig } from '@rdlabo/ionic-theme-md3'; + +provideIonicAngular(md3ThemeConfig()); +``` + +### React + +```ts +import { setupIonicReact } from '@ionic/react'; +import { md3ThemeConfig } from '@rdlabo/ionic-theme-md3'; + +setupIonicReact(md3ThemeConfig()); +``` + +### Vue + +```ts +import { IonicVue } from '@ionic/vue'; +import { md3ThemeConfig } from '@rdlabo/ionic-theme-md3'; + +app.use(IonicVue, md3ThemeConfig()); +``` + +The helper defaults to `mode: 'md'` with the MD3 page transition. For an existing +configuration, pass `md3ThemeConfig(existingIonicConfig)` to retain its explicit +options, including custom animations. An explicit `mode: 'ios'` applies Ionic's +iOS animation defaults. The helper returns its result synchronously and can be +imported during server rendering. + +## Preview a screen + +Start your app's usual development server. Open a page containing this markup, +using your framework's component syntax: + +```html + + + Notifications + Appearance + + +``` + +Check the grouped list, navigate between pages, and switch the device appearance +using your chosen Ionic dark-palette policy. See [list structure](using-ion-item-group.md) +for the expected grouped markup and [configuration](configuration.md) for individual +stylesheets, animations and existing platform-based mode selection. diff --git a/package.json b/package.json index 6c73d7d4..2be8d216 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "import": "./dist/index.js" }, "./dist/css/*": "./dist/css/*", + "./preset/default.css": "./dist/preset/default.css", "./src/styles/*": "./src/styles/*", "./dynamic-colors": { "types": "./dist/dynamic-colors.d.ts", @@ -33,14 +34,16 @@ "prebuild": "rm -rf dist", "build": "npm run build:css && npm run build:ts", "prebuild:css": "rdlabo-copy-structured-list src/styles/utils/structured-list.scss", - "build:css": "rm -rf dist/css && sass src/styles:dist/css --style=compressed --no-source-map", + "build:css": "rm -rf dist/css && sass src/styles:dist/css --style=compressed --no-source-map && npm run build:presets", + "build:presets": "node scripts/build-presets.mjs", "build:ts": "tsc --noEmit && rdlabo-build-theme", "build:demo": "npm run build && cd demo && npm install && npm run build -- --configuration=production", "lint": "prettier --check \"./**/*.{scss,ts}\" && prettier --parser angular --check \"./**/*.html\"", "fmt": "prettier --write \"./**/*.{scss,ts}\" && prettier --parser angular --write \"./**/*.html\"", "release": "np --no-tests --no-publish", "prepublishOnly": "npm run build", - "test:esm": "rdlabo-check-esm", + "test:esm": "rdlabo-check-esm && node --test scripts/presets.test.mjs", + "test:presets": "npm run build && node --test scripts/presets.test.mjs", "test:dynamic-colors": "npm --prefix demo run test:dynamic-colors" }, "repository": { diff --git a/scripts/build-presets.mjs b/scripts/build-presets.mjs new file mode 100644 index 00000000..d43e207f --- /dev/null +++ b/scripts/build-presets.mjs @@ -0,0 +1,9 @@ +import { mkdir, readFile, rm, writeFile } from 'node:fs/promises'; + +const theme = await Promise.all( + ['default-variables', 'ionic-theme-md3'].map((name) => readFile(new URL(`../dist/css/${name}.css`, import.meta.url), 'utf8')), +); +const output = new URL('../dist/preset/', import.meta.url); +await rm(output, { recursive: true, force: true }); +await mkdir(output, { recursive: true }); +await writeFile(new URL('default.css', output), `${theme.join('\n')}\n`); diff --git a/scripts/presets.test.mjs b/scripts/presets.test.mjs new file mode 100644 index 00000000..d7de697b --- /dev/null +++ b/scripts/presets.test.mjs @@ -0,0 +1,50 @@ +import assert from 'node:assert/strict'; +import { execFileSync } from 'node:child_process'; +import { mkdtemp, readFile, readdir, rm, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { test } from 'node:test'; +import { md3ThemeConfig, mdTransitionAnimation } from '../dist/index.js'; + +test('MD3 configuration supports defaults and application overrides during SSR', () => { + assert.equal(md3ThemeConfig().mode, 'md'); + assert.equal(md3ThemeConfig().navAnimation, mdTransitionAnimation); + assert.equal(md3ThemeConfig({ mode: undefined }).mode, 'md'); + assert.deepEqual(md3ThemeConfig({ mode: 'ios' }), { mode: 'ios' }); + const customAnimation = () => {}; + const existing = Object.freeze({ mode: 'md', navAnimation: customAnimation, animated: false }); + assert.deepEqual(md3ThemeConfig(existing), existing); + assert.equal(md3ThemeConfig({ navAnimation: undefined }).navAnimation, undefined); +}); + +test('the single MD3 preset is ordered, exported and packed without stale variants', async () => { + const cache = await mkdtemp(join(tmpdir(), 'md3-preset-pack-')); + try { + await writeFile(new URL('../dist/preset/stale.css', import.meta.url), 'stale'); + execFileSync(process.execPath, ['scripts/build-presets.mjs'], { cwd: new URL('../', import.meta.url) }); + assert.deepEqual(await readdir(new URL('../dist/preset/', import.meta.url)), ['default.css']); + const [packed] = JSON.parse( + execFileSync('npm', ['pack', '--dry-run', '--ignore-scripts', '--json', '--cache', cache], { + cwd: new URL('../', import.meta.url), + encoding: 'utf8', + }), + ); + assert.deepEqual( + packed.files.map(({ path }) => path).filter((path) => path.startsWith('dist/preset/')), + ['dist/preset/default.css'], + ); + const url = import.meta.resolve('@rdlabo/ionic-theme-md3/preset/default.css'); + const css = await readFile(new URL(url), 'utf8'); + const expected = await Promise.all( + ['default-variables', 'ionic-theme-md3'].map((name) => readFile(new URL(`../dist/css/${name}.css`, import.meta.url), 'utf8')), + ); + assert.equal(css, `${expected.join('\n')}\n`); + assert(!css.includes('@import')); + assert(!css.includes('sourceMappingURL=')); + for (const mode of ['system', 'class', 'always']) { + assert.throws(() => import.meta.resolve(`@rdlabo/ionic-theme-md3/preset/${mode}.css`), { code: 'ERR_PACKAGE_PATH_NOT_EXPORTED' }); + } + } finally { + await rm(cache, { recursive: true, force: true }); + } +}); diff --git a/src/config.ts b/src/config.ts new file mode 100644 index 00000000..1afe1107 --- /dev/null +++ b/src/config.ts @@ -0,0 +1,12 @@ +import type { IonicConfig } from '@ionic/core/components'; +import { mdTransitionAnimation } from './transition/md.transition'; + +/** Apply MD3 defaults before passing the result to your framework's Ionic initializer. */ +export const md3ThemeConfig = (existing: IonicConfig = {}): IonicConfig => { + const mode = existing.mode ?? 'md'; + return { + ...(mode === 'md' ? { navAnimation: mdTransitionAnimation } : {}), + ...existing, + mode, + }; +}; diff --git a/src/index.ts b/src/index.ts index 8dc6aaa5..65724e4d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,5 @@ export * from './transition/md.transition'; +export { md3ThemeConfig } from './config'; export { materialToIonicColors, materialToMd3Colors, materialColorRoles, enableDynamicColors } from './dynamic-colors'; export type { MaterialColorScheme, From bcbdbc6f4cee235703f6a363d71cb08dd6958d86 Mon Sep 17 00:00:00 2001 From: rdlabo Date: Wed, 11 Nov 2026 10:43:55 +0900 Subject: [PATCH 2/5] docs: show setup migration as diffs --- docs/migration.md | 44 +++++++++++++++----------------------------- 1 file changed, 15 insertions(+), 29 deletions(-) diff --git a/docs/migration.md b/docs/migration.md index a7b2fef6..9dfba414 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -16,19 +16,11 @@ the CSS preset and configuration helper independently. ### Replace the theme stylesheet imports -Before: - -```css -@import '@ionic/core/css/palettes/dark.system.css'; -@import '@rdlabo/ionic-theme-md3/dist/css/default-variables.css'; -@import '@rdlabo/ionic-theme-md3/dist/css/ionic-theme-md3.css'; -``` - -After: - -```css -@import '@ionic/core/css/palettes/dark.system.css'; -@import '@rdlabo/ionic-theme-md3/preset/default.css'; +```diff + @import '@ionic/core/css/palettes/dark.system.css'; +-@import '@rdlabo/ionic-theme-md3/dist/css/default-variables.css'; +-@import '@rdlabo/ionic-theme-md3/dist/css/ionic-theme-md3.css'; ++@import '@rdlabo/ionic-theme-md3/preset/default.css'; ``` Keep the Ionic dark palette your application already selects. The example uses @@ -38,23 +30,17 @@ application overrides after them. MD3 provides one preset shared by these modes. ### Replace animation wiring -For an app already using Material Design mode, the manual setup: - -```ts -import { mdTransitionAnimation } from '@rdlabo/ionic-theme-md3'; - -const ionicConfig = { - mode: 'md' as const, - navAnimation: mdTransitionAnimation, -}; -``` - -becomes: +For an app already using Material Design mode, replace the manual setup as follows. -```ts -import { md3ThemeConfig } from '@rdlabo/ionic-theme-md3'; - -const ionicConfig = md3ThemeConfig(); +```diff +-import { mdTransitionAnimation } from '@rdlabo/ionic-theme-md3'; ++import { md3ThemeConfig } from '@rdlabo/ionic-theme-md3'; + +-const ionicConfig = { +- mode: 'md' as const, +- navAnimation: mdTransitionAnimation, +-}; ++const ionicConfig = md3ThemeConfig(); ``` Pass the result to your existing framework initializer. The helper defaults to From 7b478243e9a96440d29cf3fba778626a2e4428e3 Mon Sep 17 00:00:00 2001 From: rdlabo Date: Wed, 11 Nov 2026 10:45:18 +0900 Subject: [PATCH 3/5] docs: space migration diff markers --- docs/migration.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/migration.md b/docs/migration.md index 9dfba414..9ae86969 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -18,9 +18,9 @@ the CSS preset and configuration helper independently. ```diff @import '@ionic/core/css/palettes/dark.system.css'; --@import '@rdlabo/ionic-theme-md3/dist/css/default-variables.css'; --@import '@rdlabo/ionic-theme-md3/dist/css/ionic-theme-md3.css'; -+@import '@rdlabo/ionic-theme-md3/preset/default.css'; +- @import '@rdlabo/ionic-theme-md3/dist/css/default-variables.css'; +- @import '@rdlabo/ionic-theme-md3/dist/css/ionic-theme-md3.css'; ++ @import '@rdlabo/ionic-theme-md3/preset/default.css'; ``` Keep the Ionic dark palette your application already selects. The example uses @@ -33,14 +33,14 @@ application overrides after them. MD3 provides one preset shared by these modes. For an app already using Material Design mode, replace the manual setup as follows. ```diff --import { mdTransitionAnimation } from '@rdlabo/ionic-theme-md3'; -+import { md3ThemeConfig } from '@rdlabo/ionic-theme-md3'; - --const ionicConfig = { -- mode: 'md' as const, -- navAnimation: mdTransitionAnimation, --}; -+const ionicConfig = md3ThemeConfig(); +- import { mdTransitionAnimation } from '@rdlabo/ionic-theme-md3'; ++ import { md3ThemeConfig } from '@rdlabo/ionic-theme-md3'; + +- const ionicConfig = { +- mode: 'md' as const, +- navAnimation: mdTransitionAnimation, +- }; ++ const ionicConfig = md3ThemeConfig(); ``` Pass the result to your existing framework initializer. The helper defaults to From afa6be2d413c5bfb7d86418c71b0c7452f866f9c Mon Sep 17 00:00:00 2001 From: rdlabo Date: Wed, 11 Nov 2026 10:51:05 +0900 Subject: [PATCH 4/5] refactor: expose theme configuration as an object --- README.md | 6 +++--- docs/configuration.md | 40 +++++++++++++++++++++++++++------------- docs/migration.md | 35 +++++++++++++++++++---------------- docs/setup.md | 27 ++++++++++++++++++--------- scripts/presets.test.mjs | 17 +++++++++-------- src/config.ts | 12 ++++-------- 6 files changed, 80 insertions(+), 57 deletions(-) diff --git a/README.md b/README.md index 6495759a..66692565 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,8 @@ Designed for compatibility with `@rdlabo/ionic-theme-ios27`, so one markup tree ## Installation Use the [setup guide](docs/setup.md) to install the package, import -`@rdlabo/ionic-theme-md3/preset/default.css`, and pass `md3ThemeConfig()` to your -existing Ionic initializer. Ionic `>=8.8.0 <10` is supported. Apps on older Ionic +`@rdlabo/ionic-theme-md3/preset/default.css`, and spread `md3ThemeConfig` into your +existing Ionic initializer's options. Ionic `>=8.8.0 <10` is supported. Apps on older Ionic versions can use `@rdlabo/ionic-theme-md3@1.0.2`. For existing apps, follow the [optional wrapper migration](docs/migration.md#optional-adopt-the-setup-wrappers). @@ -41,7 +41,7 @@ for stylesheet ordering and platform-based animation selection. ## Documentation -- [Setup](docs/setup.md) — install and configure the theme with the preset and configuration helper. +- [Setup](docs/setup.md) — install and configure the theme with the preset and configuration object. - [Configuration](docs/configuration.md) — individual stylesheets, animations and existing mode selection. - [Android dynamic colors](docs/dynamic-colors.md) — opt-in Material You setup, light/dark appearance, lifecycle and role mapping. - [Color system](docs/color-system.md) — Ionic palette defaults, optional Material roles and component color assignments. diff --git a/docs/configuration.md b/docs/configuration.md index 2294c285..bbd3fb11 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -4,7 +4,7 @@ title: Theme configuration # Theme configuration -The [setup guide](setup.md) uses the combined MD3 CSS preset and `md3ThemeConfig()`. +The [setup guide](setup.md) uses the combined MD3 CSS preset and `md3ThemeConfig`. The individual stylesheets and animation exports support custom composition. ## Load individual stylesheets @@ -46,25 +46,26 @@ imports `provideIonicAngular` from `@ionic/angular` in Ionic 9 and from [Combined theme configuration](#use-md3-and-ios-27-together) shows platform-based transitions when both themes are installed. -## Preserve existing mode selection with the helper +## Preserve existing mode selection -`md3ThemeConfig()` defaults to Material Design mode. Pass an explicit mode to -retain an application's existing iOS-versus-Material-Design selection: +`md3ThemeConfig` includes both `mode: 'md'` and the MD3 transition. Select its +configuration when the application selects Material Design mode: ```ts import { isPlatform } from '@ionic/core'; import { md3ThemeConfig } from '@rdlabo/ionic-theme-md3'; -const ionicConfig = md3ThemeConfig({ - mode: isPlatform('ios') ? 'ios' : 'md', -}); +const ionicConfig = { + ...(isPlatform('ios') ? { mode: 'ios' as const } : md3ThemeConfig), + // animated: false, +}; ``` -Existing options take precedence over helper defaults. A custom `navAnimation` -passed to the helper is retained, including an explicit `undefined` value when the -app wants Ionic's default transition. An explicit `mode: 'ios'` selects Ionic's iOS -animation defaults. See [migration](migration.md#optional-adopt-the-setup-wrappers) -for a before-and-after example. +The iOS branch uses Ionic's standard iOS appearance and animations. Options after +the spread override the selected defaults, including an explicit +`navAnimation: undefined` for Ionic's default transition. See +[migration](migration.md#optional-adopt-the-setup-wrappers) for a before-and-after +example. ## Use MD3 and iOS 27 together @@ -98,7 +99,7 @@ import { mdTransitionAnimation } from '@rdlabo/ionic-theme-md3'; const ios = isPlatform('ios'); const ionicConfig = { - ...existingIonicConfig, + // Add application options here. navAnimation: ios ? iosTransitionAnimation : mdTransitionAnimation, popoverEnter: ios ? popoverEnterAnimation : undefined, popoverLeave: ios ? popoverLeaveAnimation : undefined, @@ -107,3 +108,16 @@ const ionicConfig = { Pass this object to your existing framework initializer using the imports described in [Configure animations directly](#configure-animations-directly). + +The exported theme configuration objects can also select both modes: + +```ts +import { isPlatform } from '@ionic/core'; +import { ios27ThemeConfig } from '@rdlabo/ionic-theme-ios27'; +import { md3ThemeConfig } from '@rdlabo/ionic-theme-md3'; + +const ionicConfig = { + ...(isPlatform('ios') ? ios27ThemeConfig : md3ThemeConfig), + // animated: false, +}; +``` diff --git a/docs/migration.md b/docs/migration.md index 9ae86969..49fcc02a 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -10,9 +10,9 @@ Versioned sections list changes that require application code or configuration u ## Optional: adopt the setup wrappers -The CSS preset and `md3ThemeConfig()` provide a shorter setup. Existing individual +The CSS preset and `md3ThemeConfig` provide a shorter setup. Existing individual stylesheet paths and animation exports remain supported. Applications can adopt -the CSS preset and configuration helper independently. +the CSS preset and configuration object independently. ### Replace the theme stylesheet imports @@ -40,29 +40,32 @@ For an app already using Material Design mode, replace the manual setup as follo - mode: 'md' as const, - navAnimation: mdTransitionAnimation, - }; -+ const ionicConfig = md3ThemeConfig(); ++ const ionicConfig = { ++ ...md3ThemeConfig, ++ // animated: false, ++ }; ``` -Pass the result to your existing framework initializer. The helper defaults to -`mode: 'md'`. If the app uses Ionic's automatic platform-based mode selection, -make that selection explicit while adopting the helper: +Pass the object to your existing framework initializer. The preset configuration +sets `mode: 'md'` and the matching MD3 transition. For an application that chooses +its appearance by platform, choose the configuration for the selected mode: ```ts import { isPlatform } from '@ionic/core'; import { md3ThemeConfig } from '@rdlabo/ionic-theme-md3'; -const ionicConfig = md3ThemeConfig({ - ...existingIonicConfig, - mode: existingIonicConfig.mode ?? (isPlatform('ios') ? 'ios' : 'md'), -}); +const ionicConfig = { + ...(isPlatform('ios') ? { mode: 'ios' as const } : md3ThemeConfig), + // animated: false, +}; ``` -Pass an application's explicit existing mode and other options through -`md3ThemeConfig(existingIonicConfig)`. Custom animations take precedence over the -helper defaults, including an explicit `navAnimation: undefined`. For a custom -transition, keep its function in the existing configuration. See -[setup](setup.md) for framework imports and [configuration](configuration.md) -for individual APIs and mode selection. Dynamic Colors continues to use Ionic's +The application owns mode selection. Retain an existing explicit mode by selecting +the matching theme configuration. Put application settings after the spread so +custom animations take precedence, including an explicit +`navAnimation: undefined` for Ionic's default transition. See [setup](setup.md) +for framework imports and [configuration](configuration.md) for individual APIs +and combined-theme selection. Dynamic Colors continues to use Ionic's [class-based palette](dynamic-colors.md). ## Migrating to 9.2.0: Android Settings alignment diff --git a/docs/setup.md b/docs/setup.md index 628270a0..aac4524e 100644 --- a/docs/setup.md +++ b/docs/setup.md @@ -30,7 +30,7 @@ preset. MD3 has one preset for all appearance modes. For ## Configure Ionic -Pass `md3ThemeConfig()` to the Ionic initializer your app already calls, before +Spread `md3ThemeConfig` into the options passed to the Ionic initializer your app already calls, before rendering components. Choose the example for your framework. ### Angular @@ -40,7 +40,10 @@ import { provideIonicAngular } from '@ionic/angular'; // Ionic 9 // Ionic 8: import { provideIonicAngular } from '@ionic/angular/standalone'; import { md3ThemeConfig } from '@rdlabo/ionic-theme-md3'; -provideIonicAngular(md3ThemeConfig()); +provideIonicAngular({ + ...md3ThemeConfig, + // animated: false, +}); ``` ### React @@ -49,7 +52,10 @@ provideIonicAngular(md3ThemeConfig()); import { setupIonicReact } from '@ionic/react'; import { md3ThemeConfig } from '@rdlabo/ionic-theme-md3'; -setupIonicReact(md3ThemeConfig()); +setupIonicReact({ + ...md3ThemeConfig, + // animated: false, +}); ``` ### Vue @@ -58,14 +64,17 @@ setupIonicReact(md3ThemeConfig()); import { IonicVue } from '@ionic/vue'; import { md3ThemeConfig } from '@rdlabo/ionic-theme-md3'; -app.use(IonicVue, md3ThemeConfig()); +app.use(IonicVue, { + ...md3ThemeConfig, + // animated: false, +}); ``` -The helper defaults to `mode: 'md'` with the MD3 page transition. For an existing -configuration, pass `md3ThemeConfig(existingIonicConfig)` to retain its explicit -options, including custom animations. An explicit `mode: 'ios'` applies Ionic's -iOS animation defaults. The helper returns its result synchronously and can be -imported during server rendering. +The configuration sets `mode: 'md'` and the MD3 page transition. Add application +options after the spread to override these defaults. For platform-dependent +appearance, select the configuration matching the mode as shown in +[configuration](configuration.md#preserve-existing-mode-selection). +The exported object supports imports during server rendering. ## Preview a screen diff --git a/scripts/presets.test.mjs b/scripts/presets.test.mjs index d7de697b..a0d8fe97 100644 --- a/scripts/presets.test.mjs +++ b/scripts/presets.test.mjs @@ -6,15 +6,16 @@ import { join } from 'node:path'; import { test } from 'node:test'; import { md3ThemeConfig, mdTransitionAnimation } from '../dist/index.js'; -test('MD3 configuration supports defaults and application overrides during SSR', () => { - assert.equal(md3ThemeConfig().mode, 'md'); - assert.equal(md3ThemeConfig().navAnimation, mdTransitionAnimation); - assert.equal(md3ThemeConfig({ mode: undefined }).mode, 'md'); - assert.deepEqual(md3ThemeConfig({ mode: 'ios' }), { mode: 'ios' }); +test('MD3 configuration supports object spread and overrides during SSR', () => { + assert.equal(md3ThemeConfig.mode, 'md'); + assert.equal(md3ThemeConfig.navAnimation, mdTransitionAnimation); const customAnimation = () => {}; - const existing = Object.freeze({ mode: 'md', navAnimation: customAnimation, animated: false }); - assert.deepEqual(md3ThemeConfig(existing), existing); - assert.equal(md3ThemeConfig({ navAnimation: undefined }).navAnimation, undefined); + const config = { ...md3ThemeConfig, navAnimation: customAnimation, animated: false }; + assert.equal(config.navAnimation, customAnimation); + assert.equal(config.animated, false); + assert.equal(md3ThemeConfig.navAnimation, mdTransitionAnimation); + assert.equal({ ...md3ThemeConfig, navAnimation: undefined }.navAnimation, undefined); + assert.equal({ ...md3ThemeConfig, mode: undefined }.mode, undefined); }); test('the single MD3 preset is ordered, exported and packed without stale variants', async () => { diff --git a/src/config.ts b/src/config.ts index 1afe1107..2bb8f844 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,12 +1,8 @@ import type { IonicConfig } from '@ionic/core/components'; import { mdTransitionAnimation } from './transition/md.transition'; -/** Apply MD3 defaults before passing the result to your framework's Ionic initializer. */ -export const md3ThemeConfig = (existing: IonicConfig = {}): IonicConfig => { - const mode = existing.mode ?? 'md'; - return { - ...(mode === 'md' ? { navAnimation: mdTransitionAnimation } : {}), - ...existing, - mode, - }; +/** Spread MD3 defaults into your framework's Ionic initialization options. */ +export const md3ThemeConfig: IonicConfig = { + mode: 'md', + navAnimation: mdTransitionAnimation, }; From b953ec11ea1af9cda6465cf4c02bb64010e7db12 Mon Sep 17 00:00:00 2001 From: rdlabo Date: Wed, 11 Nov 2026 10:55:56 +0900 Subject: [PATCH 5/5] refactor: expose bundled theme CSS through styles --- README.md | 8 ++++---- docs/configuration.md | 6 +++--- docs/migration.md | 14 +++++++------- docs/setup.md | 8 ++++---- package.json | 2 +- scripts/build-presets.mjs | 5 +++-- scripts/presets.test.mjs | 18 ++++++++++-------- 7 files changed, 32 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 66692565..227a5cdd 100644 --- a/README.md +++ b/README.md @@ -15,11 +15,11 @@ Designed for compatibility with `@rdlabo/ionic-theme-ios27`, so one markup tree ## Installation Use the [setup guide](docs/setup.md) to install the package, import -`@rdlabo/ionic-theme-md3/preset/default.css`, and spread `md3ThemeConfig` into your +`@rdlabo/ionic-theme-md3/styles/theme.css`, and spread `md3ThemeConfig` into your existing Ionic initializer's options. Ionic `>=8.8.0 <10` is supported. Apps on older Ionic versions can use `@rdlabo/ionic-theme-md3@1.0.2`. -For existing apps, follow the [optional wrapper migration](docs/migration.md#optional-adopt-the-setup-wrappers). +For existing apps, follow the [optional setup simplification](docs/migration.md#optional-simplify-the-setup). For individual CSS files and animation settings, use [configuration](docs/configuration.md). ### Android Settings appearance @@ -41,7 +41,7 @@ for stylesheet ordering and platform-based animation selection. ## Documentation -- [Setup](docs/setup.md) — install and configure the theme with the preset and configuration object. +- [Setup](docs/setup.md) — install and configure the theme with the theme stylesheet and configuration object. - [Configuration](docs/configuration.md) — individual stylesheets, animations and existing mode selection. - [Android dynamic colors](docs/dynamic-colors.md) — opt-in Material You setup, light/dark appearance, lifecycle and role mapping. - [Color system](docs/color-system.md) — Ionic palette defaults, optional Material roles and component color assignments. @@ -49,7 +49,7 @@ for stylesheet ordering and platform-based animation selection. - [Using ion-item-group](https://docs.rdlabo.dev/projects/ionic-theme-md3/docs/using-ion-item-group) — shared inset-list markup for iOS 27 and MD3. - [Special markup](https://docs.rdlabo.dev/projects/ionic-theme-md3/docs/special-markup) — opt-in component combinations used by the demo. - [ESLint](https://docs.rdlabo.dev/projects/ionic-theme-md3/docs/eslint) — check list structure with ESLint rules. -- [Migration](docs/migration.md) — optional wrapper adoption and version-specific upgrade steps. +- [Migration](docs/migration.md) — optional setup simplification and version-specific upgrade steps. ## Related Projects diff --git a/docs/configuration.md b/docs/configuration.md index bbd3fb11..98d7e715 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -4,7 +4,7 @@ title: Theme configuration # Theme configuration -The [setup guide](setup.md) uses the combined MD3 CSS preset and `md3ThemeConfig`. +The [setup guide](setup.md) uses the combined MD3 theme stylesheet and `md3ThemeConfig`. The individual stylesheets and animation exports support custom composition. ## Load individual stylesheets @@ -16,7 +16,7 @@ Place these imports after Ionic's core CSS and your chosen Ionic dark palette: @import '@rdlabo/ionic-theme-md3/dist/css/ionic-theme-md3.css'; ``` -These two files form `preset/default.css`. Use either the preset or the individual +These two files form `styles/theme.css`. Use either the theme stylesheet or the individual imports. Put application CSS overrides after the theme. Ionic owns dark-palette selection. Choose `dark.system.css`, `dark.class.css` or @@ -64,7 +64,7 @@ const ionicConfig = { The iOS branch uses Ionic's standard iOS appearance and animations. Options after the spread override the selected defaults, including an explicit `navAnimation: undefined` for Ionic's default transition. See -[migration](migration.md#optional-adopt-the-setup-wrappers) for a before-and-after +[migration](migration.md#optional-simplify-the-setup) for a before-and-after example. ## Use MD3 and iOS 27 together diff --git a/docs/migration.md b/docs/migration.md index 49fcc02a..4a098465 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -6,13 +6,13 @@ title: Migration Review every section newer than the version currently installed, in ascending order. For example, when upgrading from 1.x to 9.0.0, complete the 2.0.0 migration steps before reviewing 9.0.0. -Versioned sections list changes that require application code or configuration updates. The setup-wrapper migration below is optional. +Versioned sections list changes that require application code or configuration updates. The setup simplification below is optional. -## Optional: adopt the setup wrappers +## Optional: simplify the setup -The CSS preset and `md3ThemeConfig` provide a shorter setup. Existing individual +The theme stylesheet and `md3ThemeConfig` provide a shorter setup. Existing individual stylesheet paths and animation exports remain supported. Applications can adopt -the CSS preset and configuration object independently. +the theme stylesheet and configuration object independently. ### Replace the theme stylesheet imports @@ -20,13 +20,13 @@ the CSS preset and configuration object independently. @import '@ionic/core/css/palettes/dark.system.css'; - @import '@rdlabo/ionic-theme-md3/dist/css/default-variables.css'; - @import '@rdlabo/ionic-theme-md3/dist/css/ionic-theme-md3.css'; -+ @import '@rdlabo/ionic-theme-md3/preset/default.css'; ++ @import '@rdlabo/ionic-theme-md3/styles/theme.css'; ``` Keep the Ionic dark palette your application already selects. The example uses system appearance; class-controlled and always-dark applications keep their corresponding palette. Keep Ionic's base styles before these imports and -application overrides after them. MD3 provides one preset shared by these modes. +application overrides after them. MD3 provides one theme stylesheet shared by these modes. ### Replace animation wiring @@ -46,7 +46,7 @@ For an app already using Material Design mode, replace the manual setup as follo + }; ``` -Pass the object to your existing framework initializer. The preset configuration +Pass the object to your existing framework initializer. The theme configuration sets `mode: 'md'` and the matching MD3 transition. For an application that chooses its appearance by platform, choose the configuration for the selected mode: diff --git a/docs/setup.md b/docs/setup.md index aac4524e..d0009e60 100644 --- a/docs/setup.md +++ b/docs/setup.md @@ -12,20 +12,20 @@ Use an existing Ionic Angular, React or Vue app with Ionic `>=8.8.0 <10`. npm install @rdlabo/ionic-theme-md3 ``` -## Load the preset +## Load the theme stylesheet Add one import to your global stylesheet after Ionic's base CSS and your selected Ionic dark palette: ```css -@import '@rdlabo/ionic-theme-md3/preset/default.css'; +@import '@rdlabo/ionic-theme-md3/styles/theme.css'; ``` -This preset combines the default variables and MD3 component styles. When adopting +This stylesheet combines the default variables and MD3 component styles. When adopting it in an existing app, replace the individual MD3 stylesheet imports. Keep your chosen Ionic dark-palette import, such as `@ionic/core/css/palettes/dark.system.css`, and put application overrides after the -preset. MD3 has one preset for all appearance modes. For +theme stylesheet. MD3 has one theme stylesheet for all appearance modes. For [Dynamic Colors](dynamic-colors.md), select Ionic's `dark.class.css` palette. ## Configure Ionic diff --git a/package.json b/package.json index 2be8d216..5cda3c02 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "import": "./dist/index.js" }, "./dist/css/*": "./dist/css/*", - "./preset/default.css": "./dist/preset/default.css", + "./styles/theme.css": "./dist/styles/theme.css", "./src/styles/*": "./src/styles/*", "./dynamic-colors": { "types": "./dist/dynamic-colors.d.ts", diff --git a/scripts/build-presets.mjs b/scripts/build-presets.mjs index d43e207f..81aa8207 100644 --- a/scripts/build-presets.mjs +++ b/scripts/build-presets.mjs @@ -3,7 +3,8 @@ import { mkdir, readFile, rm, writeFile } from 'node:fs/promises'; const theme = await Promise.all( ['default-variables', 'ionic-theme-md3'].map((name) => readFile(new URL(`../dist/css/${name}.css`, import.meta.url), 'utf8')), ); -const output = new URL('../dist/preset/', import.meta.url); +const output = new URL('../dist/styles/', import.meta.url); +await rm(new URL('../dist/preset/', import.meta.url), { recursive: true, force: true }); await rm(output, { recursive: true, force: true }); await mkdir(output, { recursive: true }); -await writeFile(new URL('default.css', output), `${theme.join('\n')}\n`); +await writeFile(new URL('theme.css', output), `${theme.join('\n')}\n`); diff --git a/scripts/presets.test.mjs b/scripts/presets.test.mjs index a0d8fe97..e384455f 100644 --- a/scripts/presets.test.mjs +++ b/scripts/presets.test.mjs @@ -1,6 +1,6 @@ import assert from 'node:assert/strict'; import { execFileSync } from 'node:child_process'; -import { mkdtemp, readFile, readdir, rm, writeFile } from 'node:fs/promises'; +import { mkdir, mkdtemp, readFile, readdir, rm, writeFile } from 'node:fs/promises'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { test } from 'node:test'; @@ -18,12 +18,14 @@ test('MD3 configuration supports object spread and overrides during SSR', () => assert.equal({ ...md3ThemeConfig, mode: undefined }.mode, undefined); }); -test('the single MD3 preset is ordered, exported and packed without stale variants', async () => { +test('the MD3 stylesheet is ordered, exported and packed without stale variants', async () => { const cache = await mkdtemp(join(tmpdir(), 'md3-preset-pack-')); try { - await writeFile(new URL('../dist/preset/stale.css', import.meta.url), 'stale'); + await writeFile(new URL('../dist/styles/stale.css', import.meta.url), 'stale'); + await mkdir(new URL('../dist/preset/', import.meta.url), { recursive: true }); + await writeFile(new URL('../dist/preset/default.css', import.meta.url), 'legacy'); execFileSync(process.execPath, ['scripts/build-presets.mjs'], { cwd: new URL('../', import.meta.url) }); - assert.deepEqual(await readdir(new URL('../dist/preset/', import.meta.url)), ['default.css']); + assert.deepEqual(await readdir(new URL('../dist/styles/', import.meta.url)), ['theme.css']); const [packed] = JSON.parse( execFileSync('npm', ['pack', '--dry-run', '--ignore-scripts', '--json', '--cache', cache], { cwd: new URL('../', import.meta.url), @@ -31,10 +33,10 @@ test('the single MD3 preset is ordered, exported and packed without stale varian }), ); assert.deepEqual( - packed.files.map(({ path }) => path).filter((path) => path.startsWith('dist/preset/')), - ['dist/preset/default.css'], + packed.files.map(({ path }) => path).filter((path) => path.startsWith('dist/styles/') || path.startsWith('dist/preset/')), + ['dist/styles/theme.css'], ); - const url = import.meta.resolve('@rdlabo/ionic-theme-md3/preset/default.css'); + const url = import.meta.resolve('@rdlabo/ionic-theme-md3/styles/theme.css'); const css = await readFile(new URL(url), 'utf8'); const expected = await Promise.all( ['default-variables', 'ionic-theme-md3'].map((name) => readFile(new URL(`../dist/css/${name}.css`, import.meta.url), 'utf8')), @@ -42,7 +44,7 @@ test('the single MD3 preset is ordered, exported and packed without stale varian assert.equal(css, `${expected.join('\n')}\n`); assert(!css.includes('@import')); assert(!css.includes('sourceMappingURL=')); - for (const mode of ['system', 'class', 'always']) { + for (const mode of ['default', 'system', 'class', 'always']) { assert.throws(() => import.meta.resolve(`@rdlabo/ionic-theme-md3/preset/${mode}.css`), { code: 'ERR_PACKAGE_PATH_NOT_EXPORTED' }); } } finally {