@m3ui-vue/nuxt 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Fadel
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,127 @@
1
- # Temporary Holding Version
1
+ # @m3ui-vue/nuxt
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ <p>
4
+ <a href="https://www.npmjs.com/package/@m3ui-vue/nuxt"><img src="https://img.shields.io/npm/v/@m3ui-vue/nuxt?color=blue" alt="npm version"></a>
5
+ <a href="https://www.npmjs.com/package/@m3ui-vue/nuxt"><img src="https://img.shields.io/npm/l/@m3ui-vue/nuxt" alt="license"></a>
6
+ </p>
7
+
8
+ Nuxt module for [m3ui-vue](https://m3ui.dev), the Material Design 3 component library for Vue 3 + Tailwind CSS v4.
9
+
10
+ It installs the library's plugin, auto-imports its components and composables, adds its stylesheet, and puts the
11
+ user's theme (dark mode, palette, contrast) on the server-rendered page before the first paint.
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ pnpm add @m3ui-vue/nuxt @m3ui-vue/m3ui-vue
17
+ pnpm add -D tailwindcss @tailwindcss/vite
18
+ ```
19
+
20
+ ```ts
21
+ // nuxt.config.ts
22
+ import tailwindcss from '@tailwindcss/vite'
23
+
24
+ export default defineNuxtConfig({
25
+ modules: ['@m3ui-vue/nuxt'],
26
+ css: ['~/assets/main.css'],
27
+ vite: { plugins: [tailwindcss()] },
28
+ m3ui: {
29
+ palette: 'red',
30
+ locale: 'es',
31
+ },
32
+ })
33
+ ```
34
+
35
+ Keep `vue` in your app's own dependencies, as Nuxt's starter does: with pnpm, an app that only gets Vue through
36
+ `nuxt` can end up loading a second copy on the server, which fails to render.
37
+
38
+ The theme and the palettes are Tailwind CSS, so they go in your own stylesheet, after Tailwind:
39
+
40
+ ```css
41
+ /* assets/main.css */
42
+ @import 'tailwindcss';
43
+ @import '@m3ui-vue/m3ui-vue/theme';
44
+ @import '@m3ui-vue/m3ui-vue/palettes';
45
+ ```
46
+
47
+ Load the fonts as the [library's README](https://github.com/SrWither/m3ui-vue#fonts) says (Roboto and Material Symbols),
48
+ for example in `app.head.link`.
49
+
50
+ ## Usage
51
+
52
+ Components work in any page or component without importing them:
53
+
54
+ ```vue
55
+ <template>
56
+ <MButton @click="toast.success('Saved')">Save</MButton>
57
+ </template>
58
+
59
+ <script setup lang="ts">
60
+ const toast = useM3Toast()
61
+ </script>
62
+ ```
63
+
64
+ Each component is bundled only where it's used. `MChart`, `MCodeEditor`, `MJsonEditor`, `MMarkdown`,
65
+ `MRichTextEditor`, `MTerminal`, `MQRCode` and `MBarcode` are registered when their optional dependency is installed
66
+ (see the library's README).
67
+
68
+ The composables are prefixed so they can't clash with other modules (`useDevice`, `useTheme`… are common names):
69
+
70
+ | Library | Auto-imported as |
71
+ |---|---|
72
+ | `useTheme` | `useM3Theme` |
73
+ | `useColorPalette` | `useM3ColorPalette` |
74
+ | `useToast` | `useM3Toast` |
75
+ | `useNotification` | `useM3Notification` |
76
+ | `useLocale` | `useM3Locale` |
77
+ | `useDevice` | `useM3Device` |
78
+ | `useWindowSizeClass` | `useM3WindowSizeClass` |
79
+ | `useFieldBg`, `useDebounce`, `usePageProgress`, `useSpring` | `useM3FieldBg`, `useM3Debounce`, `useM3PageProgress`, `useM3Spring` |
80
+
81
+ Anything else (types, `palettes`, `motionSprings`…) is imported from `@m3ui-vue/m3ui-vue` as usual.
82
+
83
+ ## Options
84
+
85
+ Everything `createM3UI()` takes, plus what the module itself does:
86
+
87
+ | Option | Default | |
88
+ |---|---|---|
89
+ | `palette`, `seed`, `seedOptions`, `contrast`, `persistPalette`, `customPalettes`, `themeColor` | | As in `createM3UI()` |
90
+ | `locale` | English | A preset's code (`'es'`, `'fr'`, `'pt'`, `'de'`, `'ja'`, `'zh'`, `'ko'`) or your own strings |
91
+ | `components` | `true` | Auto-import the components |
92
+ | `composables` | `{ prefix: 'M3' }` | Auto-import the composables with this prefix; `false` to import them yourself |
93
+ | `css` | `true` | Add `@m3ui-vue/m3ui-vue/styles` |
94
+ | `themeScript` | `true` | Inline `themeInitScript()` in `<head>` |
95
+
96
+ ## Server-side rendering
97
+
98
+ The user's theme lives in `localStorage`, which the server can't read. The inlined script applies it to `<html>`
99
+ before the page paints, so there's no flash of the default theme, but the composables still start from the defaults
100
+ on the server (`theme` is `'system'`, `palette` is `'purple'`) and switch to the user's choice when the app hydrates.
101
+ Render anything that depends on them inside `<ClientOnly>`, like an icon showing the current theme:
102
+
103
+ ```vue
104
+ <ClientOnly>
105
+ <MIconButton :icon="theme === 'dark' ? 'dark_mode' : 'light_mode'" label="Theme" @click="cycle" />
106
+ </ClientOnly>
107
+ ```
108
+
109
+ The adaptive layouts (`MNavigationSuite`, `MListDetail`, `MSupportingPane`) measure their own size, which the server
110
+ doesn't know either: they render their compact layout there and adapt on the client.
111
+
112
+ A `seed` default can't be generated before the app loads: on the first visit the page shows the baseline palette
113
+ until it does (later visits use the cached scheme).
114
+
115
+ ## Development
116
+
117
+ ```bash
118
+ pnpm install
119
+ pnpm dev:prepare # stub the module and generate types
120
+ pnpm dev # the playground, with the library linked from ../m3ui-vue
121
+ pnpm test # builds a fixture app and checks its server-rendered HTML
122
+ pnpm test:types
123
+ ```
124
+
125
+ ## License
126
+
127
+ MIT
@@ -0,0 +1,42 @@
1
+ import * as _nuxt_schema from '@nuxt/schema';
2
+ import { M3UIOptions, M3Locale } from '@m3ui-vue/m3ui-vue';
3
+
4
+ /** The presets shipped in `@m3ui-vue/m3ui-vue/locales`, by language code. English is the built-in default. */
5
+ declare const LOCALE_PRESETS: {
6
+ readonly es: "esLocale";
7
+ readonly fr: "frLocale";
8
+ readonly pt: "ptLocale";
9
+ readonly de: "deLocale";
10
+ readonly ja: "jaLocale";
11
+ readonly zh: "zhLocale";
12
+ readonly ko: "koLocale";
13
+ };
14
+ type LocalePreset = keyof typeof LOCALE_PRESETS | 'en';
15
+ interface ModuleOptions extends Omit<M3UIOptions, 'locale'> {
16
+ /**
17
+ * Built-in text: a preset's language code (`'es'`, `'fr'`, `'pt'`, `'de'`, `'ja'`, `'zh'`, `'ko'`; `'en'` is the
18
+ * default) or your own strings, which override English.
19
+ */
20
+ locale?: LocalePreset | Partial<M3Locale>;
21
+ /** Auto-import the components (`<MButton>`…). Each one is bundled only where it's used. Default `true`. */
22
+ components?: boolean;
23
+ /**
24
+ * Auto-import the composables, prefixed so they can't clash with other modules: `useTheme` becomes `useM3Theme`,
25
+ * `useColorPalette` `useM3ColorPalette`… Set the `prefix`, or `false` to import them yourself from
26
+ * `@m3ui-vue/m3ui-vue`. Default `{ prefix: 'M3' }`.
27
+ */
28
+ composables?: boolean | {
29
+ prefix?: string;
30
+ };
31
+ /** Add the components' own stylesheet (`@m3ui-vue/m3ui-vue/styles`). Default `true`. */
32
+ css?: boolean;
33
+ /**
34
+ * Inline `themeInitScript()` in `<head>`, so dark mode, the palette and the contrast level the user picked are
35
+ * on the server-rendered page before the first paint. Default `true`.
36
+ */
37
+ themeScript?: boolean;
38
+ }
39
+ declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
40
+
41
+ export { _default as default };
42
+ export type { LocalePreset, ModuleOptions };
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "@m3ui-vue/nuxt",
3
+ "configKey": "m3ui",
4
+ "compatibility": {
5
+ "nuxt": ">=3.0.0"
6
+ },
7
+ "version": "0.1.1",
8
+ "builder": {
9
+ "@nuxt/module-builder": "1.0.3",
10
+ "unbuild": "unknown"
11
+ }
12
+ }
@@ -0,0 +1,77 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { join, dirname } from 'node:path';
3
+ import { defineNuxtModule, useLogger, createResolver, resolvePath, tryResolveModule, addComponent, addImports, addTemplate, addTypeTemplate, addPlugin } from '@nuxt/kit';
4
+
5
+ const LIB = "@m3ui-vue/m3ui-vue";
6
+ const LOCALE_PRESETS = { es: "esLocale", fr: "frLocale", pt: "ptLocale", de: "deLocale", ja: "jaLocale", zh: "zhLocale", ko: "koLocale" };
7
+ const OPTIONAL_ENTRIES = {
8
+ [`${LIB}/chart`]: "chart.js",
9
+ [`${LIB}/code-editor`]: "codemirror",
10
+ [`${LIB}/markdown`]: "markdown-it",
11
+ [`${LIB}/rich-text-editor`]: "@tiptap/vue-3",
12
+ [`${LIB}/terminal`]: "@xterm/xterm",
13
+ [`${LIB}/qrcode`]: "qrcode-generator",
14
+ [`${LIB}/barcode`]: "jsbarcode"
15
+ };
16
+ const module$1 = defineNuxtModule({
17
+ meta: {
18
+ name: "@m3ui-vue/nuxt",
19
+ configKey: "m3ui",
20
+ compatibility: { nuxt: ">=3.0.0" }
21
+ },
22
+ defaults: {
23
+ components: true,
24
+ composables: { prefix: "M3" },
25
+ css: true,
26
+ themeScript: true
27
+ },
28
+ async setup(options, nuxt) {
29
+ const logger = useLogger("@m3ui-vue/nuxt");
30
+ const resolver = createResolver(import.meta.url);
31
+ const { components, composables, css, themeScript, locale, ...plugin } = options;
32
+ const entry = await resolvePath(LIB, { extensions: [".js", ".mjs"] });
33
+ let api;
34
+ try {
35
+ api = JSON.parse(readFileSync(join(dirname(entry), "api.json"), "utf8"));
36
+ } catch {
37
+ logger.error(`Couldn't read ${LIB}'s dist/api.json: is ${LIB} installed?`);
38
+ return;
39
+ }
40
+ if (components) {
41
+ for (const component of api.components) {
42
+ const peer = OPTIONAL_ENTRIES[component.import];
43
+ if (peer && !await tryResolveModule(peer, nuxt.options.modulesDir)) continue;
44
+ addComponent({ name: component.name, export: component.name, filePath: component.import });
45
+ }
46
+ }
47
+ if (composables) {
48
+ const prefix = typeof composables === "object" ? composables.prefix ?? "" : "M3";
49
+ addImports(api.values.filter((value) => /^use[A-Z]/.test(value.name)).map((value) => ({ name: value.name, as: `use${prefix}${value.name.slice(3)}`, from: value.import })));
50
+ }
51
+ if (css) nuxt.options.css.push(`${LIB}/styles`);
52
+ const preset = typeof locale === "string" && locale !== "en" ? LOCALE_PRESETS[locale] : void 0;
53
+ if (typeof locale === "string" && locale !== "en" && !preset) logger.warn(`Unknown locale preset '${locale}', using English`);
54
+ addTemplate({
55
+ filename: "m3ui.options.mjs",
56
+ getContents: () => [
57
+ preset ? `import { ${preset} } from '${LIB}/locales'` : "",
58
+ `export const options = ${JSON.stringify(plugin)}`,
59
+ `export const locale = ${preset ?? (typeof locale === "object" ? JSON.stringify(locale) : "undefined")}`,
60
+ `export const themeScript = ${JSON.stringify(themeScript)}`
61
+ ].join("\n")
62
+ });
63
+ addTypeTemplate({
64
+ filename: "types/m3ui.options.d.ts",
65
+ getContents: () => [
66
+ `declare module '#build/m3ui.options.mjs' {`,
67
+ ` export const options: import('${LIB}').M3UIOptions`,
68
+ ` export const locale: Partial<import('${LIB}').M3Locale> | undefined`,
69
+ ` export const themeScript: boolean`,
70
+ `}`
71
+ ].join("\n")
72
+ });
73
+ addPlugin(resolver.resolve("./runtime/plugin"));
74
+ }
75
+ });
76
+
77
+ export { module$1 as default };
@@ -0,0 +1,2 @@
1
+ declare const _default: import("#app").Plugin<Record<string, unknown>> & import("#app").ObjectPlugin<Record<string, unknown>>;
2
+ export default _default;
@@ -0,0 +1,19 @@
1
+ import { createM3UI, themeInitScript } from "@m3ui-vue/m3ui-vue";
2
+ import { defineNuxtPlugin, useHead } from "#app";
3
+ import { locale, options, themeScript } from "#build/m3ui.options.mjs";
4
+ export default defineNuxtPlugin({
5
+ name: "m3ui",
6
+ enforce: "pre",
7
+ setup(nuxtApp) {
8
+ nuxtApp.vueApp.use(createM3UI({ ...options, locale, isHydrating: () => !!nuxtApp.isHydrating }));
9
+ if (import.meta.server && themeScript) {
10
+ useHead({
11
+ script: [{
12
+ key: "m3ui-theme",
13
+ innerHTML: themeInitScript({ palette: options.palette, contrast: options.contrast, persistPalette: options.persistPalette }),
14
+ tagPriority: "critical"
15
+ }]
16
+ });
17
+ }
18
+ }
19
+ });
@@ -0,0 +1,3 @@
1
+ export { default } from './module.mjs'
2
+
3
+ export { type LocalePreset, type ModuleOptions } from './module.mjs'
package/package.json CHANGED
@@ -1,6 +1,68 @@
1
1
  {
2
2
  "name": "@m3ui-vue/nuxt",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.1",
4
+ "description": "Nuxt module for m3ui-vue, the Material Design 3 component library for Vue 3 + Tailwind CSS v4",
5
+ "keywords": [
6
+ "nuxt",
7
+ "nuxt-module",
8
+ "material-design",
9
+ "material-3",
10
+ "m3",
11
+ "vue",
12
+ "tailwindcss"
13
+ ],
14
+ "homepage": "https://m3ui.dev",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+https://github.com/SrWither/m3ui-vue-nuxt.git"
18
+ },
19
+ "license": "MIT",
20
+ "type": "module",
21
+ "exports": {
22
+ ".": {
23
+ "types": "./dist/types.d.mts",
24
+ "import": "./dist/module.mjs"
25
+ }
26
+ },
27
+ "main": "./dist/module.mjs",
28
+ "typesVersions": {
29
+ "*": {
30
+ ".": [
31
+ "./dist/types.d.mts"
32
+ ]
33
+ }
34
+ },
35
+ "files": [
36
+ "dist"
37
+ ],
38
+ "scripts": {
39
+ "build": "nuxt-module-build prepare && nuxt-module-build build",
40
+ "prepack": "pnpm build",
41
+ "dev": "pnpm dev:prepare && nuxt dev playground",
42
+ "dev:build": "nuxt build playground",
43
+ "dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxt prepare playground",
44
+ "test": "vitest run",
45
+ "test:watch": "vitest watch",
46
+ "test:types": "vue-tsc --noEmit && cd playground && vue-tsc --noEmit"
47
+ },
48
+ "dependencies": {
49
+ "@nuxt/kit": "^4.6.2"
50
+ },
51
+ "peerDependencies": {
52
+ "@m3ui-vue/m3ui-vue": "^1.0.2"
53
+ },
54
+ "devDependencies": {
55
+ "@m3ui-vue/m3ui-vue": "^1.0.2",
56
+ "@nuxt/module-builder": "^1.0.3",
57
+ "@nuxt/schema": "^4.6.2",
58
+ "@nuxt/test-utils": "^4.3.4",
59
+ "@tailwindcss/vite": "^4.3.3",
60
+ "@types/node": "^24.0.0",
61
+ "nuxt": "^4.6.2",
62
+ "tailwindcss": "^4.3.3",
63
+ "typescript": "^6.0.3",
64
+ "vitest": "^5.0.5",
65
+ "vue": "^3.5.44",
66
+ "vue-tsc": "^3.3.12"
67
+ }
68
+ }