origam 2.27.0 → 2.29.2
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/CHANGELOG.md +54 -0
- package/dist/src/assets/css/main.css +1 -1
- package/dist/src/assets/css/tokens/dark.css +2 -0
- package/dist/src/assets/css/tokens/light.css +1 -0
- package/dist/src/assets/scss/tokens/_dark.scss +2 -0
- package/dist/src/assets/scss/tokens/_light.scss +1 -0
- package/dist/src/components/Btn/OrigamBtn.vue +53 -14
- package/dist/src/components/Chart/OrigamChartCartesian.vue +1 -1
- package/dist/src/components/Chart/OrigamChartPolar.vue +1 -1
- package/dist/src/components/Chip/OrigamChip.vue +1 -1
- package/dist/src/components/Code/OrigamCode.vue +0 -2
- package/dist/src/composables/Commons/style.composable.cjs +14 -1
- package/dist/src/composables/Commons/style.composable.d.ts +0 -14
- package/dist/src/composables/Commons/style.composable.js +13 -2
- package/dist/src/composables/Commons/styleTag.composable.cjs +10 -4
- package/dist/src/composables/Commons/styleTag.composable.js +11 -5
- package/dist/src/consts/Commons/ssr-style.const.cjs +8 -0
- package/dist/src/consts/Commons/ssr-style.const.d.ts +19 -0
- package/dist/src/consts/Commons/ssr-style.const.js +2 -0
- package/dist/src/consts/index.cjs +11 -0
- package/dist/src/consts/index.d.ts +1 -0
- package/dist/src/consts/index.js +1 -0
- package/dist/src/directives/Contrast/contrast.directive.cjs +58 -6
- package/dist/src/directives/Contrast/contrast.directive.d.ts +10 -0
- package/dist/src/directives/Contrast/contrast.directive.js +61 -9
- package/dist/src/interfaces/Btn/btn.interface.d.ts +1 -0
- package/dist/src/interfaces/Commons/commons.interface.d.ts +14 -0
- package/dist/src/interfaces/Commons/nuxt-module.interface.d.ts +18 -4
- package/dist/src/interfaces/Commons/style.interface.d.ts +21 -0
- package/dist/src/nuxt/module.d.ts +8 -2
- package/dist/src/nuxt/plugin.client.cjs +10 -2
- package/dist/src/nuxt/plugin.client.js +12 -4
- package/dist/src/nuxt/plugin.server.cjs +29 -20
- package/dist/src/nuxt/plugin.server.js +26 -22
- package/dist/src/origam.cjs +3 -0
- package/dist/src/origam.js +5 -1
- package/dist/src/types/tokens.type.d.ts +1 -1
- package/dist/src/utils/Commons/apply-theme.util.cjs +20 -0
- package/dist/src/utils/Commons/apply-theme.util.d.ts +34 -0
- package/dist/src/utils/Commons/apply-theme.util.js +18 -0
- package/dist/src/utils/Commons/ssr-styles.util.cjs +41 -0
- package/dist/src/utils/Commons/ssr-styles.util.d.ts +6 -0
- package/dist/src/utils/Commons/ssr-styles.util.js +26 -0
- package/dist/src/utils/index.cjs +11 -0
- package/dist/src/utils/index.d.ts +1 -0
- package/dist/src/utils/index.js +1 -0
- package/package.json +1 -1
|
@@ -120,15 +120,70 @@ function enforceContrast(el, enabled) {
|
|
|
120
120
|
const better = wcagRatio(WHITE, bg) >= wcagRatio(BLACK, bg) ? "#fff" : "#000";
|
|
121
121
|
el.style.setProperty("color", better, "important");
|
|
122
122
|
el.dataset.origamContrastFixed = "true";
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
123
|
+
if (import.meta.env?.DEV) {
|
|
124
|
+
console.warn(
|
|
125
|
+
`[origam] Low text contrast (${ratio.toFixed(2)}:1 < ${config.threshold}:1): text rgb(${fg.join(", ")}) on background rgb(${bg.join(", ")}). Overriding text colour to ${better} for legibility. Disable with createOrigam({ contrast: false }).`,
|
|
126
|
+
el
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
const MAX_SETTLE_PASSES = 4;
|
|
131
|
+
const COLOR_TRANSITION_PROPERTIES = /* @__PURE__ */ new Set(["color", "background-color"]);
|
|
132
|
+
function declaredTransitionMs(el) {
|
|
133
|
+
const toMs = (value) => {
|
|
134
|
+
const n = parseFloat(value);
|
|
135
|
+
if (Number.isNaN(n)) return 0;
|
|
136
|
+
return value.trim().endsWith("ms") ? n : n * 1e3;
|
|
137
|
+
};
|
|
138
|
+
let longest = 0;
|
|
139
|
+
for (let node = el; node; node = node.parentElement) {
|
|
140
|
+
const style = getComputedStyle(node);
|
|
141
|
+
const durations = style.transitionDuration.split(",");
|
|
142
|
+
const delays = style.transitionDelay.split(",");
|
|
143
|
+
durations.forEach((duration, i) => {
|
|
144
|
+
longest = Math.max(longest, toMs(duration) + toMs(delays[i % delays.length] ?? "0"));
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
return longest;
|
|
148
|
+
}
|
|
149
|
+
function runningColorTransitions(el) {
|
|
150
|
+
const found = [];
|
|
151
|
+
for (let node = el; node; node = node.parentElement) {
|
|
152
|
+
for (const animation of node.getAnimations()) {
|
|
153
|
+
const property = animation.transitionProperty;
|
|
154
|
+
if (property && COLOR_TRANSITION_PROPERTIES.has(property) && animation.playState !== "finished") {
|
|
155
|
+
found.push(animation);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return found;
|
|
160
|
+
}
|
|
161
|
+
function forceStyleRecalc(el) {
|
|
162
|
+
return getComputedStyle(el).color;
|
|
163
|
+
}
|
|
164
|
+
function settleThenEnforce(el, enabled, pending, pass = 0) {
|
|
165
|
+
if (pending.cancelled) return;
|
|
166
|
+
if (!forceStyleRecalc(el)) return;
|
|
167
|
+
if (typeof el.getAnimations === "function") {
|
|
168
|
+
const running = pass < MAX_SETTLE_PASSES ? runningColorTransitions(el) : [];
|
|
169
|
+
if (running.length) {
|
|
170
|
+
Promise.allSettled(running.map((animation) => animation.finished)).then(() => settleThenEnforce(el, enabled, pending, pass + 1));
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
enforceContrast(el, enabled);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
const wait = declaredTransitionMs(el);
|
|
177
|
+
if (wait > 0 && pass === 0 && typeof setTimeout !== "undefined") {
|
|
178
|
+
pending.timeout = setTimeout(() => settleThenEnforce(el, enabled, pending, 1), wait);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
enforceContrast(el, enabled);
|
|
127
182
|
}
|
|
128
|
-
const SETTLE_MS = 250;
|
|
129
183
|
function cancelScheduled(el) {
|
|
130
184
|
const pending = el._contrastTimers;
|
|
131
185
|
if (!pending) return;
|
|
186
|
+
pending.cancelled = true;
|
|
132
187
|
if (pending.raf !== void 0 && typeof cancelAnimationFrame !== "undefined") {
|
|
133
188
|
cancelAnimationFrame(pending.raf);
|
|
134
189
|
}
|
|
@@ -141,10 +196,7 @@ function schedule(el, enabled) {
|
|
|
141
196
|
cancelScheduled(el);
|
|
142
197
|
const pending = {};
|
|
143
198
|
if (typeof requestAnimationFrame !== "undefined") {
|
|
144
|
-
pending.raf = requestAnimationFrame(() =>
|
|
145
|
-
}
|
|
146
|
-
if (typeof setTimeout !== "undefined") {
|
|
147
|
-
pending.timeout = setTimeout(() => enforceContrast(el, enabled), SETTLE_MS);
|
|
199
|
+
pending.raf = requestAnimationFrame(() => settleThenEnforce(el, enabled, pending));
|
|
148
200
|
}
|
|
149
201
|
el._contrastTimers = pending;
|
|
150
202
|
}
|
|
@@ -15,6 +15,20 @@ import { TSSROptions } from '../../types/Commons/display.type';
|
|
|
15
15
|
* `enabled` toggles the whole feature; `threshold` is the minimum acceptable
|
|
16
16
|
* WCAG contrast ratio (default 4.5:1 — AA for normal text).
|
|
17
17
|
*/
|
|
18
|
+
/*********************************************************
|
|
19
|
+
* IContrastScheduled
|
|
20
|
+
*
|
|
21
|
+
* @description
|
|
22
|
+
* What `v-contrast` has queued for one element: the animation frame that
|
|
23
|
+
* starts the measure, the fallback timer (browsers without `getAnimations`,
|
|
24
|
+
* derived from the declared transition) and a flag that cancels a measure
|
|
25
|
+
* already waiting on a transition. Stored on the element as `_contrastTimers`.
|
|
26
|
+
********************************************************/
|
|
27
|
+
export interface IContrastScheduled {
|
|
28
|
+
raf?: number;
|
|
29
|
+
timeout?: number;
|
|
30
|
+
cancelled?: boolean;
|
|
31
|
+
}
|
|
18
32
|
export interface IContrastOptions {
|
|
19
33
|
enabled?: boolean;
|
|
20
34
|
threshold?: number;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { IOrigamTheme } from './theme.interface';
|
|
2
|
+
import type { TMode, TTheme } from '../../types/Commons/theme.type';
|
|
2
3
|
/**
|
|
3
4
|
* Options passed by a consumer in `nuxt.config.ts` under the `origam` key.
|
|
4
5
|
*
|
|
@@ -9,7 +10,7 @@ import type { IOrigamTheme } from './theme.interface';
|
|
|
9
10
|
* a name×mode scoped `--origam-*` block. The theme-invariant `primitive` +
|
|
10
11
|
* `utilities` sheets are still loaded as CSS. Two orthogonal axes are resolved
|
|
11
12
|
* SSR-side to avoid FOUC: the brand `theme` (cookie) and the color `mode`
|
|
12
|
-
* (cookie
|
|
13
|
+
* (cookie, else the system `prefers-color-scheme` via `@media`).
|
|
13
14
|
*
|
|
14
15
|
* ADR-004 (Implemented): the DS ships exactly ONE neutral identity (the origam
|
|
15
16
|
* baseline). Brand themes live in the consuming app (e.g. the marketing
|
|
@@ -40,9 +41,9 @@ export interface IOrigamNuxtModuleOptions {
|
|
|
40
41
|
*/
|
|
41
42
|
modes?: string[];
|
|
42
43
|
/**
|
|
43
|
-
* Color mode applied when no cookie is set
|
|
44
|
-
* `
|
|
45
|
-
*
|
|
44
|
+
* Color mode applied when no cookie is set. `'light'` / `'dark'` pins it.
|
|
45
|
+
* `'auto'` leaves it to the system: the server inlines both modes, the dark
|
|
46
|
+
* one under `@media (prefers-color-scheme: dark)` (#1103).
|
|
46
47
|
*
|
|
47
48
|
* @default 'auto'
|
|
48
49
|
*/
|
|
@@ -111,3 +112,16 @@ export interface IOrigamNuxtRuntimeConfig {
|
|
|
111
112
|
modeCookieName: string;
|
|
112
113
|
cookieMaxAge: number;
|
|
113
114
|
}
|
|
115
|
+
/*********************************************************
|
|
116
|
+
* IOrigamNuxtProvide
|
|
117
|
+
*
|
|
118
|
+
* @description
|
|
119
|
+
* Shape of what the Nuxt plugins `provide` under `nuxtApp.$origam`.
|
|
120
|
+
* @description
|
|
121
|
+
* `mode` is `'auto'` when the colour mode is NOT pinned (#1103), otherwise the
|
|
122
|
+
* pinned concrete mode.
|
|
123
|
+
********************************************************/
|
|
124
|
+
export interface IOrigamNuxtProvide {
|
|
125
|
+
theme: TTheme;
|
|
126
|
+
mode: TMode;
|
|
127
|
+
}
|
|
@@ -23,3 +23,24 @@ export interface IStyleTagOptions extends IConfigurableDocument {
|
|
|
23
23
|
*/
|
|
24
24
|
id?: string;
|
|
25
25
|
}
|
|
26
|
+
/*********************************************************
|
|
27
|
+
* ISsrStyleEntry / ISsrStyleCollector (#1092)
|
|
28
|
+
*
|
|
29
|
+
* @description
|
|
30
|
+
* `ISsrStyleEntry` is one `useStyle()` rule resolved for the server render:
|
|
31
|
+
* `id` is the DOM id of the `<style>` tag it belongs to, `css` the
|
|
32
|
+
* `#element-id { … }` rule, already safe to embed in a `<style>`.
|
|
33
|
+
*
|
|
34
|
+
* @description
|
|
35
|
+
* `ISsrStyleCollector` is the per-app registry of those rules. Rules are
|
|
36
|
+
* registered as GETTERS and read at collection time, so a value a later pass
|
|
37
|
+
* of the render settled on is what ships.
|
|
38
|
+
********************************************************/
|
|
39
|
+
export interface ISsrStyleEntry {
|
|
40
|
+
id: string;
|
|
41
|
+
css: string;
|
|
42
|
+
}
|
|
43
|
+
export interface ISsrStyleCollector {
|
|
44
|
+
add(id: string, css: () => string): void;
|
|
45
|
+
entries(): ISsrStyleEntry[];
|
|
46
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IOrigamNuxtModuleOptions, IOrigamNuxtRuntimeConfig } from '../interfaces/Commons/nuxt-module.interface'
|
|
1
|
+
import type { IOrigamNuxtModuleOptions, IOrigamNuxtProvide, IOrigamNuxtRuntimeConfig } from '../interfaces/Commons/nuxt-module.interface'
|
|
2
2
|
|
|
3
3
|
declare module '@nuxt/schema' {
|
|
4
4
|
interface NuxtConfig {
|
|
@@ -14,6 +14,12 @@ declare module '@nuxt/schema' {
|
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
declare module '#app' {
|
|
18
|
+
interface NuxtApp {
|
|
19
|
+
$origam: IOrigamNuxtProvide
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
17
23
|
declare module 'nuxt/schema' {
|
|
18
24
|
interface NuxtConfig {
|
|
19
25
|
origam?: IOrigamNuxtModuleOptions
|
|
@@ -28,4 +34,4 @@ declare module 'nuxt/schema' {
|
|
|
28
34
|
}
|
|
29
35
|
}
|
|
30
36
|
|
|
31
|
-
export { IOrigamNuxtModuleOptions, IOrigamNuxtRuntimeConfig }
|
|
37
|
+
export { IOrigamNuxtModuleOptions, IOrigamNuxtProvide, IOrigamNuxtRuntimeConfig }
|
|
@@ -7,6 +7,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
7
7
|
var _vue = require("vue");
|
|
8
8
|
var _theme = require("../composables/Commons/theme.composable.cjs");
|
|
9
9
|
var _origam = require("../origam.cjs");
|
|
10
|
+
var _applyTheme = require("../utils/Commons/apply-theme.util.cjs");
|
|
10
11
|
var _app = require("#app");
|
|
11
12
|
module.exports = (0, _app.defineNuxtPlugin)({
|
|
12
13
|
name: "origam:client",
|
|
@@ -23,6 +24,7 @@ module.exports = (0, _app.defineNuxtPlugin)({
|
|
|
23
24
|
sameSite: "lax",
|
|
24
25
|
path: "/"
|
|
25
26
|
});
|
|
27
|
+
const modePinned = (0, _applyTheme.isModePinned)(modeCookie.value, config.defaultMode);
|
|
26
28
|
const themeFromDom = typeof document !== "undefined" && document.documentElement.dataset.theme || null;
|
|
27
29
|
const initialTheme = themeFromDom ?? themeCookie.value ?? config.defaultTheme;
|
|
28
30
|
const initialMode = modeCookie.value ?? config.defaultMode;
|
|
@@ -35,8 +37,14 @@ module.exports = (0, _app.defineNuxtPlugin)({
|
|
|
35
37
|
const themeApi = (0, _theme.useTheme)();
|
|
36
38
|
themeApi.setTheme(initialTheme);
|
|
37
39
|
themeApi.setMode(initialMode);
|
|
38
|
-
(0, _vue.
|
|
39
|
-
|
|
40
|
+
const hydrated = (0, _vue.ref)(modePinned);
|
|
41
|
+
if (!modePinned) {
|
|
42
|
+
nuxtApp.hook("app:mounted", () => {
|
|
43
|
+
hydrated.value = true;
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
(0, _vue.watch)([themeApi.theme, themeApi.resolvedMode, hydrated], ([brand, mode, isHydrated]) => {
|
|
47
|
+
origam._defaultsRef.value = origam._activeDefaultsFor(brand === "auto" ? "" : brand, isHydrated ? mode : "light");
|
|
40
48
|
}, {
|
|
41
49
|
immediate: true
|
|
42
50
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { watch } from "vue";
|
|
1
|
+
import { ref, watch } from "vue";
|
|
2
2
|
import { useTheme } from "../composables/Commons/theme.composable.js";
|
|
3
3
|
import { createOrigam } from "../origam.js";
|
|
4
|
+
import { isModePinned } from "../utils/Commons/apply-theme.util.js";
|
|
4
5
|
import { defineNuxtPlugin, useCookie, useRuntimeConfig } from "#app";
|
|
5
6
|
export default defineNuxtPlugin({
|
|
6
7
|
name: "origam:client",
|
|
@@ -17,6 +18,7 @@ export default defineNuxtPlugin({
|
|
|
17
18
|
sameSite: "lax",
|
|
18
19
|
path: "/"
|
|
19
20
|
});
|
|
21
|
+
const modePinned = isModePinned(modeCookie.value, config.defaultMode);
|
|
20
22
|
const themeFromDom = typeof document !== "undefined" && document.documentElement.dataset.theme || null;
|
|
21
23
|
const initialTheme = themeFromDom ?? themeCookie.value ?? config.defaultTheme;
|
|
22
24
|
const initialMode = modeCookie.value ?? config.defaultMode;
|
|
@@ -26,12 +28,18 @@ export default defineNuxtPlugin({
|
|
|
26
28
|
const themeApi = useTheme();
|
|
27
29
|
themeApi.setTheme(initialTheme);
|
|
28
30
|
themeApi.setMode(initialMode);
|
|
31
|
+
const hydrated = ref(modePinned);
|
|
32
|
+
if (!modePinned) {
|
|
33
|
+
nuxtApp.hook("app:mounted", () => {
|
|
34
|
+
hydrated.value = true;
|
|
35
|
+
});
|
|
36
|
+
}
|
|
29
37
|
watch(
|
|
30
|
-
[themeApi.theme, themeApi.resolvedMode],
|
|
31
|
-
([brand, mode]) => {
|
|
38
|
+
[themeApi.theme, themeApi.resolvedMode, hydrated],
|
|
39
|
+
([brand, mode, isHydrated]) => {
|
|
32
40
|
origam._defaultsRef.value = origam._activeDefaultsFor(
|
|
33
41
|
brand === "auto" ? "" : brand,
|
|
34
|
-
mode
|
|
42
|
+
isHydrated ? mode : "light"
|
|
35
43
|
);
|
|
36
44
|
},
|
|
37
45
|
{ immediate: true }
|
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
|
|
7
7
|
var _origam = require("../origam.cjs");
|
|
8
8
|
var _applyTheme = require("../utils/Commons/apply-theme.util.cjs");
|
|
9
|
+
var _ssrStyles = require("../utils/Commons/ssr-styles.util.cjs");
|
|
9
10
|
var _theme = require("../consts/Commons/theme.const.cjs");
|
|
10
11
|
var _app = require("#app");
|
|
11
12
|
function resolveServerTheme(cookieValue, config) {
|
|
@@ -17,21 +18,11 @@ function resolveServerTheme(cookieValue, config) {
|
|
|
17
18
|
}
|
|
18
19
|
return _theme.ORIGAM_THEME_AUTO;
|
|
19
20
|
}
|
|
20
|
-
function resolveServerMode(cookieValue, config
|
|
21
|
+
function resolveServerMode(cookieValue, config) {
|
|
21
22
|
if (cookieValue === _theme.ORIGAM_MODE_LIGHT || cookieValue === _theme.ORIGAM_MODE_DARK) {
|
|
22
23
|
return cookieValue;
|
|
23
24
|
}
|
|
24
|
-
|
|
25
|
-
return config.defaultMode;
|
|
26
|
-
}
|
|
27
|
-
const hint = headers["sec-ch-prefers-color-scheme"];
|
|
28
|
-
if (hint === _theme.ORIGAM_MODE_DARK && config.modes.includes(_theme.ORIGAM_MODE_DARK)) {
|
|
29
|
-
return _theme.ORIGAM_MODE_DARK;
|
|
30
|
-
}
|
|
31
|
-
if (hint === _theme.ORIGAM_MODE_LIGHT && config.modes.includes(_theme.ORIGAM_MODE_LIGHT)) {
|
|
32
|
-
return _theme.ORIGAM_MODE_LIGHT;
|
|
33
|
-
}
|
|
34
|
-
return _theme.ORIGAM_MODE_LIGHT;
|
|
25
|
+
return config.defaultMode === _theme.ORIGAM_MODE_DARK ? _theme.ORIGAM_MODE_DARK : _theme.ORIGAM_MODE_LIGHT;
|
|
35
26
|
}
|
|
36
27
|
module.exports = (0, _app.defineNuxtPlugin)({
|
|
37
28
|
name: "origam:server",
|
|
@@ -49,22 +40,23 @@ module.exports = (0, _app.defineNuxtPlugin)({
|
|
|
49
40
|
sameSite: "lax",
|
|
50
41
|
path: "/"
|
|
51
42
|
});
|
|
52
|
-
const headers = (0, _app.useRequestHeaders)(["sec-ch-prefers-color-scheme"]);
|
|
53
43
|
const resolvedTheme = resolveServerTheme(themeCookie.value, config);
|
|
54
|
-
const
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
44
|
+
const modePinned = (0, _applyTheme.isModePinned)(modeCookie.value, config.defaultMode);
|
|
45
|
+
const resolvedMode = resolveServerMode(modeCookie.value, config);
|
|
46
|
+
const htmlAttrs = {};
|
|
47
|
+
if (modePinned) {
|
|
48
|
+
htmlAttrs[_theme.ORIGAM_MODE_ATTR] = resolvedMode;
|
|
49
|
+
}
|
|
58
50
|
if (resolvedTheme !== _theme.ORIGAM_THEME_AUTO) {
|
|
59
51
|
htmlAttrs[_theme.ORIGAM_THEME_ATTR] = resolvedTheme;
|
|
60
52
|
}
|
|
61
53
|
const themes = config.themes ?? [];
|
|
62
54
|
const activeThemes = themes.filter(theme => {
|
|
63
55
|
const brandMatches = resolvedTheme === _theme.ORIGAM_THEME_AUTO ? theme.name === void 0 || theme.name === "" : theme.name === resolvedTheme;
|
|
64
|
-
const modeMatches = theme.mode === void 0 || theme.mode === resolvedMode;
|
|
56
|
+
const modeMatches = !modePinned || theme.mode === void 0 || theme.mode === "auto" || theme.mode === resolvedMode;
|
|
65
57
|
return brandMatches && modeMatches;
|
|
66
58
|
});
|
|
67
|
-
const ssrThemeCss = activeThemes.map(_applyTheme.themeToCss).join("\n");
|
|
59
|
+
const ssrThemeCss = modePinned ? activeThemes.map(_applyTheme.themeToCss).join("\n") : [...activeThemes.filter(t => t.mode !== "light" && t.mode !== "dark").map(_applyTheme.themeToCss), ...activeThemes.filter(t => t.mode === "light").map(_applyTheme.themeToUnpinnedCss), ...activeThemes.filter(t => t.mode === "dark").map(_applyTheme.themeToUnpinnedCss)].join("\n");
|
|
68
60
|
(0, _app.useHead)({
|
|
69
61
|
htmlAttrs,
|
|
70
62
|
style: ssrThemeCss ? [{
|
|
@@ -79,11 +71,28 @@ module.exports = (0, _app.defineNuxtPlugin)({
|
|
|
79
71
|
});
|
|
80
72
|
origam._defaultsRef.value = origam._activeDefaultsFor(resolvedTheme === _theme.ORIGAM_THEME_AUTO ? "" : resolvedTheme, resolvedMode);
|
|
81
73
|
nuxtApp.vueApp.use(origam);
|
|
74
|
+
nuxtApp.hook("app:rendered", ({
|
|
75
|
+
ssrContext
|
|
76
|
+
}) => {
|
|
77
|
+
const styles = (0, _ssrStyles.getSsrStyles)(nuxtApp.vueApp);
|
|
78
|
+
if (styles.length && ssrContext) {
|
|
79
|
+
ssrContext.head.push({
|
|
80
|
+
style: styles.map(({
|
|
81
|
+
id,
|
|
82
|
+
css
|
|
83
|
+
}) => ({
|
|
84
|
+
id,
|
|
85
|
+
key: id,
|
|
86
|
+
innerHTML: css
|
|
87
|
+
}))
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
});
|
|
82
91
|
return {
|
|
83
92
|
provide: {
|
|
84
93
|
origam: {
|
|
85
94
|
theme: resolvedTheme,
|
|
86
|
-
mode: resolvedMode
|
|
95
|
+
mode: modePinned ? resolvedMode : "auto"
|
|
87
96
|
}
|
|
88
97
|
}
|
|
89
98
|
};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { createOrigam } from "../origam.js";
|
|
2
|
-
import { themeToCss } from "../utils/Commons/apply-theme.util.js";
|
|
2
|
+
import { isModePinned, themeToCss, themeToUnpinnedCss } from "../utils/Commons/apply-theme.util.js";
|
|
3
|
+
import { getSsrStyles } from "../utils/Commons/ssr-styles.util.js";
|
|
3
4
|
import { ORIGAM_MODE_ATTR, ORIGAM_MODE_DARK, ORIGAM_MODE_LIGHT, ORIGAM_THEME_ATTR, ORIGAM_THEME_AUTO } from "../consts/Commons/theme.const.js";
|
|
4
|
-
import { defineNuxtPlugin, useCookie, useHead,
|
|
5
|
+
import { defineNuxtPlugin, useCookie, useHead, useRuntimeConfig } from "#app";
|
|
5
6
|
function resolveServerTheme(cookieValue, config) {
|
|
6
7
|
if (cookieValue && cookieValue !== ORIGAM_THEME_AUTO) {
|
|
7
8
|
return cookieValue;
|
|
@@ -11,21 +12,11 @@ function resolveServerTheme(cookieValue, config) {
|
|
|
11
12
|
}
|
|
12
13
|
return ORIGAM_THEME_AUTO;
|
|
13
14
|
}
|
|
14
|
-
function resolveServerMode(cookieValue, config
|
|
15
|
+
function resolveServerMode(cookieValue, config) {
|
|
15
16
|
if (cookieValue === ORIGAM_MODE_LIGHT || cookieValue === ORIGAM_MODE_DARK) {
|
|
16
17
|
return cookieValue;
|
|
17
18
|
}
|
|
18
|
-
|
|
19
|
-
return config.defaultMode;
|
|
20
|
-
}
|
|
21
|
-
const hint = headers["sec-ch-prefers-color-scheme"];
|
|
22
|
-
if (hint === ORIGAM_MODE_DARK && config.modes.includes(ORIGAM_MODE_DARK)) {
|
|
23
|
-
return ORIGAM_MODE_DARK;
|
|
24
|
-
}
|
|
25
|
-
if (hint === ORIGAM_MODE_LIGHT && config.modes.includes(ORIGAM_MODE_LIGHT)) {
|
|
26
|
-
return ORIGAM_MODE_LIGHT;
|
|
27
|
-
}
|
|
28
|
-
return ORIGAM_MODE_LIGHT;
|
|
19
|
+
return config.defaultMode === ORIGAM_MODE_DARK ? ORIGAM_MODE_DARK : ORIGAM_MODE_LIGHT;
|
|
29
20
|
}
|
|
30
21
|
export default defineNuxtPlugin({
|
|
31
22
|
name: "origam:server",
|
|
@@ -43,22 +34,27 @@ export default defineNuxtPlugin({
|
|
|
43
34
|
sameSite: "lax",
|
|
44
35
|
path: "/"
|
|
45
36
|
});
|
|
46
|
-
const headers = useRequestHeaders(["sec-ch-prefers-color-scheme"]);
|
|
47
37
|
const resolvedTheme = resolveServerTheme(themeCookie.value, config);
|
|
48
|
-
const
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
38
|
+
const modePinned = isModePinned(modeCookie.value, config.defaultMode);
|
|
39
|
+
const resolvedMode = resolveServerMode(modeCookie.value, config);
|
|
40
|
+
const htmlAttrs = {};
|
|
41
|
+
if (modePinned) {
|
|
42
|
+
htmlAttrs[ORIGAM_MODE_ATTR] = resolvedMode;
|
|
43
|
+
}
|
|
52
44
|
if (resolvedTheme !== ORIGAM_THEME_AUTO) {
|
|
53
45
|
htmlAttrs[ORIGAM_THEME_ATTR] = resolvedTheme;
|
|
54
46
|
}
|
|
55
47
|
const themes = config.themes ?? [];
|
|
56
48
|
const activeThemes = themes.filter((theme) => {
|
|
57
49
|
const brandMatches = resolvedTheme === ORIGAM_THEME_AUTO ? theme.name === void 0 || theme.name === "" : theme.name === resolvedTheme;
|
|
58
|
-
const modeMatches = theme.mode === void 0 || theme.mode === resolvedMode;
|
|
50
|
+
const modeMatches = !modePinned || theme.mode === void 0 || theme.mode === "auto" || theme.mode === resolvedMode;
|
|
59
51
|
return brandMatches && modeMatches;
|
|
60
52
|
});
|
|
61
|
-
const ssrThemeCss = activeThemes.map(themeToCss).join("\n")
|
|
53
|
+
const ssrThemeCss = modePinned ? activeThemes.map(themeToCss).join("\n") : [
|
|
54
|
+
...activeThemes.filter((t) => t.mode !== "light" && t.mode !== "dark").map(themeToCss),
|
|
55
|
+
...activeThemes.filter((t) => t.mode === "light").map(themeToUnpinnedCss),
|
|
56
|
+
...activeThemes.filter((t) => t.mode === "dark").map(themeToUnpinnedCss)
|
|
57
|
+
].join("\n");
|
|
62
58
|
useHead({
|
|
63
59
|
htmlAttrs,
|
|
64
60
|
style: ssrThemeCss ? [{ id: "origam-theme-ssr", key: "origam-theme-ssr", innerHTML: ssrThemeCss }] : []
|
|
@@ -69,11 +65,19 @@ export default defineNuxtPlugin({
|
|
|
69
65
|
resolvedMode
|
|
70
66
|
);
|
|
71
67
|
nuxtApp.vueApp.use(origam);
|
|
68
|
+
nuxtApp.hook("app:rendered", ({ ssrContext }) => {
|
|
69
|
+
const styles = getSsrStyles(nuxtApp.vueApp);
|
|
70
|
+
if (styles.length && ssrContext) {
|
|
71
|
+
ssrContext.head.push({
|
|
72
|
+
style: styles.map(({ id, css }) => ({ id, key: id, innerHTML: css }))
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
});
|
|
72
76
|
return {
|
|
73
77
|
provide: {
|
|
74
78
|
origam: {
|
|
75
79
|
theme: resolvedTheme,
|
|
76
|
-
mode: resolvedMode
|
|
80
|
+
mode: modePinned ? resolvedMode : "auto"
|
|
77
81
|
}
|
|
78
82
|
}
|
|
79
83
|
};
|
package/dist/src/origam.cjs
CHANGED
|
@@ -69,6 +69,9 @@ function createOrigam(origam = {}) {
|
|
|
69
69
|
app.provide(_consts.ORIGAM_GO_TO_KEY, goTo);
|
|
70
70
|
app.provide(_consts.ORIGAM_THEMES_KEY, installedThemes);
|
|
71
71
|
app.provide(_consts.ORIGAM_DEFAULTS_KEY, defaultsRef);
|
|
72
|
+
if (!_consts.IN_BROWSER) {
|
|
73
|
+
app.provide(_consts.ORIGAM_SSR_STYLES_KEY, (0, _utils.registerSsrStyleCollector)(app));
|
|
74
|
+
}
|
|
72
75
|
(0, _composables.installThemePropsResolver)(app, themedKeysUnion, variantPresets);
|
|
73
76
|
app.provide(_consts.ORIGAM_THEME_DEFAULTS_KEY, (brand, mode) => activeDefaultsFor(allThemes, brand, mode));
|
|
74
77
|
if (_consts.IN_BROWSER && options.ssr) {
|
package/dist/src/origam.js
CHANGED
|
@@ -20,13 +20,14 @@ import {
|
|
|
20
20
|
ORIGAM_GO_TO_KEY,
|
|
21
21
|
ORIGAM_ICONS_KEY,
|
|
22
22
|
ORIGAM_LOCALE_KEY,
|
|
23
|
+
ORIGAM_SSR_STYLES_KEY,
|
|
23
24
|
ORIGAM_THEME_DEFAULTS_KEY,
|
|
24
25
|
ORIGAM_THEMES_KEY,
|
|
25
26
|
VARIANT_PRESETS
|
|
26
27
|
} from "./consts/index.js";
|
|
27
28
|
import * as origamDirectives from "./directives/index.js";
|
|
28
29
|
import { setContrastConfig } from "./directives/Contrast/contrast.directive.js";
|
|
29
|
-
import { applyThemes, installedThemesFromList, mergeDeep } from "./utils/index.js";
|
|
30
|
+
import { applyThemes, installedThemesFromList, mergeDeep, registerSsrStyleCollector } from "./utils/index.js";
|
|
30
31
|
import "@mdi/font/css/materialdesignicons.css";
|
|
31
32
|
import { defineComponent, effectScope, nextTick, reactive } from "vue";
|
|
32
33
|
export function createOrigam(origam = {}) {
|
|
@@ -88,6 +89,9 @@ export function createOrigam(origam = {}) {
|
|
|
88
89
|
app.provide(ORIGAM_GO_TO_KEY, goTo);
|
|
89
90
|
app.provide(ORIGAM_THEMES_KEY, installedThemes);
|
|
90
91
|
app.provide(ORIGAM_DEFAULTS_KEY, defaultsRef);
|
|
92
|
+
if (!IN_BROWSER) {
|
|
93
|
+
app.provide(ORIGAM_SSR_STYLES_KEY, registerSsrStyleCollector(app));
|
|
94
|
+
}
|
|
91
95
|
installThemePropsResolver(app, themedKeysUnion, variantPresets);
|
|
92
96
|
app.provide(ORIGAM_THEME_DEFAULTS_KEY, (brand, mode) => activeDefaultsFor(allThemes, brand, mode));
|
|
93
97
|
if (IN_BROWSER && options.ssr) {
|