vueless 1.3.4-beta.2 β 1.3.4-beta.4
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/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# Vueless UI
|
|
4
4
|
|
|
5
|
-
A UI library with Open Architecture for Vue.js 3 and Nuxt.js 3 / 4, powered by [Storybook
|
|
5
|
+
A UI library with Open Architecture for Vue.js 3 and Nuxt.js 3 / 4, powered by [Storybook v10](https://storybook.js.org) and [Tailwind CSS v4](https://tailwindcss.com).
|
|
6
6
|
|
|
7
7
|
**With Vueless UI, youβre free to:**
|
|
8
8
|
- πͺοΈ Customize any component
|
|
@@ -10,13 +10,14 @@ A UI library with Open Architecture for Vue.js 3 and Nuxt.js 3 / 4, powered by [
|
|
|
10
10
|
- π§± Build your own from scratch
|
|
11
11
|
- π Document it all seamlessly in Storybook
|
|
12
12
|
|
|
13
|
-
[Documentation](https://docs.vueless.com/) | [UI Components](https://ui.vueless.com/) | [
|
|
13
|
+
[Documentation](https://docs.vueless.com/) | [UI Components](https://ui.vueless.com/) | [Theme Builder](https://my.vueless.com/theme) | [About](http://vueless.com/)
|
|
14
14
|
|
|
15
15
|
### Key features
|
|
16
16
|
|
|
17
17
|
- π§© 65+ crafted UI components (including range date picker, multi-select, and nested table)
|
|
18
18
|
- β¨ Open Architecture lets you customize, copy, extend, and create your own components
|
|
19
19
|
- π Built-in Storybook support
|
|
20
|
+
- πͺ© Theme Builder for runtime theme customization
|
|
20
21
|
- π Beautiful default UI theme
|
|
21
22
|
- π Unstyled mode
|
|
22
23
|
- π Light and dark mode
|
|
@@ -30,6 +31,22 @@ A UI library with Open Architecture for Vue.js 3 and Nuxt.js 3 / 4, powered by [
|
|
|
30
31
|
- π§ͺοΈ 1300+ unit tests ensuring consistent logic
|
|
31
32
|
- π‘οΈ Full TypeScript support with type safety
|
|
32
33
|
|
|
34
|
+
## Built-In Storybook
|
|
35
|
+
|
|
36
|
+
No setup, no hacks β just a fully functional Storybook preset ready to test your Vueless UI design system out of the box.
|
|
37
|
+
|
|
38
|
+
[Demo](https://ui.vueless.com) | [Package](https://www.npmjs.com/package/@vueless/storybook) | [Docs](https://docs.vueless.com/installation/storybook)
|
|
39
|
+
|
|
40
|
+

|
|
41
|
+
|
|
42
|
+
## Theme Builder
|
|
43
|
+
|
|
44
|
+
Customize colors, rounding, and typography at runtime, generate full palettes, and export a ready-to-use theme to your project.
|
|
45
|
+
|
|
46
|
+
[Try Vueless UI Theme Builder](https://my.vueless.com/theme) π
|
|
47
|
+
|
|
48
|
+

|
|
49
|
+
|
|
33
50
|
## Quick Start (Vue)
|
|
34
51
|
|
|
35
52
|
### New project
|
package/package.json
CHANGED
|
@@ -38,7 +38,7 @@ import {
|
|
|
38
38
|
|
|
39
39
|
import defaultConfig from "./config";
|
|
40
40
|
|
|
41
|
-
import type { Props, DateValue,
|
|
41
|
+
import type { Props, DateValue, Locale, Config } from "./types";
|
|
42
42
|
import type { DateLocale } from "./utilFormatting";
|
|
43
43
|
import type { ComponentExposed } from "../types";
|
|
44
44
|
|
|
@@ -189,21 +189,14 @@ const userFormatLocale = computed(() => {
|
|
|
189
189
|
const localValue = computed({
|
|
190
190
|
get: () => {
|
|
191
191
|
if (props.range) {
|
|
192
|
-
|
|
193
|
-
props.modelValue &&
|
|
194
|
-
typeof props.modelValue === "object" &&
|
|
195
|
-
!(props.modelValue instanceof Date);
|
|
192
|
+
if (tempRangeValue.value) return tempRangeValue.value;
|
|
196
193
|
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
: (props.modelValue as string | Date);
|
|
200
|
-
|
|
201
|
-
const from = isRangeDate(modelValue) ? modelValue.from : modelValue || null;
|
|
202
|
-
const to = isRangeDate(modelValue) ? modelValue.to : null;
|
|
194
|
+
const from = isRangeDate(props.modelValue) ? props.modelValue.from : null;
|
|
195
|
+
const to = isRangeDate(props.modelValue) ? props.modelValue.to : null;
|
|
203
196
|
|
|
204
197
|
return {
|
|
205
|
-
from: parseDate(from
|
|
206
|
-
to: parseDate(to
|
|
198
|
+
from: parseDate(from, actualDateFormat.value, locale.value),
|
|
199
|
+
to: parseDate(to, actualDateFormat.value, locale.value),
|
|
207
200
|
};
|
|
208
201
|
}
|
|
209
202
|
|
|
@@ -256,7 +249,14 @@ const localValue = computed({
|
|
|
256
249
|
|
|
257
250
|
const newRangeDate = { from: newDate, to: newDateTo };
|
|
258
251
|
|
|
259
|
-
|
|
252
|
+
if (props.range) {
|
|
253
|
+
if (newDate && newDateTo) {
|
|
254
|
+
tempRangeValue.value = null;
|
|
255
|
+
emit("update:modelValue", newRangeDate);
|
|
256
|
+
}
|
|
257
|
+
} else {
|
|
258
|
+
emit("update:modelValue", newDate);
|
|
259
|
+
}
|
|
260
260
|
|
|
261
261
|
if (parsedDate === null && isTimepickerEnabled.value && isInputRefs.value) {
|
|
262
262
|
const currentDate = new Date();
|
|
@@ -269,6 +269,7 @@ const localValue = computed({
|
|
|
269
269
|
});
|
|
270
270
|
|
|
271
271
|
const activeDate = ref();
|
|
272
|
+
const tempRangeValue = ref<TModelValue | null>(null);
|
|
272
273
|
|
|
273
274
|
if (isRangeDate(localValue.value)) {
|
|
274
275
|
activeDate.value = localValue.value.from || getDateWithoutTime();
|
|
@@ -452,18 +453,28 @@ function onInputDate(newDate: Date | null) {
|
|
|
452
453
|
}
|
|
453
454
|
|
|
454
455
|
if (props.range && isRangeDate(localValue.value)) {
|
|
455
|
-
const
|
|
456
|
-
|
|
457
|
-
(localValue.value.to && localValue.value.from);
|
|
456
|
+
const localFromTime =
|
|
457
|
+
localValue.value?.from instanceof Date ? localValue.value?.from.getTime() : 0;
|
|
458
458
|
|
|
459
|
-
const
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
459
|
+
const isSameAsFrom = newDate.getTime() === localFromTime;
|
|
460
|
+
const isNewDateLessFromDate = localValue.value.from && newDate < localValue.value.from;
|
|
461
|
+
const areToAndFromDateExists = localValue.value.to && localValue.value.from;
|
|
462
|
+
const hasFrom = localValue.value.from;
|
|
463
463
|
|
|
464
|
-
|
|
464
|
+
const isFullReset = isSameAsFrom || isNewDateLessFromDate || areToAndFromDateExists || !hasFrom;
|
|
465
465
|
|
|
466
|
-
|
|
466
|
+
const updatedValue = isFullReset
|
|
467
|
+
? { from: newDate, to: null }
|
|
468
|
+
: { from: localValue.value.from, to: newDate };
|
|
469
|
+
|
|
470
|
+
if (updatedValue.from && updatedValue.to) {
|
|
471
|
+
tempRangeValue.value = null;
|
|
472
|
+
localValue.value = updatedValue;
|
|
473
|
+
|
|
474
|
+
emit("input", updatedValue);
|
|
475
|
+
} else {
|
|
476
|
+
tempRangeValue.value = updatedValue;
|
|
477
|
+
}
|
|
467
478
|
} else {
|
|
468
479
|
localValue.value = newDate;
|
|
469
480
|
|
|
@@ -117,18 +117,18 @@ describe("UCalendar.vue", () => {
|
|
|
117
117
|
const days = dayView.findAll('[vl-key="day"]');
|
|
118
118
|
|
|
119
119
|
await days[0].trigger("click");
|
|
120
|
+
|
|
121
|
+
expect(component.emitted("update:modelValue")).toBeFalsy();
|
|
122
|
+
|
|
120
123
|
await days[3].trigger("click");
|
|
121
124
|
|
|
122
125
|
expect(component.emitted("update:modelValue")).toBeTruthy();
|
|
126
|
+
expect(component.emitted("update:modelValue")).toHaveLength(1);
|
|
123
127
|
|
|
124
|
-
const
|
|
125
|
-
const secondUpdate = component.emitted("update:modelValue")![1][0] as RangeDate;
|
|
126
|
-
|
|
127
|
-
expect(firstUpdate.from).not.toBeNull();
|
|
128
|
-
expect(firstUpdate.to).toBeNull();
|
|
128
|
+
const rangeUpdate = component.emitted("update:modelValue")![0][0] as RangeDate;
|
|
129
129
|
|
|
130
|
-
expect(
|
|
131
|
-
expect(
|
|
130
|
+
expect(rangeUpdate.from).not.toBeNull();
|
|
131
|
+
expect(rangeUpdate.to).not.toBeNull();
|
|
132
132
|
});
|
|
133
133
|
|
|
134
134
|
it("Timepicker β shows timepicker when enabled", () => {
|
|
@@ -248,28 +248,22 @@ describe("UCalendar.vue", () => {
|
|
|
248
248
|
props: {
|
|
249
249
|
range: true,
|
|
250
250
|
modelValue: {
|
|
251
|
-
from:
|
|
252
|
-
to:
|
|
251
|
+
from: null,
|
|
252
|
+
to: null,
|
|
253
253
|
},
|
|
254
254
|
dateFormat: "Y-m-d",
|
|
255
255
|
},
|
|
256
256
|
});
|
|
257
257
|
|
|
258
|
-
await component.setProps({
|
|
259
|
-
"onUpdate:modelValue": (value: RangeDate) => {
|
|
260
|
-
component.setProps({ modelValue: value });
|
|
261
|
-
},
|
|
262
|
-
});
|
|
263
|
-
|
|
264
258
|
const dayView = component.findComponent(DayView);
|
|
265
259
|
const days = dayView.findAll("button");
|
|
266
260
|
|
|
267
261
|
await days[0].trigger("click");
|
|
268
262
|
await days[3].trigger("click");
|
|
269
263
|
|
|
270
|
-
expect(component.emitted("update:modelValue")).toHaveLength(
|
|
264
|
+
expect(component.emitted("update:modelValue")).toHaveLength(2);
|
|
271
265
|
|
|
272
|
-
const updatedValue = component.emitted("update:modelValue")![
|
|
266
|
+
const updatedValue = component.emitted("update:modelValue")![1][0] as RangeDate;
|
|
273
267
|
|
|
274
268
|
expect(updatedValue.from).toMatch(dateFormatRegex);
|
|
275
269
|
expect(updatedValue.to).toMatch(dateFormatRegex);
|
|
@@ -42,7 +42,11 @@ describe("UDatePickerRange.vue", () => {
|
|
|
42
42
|
const input = component.findComponent(UInput).get("input");
|
|
43
43
|
|
|
44
44
|
await input.trigger("focus");
|
|
45
|
-
|
|
45
|
+
|
|
46
|
+
const days = component.findAll("[vl-key='day']");
|
|
47
|
+
|
|
48
|
+
await days[0].trigger("click");
|
|
49
|
+
await days[3].trigger("click");
|
|
46
50
|
|
|
47
51
|
expect(component.emitted("update:modelValue")).toBeTruthy();
|
|
48
52
|
});
|
package/utils/theme.ts
CHANGED
|
@@ -35,6 +35,7 @@ import {
|
|
|
35
35
|
DEFAULT_DISABLED_OPACITY,
|
|
36
36
|
LETTER_SPACING,
|
|
37
37
|
DEFAULT_LETTER_SPACING,
|
|
38
|
+
THEME_TOKENS,
|
|
38
39
|
LIGHT_THEME,
|
|
39
40
|
DARK_THEME,
|
|
40
41
|
SPACING,
|
|
@@ -898,12 +899,11 @@ function setCSSVariables(
|
|
|
898
899
|
`;
|
|
899
900
|
|
|
900
901
|
if (isCSR) {
|
|
901
|
-
|
|
902
|
-
let style = document.getElementById(vuelessStyleId) as HTMLStyleElement | null;
|
|
902
|
+
let style = document.getElementById(THEME_TOKENS) as HTMLStyleElement | null;
|
|
903
903
|
|
|
904
904
|
if (!style) {
|
|
905
905
|
style = document.createElement("style");
|
|
906
|
-
style.id =
|
|
906
|
+
style.id = THEME_TOKENS;
|
|
907
907
|
|
|
908
908
|
const firstStyleOrLink = document.querySelector("link[rel='stylesheet'], style");
|
|
909
909
|
|