@m3ui-vue/nuxt 0.2.3 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -4
- package/dist/module.d.mts +7 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +20 -6
- package/dist/runtime/plugin.js +20 -4
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -67,21 +67,25 @@ const toast = useM3Toast()
|
|
|
67
67
|
```
|
|
68
68
|
|
|
69
69
|
Each component is bundled only where it's used. `MChart`, `MCodeEditor`, `MJsonEditor`, `MMarkdown`,
|
|
70
|
-
`MRichTextEditor`, `MTerminal`, `MQRCode` and `
|
|
71
|
-
(see the library's README)
|
|
70
|
+
`MRichTextEditor`, `MTerminal`, `MQRCode`, `MBarcode` and the `MMap` family are registered when their optional
|
|
71
|
+
dependency is installed (see the library's README); so are `useMap`, `useMapLayers` and `useMapFilter`.
|
|
72
72
|
|
|
73
73
|
The composables are prefixed so they can't clash with other modules (`useDevice`, `useTheme`… are common names):
|
|
74
74
|
|
|
75
75
|
| Library | Auto-imported as |
|
|
76
76
|
|---|---|
|
|
77
77
|
| `useTheme` | `useM3Theme` |
|
|
78
|
+
| `useThemeTokens` | `useM3ThemeTokens` |
|
|
78
79
|
| `useColorPalette` | `useM3ColorPalette` |
|
|
79
80
|
| `useToast` | `useM3Toast` |
|
|
80
81
|
| `useNotification` | `useM3Notification` |
|
|
81
82
|
| `useLocale` | `useM3Locale` |
|
|
82
83
|
| `useDevice` | `useM3Device` |
|
|
83
84
|
| `useWindowSizeClass` | `useM3WindowSizeClass` |
|
|
84
|
-
| `
|
|
85
|
+
| `useConfetti` | `useM3Confetti` |
|
|
86
|
+
| `useContainerTransform` | `useM3ContainerTransform` |
|
|
87
|
+
| `useFieldBg`, `useDebounce`, `useAutoGrow`, `usePageProgress`, `useSpring`, `useScrollReveal` | `useM3FieldBg`, `useM3Debounce`, `useM3AutoGrow`, `useM3PageProgress`, `useM3Spring`, `useM3ScrollReveal` |
|
|
88
|
+
| `useMap`, `useMapLayers`, `useMapFilter` (with `maplibre-gl`) | `useM3Map`, `useM3MapLayers`, `useM3MapFilter` |
|
|
85
89
|
|
|
86
90
|
Anything else (types, `palettes`, `motionSprings`…) is imported from `@m3ui-vue/m3ui-vue` as usual.
|
|
87
91
|
|
|
@@ -97,6 +101,7 @@ Everything `createM3UI()` takes, plus what the module itself does:
|
|
|
97
101
|
| `composables` | `{ prefix: 'M3' }` | Auto-import the composables with this prefix; `false` to import them yourself |
|
|
98
102
|
| `css` | `true` | Add `@m3ui-vue/m3ui-vue/styles` |
|
|
99
103
|
| `cookies` | `true` | Keep the theme, palette and contrast in cookies too, so the server renders with them |
|
|
104
|
+
| `viewportHints` | `false` | Ask Chromium for the window's exact size with client hints, so the adaptive layouts render at it on a first visit too (that visit's request is repeated once) |
|
|
100
105
|
| `themeScript` | `true` | Inline `themeInitScript()` in `<head>` |
|
|
101
106
|
|
|
102
107
|
## With @nuxtjs/i18n
|
|
@@ -145,7 +150,11 @@ a theme saved in the user's account, for instance.
|
|
|
145
150
|
The adaptive layouts (`MNavigationSuite`, `MListDetail`, `MSupportingPane`) measure their own size, which the server
|
|
146
151
|
can't. With `cookies`, the window's size is kept in a cookie too (`m3-viewport`), so from the second visit on they
|
|
147
152
|
render on the server for the user's screen (one in a narrower column corrects itself on the client). On a first visit
|
|
148
|
-
|
|
153
|
+
there's no cookie yet: with `@m3ui-vue/m3ui-vue` 1.2.0 or later the server renders for a size standing for the kind of
|
|
154
|
+
device (a phone, a tablet or a desktop, from `Sec-CH-UA-Mobile` and the user agent), and the layout settles on the exact
|
|
155
|
+
one once the page is interactive; before 1.2.0, the compact layout. With `viewportHints`, Chromium sends the exact size
|
|
156
|
+
on a first visit too: the server asks for it (`Accept-CH` / `Critical-CH: Sec-CH-Viewport-Width,
|
|
157
|
+
Sec-CH-Viewport-Height`) and Chromium repeats that first request once with it.
|
|
149
158
|
|
|
150
159
|
A `seed` default can't be generated before the app loads: on the first visit the page shows the baseline palette
|
|
151
160
|
until it does (later visits use the cached scheme).
|
package/dist/module.d.mts
CHANGED
|
@@ -38,6 +38,13 @@ interface ModuleOptions extends Omit<M3UIOptions, 'locale'> {
|
|
|
38
38
|
* `MListDetail`, `MSupportingPane`) render for the user's screen instead of compact. Default `true`.
|
|
39
39
|
*/
|
|
40
40
|
cookies?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Ask Chromium for the window's exact size with client hints (`Accept-CH` / `Critical-CH: Sec-CH-Viewport-Width,
|
|
43
|
+
* Sec-CH-Viewport-Height`), so the adaptive layouts render at it even on a first visit. It costs that first
|
|
44
|
+
* visit one repeated request in Chromium; later visits have the size in a cookie anyway. Without it, a first
|
|
45
|
+
* visit renders at a size guessed from the kind of device (phone, tablet, desktop). Needs `cookies`. Default `false`.
|
|
46
|
+
*/
|
|
47
|
+
viewportHints?: boolean;
|
|
41
48
|
/**
|
|
42
49
|
* Inline `themeInitScript()` in `<head>`, so dark mode, the palette and the contrast level the user picked are
|
|
43
50
|
* on the server-rendered page before the first paint. Default `true`.
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs';
|
|
2
2
|
import { join, dirname } from 'node:path';
|
|
3
|
-
import { defineNuxtModule, useLogger, createResolver, resolvePath,
|
|
3
|
+
import { defineNuxtModule, useLogger, createResolver, resolvePath, addComponent, addImports, hasNuxtModule, addTemplate, addTypeTemplate, addPlugin, tryResolveModule } from '@nuxt/kit';
|
|
4
4
|
|
|
5
5
|
const LIB = "@m3ui-vue/m3ui-vue";
|
|
6
6
|
const LOCALE_PRESETS = { es: "esLocale", fr: "frLocale", pt: "ptLocale", de: "deLocale", ja: "jaLocale", zh: "zhLocale", ko: "koLocale" };
|
|
@@ -11,7 +11,8 @@ const OPTIONAL_ENTRIES = {
|
|
|
11
11
|
[`${LIB}/rich-text-editor`]: "@tiptap/vue-3",
|
|
12
12
|
[`${LIB}/terminal`]: "@xterm/xterm",
|
|
13
13
|
[`${LIB}/qrcode`]: "qrcode-generator",
|
|
14
|
-
[`${LIB}/barcode`]: "jsbarcode"
|
|
14
|
+
[`${LIB}/barcode`]: "jsbarcode",
|
|
15
|
+
[`${LIB}/map`]: "maplibre-gl"
|
|
15
16
|
};
|
|
16
17
|
const module$1 = defineNuxtModule({
|
|
17
18
|
meta: {
|
|
@@ -24,12 +25,13 @@ const module$1 = defineNuxtModule({
|
|
|
24
25
|
composables: { prefix: "M3" },
|
|
25
26
|
css: true,
|
|
26
27
|
cookies: true,
|
|
28
|
+
viewportHints: false,
|
|
27
29
|
themeScript: true
|
|
28
30
|
},
|
|
29
31
|
async setup(options, nuxt) {
|
|
30
32
|
const logger = useLogger("@m3ui-vue/nuxt");
|
|
31
33
|
const resolver = createResolver(import.meta.url);
|
|
32
|
-
const { components, composables, css, cookies, themeScript, locale, ...plugin } = options;
|
|
34
|
+
const { components, composables, css, cookies, viewportHints, themeScript, locale, ...plugin } = options;
|
|
33
35
|
const entry = await resolvePath(LIB, { extensions: [".js", ".mjs"] });
|
|
34
36
|
let api;
|
|
35
37
|
try {
|
|
@@ -38,16 +40,26 @@ const module$1 = defineNuxtModule({
|
|
|
38
40
|
logger.error(`Couldn't read ${LIB}'s dist/api.json: is ${LIB} installed?`);
|
|
39
41
|
return;
|
|
40
42
|
}
|
|
43
|
+
const available = /* @__PURE__ */ new Map();
|
|
44
|
+
const isAvailable = async (from) => {
|
|
45
|
+
const peer = OPTIONAL_ENTRIES[from];
|
|
46
|
+
if (!peer) return true;
|
|
47
|
+
if (!available.has(from)) available.set(from, !!await tryResolveModule(peer, nuxt.options.modulesDir));
|
|
48
|
+
return available.get(from);
|
|
49
|
+
};
|
|
41
50
|
if (components) {
|
|
42
51
|
for (const component of api.components) {
|
|
43
|
-
|
|
44
|
-
if (peer && !await tryResolveModule(peer, nuxt.options.modulesDir)) continue;
|
|
52
|
+
if (!await isAvailable(component.import)) continue;
|
|
45
53
|
addComponent({ name: component.name, export: component.name, filePath: component.import });
|
|
46
54
|
}
|
|
47
55
|
}
|
|
48
56
|
if (composables) {
|
|
49
57
|
const prefix = typeof composables === "object" ? composables.prefix ?? "" : "M3";
|
|
50
|
-
|
|
58
|
+
const values = [];
|
|
59
|
+
for (const value of api.values) {
|
|
60
|
+
if (/^use[A-Z]/.test(value.name) && await isAvailable(value.import)) values.push(value);
|
|
61
|
+
}
|
|
62
|
+
addImports(values.map((value) => ({ name: value.name, as: `use${prefix}${value.name.slice(3)}`, from: value.import })));
|
|
51
63
|
}
|
|
52
64
|
if (css) nuxt.options.css.push(`${LIB}/styles`);
|
|
53
65
|
const auto = locale === "auto";
|
|
@@ -68,6 +80,7 @@ const module$1 = defineNuxtModule({
|
|
|
68
80
|
`export const autoLocale = ${auto}`,
|
|
69
81
|
`export const localePresets = ${auto ? `{ ${Object.entries(LOCALE_PRESETS).map(([code, name]) => `${code}: presets.${name}`).join(", ")} }` : "{}"}`,
|
|
70
82
|
`export const cookies = ${JSON.stringify(cookies)}`,
|
|
83
|
+
`export const viewportHints = ${JSON.stringify(!!viewportHints)}`,
|
|
71
84
|
`export const themeScript = ${JSON.stringify(themeScript)}`
|
|
72
85
|
].join("\n")
|
|
73
86
|
});
|
|
@@ -80,6 +93,7 @@ const module$1 = defineNuxtModule({
|
|
|
80
93
|
` export const autoLocale: boolean`,
|
|
81
94
|
` export const localePresets: Record<string, Partial<import('${LIB}').M3Locale>>`,
|
|
82
95
|
` export const cookies: boolean`,
|
|
96
|
+
` export const viewportHints: boolean`,
|
|
83
97
|
` export const themeScript: boolean`,
|
|
84
98
|
`}`
|
|
85
99
|
].join("\n")
|
package/dist/runtime/plugin.js
CHANGED
|
@@ -1,18 +1,34 @@
|
|
|
1
1
|
import { computed } from "vue";
|
|
2
|
+
import * as m3 from "@m3ui-vue/m3ui-vue";
|
|
2
3
|
import { createM3UI, themeInitScript } from "@m3ui-vue/m3ui-vue";
|
|
3
|
-
import { defineNuxtPlugin, useCookie, useHead } from "#app";
|
|
4
|
-
import { autoLocale, cookies, locale, localePresets, options, themeScript } from "#build/m3ui.options.mjs";
|
|
4
|
+
import { defineNuxtPlugin, useCookie, useHead, useRequestEvent, useRequestHeaders, useState } from "#app";
|
|
5
|
+
import { autoLocale, cookies, locale, localePresets, options, themeScript, viewportHints } from "#build/m3ui.options.mjs";
|
|
6
|
+
const fromHeaders = m3.viewportFromHeaders;
|
|
7
|
+
const HINTS = "Sec-CH-Viewport-Width, Sec-CH-Viewport-Height";
|
|
5
8
|
export default defineNuxtPlugin({
|
|
6
9
|
name: "m3ui",
|
|
7
10
|
enforce: "pre",
|
|
8
11
|
setup(nuxtApp) {
|
|
9
12
|
const read = (name) => useCookie(name, { decode: decodeURIComponent, readonly: true }).value;
|
|
10
|
-
const
|
|
13
|
+
const viewport = useState("m3ui-viewport", () => {
|
|
14
|
+
if (import.meta.server && fromHeaders) return fromHeaders(useRequestHeaders()) ?? null;
|
|
15
|
+
const [width, height] = (read("m3-viewport") ?? "").split("x").map(Number);
|
|
16
|
+
return width && height ? { width, height } : null;
|
|
17
|
+
});
|
|
18
|
+
if (import.meta.server && cookies && viewportHints) {
|
|
19
|
+
const res = useRequestEvent()?.node.res;
|
|
20
|
+
if (res && !res.headersSent) {
|
|
21
|
+
res.setHeader("Accept-CH", HINTS);
|
|
22
|
+
res.setHeader("Critical-CH", HINTS);
|
|
23
|
+
const vary = [res.getHeader("Vary")].flat().filter(Boolean).join(", ");
|
|
24
|
+
res.setHeader("Vary", vary ? `${vary}, ${HINTS}` : HINTS);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
11
27
|
const initialState = cookies ? {
|
|
12
28
|
theme: read("m3-theme"),
|
|
13
29
|
palette: read("m3-palette"),
|
|
14
30
|
contrast: read("m3-contrast"),
|
|
15
|
-
viewport:
|
|
31
|
+
viewport: viewport.value ?? void 0
|
|
16
32
|
} : void 0;
|
|
17
33
|
const appLocale = autoLocale ? computed(() => {
|
|
18
34
|
const i18n = nuxtApp.$i18n;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@m3ui-vue/nuxt",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Nuxt module for m3ui-vue, the Material Design 3 component library for Vue 3 + Tailwind CSS v4",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"nuxt",
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"type": "git",
|
|
17
17
|
"url": "git+https://github.com/SrWither/m3ui-vue-nuxt.git"
|
|
18
18
|
},
|
|
19
|
+
"funding": "https://github.com/sponsors/SrWither",
|
|
19
20
|
"license": "MIT",
|
|
20
21
|
"type": "module",
|
|
21
22
|
"exports": {
|
|
@@ -52,7 +53,7 @@
|
|
|
52
53
|
"@m3ui-vue/m3ui-vue": "^1.1.3"
|
|
53
54
|
},
|
|
54
55
|
"devDependencies": {
|
|
55
|
-
"@m3ui-vue/m3ui-vue": "^1.
|
|
56
|
+
"@m3ui-vue/m3ui-vue": "^1.2.0",
|
|
56
57
|
"@nuxt/module-builder": "^1.0.3",
|
|
57
58
|
"@nuxt/schema": "^4.6.2",
|
|
58
59
|
"@nuxt/test-utils": "^4.3.4",
|