vueless 0.0.13 → 0.0.15
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 +33 -152
- package/package.json +2 -5
- package/preset.tailwind/index.js +95 -0
- package/service.storybook/index.js +1 -1
- package/service.ui/index.js +1 -1
- package/ui.button/index.vue +16 -3
- package/ui.button-link/index.vue +6 -3
- package/ui.container-page/configs/default.config.js +1 -1
- package/ui.data-table-cell/configs/default.config.js +2 -2
- package/ui.dropdown-badge/index.vue +11 -1
- package/ui.dropdown-button/index.vue +14 -2
- package/ui.dropdown-link/index.vue +11 -1
- package/ui.form-calendar/configs/default.config.js +1 -1
- package/ui.form-checkbox/index.vue +1 -1
- package/ui.form-color-picker/index.vue +1 -1
- package/ui.form-date-picker-range/configs/default.config.js +4 -4
- package/ui.form-input/configs/default.config.js +1 -1
- package/ui.form-input/index.vue +5 -8
- package/ui.form-input-file/configs/default.config.js +1 -1
- package/ui.form-input-file/index.vue +4 -8
- package/ui.form-input-rating/configs/default.config.js +1 -1
- package/ui.form-input-rating/index.vue +3 -7
- package/ui.form-label/configs/default.config.js +2 -0
- package/ui.form-label/index.vue +3 -3
- package/ui.form-radio/index.vue +5 -3
- package/ui.form-radio-card/composables/attrs.composable.js +3 -1
- package/ui.form-radio-card/configs/default.config.js +8 -2
- package/ui.form-radio-card/index.vue +26 -40
- package/ui.form-select/configs/default.config.js +3 -3
- package/ui.form-select/index.vue +7 -18
- package/ui.form-switch/index.vue +1 -1
- package/ui.form-textarea/index.vue +2 -2
- package/ui.navigation-stepper/index.vue +1 -1
- package/ui.notify/index.vue +3 -3
- package/ui.other-loader-top/composables/attrs.composable.js +32 -0
- package/ui.other-loader-top/configs/default.config.js +20 -0
- package/ui.other-loader-top/constants/index.js +8 -0
- package/ui.other-loader-top/index.vue +230 -0
- package/ui.other-loader-top/services/loaderTop.service.js +31 -0
- package/ui.text-badge/index.vue +7 -0
- package/web-types.json +36 -132
- package/service.tailwind/index.js +0 -103
- package/ui.loader-top/components/TopProgress.vue +0 -277
- package/ui.loader-top/index.vue +0 -221
- /package/{ui.loader-top → ui.other-loader-top}/store/index.js +0 -0
package/README.md
CHANGED
|
@@ -1,174 +1,55 @@
|
|
|
1
|
-
|
|
1
|
+

|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## Vueless UI
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
* [Documentation](https://docs.vueless.com/)
|
|
6
|
+
* [UI Components](https://ui.vueless.com/)
|
|
7
|
+
* [Website](http://vueless.com/)
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
npm install --global yarn
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
- Create project folder and clone files from Git into:
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
# download project from remote repository
|
|
15
|
-
git clone origin git@gitlab.com:<project_name>.git
|
|
16
|
-
|
|
17
|
-
# go to project folder
|
|
18
|
-
cd <project_name>
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
- Install project dependencies (node_modules):
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
yarn install
|
|
25
|
-
```
|
|
9
|
+
## Quick Start
|
|
26
10
|
|
|
27
|
-
|
|
11
|
+
1. Install `vueless` UI library packages.
|
|
28
12
|
|
|
29
13
|
```bash
|
|
30
|
-
|
|
31
|
-
cp .env.local.example .env.local
|
|
14
|
+
npm install vueless @vueless/plugin-vite
|
|
32
15
|
```
|
|
33
16
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
```bash
|
|
37
|
-
yarn dev
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
- The project is ready!
|
|
41
|
-
|
|
42
|
-
## REST API
|
|
43
|
-
|
|
44
|
-
- Public URL: https://fine.gitbook.io/api/
|
|
45
|
-
|
|
46
|
-
- Development URL (same but editable):
|
|
17
|
+
2. Create `vueless.config.js` at the root of the project.
|
|
47
18
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
## Additional commands
|
|
56
|
-
|
|
57
|
-
- Open Storybook (frontend base UI components documentation):
|
|
58
|
-
|
|
59
|
-
```bash
|
|
60
|
-
# run Storybook in development mode (with docs and stories):
|
|
61
|
-
# It's good for debugging components.
|
|
62
|
-
yarn sb:dev-full
|
|
63
|
-
|
|
64
|
-
# run Storybook in development mode (with docs only):
|
|
65
|
-
yarn sb:dev
|
|
66
|
-
|
|
67
|
-
# build Storybook (to publish in the web):
|
|
68
|
-
yarn sb:build
|
|
69
|
-
|
|
70
|
-
# Run the built application from a `/storybook-static` folder in production mode:
|
|
71
|
-
yarn sb:preview
|
|
19
|
+
```javascript filename="vueless.config.js" title="vueless.config.js"
|
|
20
|
+
export default {
|
|
21
|
+
color: {},
|
|
22
|
+
component: {},
|
|
23
|
+
};
|
|
72
24
|
```
|
|
73
25
|
|
|
74
|
-
|
|
26
|
+
3. Add TailwindCSS preset.
|
|
75
27
|
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
yarn lint
|
|
79
|
-
|
|
80
|
-
# check code style and fix all possible errors
|
|
81
|
-
yarn lint:fix
|
|
28
|
+
```javascript
|
|
29
|
+
import { vuelessPreset } from "vueless/preset.tailwind";
|
|
82
30
|
|
|
83
|
-
|
|
84
|
-
|
|
31
|
+
export default {
|
|
32
|
+
presets: [vuelessPreset],
|
|
33
|
+
...
|
|
34
|
+
};
|
|
85
35
|
```
|
|
86
36
|
|
|
87
|
-
|
|
37
|
+
4. Add Vite plugins.
|
|
88
38
|
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
yarn test:unit
|
|
39
|
+
```javascript
|
|
40
|
+
import { Vueless, VuelessUnpluginComponents } from "@vueless/plugin-vite";
|
|
92
41
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
42
|
+
export default defineConfig({
|
|
43
|
+
plugins: [
|
|
44
|
+
...
|
|
45
|
+
Vueless(),
|
|
46
|
+
VuelessUnpluginComponents(),
|
|
47
|
+
],
|
|
48
|
+
...
|
|
49
|
+
})
|
|
98
50
|
```
|
|
99
51
|
|
|
100
|
-
|
|
52
|
+
That's it! You can use components in your app now ✨
|
|
101
53
|
|
|
102
|
-
```bash
|
|
103
|
-
# for the dev / test / production servers
|
|
104
|
-
cp .env.example .env
|
|
105
54
|
|
|
106
|
-
yarn build
|
|
107
|
-
# TIP: 📐
|
|
108
|
-
# to analise and reduce the build size see the report.html in a project root folder.
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
- Run the built application from a `/dist` folder in **production mode**:
|
|
112
55
|
|
|
113
|
-
```bash
|
|
114
|
-
yarn preview
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
- Automated releases (new app release in GitLab and increase app version number):
|
|
118
|
-
|
|
119
|
-
```bash
|
|
120
|
-
# increase third app version number (0.0.X).
|
|
121
|
-
yarn release
|
|
122
|
-
|
|
123
|
-
# increase second app version number (0.X.0).
|
|
124
|
-
yarn release:production
|
|
125
|
-
|
|
126
|
-
# increase first app version number (X.0.0).
|
|
127
|
-
release:production-major
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
- Update browserslist DB to the latest version (it changes yarn.lock only):
|
|
131
|
-
|
|
132
|
-
```bash
|
|
133
|
-
npx browserslist@latest --update-db
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
- **Note**: `yarn` automatically calls the` postinstall` command,
|
|
137
|
-
which generate components web-types for IDE (props autocomplete).
|
|
138
|
-
If you need to do this manually, just use the command below:
|
|
139
|
-
|
|
140
|
-
```bash
|
|
141
|
-
node .mono/our.library.web-types-gen
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
## Capacitor (iOS & Android apps)
|
|
145
|
-
|
|
146
|
-
- Update app src after `dist` or `capacitor.config.js` file changes:
|
|
147
|
-
|
|
148
|
-
```bash
|
|
149
|
-
npx cap copy
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
- Open iOS app locally:
|
|
153
|
-
|
|
154
|
-
```bash
|
|
155
|
-
npx cap open ios
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
- Open Android app locally:
|
|
159
|
-
|
|
160
|
-
```bash
|
|
161
|
-
npx cap open android
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
- Sync the app after new capacitor plugin installation:
|
|
165
|
-
|
|
166
|
-
```bash
|
|
167
|
-
npx cap sync
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
- Generate app icons and splash screens ([docs](https://github.com/ionic-team/capacitor-assets)):
|
|
171
|
-
|
|
172
|
-
```bash
|
|
173
|
-
npx @capacitor/assets generate --assetPath 'public/static/capacitor' --iconBackgroundColor '#FFFFFF' --iconBackgroundColorDark '#111827' --splashBackgroundColor '#F3F4F6' --splashBackgroundColorDark '#1F2937' --ios --android
|
|
174
|
-
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vueless",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.15",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Vue Styleless Component Framework.",
|
|
6
6
|
"homepage": "https://vueless.com",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"sb:build": "STORYBOOK_VUELESS_ENV=1 storybook build",
|
|
20
20
|
"sb:preview": "vite preview --host --outDir=storybook-static",
|
|
21
21
|
"vueless:update": "yarn add -D file:../vite-plugin-vueless file:../vueless-storybook",
|
|
22
|
-
"vueless:prepare": "rm -rf dist && mkdir -p dist && cp -r src/* package.json LICENSE web-types.json README.md dist/
|
|
22
|
+
"vueless:prepare": "node .web-types-gen && rm -rf dist && mkdir -p dist && cp -r src/* package.json LICENSE web-types.json README.md dist/"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@kyvg/vue3-notification": "^3.2.1",
|
|
@@ -59,9 +59,6 @@
|
|
|
59
59
|
"vite-plugin-eslint": "^1.8.1",
|
|
60
60
|
"vue": "^3.4.19"
|
|
61
61
|
},
|
|
62
|
-
"resolutions": {
|
|
63
|
-
"string-width": ">=4.2.3"
|
|
64
|
-
},
|
|
65
62
|
"repository": {
|
|
66
63
|
"type": "git",
|
|
67
64
|
"url": "git+https://github.com/vuelessjs/vueless.git"
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import colors from "tailwindcss/colors.js";
|
|
2
|
+
import forms from "@tailwindcss/forms";
|
|
3
|
+
import vuelessConfig from "../../../vueless.config.js";
|
|
4
|
+
|
|
5
|
+
export const grayColors = ["slate", "gray", "zinc", "neutral", "stone"];
|
|
6
|
+
export const brandColors = [
|
|
7
|
+
"brand",
|
|
8
|
+
"red",
|
|
9
|
+
"orange",
|
|
10
|
+
"amber",
|
|
11
|
+
"yellow",
|
|
12
|
+
"lime",
|
|
13
|
+
"green",
|
|
14
|
+
"emerald",
|
|
15
|
+
"teal",
|
|
16
|
+
"cyan",
|
|
17
|
+
"sky",
|
|
18
|
+
"blue",
|
|
19
|
+
"indigo",
|
|
20
|
+
"violet",
|
|
21
|
+
"purple",
|
|
22
|
+
"fuchsia",
|
|
23
|
+
"pink",
|
|
24
|
+
"rose",
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Generates preset for TailwindCSS base on Vueless config.
|
|
29
|
+
* @returns {Object}
|
|
30
|
+
*/
|
|
31
|
+
export function vuelessPreset() {
|
|
32
|
+
const isProd = process.env.NODE_ENV === "production";
|
|
33
|
+
const brandColor = twColorWithOpacity("--color-brand");
|
|
34
|
+
const { brand, gray } = vuelessConfig;
|
|
35
|
+
|
|
36
|
+
let brandPalette = brandColors.includes(brand) ? colors[brand] : colors.green;
|
|
37
|
+
let grayPalette = grayColors.includes(gray) ? colors[gray] : colors.zinc;
|
|
38
|
+
|
|
39
|
+
if (brand === "grayscale") {
|
|
40
|
+
brandPalette = grayPalette;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const prodSafelist = getSafelist();
|
|
44
|
+
const devSafelist = [
|
|
45
|
+
{
|
|
46
|
+
pattern: /(border|bg|text|ring)-(.*)-((50|[1-9]00|950)?)$/,
|
|
47
|
+
variants: ["hover", "focus", "focus-within", "active"],
|
|
48
|
+
},
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
content: [
|
|
53
|
+
"./index.html",
|
|
54
|
+
"./src/**/*.{js,ts,jsx,tsx,vue}",
|
|
55
|
+
"./vueless.config.{js,ts}",
|
|
56
|
+
"./node_modules/vueless/**/*.{js,ts,vue}",
|
|
57
|
+
],
|
|
58
|
+
safelist: isProd ? prodSafelist : devSafelist,
|
|
59
|
+
theme: {
|
|
60
|
+
extend: {
|
|
61
|
+
colors: {
|
|
62
|
+
brand: { ...brandPalette, DEFAULT: brandColor },
|
|
63
|
+
gray: grayPalette,
|
|
64
|
+
},
|
|
65
|
+
fontSize: {
|
|
66
|
+
"2xs": ["0.625rem", "0.875rem"], // 10px
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
plugins: [forms],
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Transform CSS variable with RGB numbers into CSS color.
|
|
76
|
+
* @returns {Function}
|
|
77
|
+
*/
|
|
78
|
+
function twColorWithOpacity(variableName) {
|
|
79
|
+
return ({ opacityValue }) => {
|
|
80
|
+
return opacityValue !== undefined
|
|
81
|
+
? `rgba(var(${variableName}), ${opacityValue})`
|
|
82
|
+
: `rgb(var(${variableName}))`;
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Convert sting patterns to RegExp.
|
|
88
|
+
* @returns {Array} - TailwindCSS safelist.
|
|
89
|
+
*/
|
|
90
|
+
function getSafelist() {
|
|
91
|
+
return JSON.parse(process.env.SAFELIST_JSON || "[]").map((rule) => ({
|
|
92
|
+
...rule,
|
|
93
|
+
pattern: new RegExp(rule.pattern),
|
|
94
|
+
}));
|
|
95
|
+
}
|
package/service.ui/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { merge } from "lodash-es";
|
|
|
2
2
|
import { defineConfig } from "cva";
|
|
3
3
|
import { twMerge } from "tailwind-merge";
|
|
4
4
|
import colors from "tailwindcss/colors";
|
|
5
|
-
import { brandColors, grayColors } from "../
|
|
5
|
+
import { brandColors, grayColors } from "../preset.tailwind";
|
|
6
6
|
import vuelessConfig from "../../../vueless.config.js";
|
|
7
7
|
|
|
8
8
|
/*
|
package/ui.button/index.vue
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<button
|
|
2
|
+
<button
|
|
3
|
+
:id="id"
|
|
4
|
+
ref="buttonRef"
|
|
5
|
+
:disabled="disabled"
|
|
6
|
+
:data-cy="dataCy"
|
|
7
|
+
v-bind="buttonAttrs"
|
|
8
|
+
@click="onClick"
|
|
9
|
+
>
|
|
3
10
|
<!-- @slot Use it to add something before text. -->
|
|
4
11
|
<slot v-if="!loading" name="left" />
|
|
5
12
|
|
|
@@ -16,11 +23,13 @@
|
|
|
16
23
|
</template>
|
|
17
24
|
|
|
18
25
|
<script setup>
|
|
19
|
-
import
|
|
26
|
+
import { ref } from "vue";
|
|
27
|
+
|
|
20
28
|
import UIService, { getRandomId } from "../service.ui";
|
|
29
|
+
import ULoader from "../ui.other-loader";
|
|
21
30
|
|
|
22
|
-
import { useAttrs } from "./composables/attrs.composable";
|
|
23
31
|
import defaultConfig from "./configs/default.config";
|
|
32
|
+
import { useAttrs } from "./composables/attrs.composable";
|
|
24
33
|
import { UButton } from "./constants";
|
|
25
34
|
|
|
26
35
|
/* Should be a string for correct web-types gen */
|
|
@@ -140,6 +149,10 @@ const emit = defineEmits(["click"]);
|
|
|
140
149
|
|
|
141
150
|
const { textAttrs, buttonAttrs } = useAttrs(props);
|
|
142
151
|
|
|
152
|
+
const buttonRef = ref(null);
|
|
153
|
+
|
|
154
|
+
defineExpose({ buttonRef });
|
|
155
|
+
|
|
143
156
|
function onClick(event) {
|
|
144
157
|
if (props.disabled) return;
|
|
145
158
|
|
package/ui.button-link/index.vue
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
2
|
+
<div v-bind="wrapperAttrs" ref="wrapperRef" tabindex="-1">
|
|
3
3
|
<div v-if="hasSlotContent(slots['left'])" v-bind="leftSlotAttrs">
|
|
4
4
|
<!-- @slot Use it to add something before text. -->
|
|
5
5
|
<slot name="left" />
|
|
@@ -49,8 +49,7 @@
|
|
|
49
49
|
</template>
|
|
50
50
|
|
|
51
51
|
<script setup>
|
|
52
|
-
import { computed, useSlots } from "vue";
|
|
53
|
-
|
|
52
|
+
import { computed, useSlots, ref } from "vue";
|
|
54
53
|
import UIService from "../service.ui";
|
|
55
54
|
|
|
56
55
|
import { useAttrs } from "./composables/attrs.composable";
|
|
@@ -181,6 +180,10 @@ const props = defineProps({
|
|
|
181
180
|
|
|
182
181
|
const slots = useSlots();
|
|
183
182
|
|
|
183
|
+
const wrapperRef = ref(null);
|
|
184
|
+
|
|
185
|
+
defineExpose({ wrapperRef });
|
|
186
|
+
|
|
184
187
|
const { wrapperAttrs, linkAttrs, rightSlotAttrs, leftSlotAttrs, textAttrs, hasSlotContent } =
|
|
185
188
|
useAttrs(props);
|
|
186
189
|
|
|
@@ -2,7 +2,7 @@ export default /*tw*/ {
|
|
|
2
2
|
htmlBody: "bg-gray-50 group/body-gray",
|
|
3
3
|
wrapperMobile: "overflow-x-hidden mb-[theme('spacing.mobile-menu-height')]",
|
|
4
4
|
wrapper: {
|
|
5
|
-
base: "min-h-screen overflow-auto",
|
|
5
|
+
base: "min-h-screen overflow-auto UNotifyPage",
|
|
6
6
|
variants: {
|
|
7
7
|
width: {
|
|
8
8
|
xs: "md:w-[25rem] md:max-[500px]:!w-full",
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
export default /*tw*/ {
|
|
2
2
|
tableCell: {
|
|
3
3
|
base: `
|
|
4
|
-
p-[1.125rem] py-5 first:p-5 [&:nth-child(2)]:pl-0 group-[]/body:truncate group-[]/body:align-top
|
|
4
|
+
p-[1.125rem] py-5 first:p-5 [&:nth-child(2)]:pl-0 group-[]/body:truncate group-[]/body:align-top
|
|
5
5
|
group-[]/body:last:p-5
|
|
6
6
|
`,
|
|
7
7
|
variants: {
|
|
8
8
|
compact: {
|
|
9
9
|
true: `
|
|
10
|
-
group-[]/body:px-4 group-[]/body:py-3 group-[]/body:last:px-4 group-[]/body:last:py-3
|
|
10
|
+
group-[]/body:px-4 group-[]/body:py-3 group-[]/body:last:px-4 group-[]/body:last:py-3
|
|
11
11
|
group-[]/body:first:px-4 group-[]/body:first:py-3 group-[]/footer:p-4:
|
|
12
12
|
`,
|
|
13
13
|
},
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
<div v-bind="wrapperAttrs">
|
|
3
3
|
<UBadge
|
|
4
4
|
:id="id"
|
|
5
|
+
ref="badgeRef"
|
|
5
6
|
:label="label"
|
|
6
7
|
:size="size"
|
|
7
8
|
:color="color"
|
|
@@ -10,6 +11,7 @@
|
|
|
10
11
|
:data-cy="`${dataCy}-badge`"
|
|
11
12
|
v-bind="badgeAttrs"
|
|
12
13
|
@click.stop="onClickBadge"
|
|
14
|
+
@blur="onBlurBadge"
|
|
13
15
|
>
|
|
14
16
|
<template #right>
|
|
15
17
|
<UIcon
|
|
@@ -192,6 +194,8 @@ const emit = defineEmits(["update:modelValue"]);
|
|
|
192
194
|
|
|
193
195
|
const isShownOptions = ref(false);
|
|
194
196
|
|
|
197
|
+
const badgeRef = ref(null);
|
|
198
|
+
|
|
195
199
|
const { config, listWrapperAttrs, wrapperAttrs, badgeAttrs, listAttrs, iconAttrs, hasSlotContent } =
|
|
196
200
|
useAttrs(props, { isShownOptions });
|
|
197
201
|
|
|
@@ -227,7 +231,13 @@ function hideOptions() {
|
|
|
227
231
|
}
|
|
228
232
|
|
|
229
233
|
function onClickOutside(event) {
|
|
230
|
-
if (!
|
|
234
|
+
if (!badgeRef.value?.wrapperRef?.contains(event.target)) {
|
|
235
|
+
hideOptions();
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function onBlurBadge(event) {
|
|
240
|
+
if (!event.target.isEqualNode(event.relatedTarget) && event.relatedTarget) {
|
|
231
241
|
hideOptions();
|
|
232
242
|
}
|
|
233
243
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
<div v-bind="wrapperAttrs">
|
|
3
3
|
<UButton
|
|
4
4
|
:id="id"
|
|
5
|
+
ref="buttonRef"
|
|
5
6
|
:label="label"
|
|
6
7
|
:size="size"
|
|
7
8
|
:variant="variant"
|
|
@@ -13,6 +14,7 @@
|
|
|
13
14
|
:data-cy="`${dataCy}-button`"
|
|
14
15
|
v-bind="buttonAttrs"
|
|
15
16
|
@click.stop="onClickButton"
|
|
17
|
+
@blur="onBlurButton"
|
|
16
18
|
>
|
|
17
19
|
<template #right>
|
|
18
20
|
<UIcon
|
|
@@ -39,7 +41,10 @@
|
|
|
39
41
|
:value-key="valueKey"
|
|
40
42
|
:label-key="labelKey"
|
|
41
43
|
:data-cy="`${dataCy}-item`"
|
|
44
|
+
tabindex="-1"
|
|
42
45
|
v-bind="listAttrs"
|
|
46
|
+
@mousedown.stop
|
|
47
|
+
@click.stop
|
|
43
48
|
/>
|
|
44
49
|
</div>
|
|
45
50
|
</template>
|
|
@@ -54,8 +59,8 @@ import UDropdownList from "../ui.dropdown-list";
|
|
|
54
59
|
import UIService, { getRandomId } from "../service.ui";
|
|
55
60
|
|
|
56
61
|
import defaultConfig from "./configs/default.config";
|
|
57
|
-
import { UDropdownButton, BUTTON_VARIANT } from "./constants";
|
|
58
62
|
import { useAttrs } from "./composables/attrs.composable";
|
|
63
|
+
import { UDropdownButton, BUTTON_VARIANT } from "./constants";
|
|
59
64
|
|
|
60
65
|
/* Should be a string for correct web-types gen */
|
|
61
66
|
defineOptions({ name: "UDropdownButton", inheritAttrs: false });
|
|
@@ -217,6 +222,7 @@ provide("hideDropdownOptions", () => hideOptions);
|
|
|
217
222
|
const emit = defineEmits(["update:modelValue"]);
|
|
218
223
|
|
|
219
224
|
const isShownOptions = ref(false);
|
|
225
|
+
const buttonRef = ref(null);
|
|
220
226
|
|
|
221
227
|
const {
|
|
222
228
|
config,
|
|
@@ -264,7 +270,13 @@ function hideOptions() {
|
|
|
264
270
|
}
|
|
265
271
|
|
|
266
272
|
function onClickOutside(event) {
|
|
267
|
-
if (!
|
|
273
|
+
if (!buttonRef.value?.buttonRef?.contains(event.target)) {
|
|
274
|
+
hideOptions();
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function onBlurButton(event) {
|
|
279
|
+
if (!event.target.isEqualNode(event.relatedTarget) && event.relatedTarget) {
|
|
268
280
|
hideOptions();
|
|
269
281
|
}
|
|
270
282
|
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
<div v-bind="triggerAttrs">
|
|
4
4
|
<ULink
|
|
5
5
|
:id="id"
|
|
6
|
+
ref="linkRef"
|
|
6
7
|
:label="label"
|
|
7
8
|
:size="size"
|
|
8
9
|
:color="color"
|
|
@@ -13,6 +14,7 @@
|
|
|
13
14
|
:data-cy="`${dataCy}-link`"
|
|
14
15
|
v-bind="linkAttrs"
|
|
15
16
|
@click.stop="onClickLink"
|
|
17
|
+
@blur="onBlurLink"
|
|
16
18
|
>
|
|
17
19
|
<template #right>
|
|
18
20
|
<UIcon
|
|
@@ -210,6 +212,8 @@ const emit = defineEmits(["update:modelValue"]);
|
|
|
210
212
|
|
|
211
213
|
const isShownOptions = ref(false);
|
|
212
214
|
|
|
215
|
+
const linkRef = ref(null);
|
|
216
|
+
|
|
213
217
|
const {
|
|
214
218
|
config,
|
|
215
219
|
listWrapperAttrs,
|
|
@@ -254,7 +258,13 @@ function hideOptions() {
|
|
|
254
258
|
}
|
|
255
259
|
|
|
256
260
|
function onClickOutside(event) {
|
|
257
|
-
if (!
|
|
261
|
+
if (!linkRef.value?.wrapperRef?.contains(event.target)) {
|
|
262
|
+
hideOptions();
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function onBlurLink(event) {
|
|
267
|
+
if (!event.target.isEqualNode(event.relatedTarget) && event.relatedTarget) {
|
|
258
268
|
hideOptions();
|
|
259
269
|
}
|
|
260
270
|
}
|
|
@@ -40,7 +40,7 @@ export default /*tw*/ {
|
|
|
40
40
|
activeMonth: "bg-gray-100",
|
|
41
41
|
yearViewWrapper: "grid w-64 grid-cols-4 items-center justify-center px-3 pt-2",
|
|
42
42
|
year: `
|
|
43
|
-
mx-auto flex h-12 w-full items-center justify-center rounded-lg text-sm hover:cursor-pointer hover:bg-gray-100
|
|
43
|
+
mx-auto flex h-12 w-full items-center justify-center rounded-lg text-sm hover:cursor-pointer hover:bg-gray-100
|
|
44
44
|
disabled:opacity-50 disabled:cursor-not-allowed
|
|
45
45
|
`,
|
|
46
46
|
selectedYear: "bg-gray-900 hover:bg-gray-900 text-white",
|
|
@@ -7,14 +7,14 @@ export default /*tw*/ {
|
|
|
7
7
|
},
|
|
8
8
|
buttonWrapper: "flex h-full rounded-lg focus-within:ring-4 focus-within:ring-gray-600/[.15] max-md:justify-between",
|
|
9
9
|
button: `
|
|
10
|
-
shrink-0 grow rounded-none border-0 bg-zinc-100 py-2 text-base font-medium text-gray-900 shadow-none
|
|
11
|
-
hover:bg-zinc-200 hover:ring-gray-600/[.15] focus:border-0 focus:bg-zinc-200 focus:ring-0 focus:ring-gray-600/[.15]
|
|
10
|
+
shrink-0 grow rounded-none border-0 bg-zinc-100 py-2 text-base font-medium text-gray-900 shadow-none
|
|
11
|
+
hover:bg-zinc-200 hover:ring-gray-600/[.15] focus:border-0 focus:bg-zinc-200 focus:ring-0 focus:ring-gray-600/[.15]
|
|
12
12
|
active:bg-zinc-200 disabled:cursor-not-allowed
|
|
13
13
|
`,
|
|
14
14
|
buttonActive: "border-0 hover:bg-zinc-200 ring-0 ring-gray-600/[.15] bg-zinc-200",
|
|
15
15
|
buttonWrapperActive: "ring-4 ring-gray-600/[.15]",
|
|
16
16
|
shiftRangeButton: `
|
|
17
|
-
focus:bg-bg-zinc-200 flex items-center border-0 bg-zinc-100 py-[0.71875rem] shadow-none
|
|
17
|
+
focus:bg-bg-zinc-200 flex items-center border-0 bg-zinc-100 py-[0.71875rem] shadow-none
|
|
18
18
|
hover:bg-zinc-200 hover:ring-gray-600/[.15] focus:border-0 focus:ring-0 focus:ring-gray-600/[.15] active:bg-zinc-200
|
|
19
19
|
disabled:cursor-not-allowed last:rounded-l-none last:rounded-r-lg first:rounded-l-lg first:rounded-r-none
|
|
20
20
|
`,
|
|
@@ -29,7 +29,7 @@ export default /*tw*/ {
|
|
|
29
29
|
},
|
|
30
30
|
periodsRow: "mb-1 flex min-w-64 gap-1",
|
|
31
31
|
periodButton: `
|
|
32
|
-
flex h-[3.125rem] w-full cursor-pointer flex-col items-center justify-center rounded-lg bg-zinc-100
|
|
32
|
+
flex h-[3.125rem] w-full cursor-pointer flex-col items-center justify-center rounded-lg bg-zinc-100
|
|
33
33
|
px-1.5 py-2.5 text-center text-xs font-medium text-gray-900 hover:bg-gray-200
|
|
34
34
|
[&_span]:block [&_span]:font-normal [&_span]:text-gray-500
|
|
35
35
|
`,
|
package/ui.form-input/index.vue
CHANGED
|
@@ -123,11 +123,12 @@ const props = defineProps({
|
|
|
123
123
|
},
|
|
124
124
|
|
|
125
125
|
/**
|
|
126
|
-
*
|
|
126
|
+
* Set label placement related from the default slot.
|
|
127
|
+
* @values top, topInside, topWithDesc, bottom, left, right
|
|
127
128
|
*/
|
|
128
|
-
|
|
129
|
-
type:
|
|
130
|
-
default: UIService.get(defaultConfig, UInput).default.
|
|
129
|
+
labelAlign: {
|
|
130
|
+
type: String,
|
|
131
|
+
default: UIService.get(defaultConfig, UInput).default.labelAlign,
|
|
131
132
|
},
|
|
132
133
|
|
|
133
134
|
/**
|
|
@@ -285,10 +286,6 @@ const {
|
|
|
285
286
|
hasSlotContent,
|
|
286
287
|
} = useAttrs(props, { isTypePassword, inputPasswordClasses });
|
|
287
288
|
|
|
288
|
-
const labelAlign = computed(() => {
|
|
289
|
-
return props.labelOutside ? "top" : "topInside";
|
|
290
|
-
});
|
|
291
|
-
|
|
292
289
|
const passwordIconName = computed(() => {
|
|
293
290
|
return isShownPassword.value
|
|
294
291
|
? config.value.passwordVisibleIconName
|