origam 2.10.0 → 2.12.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.
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <component
3
- :is="tag"
3
+ :is="props.tag"
4
4
  :id="id"
5
5
  :class="avatarClasses"
6
6
  @click="handleClick"
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <component
3
- :is="tag"
3
+ :is="props.tag"
4
4
  :id="id"
5
5
  role="group"
6
6
  :class="btnGroupClasses"
@@ -30,6 +30,7 @@ import { OrigamBtn, OrigamDefaultsProvider } from "../../components";
30
30
  import {
31
31
  useDefaults,
32
32
  useDensity,
33
+ usePassedProps,
33
34
  useProps,
34
35
  useSize,
35
36
  useStateEffect,
@@ -37,6 +38,7 @@ import {
37
38
  useVariant
38
39
  } from "../../composables";
39
40
  import { DENSITY } from "../../enums";
41
+ import { omitUndefined } from "../../utils";
40
42
  import { computed, StyleValue, useSlots } from "vue";
41
43
  const _props = defineProps({
42
44
  divided: { type: Boolean, required: false },
@@ -89,19 +91,33 @@ const _props = defineProps({
89
91
  });
90
92
  const props = useDefaults(_props);
91
93
  const { filterProps } = useProps(props);
94
+ const wasPropPassed = usePassedProps(props);
92
95
  const slotDefaults = computed(() => ({
93
- "origam-btn": {
96
+ "origam-btn": omitUndefined({
97
+ // `variant` is the ONE deliberate exception, kept unconditional:
98
+ // `--variant-text` (the group's own root default, and every
99
+ // child's own component default) has NO active-state background
100
+ // rule at all — only `outlined`/`tonal` paint a filled surface
101
+ // on the selected segment (see OrigamBtn.vue's
102
+ // `&--variant-outlined { &--active { background-color: ... } }`).
103
+ // The group's OWN resolved `variant` (whether explicitly passed,
104
+ // or resolved from a theme's `'origam-btn-group'` defaults) must
105
+ // always reach the children — else a themed
106
+ // `<origam-btn-toggle variant="outlined">` gets the right root
107
+ // chrome but every child silently stays on 'text', so the active
108
+ // segment never fills — no visible selection at all.
94
109
  variant: props.variant,
95
- density: props.density,
96
- color: props.color,
97
- bgColor: props.bgColor,
98
- size: props.size,
110
+ density: wasPropPassed("density") ? props.density : void 0,
111
+ color: wasPropPassed("color") ? props.color : void 0,
112
+ bgColor: wasPropPassed("bgColor") ? props.bgColor : void 0,
113
+ size: wasPropPassed("size") ? props.size : void 0,
99
114
  // New API: `hover` / `active` accept boolean | IHoverState |
100
115
  // IActiveState; pass-through propagates the parent's intent
101
- // override to each child OrigamBtn.
102
- hover: props.hover,
103
- active: props.active
104
- }
116
+ // override to each child OrigamBtn — only when the consumer
117
+ // actually set it.
118
+ hover: wasPropPassed("hover") ? props.hover : void 0,
119
+ active: wasPropPassed("active") ? props.active : void 0
120
+ })
105
121
  }));
106
122
  const items = computed(() => props.items ?? []);
107
123
  const slots = useSlots();
@@ -77,7 +77,26 @@ const props = defineProps({
77
77
  bgColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
78
78
  active: { type: [Boolean, Object], required: false },
79
79
  activeClass: { type: String, required: false },
80
- hover: { type: [Boolean, Object], required: false }
80
+ hover: { type: [Boolean, Object], required: false },
81
+ border: { type: [Boolean, Number, String, Array], required: false, skipCheck: true },
82
+ borderTop: { type: [Boolean, Number, String], required: false },
83
+ borderLeft: { type: [Boolean, Number, String], required: false },
84
+ borderBottom: { type: [Boolean, Number, String], required: false },
85
+ borderRight: { type: [Boolean, Number, String], required: false },
86
+ borderBlock: { type: [Boolean, Number, String], required: false },
87
+ borderInline: { type: [Boolean, Number, String], required: false },
88
+ borderColor: { type: String, required: false },
89
+ borderStyle: { type: String, required: false },
90
+ borderTopColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
91
+ borderRightColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
92
+ borderBottomColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
93
+ borderLeftColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
94
+ rounded: { type: [Boolean, Number, String, null], required: false, skipCheck: true },
95
+ roundedTopRight: { type: [Boolean, Number, String], required: false },
96
+ roundedTopLeft: { type: [Boolean, Number, String], required: false },
97
+ roundedBottomLeft: { type: [Boolean, Number, String], required: false },
98
+ roundedBottomRight: { type: [Boolean, Number, String], required: false },
99
+ elevation: { type: [Number, String], required: false }
81
100
  });
82
101
  const emits = defineEmits(["update:indeterminate", "update:modelValue", "update:focused", "click:label"]);
83
102
  defineSlots();
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <component
3
- :is="tag"
3
+ :is="props.tag"
4
4
  v-contrast
5
5
  :class="expansionPanelClasses"
6
6
  :style="expansionPanelStyles"
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <component
3
- :is="tag"
3
+ :is="props.tag"
4
4
  :id="id"
5
5
  v-contrast
6
6
  :class="labelClasses"
@@ -4,7 +4,7 @@
4
4
  :transition="transition"
5
5
  >
6
6
  <component
7
- :is="tag"
7
+ :is="props.tag"
8
8
  :class="messagesClasses"
9
9
  :style="[messagesStyles, rootTypographyStyles]"
10
10
  aria-live="polite"
@@ -73,7 +73,26 @@ const props = defineProps({
73
73
  bgColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
74
74
  active: { type: [Boolean, Object], required: false },
75
75
  activeClass: { type: String, required: false },
76
- hover: { type: [Boolean, Object], required: false }
76
+ hover: { type: [Boolean, Object], required: false },
77
+ border: { type: [Boolean, Number, String, Array], required: false, skipCheck: true },
78
+ borderTop: { type: [Boolean, Number, String], required: false },
79
+ borderLeft: { type: [Boolean, Number, String], required: false },
80
+ borderBottom: { type: [Boolean, Number, String], required: false },
81
+ borderRight: { type: [Boolean, Number, String], required: false },
82
+ borderBlock: { type: [Boolean, Number, String], required: false },
83
+ borderInline: { type: [Boolean, Number, String], required: false },
84
+ borderColor: { type: String, required: false },
85
+ borderStyle: { type: String, required: false },
86
+ borderTopColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
87
+ borderRightColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
88
+ borderBottomColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
89
+ borderLeftColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
90
+ rounded: { type: [Boolean, Number, String, null], required: false, skipCheck: true },
91
+ roundedTopRight: { type: [Boolean, Number, String], required: false },
92
+ roundedTopLeft: { type: [Boolean, Number, String], required: false },
93
+ roundedBottomLeft: { type: [Boolean, Number, String], required: false },
94
+ roundedBottomRight: { type: [Boolean, Number, String], required: false },
95
+ elevation: { type: [Number, String], required: false }
77
96
  });
78
97
  const emits = defineEmits(["update:modelValue", "update:focused", "click:label"]);
79
98
  const { filterProps } = useProps(props);
@@ -15,7 +15,8 @@
15
15
 
16
16
  <div
17
17
  v-ripple="rippleProp"
18
- class="origam-selection-control__input"
18
+ :class="selectionControlInputClasses"
19
+ :style="selectionControlInputStyles"
19
20
  >
20
21
  <slot
21
22
  name="input"
@@ -69,10 +70,13 @@ import { computed, inject, nextTick, ref, shallowRef, StyleValue, useAttrs } fro
69
70
  import { ORIGAM_SELECTION_CONTROL_GROUP_KEY } from "../../consts";
70
71
  import { OrigamIcon, OrigamLabel } from "../../components";
71
72
  import {
73
+ useBorder,
72
74
  useDefaults,
73
75
  useDensity,
76
+ useElevation,
74
77
  useHover,
75
78
  useProps,
79
+ useRounded,
76
80
  useStateEffect,
77
81
  useStyle,
78
82
  useTextColor,
@@ -108,7 +112,26 @@ const _props = defineProps({
108
112
  bgColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
109
113
  active: { type: [Boolean, Object], required: false },
110
114
  activeClass: { type: String, required: false },
111
- hover: { type: [Boolean, Object], required: false }
115
+ hover: { type: [Boolean, Object], required: false },
116
+ border: { type: [Boolean, Number, String, Array], required: false, skipCheck: true },
117
+ borderTop: { type: [Boolean, Number, String], required: false },
118
+ borderLeft: { type: [Boolean, Number, String], required: false },
119
+ borderBottom: { type: [Boolean, Number, String], required: false },
120
+ borderRight: { type: [Boolean, Number, String], required: false },
121
+ borderBlock: { type: [Boolean, Number, String], required: false },
122
+ borderInline: { type: [Boolean, Number, String], required: false },
123
+ borderColor: { type: String, required: false },
124
+ borderStyle: { type: String, required: false },
125
+ borderTopColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
126
+ borderRightColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
127
+ borderBottomColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
128
+ borderLeftColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
129
+ rounded: { type: [Boolean, Number, String, null], required: false, skipCheck: true },
130
+ roundedTopRight: { type: [Boolean, Number, String], required: false },
131
+ roundedTopLeft: { type: [Boolean, Number, String], required: false },
132
+ roundedBottomLeft: { type: [Boolean, Number, String], required: false },
133
+ roundedBottomRight: { type: [Boolean, Number, String], required: false },
134
+ elevation: { type: [Number, String], required: false }
112
135
  });
113
136
  const props = useDefaults(_props);
114
137
  const emits = defineEmits(["click:label", "update:modelValue"]);
@@ -202,6 +225,9 @@ const bgColor = computed(() => {
202
225
  return model.value ? props.activeBgColor || props.bgColor : props.bgColor;
203
226
  });
204
227
  const { textColorClasses: wrapperColorClasses, textColorStyles: wrapperColorStyles } = useTextColor(color);
228
+ const { borderClasses, borderStyles } = useBorder(props);
229
+ const { roundedClasses, roundedStyles } = useRounded(props);
230
+ const { elevationClasses, elevationStyles } = useElevation(props);
205
231
  const rippleProp = computed(() => {
206
232
  if (props.ripple) {
207
233
  return [!props.disabled && !props.readonly, null, ["center", "circle"]];
@@ -219,6 +245,21 @@ const selectionControlWrapperClasses = computed(() => {
219
245
  wrapperColorClasses.value
220
246
  ];
221
247
  });
248
+ const selectionControlInputClasses = computed(() => {
249
+ return [
250
+ "origam-selection-control__input",
251
+ borderClasses.value,
252
+ roundedClasses.value,
253
+ elevationClasses.value
254
+ ];
255
+ });
256
+ const selectionControlInputStyles = computed(() => {
257
+ return [
258
+ borderStyles.value,
259
+ roundedStyles.value,
260
+ elevationStyles.value
261
+ ];
262
+ });
222
263
  const selectionControlClasses = computed(() => {
223
264
  return [
224
265
  "origam-selection-control",
@@ -254,7 +295,6 @@ defineExpose(forwardRefs({
254
295
  contain: layout;
255
296
  display: flex;
256
297
  flex: 1 0;
257
- grid-area: control;
258
298
  position: relative;
259
299
  user-select: none;
260
300
 
@@ -307,7 +347,11 @@ defineExpose(forwardRefs({
307
347
  left: 0;
308
348
  width: 100%;
309
349
  height: 100%;
310
- border-radius: 100%;
350
+ // Le halo suit la forme du contrôle. Codé en dur à 100%, il restait
351
+ // circulaire même sous `rounded="md"` : la seule surface que la prop
352
+ // pouvait peindre au repos ignorait la prop. `inherit` reprend le
353
+ // border-radius résolu par `useRounded` sur `__input`.
354
+ border-radius: inherit;
311
355
  background-color: currentColor;
312
356
  opacity: 0;
313
357
  pointer-events: none;
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <component
3
- :is="tag"
3
+ :is="props.tag"
4
4
  :id="tabDomId"
5
5
  ref="rootRef"
6
6
  v-contrast
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <component
3
- :is="tag"
3
+ :is="props.tag"
4
4
  :id="id"
5
5
  ref="rootRef"
6
6
  role="tablist"
@@ -10,24 +10,22 @@ exports.provideRtl = provideRtl;
10
10
  exports.useLocale = useLocale;
11
11
  exports.useRtl = useRtl;
12
12
  var _vue = require("vue");
13
- var _vueI18n = require("vue-i18n");
14
13
  var origamMessages = _interopRequireWildcard(require("../../assets/locales/index.cjs"));
15
14
  var _consts = require("../../consts/index.cjs");
16
15
  var _utils = require("../../utils/index.cjs");
17
16
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
18
17
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
19
18
  function createLocale(options) {
20
- const i18nOptions = (0, _utils.mergeDeep)({
19
+ const merged = (0, _utils.mergeDeep)({
21
20
  locale: "en",
22
21
  fallbackLocale: "en",
23
- messages: JSON.parse(JSON.stringify(origamMessages)),
22
+ messages: JSON.parse(JSON.stringify(origamMessages))
24
23
  // Fix problems with json file imported
25
- legacy: false
26
24
  }, options);
27
- const i18n = (0, _vueI18n.createI18n)(i18nOptions);
28
- const locale = (0, _utils.createVueI18nAdapter)({
29
- i18n,
30
- useI18n: _vueI18n.useI18n
25
+ const locale = options?.adapter ?? (0, _utils.createBuiltinAdapter)({
26
+ current: (0, _vue.ref)(merged.locale),
27
+ fallback: (0, _vue.ref)(merged.fallbackLocale),
28
+ messages: (0, _vue.computed)(() => merged.messages)
31
29
  });
32
30
  const rtl = createRtl(locale, options);
33
31
  return {
@@ -1,4 +1,4 @@
1
- import type { ILocaleInstance, ILocaleOptions, ILocaleProps, IRtlInstance, IRtlOptions, IRtlProps } from "../../interfaces";
1
+ import type { ILocaleInstance, ILocaleOptions, ILocaleProps, IRtlInstance, IRtlOptions, IRtlProps, ILocaleMessages } from "../../interfaces";
2
2
  /*********************************************************
3
3
  * createLocale
4
4
  ********************************************************/
@@ -6,7 +6,7 @@ export declare function createLocale(options?: ILocaleOptions & IRtlOptions): {
6
6
  isRtl: import("vue").Ref<boolean>;
7
7
  rtl: import("vue").Ref<Record<string, boolean>>;
8
8
  name: string;
9
- messages: import("vue").ComputedRef<import("../../interfaces").ILocaleMessages>;
9
+ messages: import("vue").ComputedRef<ILocaleMessages>;
10
10
  current: import("vue").Ref<string>;
11
11
  fallback: import("vue").Ref<string>;
12
12
  t: (key: string, ...params: unknown[]) => string;
@@ -24,7 +24,7 @@ export declare function provideLocale(props: ILocaleProps & IRtlProps): {
24
24
  isRtl: import("vue").Ref<boolean>;
25
25
  rtl: import("vue").Ref<Record<string, boolean>>;
26
26
  name: string;
27
- messages: import("vue").ComputedRef<import("../../interfaces").ILocaleMessages>;
27
+ messages: import("vue").ComputedRef<ILocaleMessages>;
28
28
  current: import("vue").Ref<string>;
29
29
  fallback: import("vue").Ref<string>;
30
30
  t: (key: string, ...params: unknown[]) => string;
@@ -1,18 +1,19 @@
1
1
  import { computed, inject, provide, ref } from "vue";
2
- import { createI18n, useI18n } from "vue-i18n";
3
2
  import * as origamMessages from "../../assets/locales/index.js";
4
3
  import { LOCALE_RTL_DEFAULT, ORIGAM_LOCALE_KEY } from "../../consts/index.js";
5
- import { createVueI18nAdapter, getCurrentInstanceName, mergeDeep } from "../../utils/index.js";
4
+ import { createBuiltinAdapter, getCurrentInstanceName, mergeDeep } from "../../utils/index.js";
6
5
  export function createLocale(options) {
7
- const i18nOptions = mergeDeep({
6
+ const merged = mergeDeep({
8
7
  locale: "en",
9
8
  fallbackLocale: "en",
10
- messages: JSON.parse(JSON.stringify(origamMessages)),
9
+ messages: JSON.parse(JSON.stringify(origamMessages))
11
10
  // Fix problems with json file imported
12
- legacy: false
13
11
  }, options);
14
- const i18n = createI18n(i18nOptions);
15
- const locale = createVueI18nAdapter({ i18n, useI18n });
12
+ const locale = options?.adapter ?? createBuiltinAdapter({
13
+ current: ref(merged.locale),
14
+ fallback: ref(merged.fallbackLocale),
15
+ messages: computed(() => merged.messages)
16
+ });
16
17
  const rtl = createRtl(locale, options);
17
18
  return { ...locale, ...rtl };
18
19
  }
@@ -1,5 +1,4 @@
1
1
  import type { ComputedRef, Ref } from "vue";
2
- import type { I18n, useI18n } from "vue-i18n";
3
2
  export interface ILocaleMessages {
4
3
  [key: string]: ILocaleMessages | string;
5
4
  }
@@ -17,9 +16,37 @@ export interface ILocaleOptions {
17
16
  fallbackLocale: string;
18
17
  messages: Record<string, unknown>;
19
18
  }
19
+ /**
20
+ * Formes STRUCTURELLES de vue-i18n, declarees localement.
21
+ *
22
+ * `vue-i18n` est un peer OPTIONNEL : le DS ne doit pas en dependre, meme au
23
+ * niveau des types. Un `import type` reste inoffensif a l'execution mais fait
24
+ * echouer le type-check d'un projet qui ne l'installe pas (des lors que
25
+ * `skipLibCheck` est a false) — c'est la meme classe de bug que l'import
26
+ * runtime, un cran plus loin.
27
+ *
28
+ * On decrit donc uniquement ce que le DS consomme reellement. Une vraie
29
+ * instance vue-i18n satisfait ces formes structurellement, sans que le DS ait
30
+ * a connaitre le paquet.
31
+ */
32
+ export interface IVueI18nGlobalLike {
33
+ locale: Ref<string>;
34
+ fallbackLocale: unknown;
35
+ messages: unknown;
36
+ t: (key: string, ...args: unknown[]) => string;
37
+ n: (value: number, ...args: unknown[]) => string;
38
+ }
39
+ export interface IVueI18nLike {
40
+ global: IVueI18nGlobalLike;
41
+ }
42
+ export type TUseI18nLike = (options: Record<string, unknown>) => {
43
+ locale: Ref<string>;
44
+ t: (key: string, ...args: unknown[]) => string;
45
+ n: (value: number, ...args: unknown[]) => string;
46
+ };
20
47
  export interface ILocaleI18n {
21
- i18n: I18n<Record<string, unknown>, Record<string, unknown>, Record<string, unknown>, string, false>;
22
- useI18n: typeof useI18n;
48
+ i18n: IVueI18nLike;
49
+ useI18n: TUseI18nLike;
23
50
  }
24
51
  export interface ILocaleProps {
25
52
  messages?: ILocaleMessages;
@@ -1,6 +1,17 @@
1
- import type { IActiveProps, IBgColorProps, IColorProps, ICommonsComponentEmits, ICommonsComponentProps, IDensityProps, ISelectionControlGroupProps, IHoverProps } from '../../interfaces';
1
+ import type { IActiveProps, IBgColorProps, IBorderProps, IColorProps, ICommonsComponentEmits, ICommonsComponentProps, IDensityProps, IElevationProps, ISelectionControlGroupProps, IHoverProps, IRoundedProps } from '../../interfaces';
2
2
  import type { TColor, TIcon } from '../../types';
3
- export interface ISelectionControlProps extends ICommonsComponentProps, Partial<Omit<ISelectionControlGroupProps, 'items'>>, IColorProps, IBgColorProps, IActiveProps, IHoverProps, IDensityProps {
3
+ /**
4
+ * `border` / `rounded` / `elevation` (props-first, issue #241) — declared
5
+ * here so `OrigamSelectionControl` (the element that owns the visible
6
+ * state-layer box behind the Checkbox/Radio glyph) can consume them via
7
+ * the standard `useBorder` / `useRounded` / `useElevation` composables,
8
+ * mirroring the `ISwitchTrackProps` pattern (the track owns the surface,
9
+ * not the outer `OrigamSwitch`). `ICheckboxBtnProps` / `IRadioBtnProps`
10
+ * extend this interface, so `OrigamCheckbox(Btn)` / `OrigamRadio(Btn)`
11
+ * forward these values down automatically through `filterProps` without
12
+ * any additional wiring.
13
+ */
14
+ export interface ISelectionControlProps extends ICommonsComponentProps, Partial<Omit<ISelectionControlGroupProps, 'items'>>, IColorProps, IBgColorProps, IActiveProps, IHoverProps, IDensityProps, IBorderProps, IRoundedProps, IElevationProps {
4
15
  label?: string;
5
16
  trueValue?: any;
6
17
  falseValue?: any;
@@ -3,6 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
+ exports.createBuiltinAdapter = createBuiltinAdapter;
6
7
  exports.createProvideFunction = createProvideFunction;
7
8
  exports.createVueI18nAdapter = createVueI18nAdapter;
8
9
  exports.useProvided = useProvided;
@@ -16,7 +17,7 @@ function callI18nT(fn, key, params) {
16
17
  }
17
18
  function createVueI18nAdapter({
18
19
  i18n,
19
- useI18n: useI18n2
20
+ useI18n
20
21
  }) {
21
22
  const current = i18n.global.locale;
22
23
  const fallback = i18n.global.fallbackLocale;
@@ -32,7 +33,7 @@ function createVueI18nAdapter({
32
33
  current,
33
34
  fallback,
34
35
  messages,
35
- useI18n: useI18n2
36
+ useI18n
36
37
  })
37
38
  };
38
39
  }
@@ -77,4 +78,59 @@ function useProvided(props, prop, provided) {
77
78
  }
78
79
  });
79
80
  return internal;
81
+ }
82
+ function resolveKey(messages, key) {
83
+ const value = key.split(".").reduce((acc, segment) => acc && typeof acc === "object" ? acc[segment] : void 0, messages);
84
+ return typeof value === "string" ? value : void 0;
85
+ }
86
+ function stringifyParam(raw) {
87
+ if (typeof raw === "string") return raw;
88
+ if (typeof raw === "number" || typeof raw === "boolean" || typeof raw === "bigint") {
89
+ return raw.toString();
90
+ }
91
+ return "";
92
+ }
93
+ function asNamedParams(params) {
94
+ if (params.length !== 1) return void 0;
95
+ const first = params[0];
96
+ if (first === null || typeof first !== "object" || Array.isArray(first)) return void 0;
97
+ return first;
98
+ }
99
+ function interpolate(template, params) {
100
+ const named = asNamedParams(params);
101
+ const lookup = token => {
102
+ if (named) return named[token];
103
+ if (/^\d+$/.test(token)) return params[Number(token)];
104
+ return void 0;
105
+ };
106
+ return template.replace(/\{([^{}]+)\}/g, (_match, token) => {
107
+ return stringifyParam(lookup(token));
108
+ });
109
+ }
110
+ function createBuiltinAdapter(data) {
111
+ const translate = (key, ...params) => {
112
+ if (typeof key !== "string" || !key) return key;
113
+ const all = data.messages.value;
114
+ const template = resolveKey(all?.[data.current.value] ?? {}, key) ?? resolveKey(all?.[data.fallback.value] ?? {}, key);
115
+ if (template === void 0) return key;
116
+ return params.length ? interpolate(template, params) : template;
117
+ };
118
+ return {
119
+ name: "origam-builtin",
120
+ current: data.current,
121
+ fallback: data.fallback,
122
+ messages: data.messages,
123
+ t: translate,
124
+ n: value => new Intl.NumberFormat(data.current.value).format(value),
125
+ provide: props => {
126
+ const current = useProvided(props, "locale", data.current);
127
+ const fallback = useProvided(props, "fallback", data.fallback);
128
+ const messages = useProvided(props, "messages", data.messages);
129
+ return createBuiltinAdapter({
130
+ current,
131
+ fallback,
132
+ messages
133
+ });
134
+ }
135
+ };
80
136
  }
@@ -1,6 +1,5 @@
1
1
  import { ComputedRef, Ref } from "vue";
2
- import { useI18n } from "vue-i18n";
3
- import type { ILocaleI18n, ILocaleInstance, ILocaleMessages, ILocaleProps } from "../../interfaces";
2
+ import type { ILocaleI18n, ILocaleInstance, ILocaleMessages, ILocaleProps, TUseI18nLike } from "../../interfaces";
4
3
  /**
5
4
  * Create vue i 18 n adapter.
6
5
  *
@@ -17,7 +16,7 @@ export declare function createProvideFunction(data: {
17
16
  current: Ref<string>;
18
17
  fallback: Ref<string>;
19
18
  messages: ComputedRef<ILocaleMessages>;
20
- useI18n: typeof useI18n;
19
+ useI18n: TUseI18nLike;
21
20
  }): (props: ILocaleProps) => ILocaleInstance;
22
21
  /**
23
22
  * Use provided.
@@ -28,3 +27,8 @@ export declare function createProvideFunction(data: {
28
27
  * @returns …
29
28
  */
30
29
  export declare function useProvided<T>(props: any, prop: string, provided: Ref<T>): Ref<T>;
30
+ export declare function createBuiltinAdapter(data: {
31
+ current: Ref<string>;
32
+ fallback: Ref<string>;
33
+ messages: ComputedRef<ILocaleMessages>;
34
+ }): ILocaleInstance;
@@ -6,7 +6,7 @@ function callI18nT(fn, key, params) {
6
6
  const list = params.map((p) => p == null ? "" : p);
7
7
  return fn(key, list);
8
8
  }
9
- export function createVueI18nAdapter({ i18n, useI18n: useI18n2 }) {
9
+ export function createVueI18nAdapter({ i18n, useI18n }) {
10
10
  const current = i18n.global.locale;
11
11
  const fallback = i18n.global.fallbackLocale;
12
12
  const messages = i18n.global.messages;
@@ -17,7 +17,7 @@ export function createVueI18nAdapter({ i18n, useI18n: useI18n2 }) {
17
17
  messages,
18
18
  t: (key, ...params) => callI18nT(i18n.global.t.bind(i18n.global), key, params),
19
19
  n: i18n.global.n,
20
- provide: createProvideFunction({ current, fallback, messages, useI18n: useI18n2 })
20
+ provide: createProvideFunction({ current, fallback, messages, useI18n })
21
21
  };
22
22
  }
23
23
  export function createProvideFunction(data) {
@@ -57,3 +57,57 @@ export function useProvided(props, prop, provided) {
57
57
  });
58
58
  return internal;
59
59
  }
60
+ function resolveKey(messages, key) {
61
+ const value = key.split(".").reduce(
62
+ (acc, segment) => acc && typeof acc === "object" ? acc[segment] : void 0,
63
+ messages
64
+ );
65
+ return typeof value === "string" ? value : void 0;
66
+ }
67
+ function stringifyParam(raw) {
68
+ if (typeof raw === "string") return raw;
69
+ if (typeof raw === "number" || typeof raw === "boolean" || typeof raw === "bigint") {
70
+ return raw.toString();
71
+ }
72
+ return "";
73
+ }
74
+ function asNamedParams(params) {
75
+ if (params.length !== 1) return void 0;
76
+ const first = params[0];
77
+ if (first === null || typeof first !== "object" || Array.isArray(first)) return void 0;
78
+ return first;
79
+ }
80
+ function interpolate(template, params) {
81
+ const named = asNamedParams(params);
82
+ const lookup = (token) => {
83
+ if (named) return named[token];
84
+ if (/^\d+$/.test(token)) return params[Number(token)];
85
+ return void 0;
86
+ };
87
+ return template.replace(/\{([^{}]+)\}/g, (_match, token) => {
88
+ return stringifyParam(lookup(token));
89
+ });
90
+ }
91
+ export function createBuiltinAdapter(data) {
92
+ const translate = (key, ...params) => {
93
+ if (typeof key !== "string" || !key) return key;
94
+ const all = data.messages.value;
95
+ const template = resolveKey(all?.[data.current.value] ?? {}, key) ?? resolveKey(all?.[data.fallback.value] ?? {}, key);
96
+ if (template === void 0) return key;
97
+ return params.length ? interpolate(template, params) : template;
98
+ };
99
+ return {
100
+ name: "origam-builtin",
101
+ current: data.current,
102
+ fallback: data.fallback,
103
+ messages: data.messages,
104
+ t: translate,
105
+ n: (value) => new Intl.NumberFormat(data.current.value).format(value),
106
+ provide: (props) => {
107
+ const current = useProvided(props, "locale", data.current);
108
+ const fallback = useProvided(props, "fallback", data.fallback);
109
+ const messages = useProvided(props, "messages", data.messages);
110
+ return createBuiltinAdapter({ current, fallback, messages });
111
+ }
112
+ };
113
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "origam",
3
- "version": "2.10.0",
3
+ "version": "2.12.0",
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": [