origam 2.36.0 → 2.37.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/CHANGELOG.md CHANGED
@@ -18,6 +18,26 @@ This project follows [Semantic Versioning](https://semver.org).
18
18
 
19
19
  ## [Unreleased]
20
20
 
21
+ ## [2.37.1] - 2026-10-19
22
+
23
+ ### Fixed — `OrigamImg` / `OrigamResponsive` : prop `tag`, `<img>` visible en SSR, fondu en rendu client seul (#1182)
24
+
25
+ Un `<origam-img>` placé dans un `<p>` (contenu prose) produisait un `<div>` invalide dans un paragraphe, que le parseur HTML expulse : DOM serveur et client divergeaient. Et l'`<img>` était servie en `display:none` jusqu'au `load` côté client, donc invisible tant que le JS n'avait pas tourné.
26
+
27
+ - **Nouvelle prop `tag`** (défaut `'div'`) sur `OrigamResponsive` et `OrigamImg` (transmise au Responsive et aux conteneurs placeholder / error / gradient). `tag="span"` garde un DOM valide dans un `<p>`.
28
+ - **`<img>` visible dans le HTML serveur** : elle n'est plus masquée avant le `load`.
29
+ - **Fondu conservé uniquement au montage client** (navigation SPA, `v-if` après hydratation). Une image hydratée depuis le HTML serveur s'affiche sans fondu et sans clignotement.
30
+ - ⚠️ Changement de rendu assumé : en rendu serveur puis hydratation, l'image n'apparaît plus en fondu.
31
+
32
+ ## [2.37.0] - 2026-10-19
33
+
34
+ ### Added — module Nuxt : options `locale` transmises à `createOrigam` (#1181)
35
+
36
+ - Le module accepte `origam: { locale: { locale, fallbackLocale, messages } }` (même forme que `createOrigam({ locale })`, type `ILocaleOptions`). Les options transitent par `runtimeConfig.public.origam.locale` et sont passées à l'identique par les plugins client et serveur : pas d'écart d'hydratation.
37
+ - Avant, les deux plugins appelaient `createOrigam({ themes, ssr: true })` sans locale : sous Nuxt, `useLocale().current` valait toujours `en`, et les libellés intégrés (noms accessibles des blocs de code, palette de commandes…) restaient en anglais sur un site ja/ko/zh.
38
+ - `messages` est fusionné avec les locales intégrées `en` et `fr` : un site peut fournir `ja` complet ou surcharger quelques clés `fr`. `fallbackLocale` et `messages` deviennent optionnels dans `ILocaleOptions`.
39
+ - Doc : section « Ajouter une langue (gabarit de traduction) » dans le guide i18n ; la liste des clés est `origam/assets/locales/en.json`.
40
+
21
41
  ## [2.36.0] - 2026-10-19
22
42
 
23
43
  ### Added — `OrigamCodeGroup` : groupe de code à onglets (npm / pnpm / yarn) en une seule surface (#1179)
@@ -76,6 +76,7 @@ const props = defineProps({
76
76
  id: { type: String, required: false },
77
77
  class: { type: [String, Array, Object], required: false },
78
78
  style: { type: [String, Array, Object, Boolean, null], required: false, skipCheck: true },
79
+ tag: { type: String, required: false },
79
80
  padding: { type: [Boolean, Number, String], required: false },
80
81
  paddingTop: { type: [Boolean, Number, String], required: false },
81
82
  paddingLeft: { type: [Boolean, Number, String], required: false },
@@ -10,11 +10,11 @@
10
10
  >
11
11
  <template #additional>
12
12
  <origam-transition
13
+ :appear="fadesIn"
13
14
  :transition="transition"
14
- appear
15
15
  >
16
16
  <img
17
- v-show="isLoaded"
17
+ v-show="isPictureShown"
18
18
  ref="image"
19
19
  :alt="alt"
20
20
  :class="imgPictureClasses"
@@ -46,25 +46,28 @@
46
46
  :transition="transition"
47
47
  appear
48
48
  >
49
- <div
49
+ <component
50
+ :is="tag"
50
51
  v-if="(isLoading || (isError && !slots.error)) && slots.placeholder"
51
52
  class="origam-img__placeholder"
52
53
  >
53
54
  <slot name="placeholder"/>
54
- </div>
55
+ </component>
55
56
  </origam-transition>
56
57
  <origam-transition
57
58
  :transition="transition"
58
59
  appear
59
60
  >
60
- <div
61
+ <component
62
+ :is="tag"
61
63
  v-if="isError && slots.error"
62
64
  class="origam-img__error"
63
65
  >
64
66
  <slot name="error"/>
65
- </div>
67
+ </component>
66
68
  </origam-transition>
67
- <div
69
+ <component
70
+ :is="tag"
68
71
  v-if="gradient"
69
72
  :style="imgGradientStyles"
70
73
  class="origam-img__gradient"
@@ -133,6 +136,7 @@ const props = defineProps({
133
136
  id: { type: String, required: false },
134
137
  class: { type: [String, Array, Object], required: false },
135
138
  style: { type: [String, Array, Object, Boolean, null], required: false, skipCheck: true },
139
+ tag: { type: String, required: false, default: "div" },
136
140
  padding: { type: [Boolean, Number, String], required: false },
137
141
  paddingTop: { type: [Boolean, Number, String], required: false },
138
142
  paddingLeft: { type: [Boolean, Number, String], required: false },
@@ -219,7 +223,7 @@ const normalisedSrc = computed(() => {
219
223
  const aspectRatio = computed(() => {
220
224
  return normalisedSrc.value.aspectRatio || naturalWidth.value / naturalHeight.value || 0;
221
225
  });
222
- const responsiveProps = computed(() => pick(props, ["aspectRatio", "contentClass", "height", "maxHeight", "maxWidth", "minHeight", "minWidth", "width", "class", "style"]));
226
+ const responsiveProps = computed(() => pick(props, ["tag", "aspectRatio", "contentClass", "height", "maxHeight", "maxWidth", "minHeight", "minWidth", "width", "class", "style"]));
223
227
  watch(() => props.src, () => {
224
228
  init(state.value !== IMG_STATE.IDLE);
225
229
  });
@@ -337,6 +341,10 @@ const isLoading = computed(() => {
337
341
  const isError = computed(() => {
338
342
  return state.value === IMG_STATE.ERROR;
339
343
  });
344
+ const fadesIn = IN_BROWSER && !vm.vnode.el;
345
+ const isPictureShown = computed(() => {
346
+ return fadesIn ? isLoaded.value : !isError.value;
347
+ });
340
348
  const hasContent = computed(() => {
341
349
  return slots.default;
342
350
  });
@@ -1,17 +1,19 @@
1
1
  <template>
2
- <div
2
+ <component
3
+ :is="tag"
3
4
  :id="id"
4
5
  :class="responsiveClasses"
5
6
  :style="responsiveStyles"
6
7
  >
7
8
  <slot name="additional"/>
8
- <div
9
+ <component
10
+ :is="tag"
9
11
  v-if="slots.default"
10
12
  :class="responsiveContentClasses"
11
13
  >
12
14
  <slot name="default"/>
13
- </div>
14
- </div>
15
+ </component>
16
+ </component>
15
17
  </template>
16
18
 
17
19
  <script lang="ts" setup>
@@ -36,6 +38,7 @@ const props = defineProps({
36
38
  id: { type: String, required: false },
37
39
  class: { type: [String, Array, Object], required: false },
38
40
  style: { type: [String, Array, Object, Boolean, null], required: false, skipCheck: true },
41
+ tag: { type: String, required: false, default: "div" },
39
42
  padding: { type: [Boolean, Number, String], required: false },
40
43
  paddingTop: { type: [Boolean, Number, String], required: false },
41
44
  paddingLeft: { type: [Boolean, Number, String], required: false },
@@ -13,8 +13,8 @@ export interface ILocaleInstance {
13
13
  }
14
14
  export interface ILocaleOptions {
15
15
  locale?: string;
16
- fallbackLocale: string;
17
- messages: Record<string, unknown>;
16
+ fallbackLocale?: string;
17
+ messages?: Record<string, unknown>;
18
18
  }
19
19
  /**
20
20
  * Formes STRUCTURELLES de vue-i18n, declarees localement.
@@ -1,3 +1,4 @@
1
+ import type { ILocaleOptions } from './locale.interface';
1
2
  import type { IOrigamTheme } from './theme.interface';
2
3
  import type { TMode, TTheme } from '../../types/Commons/theme.type';
3
4
  /**
@@ -26,6 +27,20 @@ export interface IOrigamNuxtModuleOptions {
26
27
  * When omitted, `createOrigam` installs the DS built-in baseline (neutral identity).
27
28
  */
28
29
  themes?: IOrigamTheme[];
30
+ /*********************************************************
31
+ * locale
32
+ *
33
+ * @description
34
+ * Locale of Origam's built-in strings (aria-labels, button labels, …), forwarded to `createOrigam({ locale })` by BOTH plugins (client and server) so the SSR markup and the hydration render agree.
35
+ * @description
36
+ * Must stay serialisable — it travels through `runtimeConfig`. `messages` is MERGED over the built-in `en` / `fr` catalogues: a site can supply a complete `ja`, or override a few `fr` keys. Origam does NOT follow `<html lang>`.
37
+ * @description
38
+ * The key list to translate is `origam/assets/locales/en.json`.
39
+ *
40
+ * @example
41
+ * origam: { locale: { locale: 'ja', fallbackLocale: 'en', messages: { ja } } }
42
+ ********************************************************/
43
+ locale?: ILocaleOptions;
29
44
  /**
30
45
  * Theme (brand) applied when no cookie is set. Use `'auto'` to render no
31
46
  * `data-theme` attribute (the default brand).
@@ -111,6 +126,7 @@ export interface IOrigamNuxtRuntimeConfig {
111
126
  cookieName: string;
112
127
  modeCookieName: string;
113
128
  cookieMaxAge: number;
129
+ locale?: ILocaleOptions;
114
130
  }
115
131
  /*********************************************************
116
132
  * IOrigamNuxtProvide
@@ -1,10 +1,10 @@
1
1
  import type { IBorderProps } from '../Commons/border.interface';
2
- import type { ICommonsComponentProps } from '../Commons/commons.interface';
2
+ import type { ICommonsComponentProps, ITagProps } from '../Commons/commons.interface';
3
3
  import type { IDimensionProps } from '../Commons/dimension.interface';
4
4
  import type { IMarginProps } from '../Commons/margin.interface';
5
5
  import type { IPaddingProps } from '../Commons/padding.interface';
6
6
  import type { IRoundedProps } from '../Commons/rounded.interface';
7
- export interface IResponsiveProps extends IDimensionProps, ICommonsComponentProps, IPaddingProps, IMarginProps, IBorderProps, IRoundedProps {
7
+ export interface IResponsiveProps extends IDimensionProps, ICommonsComponentProps, ITagProps, IPaddingProps, IMarginProps, IBorderProps, IRoundedProps {
8
8
  aspectRatio?: string | number;
9
9
  contentClass?: string;
10
10
  }
@@ -23,7 +23,8 @@ const DEFAULTS = {
23
23
  cookieMaxAge: 60 * 60 * 24 * 365,
24
24
  autoImport: true,
25
25
  includeUtilities: true,
26
- prefix: "Origam"
26
+ prefix: "Origam",
27
+ locale: {}
27
28
  };
28
29
  const SCALAR_DEFAULTS = {
29
30
  defaultTheme: DEFAULTS.defaultTheme,
@@ -139,7 +140,8 @@ const origamNuxtModule = (0, _kit.defineNuxtModule)({
139
140
  defaultMode,
140
141
  cookieName,
141
142
  modeCookieName,
142
- cookieMaxAge
143
+ cookieMaxAge,
144
+ locale: options.locale
143
145
  };
144
146
  }
145
147
  });
@@ -22,7 +22,8 @@ const DEFAULTS = {
22
22
  cookieMaxAge: 60 * 60 * 24 * 365,
23
23
  autoImport: true,
24
24
  includeUtilities: true,
25
- prefix: "Origam"
25
+ prefix: "Origam",
26
+ locale: {}
26
27
  };
27
28
  const SCALAR_DEFAULTS = {
28
29
  defaultTheme: DEFAULTS.defaultTheme,
@@ -135,7 +136,8 @@ const origamNuxtModule = defineNuxtModule({
135
136
  defaultMode,
136
137
  cookieName,
137
138
  modeCookieName,
138
- cookieMaxAge
139
+ cookieMaxAge,
140
+ locale: options.locale
139
141
  };
140
142
  }
141
143
  });
@@ -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 _nuxtLocale = require("../utils/Commons/nuxt-locale.util.cjs");
10
11
  var _applyTheme = require("../utils/Commons/apply-theme.util.cjs");
11
12
  var _app = require("#app");
12
13
  module.exports = (0, _app.defineNuxtPlugin)({
@@ -31,7 +32,8 @@ module.exports = (0, _app.defineNuxtPlugin)({
31
32
  const themes = config.themes ?? [];
32
33
  const origam = (0, _origam.createOrigam)({
33
34
  themes,
34
- ssr: true
35
+ ssr: true,
36
+ ...(0, _nuxtLocale.nuxtLocaleOptions)(config)
35
37
  });
36
38
  nuxtApp.vueApp.use(origam);
37
39
  const themeApi = (0, _theme.useTheme)();
@@ -1,6 +1,7 @@
1
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 { nuxtLocaleOptions } from "../utils/Commons/nuxt-locale.util.js";
4
5
  import { isModePinned } from "../utils/Commons/apply-theme.util.js";
5
6
  import { defineNuxtPlugin, useCookie, useRuntimeConfig } from "#app";
6
7
  export default defineNuxtPlugin({
@@ -23,7 +24,7 @@ export default defineNuxtPlugin({
23
24
  const initialTheme = themeFromDom ?? themeCookie.value ?? config.defaultTheme;
24
25
  const initialMode = modeCookie.value ?? config.defaultMode;
25
26
  const themes = config.themes ?? [];
26
- const origam = createOrigam({ themes, ssr: true });
27
+ const origam = createOrigam({ themes, ssr: true, ...nuxtLocaleOptions(config) });
27
28
  nuxtApp.vueApp.use(origam);
28
29
  const themeApi = useTheme();
29
30
  themeApi.setTheme(initialTheme);
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
 
7
7
  var _origam = require("../origam.cjs");
8
+ var _nuxtLocale = require("../utils/Commons/nuxt-locale.util.cjs");
8
9
  var _applyTheme = require("../utils/Commons/apply-theme.util.cjs");
9
10
  var _ssrStyles = require("../utils/Commons/ssr-styles.util.cjs");
10
11
  var _theme = require("../consts/Commons/theme.const.cjs");
@@ -67,7 +68,8 @@ module.exports = (0, _app.defineNuxtPlugin)({
67
68
  });
68
69
  const origam = (0, _origam.createOrigam)({
69
70
  themes,
70
- ssr: true
71
+ ssr: true,
72
+ ...(0, _nuxtLocale.nuxtLocaleOptions)(config)
71
73
  });
72
74
  origam._defaultsRef.value = origam._activeDefaultsFor(resolvedTheme === _theme.ORIGAM_THEME_AUTO ? "" : resolvedTheme, resolvedMode);
73
75
  nuxtApp.vueApp.use(origam);
@@ -1,4 +1,5 @@
1
1
  import { createOrigam } from "../origam.js";
2
+ import { nuxtLocaleOptions } from "../utils/Commons/nuxt-locale.util.js";
2
3
  import { isModePinned, themeToCss, themeToUnpinnedCss } from "../utils/Commons/apply-theme.util.js";
3
4
  import { getSsrStyles } from "../utils/Commons/ssr-styles.util.js";
4
5
  import { ORIGAM_MODE_ATTR, ORIGAM_MODE_DARK, ORIGAM_MODE_LIGHT, ORIGAM_THEME_ATTR, ORIGAM_THEME_AUTO } from "../consts/Commons/theme.const.js";
@@ -59,7 +60,7 @@ export default defineNuxtPlugin({
59
60
  htmlAttrs,
60
61
  style: ssrThemeCss ? [{ id: "origam-theme-ssr", key: "origam-theme-ssr", innerHTML: ssrThemeCss }] : []
61
62
  });
62
- const origam = createOrigam({ themes, ssr: true });
63
+ const origam = createOrigam({ themes, ssr: true, ...nuxtLocaleOptions(config) });
63
64
  origam._defaultsRef.value = origam._activeDefaultsFor(
64
65
  resolvedTheme === ORIGAM_THEME_AUTO ? "" : resolvedTheme,
65
66
  resolvedMode
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.nuxtLocaleOptions = nuxtLocaleOptions;
7
+ function nuxtLocaleOptions(config) {
8
+ return config.locale ? {
9
+ locale: config.locale
10
+ } : {};
11
+ }
@@ -0,0 +1,15 @@
1
+ import type { IOrigamOptions } from '../../interfaces/Commons/commons.interface';
2
+ import type { IOrigamNuxtRuntimeConfig } from '../../interfaces/Commons/nuxt-module.interface';
3
+ /*********************************************************
4
+ * nuxtLocaleOptions
5
+ *
6
+ * @description
7
+ * The `createOrigam()` options derived from the module's `locale` setting (#1181).
8
+ * Shared by `plugin.client.ts` and `plugin.server.ts` so both feed `createOrigam`
9
+ * the SAME locale — a difference would render different built-in strings on the
10
+ * server and during hydration.
11
+ * @description
12
+ * Returns `{}` when no locale is configured, so `createLocale()` keeps its own
13
+ * defaults (`en`, fallback `en`, built-in `en` / `fr` messages).
14
+ ********************************************************/
15
+ export declare function nuxtLocaleOptions(config: Pick<IOrigamNuxtRuntimeConfig, 'locale'>): Pick<IOrigamOptions, 'locale'>;
@@ -0,0 +1,3 @@
1
+ export function nuxtLocaleOptions(config) {
2
+ return config.locale ? { locale: config.locale } : {};
3
+ }
@@ -190,6 +190,17 @@ Object.keys(_locale).forEach(function (key) {
190
190
  }
191
191
  });
192
192
  });
193
+ var _nuxtLocale = require("./Commons/nuxt-locale.util.cjs");
194
+ Object.keys(_nuxtLocale).forEach(function (key) {
195
+ if (key === "default" || key === "__esModule") return;
196
+ if (key in exports && exports[key] === _nuxtLocale[key]) return;
197
+ Object.defineProperty(exports, key, {
198
+ enumerable: true,
199
+ get: function () {
200
+ return _nuxtLocale[key];
201
+ }
202
+ });
203
+ });
193
204
  var _nested = require("./Commons/nested.util.cjs");
194
205
  Object.keys(_nested).forEach(function (key) {
195
206
  if (key === "default" || key === "__esModule") return;
@@ -15,6 +15,7 @@ export * from './Commons/getCurrentInstance.util';
15
15
  export * from './Commons/ssr-styles.util';
16
16
  export * from './Commons/layout.util';
17
17
  export * from './Commons/locale.util';
18
+ export * from './Commons/nuxt-locale.util';
18
19
  export * from './Commons/nested.util';
19
20
  export * from './Commons/ripple.util';
20
21
  export * from './Commons/rounded.util';
@@ -15,6 +15,7 @@ export * from "./Commons/getCurrentInstance.util.js";
15
15
  export * from "./Commons/ssr-styles.util.js";
16
16
  export * from "./Commons/layout.util.js";
17
17
  export * from "./Commons/locale.util.js";
18
+ export * from "./Commons/nuxt-locale.util.js";
18
19
  export * from "./Commons/nested.util.js";
19
20
  export * from "./Commons/ripple.util.js";
20
21
  export * from "./Commons/rounded.util.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "origam",
3
- "version": "2.36.0",
3
+ "version": "2.37.1",
4
4
  "type": "module",
5
5
  "description": "origam — a Vue 3 design system with multi-theme design tokens, CSS-first components and TypeScript types.",
6
6
  "keywords": [