vueless 0.0.42 → 0.0.43

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.
@@ -0,0 +1,21 @@
1
+ import selectConfig from "../../ui.form-select/configs/default.config";
2
+ import switchConfig from "../../ui.form-switch/configs/default.config";
3
+ import inputFileConfig from "../../ui.form-input-file/configs/default.config";
4
+ import dropdownListConfig from "../../ui.dropdown-list/configs/default.config";
5
+ import modalConfirmConfig from "../../ui.container-modal-confirm/configs/default.config";
6
+ import tableConfig from "../../ui.data-table/configs/default.config";
7
+ import calendarConfig from "../../ui.form-calendar/configs/default.config";
8
+ import datepickerConfig from "../../ui.form-date-picker/configs/default.config";
9
+ import datepickerRangeConfig from "../../ui.form-date-picker-range/configs/default.config";
10
+
11
+ export default {
12
+ USelect: selectConfig.i18n,
13
+ USwitch: switchConfig.i18n,
14
+ UInputFile: inputFileConfig.i18n,
15
+ UDropdownList: dropdownListConfig.i18n,
16
+ UModalConfirm: modalConfirmConfig.i18n,
17
+ UTable: tableConfig.i18n,
18
+ UCalendar: calendarConfig.i18n,
19
+ UDatePicker: datepickerConfig.i18n,
20
+ UDatePickerRange: datepickerRangeConfig.i18n,
21
+ };
@@ -0,0 +1,11 @@
1
+ export default function createVueI18nAdapter(i18n) {
2
+ return {
3
+ name: "vue-i18n",
4
+ locale: i18n.global.locale,
5
+ fallback: i18n.global.fallbackLocale,
6
+ messages: i18n.global.messages,
7
+ t: (key, ...params) => i18n.global.t(key, params),
8
+ tm: i18n.global.tm,
9
+ n: i18n.global.n,
10
+ };
11
+ }
@@ -0,0 +1,117 @@
1
+ import { shallowRef, ref } from "vue";
2
+
3
+ import en from "./locales/en";
4
+
5
+ const FALLBACK_LOCALE_CODE = "en";
6
+
7
+ export default function createVuelessAdapter(options) {
8
+ const current = shallowRef(options?.locale ?? FALLBACK_LOCALE_CODE);
9
+ const fallback = shallowRef(options?.fallback ?? FALLBACK_LOCALE_CODE);
10
+
11
+ const messages = ref({ en, ...options?.messages });
12
+
13
+ return {
14
+ name: "vueless",
15
+ locale: current,
16
+ fallback,
17
+ messages,
18
+ t: createTranslateFunction(current, fallback, messages),
19
+ tm: createTranslateMessageFunction(current, fallback, messages),
20
+ n: createNumberFunction(current, fallback),
21
+ };
22
+ }
23
+
24
+ function createTranslateFunction(current, fallback, messages) {
25
+ return (key, ...params) => {
26
+ const currentLocale = current.value && messages.value[current.value];
27
+ const fallbackLocale = fallback.value && messages.value[fallback.value];
28
+
29
+ let str = getObjectValueByPath(currentLocale, key, null);
30
+
31
+ if (!str) {
32
+ // eslint-disable-next-line no-console
33
+ console.warn(
34
+ `Translation key "${key}" not found in "${current.value}", trying fallback locale`,
35
+ );
36
+ str = getObjectValueByPath(fallbackLocale, key, null);
37
+ }
38
+
39
+ if (!str) {
40
+ // eslint-disable-next-line no-console
41
+ console.warn(`Translation key "${key}" not found in fallback`);
42
+ str = key;
43
+ }
44
+
45
+ if (typeof str !== "string") {
46
+ // eslint-disable-next-line no-console
47
+ console.warn(`Translation key "${key}" has a non-string value`);
48
+ str = key;
49
+ }
50
+
51
+ return replace(str, params);
52
+ };
53
+ }
54
+
55
+ function createTranslateMessageFunction(current, fallback, messages) {
56
+ return (key) => {
57
+ const currentLocale = current.value && messages.value[current.value];
58
+ const fallbackLocale = fallback.value && messages.value[fallback.value];
59
+
60
+ let str = getObjectValueByPath(currentLocale, key, null);
61
+
62
+ if (str === undefined) {
63
+ // eslint-disable-next-line no-console
64
+ console.warn(
65
+ `Translation key "${key}" not found in "${current.value}", trying fallback locale`,
66
+ );
67
+ str = getObjectValueByPath(fallbackLocale, key, null);
68
+ }
69
+
70
+ return str;
71
+ };
72
+ }
73
+
74
+ const replace = (str, params) => {
75
+ return str.replace(/\{(\d+)\}/g, (match, index) => {
76
+ return String(params[+index]);
77
+ });
78
+ };
79
+
80
+ function createNumberFunction(current, fallback) {
81
+ return (value, options) => {
82
+ const numberFormat = new Intl.NumberFormat([current.value, fallback.value], options);
83
+
84
+ return numberFormat.format(value);
85
+ };
86
+ }
87
+
88
+ export function getObjectValueByPath(obj, path, fallback) {
89
+ if (obj == null || !path || typeof path !== "string") return fallback;
90
+ if (obj[path] !== undefined) return obj[path];
91
+ path = path.replace(/\[(\w+)\]/g, ".$1"); // convert indexes to properties
92
+ path = path.replace(/^\./, ""); // strip a leading dot
93
+
94
+ return getNestedValue(obj, path.split("."), fallback);
95
+ }
96
+
97
+ export function getNestedValue(obj, path, fallback) {
98
+ const last = path.length - 1;
99
+
100
+ if (last < 0) {
101
+ return obj === undefined ? fallback : obj;
102
+ }
103
+
104
+ for (let i = 0; i < last; i++) {
105
+ if (obj == null) {
106
+ return fallback;
107
+ }
108
+
109
+ obj = obj[path[i]];
110
+ }
111
+
112
+ if (obj == null) {
113
+ return fallback;
114
+ }
115
+
116
+ return obj[path[last]] === undefined ? fallback : obj[path[last]];
117
+ }
@@ -0,0 +1,25 @@
1
+ import { inject } from "vue";
2
+ import createVuelessAdapter from "../adatper.locale/vueless";
3
+
4
+ export const LocaleSymbol = Symbol.for("vueless:locale");
5
+
6
+ function isLocaleInstance(obj) {
7
+ return obj.name !== null;
8
+ }
9
+
10
+ export function createLocale(options) {
11
+ const i18n =
12
+ options?.adapter && isLocaleInstance(options?.adapter)
13
+ ? options?.adapter
14
+ : createVuelessAdapter(options);
15
+
16
+ return { ...i18n };
17
+ }
18
+
19
+ export function useLocale() {
20
+ const locale = inject(LocaleSymbol);
21
+
22
+ if (!locale) throw new Error("[vueless] Could not find injected locale instance");
23
+
24
+ return locale;
25
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vueless",
3
- "version": "0.0.42",
3
+ "version": "0.0.43",
4
4
  "license": "MIT",
5
5
  "description": "Vue Styleless Component Framework.",
6
6
  "homepage": "https://vueless.com",
@@ -43,7 +43,7 @@
43
43
 
44
44
  <UButton
45
45
  v-if="cancelButton"
46
- :label="config.i18n.cancel"
46
+ :label="props.config?.i18n?.cancel || t('UModalConfirm.cancel')"
47
47
  variant="thirdary"
48
48
  filled
49
49
  :data-cy="`${dataCy}-close`"
@@ -70,6 +70,7 @@ import UModal from "../ui.container-modal";
70
70
  import defaultConfig from "./configs/default.config";
71
71
  import { UModalConfirm } from "./constants/index";
72
72
  import { useAttrs } from "./composable/attrs.composable";
73
+ import { useLocale } from "../composable.locale";
73
74
 
74
75
  /* Should be a string for correct web-types gen */
75
76
  defineOptions({ name: "UModalConfirm", inheritAttrs: false });
@@ -152,8 +153,9 @@ const props = defineProps({
152
153
 
153
154
  const emit = defineEmits(["update:modelValue", "confirm", "close"]);
154
155
 
156
+ const { t } = useLocale();
157
+
155
158
  const {
156
- config,
157
159
  hasSlotContent,
158
160
  footerLeftFallbackAttrs,
159
161
  modalAttrs,
@@ -288,6 +288,7 @@ import TableService from "./services/table.service";
288
288
  import { HYPHEN_SYMBOL, PX_IN_REM } from "../service.ui";
289
289
  import { UTable } from "./constants";
290
290
  import { useAttrs } from "./composables/attrs.composable";
291
+ import { useLocale } from "../composable.locale";
291
292
 
292
293
  /* Should be a string for correct web-types gen */
293
294
  defineOptions({ name: "UTable", inheritAttrs: false });
@@ -403,6 +404,7 @@ const emit = defineEmits(["clickRow", "update:rows"]);
403
404
  defineExpose({ clearSelectedItems });
404
405
 
405
406
  const slots = useSlots();
407
+ const { t } = useLocale();
406
408
 
407
409
  const selectAll = ref(false);
408
410
  const canSelectAll = ref(true);
@@ -517,7 +519,9 @@ const hasContentBeforeFirstRowSlot = computed(() => {
517
519
  });
518
520
 
519
521
  const emptyTableMsg = computed(() => {
520
- return props.filters ? config.value.i18n.noResultsForFilters : config.value.i18n.noItems;
522
+ return props.filters
523
+ ? props.config?.i18n?.noResultsForFilters || t("UTable.noResultsForFilters")
524
+ : props.config?.i18n?.noItems || t("UTable.noItems");
521
525
  });
522
526
 
523
527
  watch(selectAll, onChangeSelectAll, { deep: true });
@@ -65,7 +65,7 @@
65
65
  :empty-styles="optionClasses"
66
66
  >
67
67
  <span v-bind="optionAttrs()">
68
- <span v-text="config.i18n.noDataToShow" />
68
+ <span v-text="props.config?.i18n?.noDataToShow || t('UDropdownList.noDataToShow')" />
69
69
  </span>
70
70
  </slot>
71
71
 
@@ -73,7 +73,7 @@
73
73
  <template v-if="addOption">
74
74
  <div v-bind="addTitleWrapperAttrs" @click="onClickAddOption">
75
75
  <div v-bind="addTitleAttrs">
76
- {{ config.i18n.add }}
76
+ {{ props.config?.i18n?.add || t("UDropdownList.add") }}
77
77
  <span v-bind="addTitleHotkeyAttrs" v-text="addOptionKeyCombination" />
78
78
  </div>
79
79
  </div>
@@ -95,6 +95,8 @@ import UIService, { getRandomId, isMac } from "../service.ui";
95
95
 
96
96
  import usePointer from "./composables/usePointer";
97
97
  import useAttrs from "./composables/attrs.composable";
98
+ import { useLocale } from "../composable.locale";
99
+
98
100
  import defaultConfig from "./configs/default.config.js";
99
101
  import { UDropdownList } from "./constants";
100
102
 
@@ -229,6 +231,8 @@ const {
229
231
  optionContentAttrs,
230
232
  } = useAttrs(props);
231
233
 
234
+ const { t } = useLocale();
235
+
232
236
  defineExpose({ pointerSet, pointerBackward, pointerForward, pointerReset, addPointerElement });
233
237
 
234
238
  const addOptionKeyCombination = computed(() => {
@@ -172,6 +172,7 @@ import {
172
172
  } from "./services/date.service";
173
173
 
174
174
  import useAttrs from "./composables/attrs.composable";
175
+ import { useLocale } from "../composable.locale";
175
176
 
176
177
  import {
177
178
  UCalendar,
@@ -288,6 +289,8 @@ const emit = defineEmits([
288
289
  "formattedDateChange",
289
290
  ]);
290
291
 
292
+ const { tm } = useLocale();
293
+
291
294
  const {
292
295
  config,
293
296
  wrapperAttrs,
@@ -342,7 +345,8 @@ const isCurrentView = computed(() => ({
342
345
  }));
343
346
 
344
347
  const locale = computed(() => {
345
- const currentLocale = props.config.i18n || config.value.i18n;
348
+ const currentLocale = props.config.i18n || tm("UCalendar");
349
+
346
350
  const formattedLocale = {
347
351
  ...currentLocale,
348
352
  months: {
@@ -359,7 +363,7 @@ const locale = computed(() => {
359
363
  });
360
364
 
361
365
  const userFormatLocale = computed(() => {
362
- const currentLocale = props.config.i18n || config.value.i18n;
366
+ const currentLocale = props.config.i18n || tm("UCalendar");
363
367
 
364
368
  const formattedLocale = {
365
369
  ...currentLocale,
@@ -67,6 +67,8 @@ import {
67
67
  } from "../ui.form-calendar/services/date.service";
68
68
 
69
69
  import useAttrs from "./composables/attrs.composable";
70
+ import { useLocale } from "../composable.locale";
71
+
70
72
  import defaultConfig from "./configs/default.config";
71
73
  import { UDatePicker } from "./constants";
72
74
 
@@ -201,6 +203,8 @@ const emit = defineEmits(["update:modelValue", "input"]);
201
203
 
202
204
  const STANDARD_USER_FORMAT = "l, j F, Y";
203
205
 
206
+ const { tm } = useLocale();
207
+
204
208
  const isShownCalendar = ref(false);
205
209
  const userFormatDate = ref("");
206
210
  const formattedDate = ref("");
@@ -254,7 +258,7 @@ function onBlur(event) {
254
258
  function formatUserDate(data) {
255
259
  if (props.dateFormat !== STANDARD_USER_FORMAT) return data;
256
260
 
257
- const currentLocale = props.config.i18n || config.value.i18n;
261
+ const currentLocale = props.config.i18n || tm("UDatePicker");
258
262
 
259
263
  let prefix = "";
260
264
  const formattedDate = data.charAt(0).toUpperCase() + data.toLowerCase().slice(1);
@@ -225,6 +225,8 @@ import {
225
225
 
226
226
  import { wrongDateFormat, wrongMonthNumber, wrongDayNumber } from "./services/validation.service";
227
227
  import useAttrs from "./composables/attrs.composable";
228
+ import { useLocale } from "../composable.locale";
229
+
228
230
  import defaultConfig from "./configs/default.config";
229
231
  import {
230
232
  UDatePickerRange,
@@ -383,6 +385,7 @@ const {
383
385
  inputRangeErrorAttrs,
384
386
  } = useAttrs(props, { isShownMenu });
385
387
  const store = useStore();
388
+ const { tm } = useLocale();
386
389
 
387
390
  const calendarValue = ref(props.modelValue);
388
391
  const activeDate = ref(
@@ -414,7 +417,7 @@ const isMobileDevice = computed(() => store.getters["breakpoint/isMobileDevice"]
414
417
  const rangeInputName = computed(() => `rangeInput-${props.id}`);
415
418
 
416
419
  const locale = computed(() => {
417
- const currentLocale = props.config.i18n || config.value.i18n;
420
+ const currentLocale = props.config.i18n || tm("UDatePickerRange");
418
421
  const formattedLocale = {
419
422
  ...currentLocale,
420
423
  months: {
@@ -431,7 +434,7 @@ const locale = computed(() => {
431
434
  });
432
435
 
433
436
  const userFormatLocale = computed(() => {
434
- const currentLocale = props.config.i18n || config.value.i18n;
437
+ const currentLocale = props.config.i18n || tm("UDatePickerRange");
435
438
 
436
439
  const formattedLocale = {
437
440
  ...currentLocale,
@@ -17,10 +17,7 @@
17
17
  v-bind="iconUploadFileAttrs"
18
18
  />
19
19
 
20
- <div
21
- v-bind="descriptionAttrs"
22
- v-text="`${config.i18n.selectOrDragImage} ${allowedFilesForUpload}`"
23
- />
20
+ <div v-bind="descriptionAttrs" v-text="descriptionText" />
24
21
  </div>
25
22
 
26
23
  <div v-bind="listAttrs">
@@ -39,7 +36,7 @@
39
36
  </div>
40
37
 
41
38
  <UButton
42
- :label="config.i18n.selectFile"
39
+ :label="props.config?.i18n?.selectFile || t('UInputFile.selectFile')"
43
40
  :size="size"
44
41
  variant="thirdary"
45
42
  filled
@@ -77,6 +74,7 @@ import UIService, { getRandomId } from "../service.ui";
77
74
  import { UInputFile } from "./constants";
78
75
  import defaultConfig from "./configs/default.config";
79
76
  import { useAttrs } from "./composables/attrs.composable";
77
+ import { useLocale } from "../composable.locale";
80
78
 
81
79
  /* Should be a string for correct web-types gen */
82
80
  defineOptions({ name: "UInputFile" });
@@ -194,6 +192,8 @@ const slots = useSlots();
194
192
 
195
193
  const emit = defineEmits(["changeFiles", "deleteFile"]);
196
194
 
195
+ const { t } = useLocale();
196
+
197
197
  const filesData = ref([]);
198
198
  const selectedFiles = ref([]);
199
199
  const errorMessage = ref("");
@@ -245,7 +245,11 @@ const uppyUpload = computed(() => {
245
245
  const allowedFilesForUpload = computed(() => {
246
246
  const allowedFormat = props.allowedFileTypes.join(", ");
247
247
 
248
- return `${config.value.i18n.canAttachFilesFormat} ${allowedFormat}`;
248
+ return `${props.config?.i18n?.canAttachFilesFormat || t("UInputFile.canAttachFilesFormat")} ${allowedFormat}`;
249
+ });
250
+
251
+ const descriptionText = computed(() => {
252
+ return `${props.config?.i18n?.selectOrDragImage || t("UInputFile.selectOrDragImage")} ${allowedFilesForUpload.value}`;
249
253
  });
250
254
 
251
255
  const componentSize = computed(() => {
@@ -360,10 +364,13 @@ function onChangeError() {
360
364
 
361
365
  function onChangeErrorFilesTypes() {
362
366
  if (errorFilesTypes.value.length) {
363
- let error = errorFilesTypes.value.join(", ");
364
- const localization = config.value.i18n;
367
+ const error = errorFilesTypes.value.join(", ");
368
+ const cannotAttachFilesStart =
369
+ props.config?.i18n?.cannotAttachFilesStart || t("UInputFile.cannotAttachFilesStart");
370
+ const cannotAttachFilesEnd =
371
+ props.config?.i18n?.cannotAttachFilesEnd || t("UInputFile.cannotAttachFilesEnd");
365
372
 
366
- errorMessage.value = `${localization.cannotAttachFilesStart} ${error} ${localization.cannotAttachFilesEnd}`;
373
+ errorMessage.value = `${cannotAttachFilesStart} ${error} ${cannotAttachFilesEnd}`;
367
374
  }
368
375
  }
369
376
 
@@ -114,7 +114,6 @@ export default /*tw*/ {
114
114
  noDataToShow: "No data to show.",
115
115
  clear: "clear",
116
116
  addMore: "Add more...",
117
- add: "Add",
118
117
  },
119
118
  defaultVariants: {
120
119
  size: "md",
@@ -151,7 +151,7 @@
151
151
  v-bind="caretClearTextAttrs"
152
152
  @mousedown.prevent.capture="removeElement(localValue)"
153
153
  @click.prevent.capture
154
- v-text="config.i18n.clear"
154
+ v-text="props.config?.i18n?.clear || t('USelect.clear')"
155
155
  />
156
156
  </div>
157
157
 
@@ -189,11 +189,15 @@
189
189
  </template>
190
190
 
191
191
  <template #empty="{ emptyStyles }">
192
- <span v-show="isEmpty" :class="emptyStyles" v-text="config.i18n.listIsEmpty" />
192
+ <span
193
+ v-show="isEmpty"
194
+ :class="emptyStyles"
195
+ v-text="props.config?.i18n?.listIsEmpty || t('USelect.listIsEmpty')"
196
+ />
193
197
  <span
194
198
  v-show="options.length === 0 && !search && !isEmpty"
195
199
  :class="emptyStyles"
196
- v-text="config.i18n.noDataToShow"
200
+ v-text="props.config?.i18n?.noDataToShow || t('USelect.noDataToShow')"
197
201
  />
198
202
  </template>
199
203
  </UDropdownList>
@@ -215,6 +219,8 @@ import useAttrs from "./composables/attrs.composable";
215
219
  import defaultConfig from "./configs/default.config";
216
220
  import { USelect, DIRECTION, KEY_CODES } from "./constants";
217
221
 
222
+ import { useLocale } from "../composable.locale";
223
+
218
224
  /* Should be a string for correct web-types gen */
219
225
  defineOptions({ name: "USelect", inheritAttrs: false });
220
226
 
@@ -438,6 +444,7 @@ const emit = defineEmits([
438
444
  ]);
439
445
 
440
446
  const slots = useSlots();
447
+ const { t } = useLocale();
441
448
 
442
449
  const isOpen = ref(false);
443
450
  const preferredOpenDirection = ref(DIRECTION.bottom);
@@ -486,7 +493,9 @@ const {
486
493
  } = useAttrs(props, { isTop, isOpen, selectedLabel });
487
494
 
488
495
  const inputPlaceholder = computed(() => {
489
- return props.multiple && localValue.value.length ? config.value.i18n.addMore : props.placeholder;
496
+ const message = props.config?.i18n?.value.addMore || t("USelect.addMore");
497
+
498
+ return props.multiple && localValue.value.length ? message : props.placeholder;
490
499
  });
491
500
 
492
501
  const dropdownValue = computed({
@@ -572,7 +581,7 @@ if (props.addOption) {
572
581
  document.addEventListener("keydown", onKeydownAddOption);
573
582
  }
574
583
 
575
- onMounted(() => setLabelPosition());
584
+ onMounted(setLabelPosition);
576
585
 
577
586
  const onSearchChange = debounce(async function (query) {
578
587
  emit("searchChange", query);
@@ -46,6 +46,7 @@ import UIService, { getRandomId } from "../service.ui";
46
46
  import { USwitch } from "./constants";
47
47
  import defaultConfig from "./configs/default.config";
48
48
  import { useAttrs } from "./composables/attrs.composable";
49
+ import { useLocale } from "../composable.locale";
49
50
 
50
51
  /* Should be a string for correct web-types gen */
51
52
  defineOptions({ name: "USwitch", inheritAttrs: false });
@@ -153,6 +154,8 @@ const props = defineProps({
153
154
 
154
155
  const emit = defineEmits(["update:modelValue"]);
155
156
 
157
+ const { t } = useLocale();
158
+
156
159
  const checkedValue = computed({
157
160
  get: () => props.modelValue,
158
161
  set: (value) => emit("update:modelValue", value),
@@ -162,7 +165,9 @@ const { config, iconAttrs, labelAttrs, inputAttrs, wrapperAttrs, circleAttrs, to
162
165
  useAttrs(props, { checked: checkedValue });
163
166
 
164
167
  const switchLabel = computed(() => {
165
- return checkedValue.value ? config.value.i18n.active : config.value.i18n.inactive;
168
+ return checkedValue.value
169
+ ? props.config?.i18n?.active || t("USwitch.active")
170
+ : props.config?.i18n?.inactive || t("USwitch.inactive");
166
171
  });
167
172
 
168
173
  const iconSize = computed(() => {
package/web-types.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "framework": "vue",
3
3
  "name": "vueless",
4
- "version": "0.0.42",
4
+ "version": "0.0.43",
5
5
  "contributions": {
6
6
  "html": {
7
7
  "description-markup": "markdown",