@fy-/fws-vue 2.4.1 → 2.4.3

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.
@@ -139,11 +139,19 @@ onUnmounted(() => {
139
139
 
140
140
  <!-- Input field -->
141
141
  <div class="mb-6">
142
+ <!-- Label uses v-html so entity-escaped strings render decoded. -->
143
+ <label
144
+ v-if="inputLabel"
145
+ for="confirmInput"
146
+ class="block mb-2 text-sm font-medium text-fv-neutral-900 dark:text-white"
147
+ :class="{ 'text-red-600 dark:text-red-400': inputError }"
148
+ v-html="inputLabel"
149
+ />
142
150
  <DefaultInput
143
151
  id="confirmInput"
144
152
  v-model="inputValue"
145
153
  type="text"
146
- :label="inputLabel"
154
+ :show-label="false"
147
155
  :placeholder="inputPlaceholder"
148
156
  :error="inputError"
149
157
  autocomplete="off"
package/index.ts CHANGED
@@ -1,8 +1,10 @@
1
+ import type { TFunction } from 'i18next'
1
2
  import type { Emitter } from 'mitt'
2
3
  import type { App, Plugin } from 'vue'
3
4
  import type { Events } from './composables/event-bus'
4
5
  import i18next from 'i18next'
5
6
  import mitt from 'mitt'
7
+ import { shallowRef } from 'vue'
6
8
  import CmsArticleBoxed from './components/fws/CmsArticleBoxed.vue'
7
9
  import CmsArticleSingle from './components/fws/CmsArticleSingle.vue'
8
10
  import DataTable from './components/fws/DataTable.vue'
@@ -70,15 +72,40 @@ function createFWS(): Plugin {
70
72
  // @ts-expect-error: Emitter<Events> is not assignable to Emitter<Events>
71
73
  const eventBus: Emitter<Events> = mitt<Events>()
72
74
 
75
+ // i18next's `t` is NOT reactive. If a component renders a key during a window
76
+ // where the resource isn't loaded yet (cold deep-link, client-nav before a late
77
+ // locale fetch, hydration race) it paints the RAW token and Vue never re-renders
78
+ // — nothing reactive changed, so the miss sticks. Wrap `t` so it depends on a
79
+ // tick bumped by i18next's own events: any raw key then self-heals the instant
80
+ // resources land, and `changeLanguage` live-updates every string. Client-only:
81
+ // on the server strings are already resolved by the `await i18nextPromise` before
82
+ // render, and `install()` runs per-request there — adding listeners to the global
83
+ // i18next singleton each request would leak. So SSR keeps the plain `t`.
84
+ let translate: TFunction = i18next.t
85
+ if (typeof window !== 'undefined') {
86
+ const tick = shallowRef(0)
87
+ const bump = (): void => {
88
+ tick.value++
89
+ }
90
+ i18next.on('loaded', bump)
91
+ i18next.on('added', bump)
92
+ i18next.on('languageChanged', bump)
93
+ const rawT = i18next.t as unknown as (...a: unknown[]) => unknown
94
+ translate = ((...args: Parameters<typeof i18next.t>) => {
95
+ void tick.value
96
+ return rawT(...args)
97
+ }) as unknown as TFunction
98
+ }
99
+
73
100
  return {
74
101
  install(app: App) {
75
102
  if (app.config.globalProperties) {
76
103
  app.config.globalProperties.$eventBus = eventBus
77
104
  app.provide('fwsVueEventBus', eventBus)
78
105
 
79
- // i18next
80
- app.config.globalProperties.$t = i18next.t
81
- app.provide('fwsVueTranslate', i18next.t)
106
+ // i18next (reactive wrapper — see note above)
107
+ app.config.globalProperties.$t = translate
108
+ app.provide('fwsVueTranslate', translate)
82
109
 
83
110
  // Templating
84
111
  app.config.globalProperties.$cropText = cropText
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fy-/fws-vue",
3
- "version": "2.4.1",
3
+ "version": "2.4.3",
4
4
  "author": "Florian 'Fy' Gasquez <m@fy.to>",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/fy-to/FWJS#readme",