@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 +21 -0
- package/README.md +126 -2
- package/dist/module.d.mts +42 -0
- package/dist/module.json +12 -0
- package/dist/module.mjs +77 -0
- package/dist/runtime/plugin.d.ts +2 -0
- package/dist/runtime/plugin.js +19 -0
- package/dist/types.d.mts +3 -0
- package/package.json +66 -4
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
|
-
#
|
|
1
|
+
# @m3ui-vue/nuxt
|
|
2
2
|
|
|
3
|
-
|
|
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 };
|
package/dist/module.json
ADDED
package/dist/module.mjs
ADDED
|
@@ -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,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
|
+
});
|
package/dist/types.d.mts
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,68 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@m3ui-vue/nuxt",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
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
|
+
}
|