vueless 0.0.454 → 0.0.456

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vueless",
3
- "version": "0.0.454",
3
+ "version": "0.0.456",
4
4
  "license": "MIT",
5
5
  "description": "Vue Styleless UI Component Library, powered by Tailwind CSS.",
6
6
  "keywords": [
@@ -2,7 +2,7 @@
2
2
  <div :data-test="dataTest" v-bind="wrapperAttrs">
3
3
  <div
4
4
  v-show="isHeaderSticky || isShownActionsHeader"
5
- ref="stickyHeaderRowRef"
5
+ ref="sticky-header-row"
6
6
  :style="tableRowWidthStyle"
7
7
  v-bind="stickyHeaderAttrs"
8
8
  >
@@ -82,7 +82,7 @@
82
82
  />
83
83
  </div>
84
84
 
85
- <div ref="tableWrapperRef" v-bind="tableWrapperAttrs">
85
+ <div ref="table-wrapper" v-bind="tableWrapperAttrs">
86
86
  <table v-bind="tableAttrs">
87
87
  <thead v-bind="headerAttrs" :style="tableRowWidthStyle">
88
88
  <tr v-if="hasSlotContent($slots['before-header'])" v-bind="headerRowAttrs">
@@ -101,7 +101,7 @@
101
101
 
102
102
  <tr v-if="hasSlotContent($slots['before-header'])" v-bind="headerRowAttrs"></tr>
103
103
 
104
- <tr ref="headerRowRef" v-bind="headerRowAttrs">
104
+ <tr ref="header-row" v-bind="headerRowAttrs">
105
105
  <th v-if="selectable" v-bind="headerCellCheckboxAttrs">
106
106
  <UCheckbox
107
107
  v-model="selectAll"
@@ -241,7 +241,7 @@
241
241
  </tbody>
242
242
 
243
243
  <tfoot v-if="hasSlotContent($slots['footer'])" v-bind="footerAttrs">
244
- <tr ref="footerRowRef" v-bind="footerRowAttrs">
244
+ <tr ref="footer-row" v-bind="footerRowAttrs">
245
245
  <td v-if="selectable" />
246
246
 
247
247
  <!--
@@ -251,7 +251,7 @@
251
251
  <slot name="footer" :cols-count="colsCount" />
252
252
  </tr>
253
253
 
254
- <tr ref="stickyFooterRowRef" :style="tableRowWidthStyle" v-bind="stickyFooterRowAttrs">
254
+ <tr ref="sticky-footer-row" :style="tableRowWidthStyle" v-bind="stickyFooterRowAttrs">
255
255
  <td v-if="selectable" />
256
256
 
257
257
  <!--
@@ -277,6 +277,7 @@ import {
277
277
  onMounted,
278
278
  onUpdated,
279
279
  onBeforeUnmount,
280
+ useTemplateRef,
280
281
  } from "vue";
281
282
  import { merge } from "lodash-es";
282
283
 
@@ -422,11 +423,11 @@ const tableWidth = ref(0);
422
423
  const tableHeight = ref(0);
423
424
  const pagePositionY = ref(0);
424
425
 
425
- const headerRowRef = ref(null);
426
- const footerRowRef = ref(null);
427
- const tableWrapperRef = ref(null);
428
- const stickyFooterRowRef = ref(null);
429
- const stickyHeaderRowRef = ref(null);
426
+ const headerRowRef = useTemplateRef("header-row");
427
+ const footerRowRef = useTemplateRef("footer-row");
428
+ const tableWrapperRef = useTemplateRef("table-wrapper");
429
+ const stickyFooterRowRef = useTemplateRef("sticky-footer-row");
430
+ const stickyHeaderRowRef = useTemplateRef("sticky-header-row");
430
431
 
431
432
  const i18nGlobal = tm(UTable);
432
433
  const currentLocale = computed(() => merge(defaultConfig.i18n, i18nGlobal, props.config.i18n));
@@ -31,21 +31,27 @@
31
31
  :style="getNestedShift()"
32
32
  v-bind="bodyCellNestedAttrs"
33
33
  >
34
- <UIcon
35
- v-if="isShownToggleIcon"
36
- size="xs"
37
- internal
38
- interactive
39
- :name="getToggleIconName(row)"
40
- color="brand"
41
- v-bind="toggleIconConfig"
42
- @click.stop="onClickToggleIcon"
43
- />
44
-
34
+ <div
35
+ ref="toggle-wrapper"
36
+ v-bind="bodyCellNestedExpandIconWrapperAttrs"
37
+ :style="{ width: getIconWidth() }"
38
+ >
39
+ <UIcon
40
+ v-if="isShownToggleIcon"
41
+ size="xs"
42
+ internal
43
+ interactive
44
+ :data-row-toggle-icon="row.id"
45
+ :name="getToggleIconName(row)"
46
+ color="brand"
47
+ v-bind="toggleIconConfig"
48
+ @click.stop="onClickToggleIcon"
49
+ />
50
+ </div>
45
51
  <slot :name="`cell-${key}`" :value="value" :row="row" :index="index">
46
52
  <div
47
53
  v-bind="bodyCellContentAttrs"
48
- ref="cellRef"
54
+ ref="cell"
49
55
  :class="cx([bodyCellContentAttrs.class, getCellContentClasses(row, key)])"
50
56
  :data-test="`${dataTest}-${key}-cell`"
51
57
  >
@@ -58,7 +64,7 @@
58
64
  <slot :name="`cell-${key}`" :value="value" :row="row" :index="index">
59
65
  <div
60
66
  v-bind="bodyCellContentAttrs"
61
- ref="cellRef"
67
+ ref="cell"
62
68
  :class="cx([bodyCellContentAttrs.class, getCellContentClasses(row, key)])"
63
69
  :data-test="`${dataTest}-${key}-cell`"
64
70
  >
@@ -147,11 +153,11 @@
147
153
  </template>
148
154
 
149
155
  <script setup>
150
- import { computed, onMounted, ref, useSlots } from "vue";
156
+ import { computed, onMounted, useSlots, useTemplateRef } from "vue";
151
157
  import { cx } from "../utils/utilUI.js";
152
158
  import useUI from "../composables/useUI.js";
153
159
 
154
- import { HYPHEN_SYMBOL } from "../constants.js";
160
+ import { HYPHEN_SYMBOL, PX_IN_REM } from "../constants.js";
155
161
  import { getFilteredRow } from "./utilTable.js";
156
162
 
157
163
  import { useMutationObserver } from "../composables/useMutationObserver.js";
@@ -207,7 +213,8 @@ const emit = defineEmits(["toggleRowVisibility", "click", "click-cell"]);
207
213
 
208
214
  const selectedRows = defineModel("selectedRows", { type: Array, default: () => [] });
209
215
 
210
- const cellRef = ref([]);
216
+ const cellRef = useTemplateRef("cell");
217
+ const toggleWrapperRef = useTemplateRef("toggle-wrapper");
211
218
  const slots = useSlots();
212
219
 
213
220
  useMutationObserver(cellRef, setCellTitle, { childList: true });
@@ -220,6 +227,7 @@ const {
220
227
  bodyCellNestedExpandIconAttrs,
221
228
  bodyCellNestedCollapseIconAttrs,
222
229
  bodyCellBaseAttrs,
230
+ bodyCellNestedExpandIconWrapperAttrs,
223
231
  } = props.attrs;
224
232
 
225
233
  const toggleIconConfig = computed(() =>
@@ -251,7 +259,13 @@ const isShownToggleIcon = computed(() => {
251
259
  );
252
260
  });
253
261
 
254
- const getToggleIconName = computed(() => (row) => {
262
+ onMounted(() => {
263
+ if (cellRef.value) {
264
+ cellRef.value.forEach(setElementTitle);
265
+ }
266
+ });
267
+
268
+ function getToggleIconName(row) {
255
269
  const isHiddenNestedRow = Array.isArray(row.row)
256
270
  ? row.row.some((nestedRow) => nestedRow.isHidden)
257
271
  : row.row?.isHidden;
@@ -259,11 +273,18 @@ const getToggleIconName = computed(() => (row) => {
259
273
  const isHidden = isHiddenNestedRow || row.nestedData?.isHidden;
260
274
 
261
275
  return isHidden ? props.config.defaults.expandIcon : props.config.defaults.collapseIcon;
262
- });
276
+ }
263
277
 
264
- onMounted(() => {
265
- cellRef.value.forEach(setElementTitle);
266
- });
278
+ function getIconWidth() {
279
+ const icon = document.querySelector(`[data-row-toggle-icon='${props.row.id}']`);
280
+ const currentWrapperWidth = toggleWrapperRef.value?.at(0)?.getBoundingClientRect()?.width;
281
+
282
+ if (icon) {
283
+ return `${icon.getBoundingClientRect().width / PX_IN_REM}rem`;
284
+ }
285
+
286
+ return `${currentWrapperWidth / PX_IN_REM || 1}rem`;
287
+ }
267
288
 
268
289
  function getCellClasses(row, key) {
269
290
  const cellClasses = row[key]?.class || "";
@@ -1,5 +1,5 @@
1
1
  export default /*tw*/ {
2
- wrapper: "relative",
2
+ wrapper: "relative w-full overflow-auto",
3
3
  headerCounterBase: "mr-1.5 pr-1.5 font-medium text-sm text-gray-900",
4
4
  stickyHeader: "fixed top-0 flex items-center z-30 overflow-hidden rounded-none border",
5
5
  stickyHeaderRow: "border-gray-200 bg-white",
@@ -18,7 +18,7 @@ export default /*tw*/ {
18
18
  stickyHeaderActionsCheckbox: "{UCheckbox}",
19
19
  stickyHeaderActionsCounter: "-ml-2",
20
20
  tableWrapper: "border border-gray-200 rounded-dynamic bg-white",
21
- table: "min-w-full border-none text-sm w-full table-fixed",
21
+ table: "min-w-full border-none text-sm w-full table-auto",
22
22
  header: "border-b border-gray-200",
23
23
  headerRow: "",
24
24
  headerCellBase: {
@@ -60,6 +60,7 @@ export default /*tw*/ {
60
60
  bodyCellCheckbox: "first:px-4", // try to remove first
61
61
  bodyCellDateDivider: "",
62
62
  bodyCellNested: "mr-2 flex gap-0.5",
63
+ bodyCellNestedExpandIconWrapper: "",
63
64
  bodyCellNestedExpandIcon: {
64
65
  component: "{UIcon}",
65
66
  wrapper: "rounded-sm",
@@ -228,7 +228,6 @@ NestedContent.args = {
228
228
  };
229
229
  }
230
230
  },
231
- selectable: true,
232
231
  slotTemplate: `
233
232
  <template #nested-content="{ row }">
234
233
  <div class="p-4 bg-gray-100">
@@ -312,12 +312,6 @@ const emit = defineEmits([
312
312
  * @property {string} value
313
313
  */
314
314
  "userDateChange",
315
-
316
- /**
317
- * Triggers when the date format applied to the input changes.
318
- * @property {string} value
319
- */
320
- "formattedDateChange",
321
315
  ]);
322
316
 
323
317
  const { tm } = useLocale();
@@ -519,10 +513,6 @@ const selectedDateTo = computed(() => {
519
513
  : undefined;
520
514
  });
521
515
 
522
- const formattedDate = computed(() => {
523
- return formatDate(selectedDate.value, actualDateFormat.value, locale.value);
524
- });
525
-
526
516
  const userFormattedDate = computed(() => {
527
517
  const date = formatDate(selectedDate.value, actualUserFormat.value, userFormatLocale.value);
528
518
  const dateTo = props.range
@@ -547,10 +537,6 @@ watch(userFormattedDate, () => {
547
537
  emit("userDateChange", userFormattedDate.value);
548
538
  });
549
539
 
550
- watch(formattedDate, () => {
551
- emit("formattedDateChange", userFormattedDate.value);
552
- });
553
-
554
540
  // This watcher force updates value when range props changed
555
541
  watch(
556
542
  () => props.range,
@@ -573,7 +559,6 @@ const unwatchInit = watch(
573
559
  minutesRef.value.value = String(selectedDate.value.getMinutes()).padStart(2, "0");
574
560
  secondsRef.value.value = String(selectedDate.value.getSeconds()).padStart(2, "0");
575
561
 
576
- emit("formattedDateChange", userFormattedDate.value);
577
562
  emit("userDateChange", userFormattedDate.value);
578
563
 
579
564
  isInit = true;
@@ -6,7 +6,14 @@ export default /*tw*/ {
6
6
  dayView: "",
7
7
  weekDays: "grid grid-cols-7 justify-items-center gap-1",
8
8
  weekDay: "flex size-8 items-center justify-center text-xs uppercase text-gray-500",
9
- days: "grid grid-cols-7 justify-items-center gap-1",
9
+ days: {
10
+ base: "grid grid-cols-7 justify-items-center gap-1",
11
+ variants: {
12
+ range: {
13
+ true: "gap-0 gap-y-0.5",
14
+ },
15
+ },
16
+ },
10
17
  dateInRange: "bg-brand/15 font-semibold !text-brand-900 hover:bg-brand/30 rounded-none",
11
18
  edgeDateInRange: "",
12
19
  firstDateInRange: "rounded-r-none",
@@ -20,9 +27,9 @@ export default /*tw*/ {
20
27
  dayInRange: "",
21
28
  currentDayInRange: "",
22
29
  anotherMonthDay: "",
23
- firstDayInRange: "",
30
+ firstDayInRange: "font-semibold",
24
31
  anotherMonthFirstDayInRange: "",
25
- lastDayInRange: "",
32
+ lastDayInRange: "font-semibold",
26
33
  currentLastDayInRange: "",
27
34
  currentFirstDayInRange: "",
28
35
  anotherMonthLastDayInRange: "",
@@ -65,7 +65,6 @@
65
65
  v-bind="calendarAttrs"
66
66
  @keydown.esc="deactivate"
67
67
  @user-date-change="onUserFormatDateChange"
68
- @formatted-date-change="onFormattedDateChange"
69
68
  @input="onInput"
70
69
  @blur="onBlur"
71
70
  @submit="onSubmit"
@@ -355,10 +354,6 @@ function onUserFormatDateChange(value) {
355
354
  userFormatDate.value = formatUserDate(value) || "";
356
355
  }
357
356
 
358
- function onFormattedDateChange(value) {
359
- formattedDate.value = value || "";
360
- }
361
-
362
357
  function onSubmit() {
363
358
  deactivate();
364
359
  }
@@ -402,7 +397,6 @@ function onInput() {
402
397
  calendarRef.value?.wrapperRef?.blur();
403
398
  emit("input", {
404
399
  value: localValue.value,
405
- formattedDate: formattedDate.value,
406
400
  userFormatDate: formatUserDate(userFormatDate.value),
407
401
  });
408
402
  });
@@ -279,6 +279,14 @@ const props = defineProps({
279
279
  default: getDefault(defaultConfig, UDatePickerRange).dateFormat,
280
280
  },
281
281
 
282
+ /**
283
+ * User-friendly date format (it will be shown in UI).
284
+ */
285
+ userDateFormat: {
286
+ type: String,
287
+ default: getDefault(defaultConfig, UDatePickerRange).userDateFormat,
288
+ },
289
+
282
290
  /**
283
291
  * Datepicker size.
284
292
  * @values sm, md, lg
@@ -498,7 +506,13 @@ const clickOutsideOptions = computed(() => {
498
506
  };
499
507
  });
500
508
 
501
- const { userFormatDate } = useUserFormat(localValue, userFormatLocale, isPeriod, isVariant);
509
+ const { userFormatDate } = useUserFormat(
510
+ localValue,
511
+ userFormatLocale,
512
+ isPeriod,
513
+ locale,
514
+ props.userDateFormat,
515
+ );
502
516
 
503
517
  watch(
504
518
  calendarValue,
@@ -3,7 +3,14 @@ export default /*tw*/ {
3
3
  input: "{UInput}",
4
4
  activeInput: {
5
5
  component: "{UInput}",
6
- wrapper: "ring-dynamic rounded-dynamic ring-offset-dynamic ring-brand-700/15 border-brand-500 hover:border-brand-500",
6
+ wrapper: {
7
+ base: "ring-dynamic rounded-dynamic ring-offset-dynamic ring-brand-700/15 border-brand-500 hover:border-brand-500",
8
+ variants: {
9
+ error: {
10
+ true: "ring-red-500/15",
11
+ },
12
+ },
13
+ },
7
14
  },
8
15
  buttonWrapper: `
9
16
  flex rounded-dynamic max-md:justify-between
@@ -96,7 +103,6 @@ export default /*tw*/ {
96
103
  component: "{UCalendar}",
97
104
  wrapper: "p-0 pt-2 w-full border-none shadow-none rounded-none",
98
105
  navigation: "pb-0 mb-0 border-none",
99
- days: "gap-0 gap-y-0.5",
100
106
  day: "w-full",
101
107
  },
102
108
  i18n: {
@@ -185,6 +191,7 @@ export default /*tw*/ {
185
191
  },
186
192
  },
187
193
  defaults: {
194
+ userDateFormat: "j F Y",
188
195
  size: "md",
189
196
  variant: "button",
190
197
  labelAlign: "topInside",
@@ -1,12 +1,9 @@
1
1
  import { computed } from "vue";
2
2
 
3
- import useBreakpoint from "../composables/useBreakpoint.js";
4
-
5
3
  import { isSameMonth } from "../ui.form-calendar/utilDate.js";
4
+ import { formatDate } from "../ui.form-calendar/utilCalendar.js";
6
5
 
7
- export function useUserFormat(localValue, userFormatLocale, isPeriod, isVariant) {
8
- const { isMobileBreakpoint } = useBreakpoint();
9
-
6
+ export function useUserFormat(localValue, userFormatLocale, isPeriod, locale, userDateFormat) {
10
7
  const userFormatDate = computed(() => {
11
8
  if ((!localValue.value.from && !localValue.value.to) || !localValue.value.from) return "";
12
9
 
@@ -19,7 +16,6 @@ export function useUserFormat(localValue, userFormatLocale, isPeriod, isVariant)
19
16
 
20
17
  if (isDefaultTitle) {
21
18
  let startMonthName = userFormatLocale.value.months.longhand[from.getMonth()];
22
- let startYear = from.getFullYear();
23
19
  let endMonthName = userFormatLocale.value.months.longhand[to?.getMonth()];
24
20
  let endYear = to?.getFullYear();
25
21
 
@@ -27,54 +23,34 @@ export function useUserFormat(localValue, userFormatLocale, isPeriod, isVariant)
27
23
  startMonthName = "";
28
24
  }
29
25
 
30
- if (startYear.year === endYear) {
31
- startYear = "";
32
- }
26
+ const isDateToSameMonth = isSameMonth(from, to);
27
+ const isDateToSameYear = from.getFullYear() === to.getFullYear();
33
28
 
34
- const isDatesToSameMonth = isSameMonth(from, to);
35
- const isDatesToSameYear = from.getFullYear() === to.getFullYear();
29
+ let fromFormat = userDateFormat;
36
30
 
37
- let fromTitle = `${from.getDate()} ${startMonthName} ${startYear}`;
38
-
39
- if (isDatesToSameMonth && isDatesToSameYear) {
40
- fromTitle = from.getDate();
31
+ if (isDateToSameMonth && isDateToSameYear) {
32
+ fromFormat = fromFormat.replace(/[YyMmFnU]/g, "");
41
33
  }
42
34
 
43
- if (!isDatesToSameMonth && isDatesToSameYear) {
44
- fromTitle = `${from.getDate()} ${startMonthName}`;
35
+ if (!isDateToSameMonth && isDateToSameYear) {
36
+ fromFormat = fromFormat.replace(/[Yy]/g, "");
45
37
  }
46
38
 
47
- const toTitle = to ? `${to.getDate()} ${endMonthName} ${endYear}` : "";
39
+ const fromTitle = from ? formatDate(from, fromFormat, locale.value) : "";
40
+ const toTitle = to ? formatDate(to, userDateFormat, locale.value) : "";
48
41
 
49
42
  title = `${fromTitle} – ${toTitle}`;
50
43
  }
51
44
 
52
45
  if (isPeriod.value.month) {
53
- const startMonthName = userFormatLocale.value.months.longhand[from.getMonth()];
54
- const startYear = from.getFullYear();
55
-
56
- title = `${startMonthName} ${startYear}`;
46
+ title = formatDate(from, "F Y", locale.value);
57
47
  }
58
48
 
59
49
  if (isPeriod.value.quarter || isPeriod.value.year) {
60
- const startMonthName = userFormatLocale.value.months.longhand[from.getMonth()];
61
- const endMonthName = userFormatLocale.value.months.longhand[to?.getMonth()];
62
- const endYear = to?.getFullYear();
63
-
64
- const fromTitle = `${from.getDate()} ${startMonthName}`;
65
- const toTitle = to ? `${to.getDate()} ${endMonthName} ${endYear}` : "";
66
-
67
- title = `${fromTitle} – ${toTitle}`;
68
- }
69
-
70
- if (isMobileBreakpoint.value && !isPeriod.value.month && isVariant.value.button) {
71
- const startDay = String(from.getDate()).padStart(2, "0");
72
- const endDay = String(to?.getDate())?.padStart(2, "0");
73
- const startMonth = String(from.getMonth()).padStart(2, "0");
74
- const endMonth = String(to?.getMonth())?.padStart(2, "0");
50
+ const fromFormat = userDateFormat.replace(/[Yy]/g, "");
75
51
 
76
- const fromTitle = `${startDay}.${startMonth}`;
77
- const toTitle = to ? `${endDay}.${endMonth} / ${to.getFullYear()}` : "";
52
+ const fromTitle = from ? formatDate(from, fromFormat, locale.value) : "";
53
+ const toTitle = to ? formatDate(to, userDateFormat, locale.value) : "";
78
54
 
79
55
  title = `${fromTitle} – ${toTitle}`;
80
56
  }
package/web-types.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "framework": "vue",
3
3
  "name": "vueless",
4
- "version": "0.0.454",
4
+ "version": "0.0.456",
5
5
  "contributions": {
6
6
  "html": {
7
7
  "description-markup": "markdown",
@@ -1058,18 +1058,6 @@
1058
1058
  "name": "value"
1059
1059
  }
1060
1060
  ]
1061
- },
1062
- {
1063
- "name": "formattedDateChange",
1064
- "description": "Triggers when the date format applied to the input changes.",
1065
- "properties": [
1066
- {
1067
- "type": [
1068
- "string"
1069
- ],
1070
- "name": "value"
1071
- }
1072
- ]
1073
1061
  }
1074
1062
  ],
1075
1063
  "exposes": [
@@ -2683,6 +2671,15 @@
2683
2671
  "type": "string"
2684
2672
  }
2685
2673
  },
2674
+ {
2675
+ "name": "userDateFormat",
2676
+ "description": "User-friendly date format (it will be shown in UI).",
2677
+ "value": {
2678
+ "kind": "expression",
2679
+ "type": "string"
2680
+ },
2681
+ "default": "j F Y"
2682
+ },
2686
2683
  {
2687
2684
  "name": "size",
2688
2685
  "description": "Datepicker size.",