vlite3 0.2.1 → 0.2.2
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 +173 -54
- package/components/Dropdown/DropdownMenu.vue.js +48 -47
- package/components/GoogleLogin.vue.d.ts +3 -3
- package/components/GoogleLogin.vue.js +60 -0
- package/components/GoogleLogin.vue2.js +4 -0
- package/components/ProgressBar/ProgressBar.vue.js +7 -0
- package/components/ProgressBar/ProgressBar.vue2.js +158 -0
- package/directives/vScrollReveal.d.ts +2 -0
- package/directives/vScrollReveal.js +48 -0
- package/index.d.ts +6 -0
- package/index.js +160 -146
- package/package.json +5 -3
- package/style.css +24 -3
- package/utils/env.d.ts +14 -0
- package/utils/env.js +4 -0
- package/utils/index.d.ts +2 -0
- package/utils/search.util.d.ts +127 -0
- package/utils/search.util.js +363 -0
package/README.md
CHANGED
|
@@ -4,14 +4,10 @@ A lightweight Vue 3 UI component library built with Tailwind CSS, created for pe
|
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
|
-
### NPM
|
|
8
|
-
|
|
9
7
|
```bash
|
|
10
8
|
npm install vlite3
|
|
11
9
|
```
|
|
12
10
|
|
|
13
|
-
### Yarn
|
|
14
|
-
|
|
15
11
|
```bash
|
|
16
12
|
yarn add vlite3
|
|
17
13
|
```
|
|
@@ -55,34 +51,148 @@ import { Button, Input } from 'vlite3'
|
|
|
55
51
|
</template>
|
|
56
52
|
```
|
|
57
53
|
|
|
58
|
-
##
|
|
59
|
-
|
|
60
|
-
vlite3
|
|
61
|
-
|
|
62
|
-
###
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
54
|
+
## Global Configuration (Registry System)
|
|
55
|
+
|
|
56
|
+
vlite3 features a plugin-based architecture that allows you to register global services. This is particularly useful for dependency injection, such as defining how file uploads should be handled across all `Form` components in your app.
|
|
57
|
+
|
|
58
|
+
### Setting up the Plugin
|
|
59
|
+
|
|
60
|
+
In your `main.ts` or `main.js`, import `createVLite` and `vScrollReveal` and register your services:
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import { createApp } from 'vue'
|
|
64
|
+
import App from './App.vue'
|
|
65
|
+
import { env, createVLite, vScrollReveal, GoogleSignInPlugin } from 'vlite3'
|
|
66
|
+
|
|
67
|
+
const app = createApp(App)
|
|
68
|
+
|
|
69
|
+
// Register global directives
|
|
70
|
+
app.directive('scroll-reveal', vScrollReveal)
|
|
71
|
+
|
|
72
|
+
app.use(GoogleSignInPlugin, {
|
|
73
|
+
clientId: env.VITE_GOOGLE_CLIENT_ID,
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
// Initialize VLite with custom configuration
|
|
77
|
+
const vlite = createVLite({
|
|
78
|
+
services: {
|
|
79
|
+
/**
|
|
80
|
+
* Global File Upload Handler
|
|
81
|
+
*
|
|
82
|
+
* This function will be called automatically by:
|
|
83
|
+
* - useFileUpload() composable
|
|
84
|
+
* - Form components (when using 'file', 'fileUploader', or 'avatarUpload' types)
|
|
85
|
+
*
|
|
86
|
+
* @param file - The File object to upload
|
|
87
|
+
* @param folderId - (Optional) Folder ID passed from component props
|
|
88
|
+
* @returns Promise<string> - The public URL of the uploaded file
|
|
89
|
+
*/
|
|
90
|
+
upload: async (file, folderId) => {
|
|
91
|
+
// Example: Upload to your own backend
|
|
92
|
+
const formData = new FormData()
|
|
93
|
+
formData.append('file', file)
|
|
94
|
+
if (folderId) formData.append('folder_id', folderId)
|
|
95
|
+
|
|
96
|
+
// Replace with your actual API call (e.g., Axios, Fetch)
|
|
97
|
+
const response = await fetch(
|
|
98
|
+
'[https://api.yourdomain.com/v1/upload](https://api.yourdomain.com/v1/upload)',
|
|
99
|
+
{
|
|
100
|
+
method: 'POST',
|
|
101
|
+
body: formData,
|
|
102
|
+
headers: {
|
|
103
|
+
Authorization: 'Bearer ...',
|
|
104
|
+
},
|
|
105
|
+
}
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
if (!response.ok) throw new Error('Upload failed')
|
|
109
|
+
|
|
110
|
+
const data = await response.json()
|
|
111
|
+
return data.url // MUST return the file URL string
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
app.use(vlite)
|
|
117
|
+
app.mount('#app')
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### How it works
|
|
121
|
+
|
|
122
|
+
Once registered, you don't need to pass upload handlers to individual components.
|
|
123
|
+
|
|
124
|
+
1. **Automatic Injection**: The `Form` component detects input types like `file`, `avatarUpload`, or `fileUploader`.
|
|
125
|
+
2. **Parallel Processing**: When the form is submitted, it automatically uploads all files in **parallel** using your registered `upload` service.
|
|
126
|
+
3. **URL Replacement**: The File objects in your form data are replaced with the returned URLs before the final `onSubmit` event is triggered.
|
|
127
|
+
|
|
128
|
+
## 4. Usage
|
|
129
|
+
|
|
130
|
+
Import components directly in your Vue files:
|
|
131
|
+
|
|
132
|
+
```vue
|
|
133
|
+
<script setup>
|
|
134
|
+
import { Button, Input, Form } from 'vlite3'
|
|
135
|
+
|
|
136
|
+
// The form will automatically use the global upload service defined in main.ts
|
|
137
|
+
const schema = [
|
|
138
|
+
{
|
|
139
|
+
name: 'avatar',
|
|
140
|
+
label: 'Profile Picture',
|
|
141
|
+
type: 'avatarUpload',
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
name: 'documents',
|
|
145
|
+
label: 'Attachments',
|
|
146
|
+
type: 'fileUploader',
|
|
147
|
+
props: { multiple: true },
|
|
148
|
+
},
|
|
149
|
+
]
|
|
150
|
+
|
|
151
|
+
const handleSubmit = (payload) => {
|
|
152
|
+
// payload.values.avatar will be a URL string (e.g., "https://api...")
|
|
153
|
+
// payload.values.documents will be an array of URL strings
|
|
154
|
+
console.log(payload.values)
|
|
155
|
+
}
|
|
156
|
+
</script>
|
|
157
|
+
|
|
158
|
+
<template>
|
|
159
|
+
<div class="">
|
|
160
|
+
<Form :schema="schema" @onSubmit="handleSubmit" />
|
|
161
|
+
</div>
|
|
162
|
+
</template>
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
# 🎨 Theming & Customization
|
|
166
|
+
|
|
167
|
+
Reference guide for **vlite3** and the Tailwind CSS v4 theming system. This setup uses a semantic design token approach inspired by shadcn/ui and optimized for Tailwind CSS v4.
|
|
168
|
+
|
|
169
|
+
All colors are defined as CSS variables, allowing you to customize the appearance of your application with minimal effort, including full Dark Mode support.
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Semantic Colors
|
|
174
|
+
|
|
175
|
+
Override these variables in `:root` or within a `.dark` class (when using class-based dark mode) to adjust your theme.
|
|
176
|
+
|
|
177
|
+
| Variable | Utility Class | Description | Recommended Usage |
|
|
178
|
+
| -------------------------------- | ----------------------------- | --------------------------------------- | ----------------------------------------------- |
|
|
179
|
+
| `--color-background` | `bg-background` | Default page background (white) | Main application background |
|
|
180
|
+
| `--color-foreground` | `text-foreground` | Default text color (gray-900) | Primary content text |
|
|
181
|
+
| `--color-card` | `bg-card` | Card background (gray-100) | Cards, containers, surfaces, panels, dialogs |
|
|
182
|
+
| `--color-primary` | `bg-primary` | Primary brand color (blue) | Main actions, buttons, active states |
|
|
183
|
+
| `--color-primary-foreground` | `text-primary-foreground` | Text on primary background (white) | Text/icons displayed on primary elements |
|
|
184
|
+
| `--color-secondary` | `bg-secondary` | Secondary background (gray-200) | Secondary actions, muted sections |
|
|
185
|
+
| `--color-secondary-foreground` | `text-secondary-foreground` | Text on secondary background (gray-900) | Content displayed on secondary elements |
|
|
186
|
+
| `--color-muted` | `bg-muted` | Muted background (gray-150) | Subtle surfaces, table headers, disabled states |
|
|
187
|
+
| `--color-muted` | `text-muted` | Muted text (gray-600) | Secondary text, inactive links, descriptions |
|
|
188
|
+
| `--color-accent` | `bg-accent` | Accent background (gray-150) | Hover states, selection highlights |
|
|
189
|
+
| `--color-accent-foreground` | `text-accent-foreground` | Text on accent background (gray-900) | Content displayed on accent elements |
|
|
190
|
+
| `--color-destructive` | `bg-destructive` | Destructive color (red) | Errors, warnings, destructive actions |
|
|
191
|
+
| `--color-destructive-foreground` | `text-destructive-foreground` | Text on destructive background (white) | Content displayed on destructive elements |
|
|
192
|
+
| `--color-border` | `border` | Default border color (gray-250) | Inputs, cards, dividers |
|
|
193
|
+
| `--radius` | `rounded` | Global border radius | Shared radius across components |
|
|
194
|
+
|
|
195
|
+
---
|
|
86
196
|
|
|
87
197
|
### Extended Color Variants
|
|
88
198
|
|
|
@@ -119,31 +229,17 @@ vlite3 also provides additional utility colors for specific feedback states:
|
|
|
119
229
|
| `--color-info` | `text-info`, `bg-info` | For informational messages/badges. |
|
|
120
230
|
| `--color-danger` | `text-danger`, `bg-danger` | Alias for destructive in some contexts. |
|
|
121
231
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
To customize the theme, simply override the CSS variables in your main CSS file:
|
|
125
|
-
|
|
126
|
-
```css
|
|
127
|
-
@layer base {
|
|
128
|
-
:root {
|
|
129
|
-
--primary: #3b82f6; /* Blue-500 */
|
|
130
|
-
--primary-foreground: #ffffff;
|
|
131
|
-
--radius: 0.75rem;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
.dark {
|
|
135
|
-
--primary: #60a5fa; /* Blue-400 */
|
|
136
|
-
--primary-foreground: #000000;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
```
|
|
232
|
+
---
|
|
140
233
|
|
|
141
234
|
## 8. Typography Scale System
|
|
142
235
|
|
|
143
|
-
The system is
|
|
236
|
+
The typography system is organized into two complementary scales:
|
|
144
237
|
|
|
145
|
-
- Compact scale (prefixed with `--text--fs-*`)
|
|
146
|
-
- Progressive scale (prefixed with `--text-fs-*`)
|
|
238
|
+
- Compact scale (prefixed with `--text--fs-*`)
|
|
239
|
+
- Progressive scale (prefixed with `--text-fs-*`)
|
|
240
|
+
|
|
241
|
+
Use the progressive scale only when you need finer visual control beyond the standard Tailwind size tokens.
|
|
242
|
+
For most layout and content needs, prefer the default Tailwind text sizes to maintain consistency.
|
|
147
243
|
|
|
148
244
|
### Compact Text Scale
|
|
149
245
|
|
|
@@ -156,6 +252,11 @@ The system is divided into two groups:
|
|
|
156
252
|
--text--fs-6: 0.6em;
|
|
157
253
|
--text--fs-7: 0.55em;
|
|
158
254
|
--text--fs-8: 0.5em;
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Progressive Text Scale
|
|
258
|
+
|
|
259
|
+
```css
|
|
159
260
|
--text-fs-0.5: 1.05em;
|
|
160
261
|
--text-fs-1: 1.1em;
|
|
161
262
|
--text-fs-1.5: 1.14em;
|
|
@@ -176,13 +277,19 @@ The system is divided into two groups:
|
|
|
176
277
|
--text-fs-9: 1.8em;
|
|
177
278
|
--text-fs-9.5: 2em;
|
|
178
279
|
--text-fs-10: 2.5em;
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Tailwind Size Tokens
|
|
179
283
|
|
|
284
|
+
```css
|
|
180
285
|
--text-xs: 0.75rem --text-sm: 0.875rem --text-base: 1rem --text-lg: 1.125rem --text-xl: 1.25rem
|
|
181
286
|
--text-2xl: 1.5rem --text-3xl: 1.875rem --text-4xl: 2.25rem --text-5xl: 3rem --text-6xl: 4rem;
|
|
182
287
|
```
|
|
183
288
|
|
|
184
289
|
---
|
|
185
290
|
|
|
291
|
+
### Usage Examples
|
|
292
|
+
|
|
186
293
|
```html
|
|
187
294
|
<p class="text-fs-2">Body text</p>
|
|
188
295
|
|
|
@@ -191,6 +298,18 @@ The system is divided into two groups:
|
|
|
191
298
|
<h1 class="text-xl font-semibold">Page Title</h1>
|
|
192
299
|
```
|
|
193
300
|
|
|
301
|
+
## Hard Rules
|
|
302
|
+
|
|
303
|
+
Follow these rules strictly to ensure visual consistency and predictable styling across the system:
|
|
304
|
+
|
|
305
|
+
- Use `border` instead of `border-border` (the default border color (gray-250) is already applied).
|
|
306
|
+
- Use `rounded` instead of `rounded-rounded`.
|
|
307
|
+
- Use `bg-muted` instead of `bg-secondary/20`.
|
|
308
|
+
- Use `gap-x-*` instead of applying `ml-*` or `mr-*` directly on sibling items.
|
|
309
|
+
- Use `gap-y-*` instead of applying `mt
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
194
313
|
## ✅ Components
|
|
195
314
|
|
|
196
315
|
- **Button**
|
|
@@ -251,7 +370,7 @@ The system is divided into two groups:
|
|
|
251
370
|
- **ProgressBar**
|
|
252
371
|
- **Spinner**
|
|
253
372
|
|
|
254
|
-
|
|
373
|
+
## Complete reference for AI agents and developers:
|
|
255
374
|
|
|
256
375
|
- [llms.txt](https://github.com/safdar-azeem/vlite3/blob/main/llms.txt).
|
|
257
376
|
- [llms-theming.txt](https://github.com/safdar-azeem/vlite3/blob/main/llms-theming.txt).
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineComponent as G, defineAsyncComponent as J, ref as B, computed as I, watch as C, toRef as Q, onMounted as W, onBeforeUnmount as X, openBlock as o, createElementBlock as c, createVNode as
|
|
1
|
+
import { defineComponent as G, defineAsyncComponent as J, ref as B, computed as I, watch as C, toRef as Q, onMounted as W, onBeforeUnmount as X, openBlock as o, createElementBlock as c, createVNode as x, createCommentVNode as i, renderSlot as v, unref as n, normalizeStyle as Y, normalizeClass as T, createBlock as m, Fragment as N, renderList as Z, withCtx as V, createElementVNode as p, toDisplayString as ee, createSlots as te, mergeProps as le, nextTick as se } from "vue";
|
|
2
2
|
import S from "../Icon.vue.js";
|
|
3
3
|
import oe from "../Input.vue.js";
|
|
4
4
|
import ne from "./DropdownItem.vue.js";
|
|
@@ -22,7 +22,7 @@ const ie = ["dir"], ue = {
|
|
|
22
22
|
key: 3,
|
|
23
23
|
class: "flex justify-center py-2"
|
|
24
24
|
}, be = {
|
|
25
|
-
key:
|
|
25
|
+
key: 3,
|
|
26
26
|
class: "shrink-0 border-t mt-1 pt-1"
|
|
27
27
|
}, Ie = /* @__PURE__ */ G({
|
|
28
28
|
__name: "DropdownMenu",
|
|
@@ -45,34 +45,34 @@ const ie = ["dir"], ue = {
|
|
|
45
45
|
direction: { default: "ltr" }
|
|
46
46
|
},
|
|
47
47
|
emits: ["select", "close", "load-more", "search"],
|
|
48
|
-
setup(r, { emit:
|
|
49
|
-
const
|
|
50
|
-
let
|
|
48
|
+
setup(r, { emit: j }) {
|
|
49
|
+
const D = J(() => import("./Dropdown.vue2.js")), t = r, u = j, $ = B(null), f = B(""), { getMenuId: E, getAllRecursiveIds: P } = ae(), _ = I(() => t.remote ? t.searchable : t.searchable && (t.options?.length || 0) > 9);
|
|
50
|
+
let g = null;
|
|
51
51
|
C(f, (e) => {
|
|
52
|
-
t.remote && (
|
|
53
|
-
e &&
|
|
52
|
+
t.remote && (g && clearTimeout(g), g = setTimeout(() => {
|
|
53
|
+
e && u("search", e);
|
|
54
54
|
}, 100));
|
|
55
55
|
});
|
|
56
56
|
const H = (e) => {
|
|
57
57
|
const s = e.target;
|
|
58
|
-
s.scrollTop + s.clientHeight >= s.scrollHeight - 50 && t.hasMore && !t.loading &&
|
|
59
|
-
},
|
|
60
|
-
e.disabled ||
|
|
58
|
+
s.scrollTop + s.clientHeight >= s.scrollHeight - 50 && t.hasMore && !t.loading && u("load-more");
|
|
59
|
+
}, k = (e, s) => {
|
|
60
|
+
e.disabled || u("select", e);
|
|
61
61
|
}, {
|
|
62
62
|
focusedIndex: h,
|
|
63
|
-
isKeyboardMode:
|
|
63
|
+
isKeyboardMode: b,
|
|
64
64
|
filteredOptions: R,
|
|
65
65
|
// rename
|
|
66
|
-
handleKeyDown:
|
|
66
|
+
handleKeyDown: M,
|
|
67
67
|
handleMouseMove: O,
|
|
68
|
-
onMouseEnterItem:
|
|
68
|
+
onMouseEnterItem: w,
|
|
69
69
|
scrollToIndex: z
|
|
70
70
|
} = ce({
|
|
71
71
|
options: Q(t, "options"),
|
|
72
72
|
searchQuery: f,
|
|
73
|
-
containerRef:
|
|
74
|
-
emit: (e, ...s) =>
|
|
75
|
-
handleSelect: (e, s) =>
|
|
73
|
+
containerRef: $,
|
|
74
|
+
emit: (e, ...s) => u(e, ...s),
|
|
75
|
+
handleSelect: (e, s) => k(e)
|
|
76
76
|
}), y = I(() => t.remote ? f.value ? t.options : t.cachedOptions.length ? t.cachedOptions : t.options : R.value), A = (e) => {
|
|
77
77
|
if (!(!t.selected || typeof t.selected != "object") && e.key && e.key in t.selected)
|
|
78
78
|
return t.selected[e.key];
|
|
@@ -84,7 +84,7 @@ const ie = ["dir"], ue = {
|
|
|
84
84
|
key: s.key,
|
|
85
85
|
data: s.data
|
|
86
86
|
};
|
|
87
|
-
|
|
87
|
+
u("select", l);
|
|
88
88
|
}, U = (e, s) => {
|
|
89
89
|
let l = s.value;
|
|
90
90
|
e.key && (l = { [e.key]: l });
|
|
@@ -94,7 +94,7 @@ const ie = ["dir"], ue = {
|
|
|
94
94
|
data: s.data,
|
|
95
95
|
key: e.key
|
|
96
96
|
};
|
|
97
|
-
|
|
97
|
+
u("select", d);
|
|
98
98
|
}, q = async () => {
|
|
99
99
|
await se();
|
|
100
100
|
let e = -1;
|
|
@@ -106,15 +106,15 @@ const ie = ["dir"], ue = {
|
|
|
106
106
|
h.value = -1;
|
|
107
107
|
}
|
|
108
108
|
), W(() => {
|
|
109
|
-
q(), window.addEventListener("keydown",
|
|
109
|
+
q(), window.addEventListener("keydown", M);
|
|
110
110
|
}), X(() => {
|
|
111
|
-
window.removeEventListener("keydown",
|
|
111
|
+
window.removeEventListener("keydown", M);
|
|
112
112
|
}), (e, s) => (o(), c("div", {
|
|
113
113
|
class: "dropdown-menu w-full min-w-[150px] flex flex-col",
|
|
114
114
|
dir: r.direction
|
|
115
115
|
}, [
|
|
116
|
-
|
|
117
|
-
|
|
116
|
+
_.value ? (o(), c("div", ue, [
|
|
117
|
+
x(oe, {
|
|
118
118
|
modelValue: f.value,
|
|
119
119
|
"onUpdate:modelValue": s[0] || (s[0] = (l) => f.value = l),
|
|
120
120
|
placeholder: "Search...",
|
|
@@ -124,13 +124,14 @@ const ie = ["dir"], ue = {
|
|
|
124
124
|
variant: "transparent",
|
|
125
125
|
"show-clear-button": !1
|
|
126
126
|
}, null, 8, ["modelValue"])
|
|
127
|
-
])) :
|
|
127
|
+
])) : i("", !0),
|
|
128
128
|
e.$slots.header ? (o(), c("div", fe, [
|
|
129
129
|
v(e.$slots, "header")
|
|
130
|
-
])) :
|
|
131
|
-
|
|
130
|
+
])) : i("", !0),
|
|
131
|
+
t?.options.length > 0 || e.$slots.menu ? (o(), c("div", {
|
|
132
|
+
key: 2,
|
|
132
133
|
ref_key: "containerRef",
|
|
133
|
-
ref:
|
|
134
|
+
ref: $,
|
|
134
135
|
tabindex: "0",
|
|
135
136
|
role: "menu",
|
|
136
137
|
class: T([
|
|
@@ -142,55 +143,55 @@ const ie = ["dir"], ue = {
|
|
|
142
143
|
(...l) => n(O) && n(O)(...l)),
|
|
143
144
|
onScroll: H
|
|
144
145
|
}, [
|
|
145
|
-
y.value.length === 0 && r.options?.length > 0 && !r.loading ? (o(), c("div", me, " No options found ")) :
|
|
146
|
+
y.value.length === 0 && r.options?.length > 0 && !r.loading ? (o(), c("div", me, " No options found ")) : i("", !0),
|
|
146
147
|
r.layout === "grouped" ? (o(), m(de, {
|
|
147
148
|
key: 1,
|
|
148
149
|
options: y.value,
|
|
149
150
|
selected: r.selected,
|
|
150
151
|
selectable: r.selectable,
|
|
151
152
|
columns: r.columns,
|
|
152
|
-
onSelect:
|
|
153
|
+
onSelect: k
|
|
153
154
|
}, null, 8, ["options", "selected", "selectable", "columns"])) : (o(!0), c(N, { key: 2 }, Z(y.value, (l, d) => (o(), c(N, { key: d }, [
|
|
154
155
|
l.label === "---" ? (o(), c("div", he)) : l.data?.isBoolean ? (o(), m(re, {
|
|
155
156
|
key: 1,
|
|
156
157
|
option: l,
|
|
157
158
|
value: F(l),
|
|
158
|
-
focused: n(
|
|
159
|
+
focused: n(b) && n(h) === d,
|
|
159
160
|
onChange: K,
|
|
160
|
-
onMouseenter: (a) => n(
|
|
161
|
-
}, null, 8, ["option", "value", "focused", "onMouseenter"])) : l.children && l.children.length > 0 ? (o(), m(n(
|
|
161
|
+
onMouseenter: (a) => n(w)(d)
|
|
162
|
+
}, null, 8, ["option", "value", "focused", "onMouseenter"])) : l.children && l.children.length > 0 ? (o(), m(n(D), {
|
|
162
163
|
key: 2,
|
|
163
164
|
position: l.position || t.nestedPosition,
|
|
164
165
|
offset: l.offset || t.nestedOffset,
|
|
165
166
|
class: "w-full",
|
|
166
167
|
options: l.children,
|
|
167
168
|
selected: A(l),
|
|
168
|
-
menuId: n(
|
|
169
|
+
menuId: n(E)(l),
|
|
169
170
|
nestedPosition: t.nestedPosition,
|
|
170
171
|
nestedOffset: t.nestedOffset,
|
|
171
172
|
selectable: t.selectable,
|
|
172
|
-
ignoreClickOutside: n(
|
|
173
|
+
ignoreClickOutside: n(P)(l.children),
|
|
173
174
|
direction: r.direction,
|
|
174
175
|
onOnSelect: (a) => U(l, a)
|
|
175
176
|
}, {
|
|
176
177
|
trigger: V(() => [
|
|
177
|
-
|
|
178
|
+
p("div", {
|
|
178
179
|
"data-dropdown-item": "",
|
|
179
180
|
class: T(["relative flex cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm font-medium outline-none transition-colors justify-between w-full", [
|
|
180
|
-
n(
|
|
181
|
+
n(b) && n(h) === d ? "bg-accent text-accent-foreground" : "hover:bg-accent hover:text-accent-foreground",
|
|
181
182
|
l.disabled ? "opacity-50 cursor-not-allowed" : ""
|
|
182
183
|
]]),
|
|
183
|
-
onMouseenter: (a) => n(
|
|
184
|
+
onMouseenter: (a) => n(w)(d)
|
|
184
185
|
}, [
|
|
185
|
-
|
|
186
|
+
p("div", ve, [
|
|
186
187
|
l.icon ? (o(), m(S, {
|
|
187
188
|
key: 0,
|
|
188
189
|
icon: l.icon,
|
|
189
190
|
class: "mr-2 h-4 w-4 shrink-0 mt-0.5"
|
|
190
|
-
}, null, 8, ["icon"])) :
|
|
191
|
-
|
|
191
|
+
}, null, 8, ["icon"])) : i("", !0),
|
|
192
|
+
p("span", ge, ee(l.label), 1)
|
|
192
193
|
]),
|
|
193
|
-
|
|
194
|
+
x(S, {
|
|
194
195
|
icon: r.direction === "rtl" ? "lucide:chevron-left" : "lucide:chevron-right",
|
|
195
196
|
class: "h-4 w-4 text-muted-foreground shrink-0 ml-2"
|
|
196
197
|
}, null, 8, ["icon"])
|
|
@@ -202,10 +203,10 @@ const ie = ["dir"], ue = {
|
|
|
202
203
|
option: l,
|
|
203
204
|
index: d,
|
|
204
205
|
selected: L(l),
|
|
205
|
-
focused: n(
|
|
206
|
+
focused: n(b) && n(h) === d,
|
|
206
207
|
selectable: r.selectable,
|
|
207
|
-
onClick: (a) =>
|
|
208
|
-
onMouseenter: (a) => n(
|
|
208
|
+
onClick: (a) => k(l),
|
|
209
|
+
onMouseenter: (a) => n(w)(d)
|
|
209
210
|
}, te({ _: 2 }, [
|
|
210
211
|
e.$slots.item ? {
|
|
211
212
|
name: "default",
|
|
@@ -217,16 +218,16 @@ const ie = ["dir"], ue = {
|
|
|
217
218
|
]), 1032, ["option", "index", "selected", "focused", "selectable", "onClick", "onMouseenter"]))
|
|
218
219
|
], 64))), 128)),
|
|
219
220
|
r.loading ? (o(), c("div", ke, [
|
|
220
|
-
|
|
221
|
+
x(S, {
|
|
221
222
|
icon: "lucide:loader-2",
|
|
222
223
|
class: "w-4 h-4 animate-spin text-muted-foreground"
|
|
223
224
|
})
|
|
224
|
-
])) :
|
|
225
|
+
])) : i("", !0),
|
|
225
226
|
v(e.$slots, "menu")
|
|
226
|
-
], 38),
|
|
227
|
+
], 38)) : i("", !0),
|
|
227
228
|
e.$slots.footer ? (o(), c("div", be, [
|
|
228
229
|
v(e.$slots, "footer")
|
|
229
|
-
])) :
|
|
230
|
+
])) : i("", !0)
|
|
230
231
|
], 8, ie));
|
|
231
232
|
}
|
|
232
233
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export interface GoogleLoginProps {
|
|
2
|
-
clientId: string;
|
|
3
2
|
buttonText?: string;
|
|
3
|
+
btnClass?: string;
|
|
4
4
|
variant?: any;
|
|
5
5
|
size?: any;
|
|
6
6
|
rounded?: any;
|
|
@@ -10,7 +10,7 @@ declare function __VLS_template(): {
|
|
|
10
10
|
attrs: Partial<{}>;
|
|
11
11
|
slots: {
|
|
12
12
|
default?(_: {
|
|
13
|
-
login: () =>
|
|
13
|
+
login: () => void;
|
|
14
14
|
loading: boolean;
|
|
15
15
|
disabled: boolean;
|
|
16
16
|
}): any;
|
|
@@ -31,7 +31,7 @@ declare const __VLS_component: import('vue').DefineComponent<GoogleLoginProps, {
|
|
|
31
31
|
variant: any;
|
|
32
32
|
rounded: any;
|
|
33
33
|
buttonText: string;
|
|
34
|
-
}, {}, {}, {}, string, import('vue').ComponentProvideOptions,
|
|
34
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, HTMLDivElement>;
|
|
35
35
|
declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, __VLS_TemplateResult["slots"]>;
|
|
36
36
|
export default _default;
|
|
37
37
|
type __VLS_WithTemplateSlots<T, S> = T & {
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { defineComponent as d, ref as u, openBlock as c, createElementBlock as f, renderSlot as m, createVNode as g, normalizeClass as v, unref as b, withCtx as C, createElementVNode as h, toDisplayString as k } from "vue";
|
|
2
|
+
import { useTokenClient as w } from "../node_modules/vue3-google-signin/dist/index.es.js";
|
|
3
|
+
import z from "./Button.vue.js";
|
|
4
|
+
const x = { class: "google-login-wrapper inline-block w-full" }, y = { class: "font-medium" }, L = /* @__PURE__ */ d({
|
|
5
|
+
__name: "GoogleLogin",
|
|
6
|
+
props: {
|
|
7
|
+
buttonText: { default: "Sign in with Google" },
|
|
8
|
+
btnClass: {},
|
|
9
|
+
variant: { default: "outline" },
|
|
10
|
+
size: { default: "md" },
|
|
11
|
+
rounded: { default: "md" },
|
|
12
|
+
disabled: { type: Boolean, default: !1 }
|
|
13
|
+
},
|
|
14
|
+
emits: ["success", "error"],
|
|
15
|
+
setup(e, { emit: n }) {
|
|
16
|
+
const s = e, o = n, l = u(!1), { login: i, isReady: r } = w({
|
|
17
|
+
onSuccess: (a) => {
|
|
18
|
+
l.value = !1, o("success", a);
|
|
19
|
+
},
|
|
20
|
+
onError: (a) => {
|
|
21
|
+
l.value = !1, o("error", a);
|
|
22
|
+
}
|
|
23
|
+
}), t = () => {
|
|
24
|
+
if (!(s.disabled || l.value)) {
|
|
25
|
+
l.value = !0;
|
|
26
|
+
try {
|
|
27
|
+
i();
|
|
28
|
+
} catch (a) {
|
|
29
|
+
l.value = !1, o("error", a);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
return (a, S) => (c(), f("div", x, [
|
|
34
|
+
m(a.$slots, "default", {
|
|
35
|
+
login: t,
|
|
36
|
+
loading: l.value,
|
|
37
|
+
disabled: e.disabled
|
|
38
|
+
}, () => [
|
|
39
|
+
g(z, {
|
|
40
|
+
variant: e.variant,
|
|
41
|
+
size: e.size,
|
|
42
|
+
rounded: e.rounded,
|
|
43
|
+
disabled: !b(r) || e.disabled || l.value,
|
|
44
|
+
loading: l.value,
|
|
45
|
+
class: v([e.btnClass, "w-full"]),
|
|
46
|
+
icon: "flat-color-icons:google",
|
|
47
|
+
onClick: t
|
|
48
|
+
}, {
|
|
49
|
+
default: C(() => [
|
|
50
|
+
h("span", y, k(e.buttonText), 1)
|
|
51
|
+
]),
|
|
52
|
+
_: 1
|
|
53
|
+
}, 8, ["variant", "size", "rounded", "disabled", "loading", "class"])
|
|
54
|
+
])
|
|
55
|
+
]));
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
export {
|
|
59
|
+
L as default
|
|
60
|
+
};
|