webcake-ui-kit 1.0.0 → 1.0.1
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/LICENSE +21 -0
- package/README.md +358 -8
- package/package.json +68 -5
- package/src/components/accordion/Accordion.vue +70 -0
- package/src/components/accordion/accordion.css +5 -0
- package/src/components/accordion-item/AccordionItem.vue +98 -0
- package/src/components/accordion-item/accordion-item.css +143 -0
- package/src/components/alert-dialog/AlertDialog.vue +82 -0
- package/src/components/alert-dialog/alert-dialog.css +33 -0
- package/src/components/badge/Badge.vue +2 -2
- package/src/components/badge/badge.css +1 -4
- package/src/components/breadcrumb/Breadcrumb.vue +85 -0
- package/src/components/breadcrumb/breadcrumb.css +90 -0
- package/src/components/button/Button.vue +77 -10
- package/src/components/button/button.css +258 -24
- package/src/components/button-group/ButtonGroup.vue +25 -0
- package/src/components/button-group/button-group.css +30 -0
- package/src/components/checkbox/Checkbox.vue +55 -0
- package/src/components/checkbox/checkbox.css +86 -0
- package/src/components/checkbox-group/CheckboxGroup.vue +50 -0
- package/src/components/checkbox-group/checkbox-group.css +35 -0
- package/src/components/dialog/Dialog.vue +355 -0
- package/src/components/dialog/dialog.css +255 -0
- package/src/components/divider/Divider.vue +35 -0
- package/src/components/divider/divider.css +38 -0
- package/src/components/input/Input.vue +99 -0
- package/src/components/input/input.css +123 -0
- package/src/components/pagination/Pagination.vue +211 -0
- package/src/components/pagination/pagination.css +13 -0
- package/src/components/radio/Radio.vue +74 -0
- package/src/components/radio/radio.css +89 -0
- package/src/components/radio-group/RadioGroup.vue +70 -0
- package/src/components/radio-group/radio_group.css +11 -0
- package/src/components/rich-checkbox-group/RichCheckboxGroup.vue +59 -0
- package/src/components/rich-checkbox-group/rich-checkbox-group.css +54 -0
- package/src/components/rich-switch-group/RichSwitchGroup.vue +49 -0
- package/src/components/rich-switch-group/rich_switch_group.css +45 -0
- package/src/components/select/Select.vue +262 -0
- package/src/components/select/select.css +207 -0
- package/src/components/select-option/SelectOption.vue +82 -0
- package/src/components/select-option/select_option.css +60 -0
- package/src/components/sidebar-group-label/SidebarGroupLabel.vue +68 -0
- package/src/components/sidebar-group-label/sidebar_group_label.css +61 -0
- package/src/components/sidebar-item/SidebarItem.vue +110 -0
- package/src/components/sidebar-item/sidebar_item.css +142 -0
- package/src/components/slider/Slider.vue +255 -0
- package/src/components/slider/slider.css +89 -0
- package/src/components/spinner/Spinner.vue +47 -0
- package/src/components/spinner/spinner.css +48 -0
- package/src/components/switch/Switch.vue +32 -0
- package/src/components/switch/switch.css +46 -0
- package/src/components/switch-group/SwitchGroup.vue +32 -0
- package/src/components/switch-group/switch_group.css +28 -0
- package/src/components/tabs/Tabs.vue +57 -0
- package/src/components/tabs/tabs.css +118 -0
- package/src/components/tag/Tag.vue +47 -0
- package/src/components/tag/tag.css +115 -0
- package/src/components/toggle/Toggle.vue +112 -0
- package/src/components/toggle/toggle.css +174 -0
- package/src/components/toggle-group/ToggleGroup.vue +57 -0
- package/src/components/toggle-group/toggle-group.css +68 -0
- package/src/icons/LoaderIcon.vue +22 -0
- package/src/index.js +29 -2
- package/src/styles/border_radius.css +3 -3
- package/src/styles/color_general.css +21 -14
- package/src/styles/shadow.css +2 -2
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Webcake Team
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,12 +1,362 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# 🍰 webcake-ui-kit
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
- Python <= 3.10
|
|
5
|
+
### The Vue UI kit that doesn't make you choose.
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
**One library. Two Vue versions. Zero build step.**
|
|
8
|
+
Ship the same components to Vue 2.7 _and_ Vue 3 — from a single source, with one import.
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
<br />
|
|
11
|
+
|
|
12
|
+
[](https://www.npmjs.com/package/webcake-ui-kit)
|
|
13
|
+
[](https://vuejs.org/)
|
|
14
|
+
[](#-why-ship-raw-sfc)
|
|
15
|
+
[](LICENSE)
|
|
16
|
+
|
|
17
|
+
<br />
|
|
18
|
+
|
|
19
|
+
### 📖 **[Live Docs & Storybook → ui.webcake.io](https://ui.webcake.io)**
|
|
20
|
+
|
|
21
|
+
<sub>Browse every component, prop, slot, and variant — running live in the browser.</sub>
|
|
22
|
+
|
|
23
|
+
<br />
|
|
24
|
+
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 👋 Welcome
|
|
30
|
+
|
|
31
|
+
Migrating from Vue 2 to Vue 3 is painful enough — your UI library shouldn't make it worse.
|
|
32
|
+
|
|
33
|
+
Most Vue component libraries force you to **pick a side**. Choose Vue 2 → you're stuck. Choose Vue 3 → you have to rewrite the app first. Either way, you carry the cost.
|
|
34
|
+
|
|
35
|
+
**webcake-ui-kit refuses that tradeoff.** Every component is hand-authored under strict dual-compatibility rules so the _same import_ compiles, renders, and behaves identically on **Vue 2.7** and **Vue 3.4+** — from a codebase you can grep, fork, and theme as if it were your own.
|
|
36
|
+
|
|
37
|
+
```js
|
|
38
|
+
import { Button, Dialog, Input } from 'webcake-ui-kit'
|
|
39
|
+
// ✅ Vue 2.7 — works
|
|
40
|
+
// ✅ Vue 3.x — works
|
|
41
|
+
// ✅ Same API. Same styles. Same behavior. One source of truth.
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
No `-vue2` package. No `-vue3` package. No build artifact gymnastics. Just `.vue` files, the way the framework intended.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## ⚡ Quick start
|
|
49
|
+
|
|
50
|
+
Get a button on screen in **under 60 seconds**.
|
|
51
|
+
|
|
52
|
+
### 1. Install
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
npm install webcake-ui-kit
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
pnpm add webcake-ui-kit
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
yarn add webcake-ui-kit
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
> Peer dependency: `vue ^2.6.0 || ^3.0.0`. That's it.
|
|
67
|
+
|
|
68
|
+
### 2. Import the styles once
|
|
69
|
+
|
|
70
|
+
```js
|
|
71
|
+
import 'webcake-ui-kit/styles'
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 3. Register components
|
|
75
|
+
|
|
76
|
+
<table>
|
|
77
|
+
<tr>
|
|
78
|
+
<th width="50%">
|
|
79
|
+
|
|
80
|
+
**Vue 3**
|
|
81
|
+
|
|
82
|
+
</th>
|
|
83
|
+
<th width="50%">
|
|
84
|
+
|
|
85
|
+
**Vue 2.7**
|
|
86
|
+
|
|
87
|
+
</th>
|
|
88
|
+
</tr>
|
|
89
|
+
<tr>
|
|
90
|
+
<td>
|
|
91
|
+
|
|
92
|
+
```js
|
|
93
|
+
// main.js
|
|
94
|
+
import { createApp } from 'vue'
|
|
95
|
+
import { Button, Dialog, Input } from 'webcake-ui-kit'
|
|
96
|
+
import 'webcake-ui-kit/styles'
|
|
97
|
+
import App from './App.vue'
|
|
98
|
+
|
|
99
|
+
const app = createApp(App)
|
|
100
|
+
app.component('Button', Button)
|
|
101
|
+
app.component('Dialog', Dialog)
|
|
102
|
+
app.component('Input', Input)
|
|
103
|
+
app.mount('#app')
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
</td>
|
|
107
|
+
<td>
|
|
108
|
+
|
|
109
|
+
```js
|
|
110
|
+
// main.js
|
|
111
|
+
import Vue from 'vue'
|
|
112
|
+
import { Button, Dialog, Input } from 'webcake-ui-kit'
|
|
113
|
+
import 'webcake-ui-kit/styles'
|
|
114
|
+
import App from './App.vue'
|
|
115
|
+
|
|
116
|
+
Vue.component('Button', Button)
|
|
117
|
+
Vue.component('Dialog', Dialog)
|
|
118
|
+
Vue.component('Input', Input)
|
|
119
|
+
|
|
120
|
+
new Vue({ render: h => h(App) }).$mount('#app')
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
</td>
|
|
124
|
+
</tr>
|
|
125
|
+
</table>
|
|
126
|
+
|
|
127
|
+
### 4. Use it
|
|
128
|
+
|
|
129
|
+
```vue
|
|
130
|
+
<template>
|
|
131
|
+
<div>
|
|
132
|
+
<Button variant="primary" @click="open = true">Open dialog</Button>
|
|
133
|
+
|
|
134
|
+
<Dialog v-model="open" title="Hello from webcake 👋">
|
|
135
|
+
<Input v-model="name" placeholder="Your name" />
|
|
136
|
+
</Dialog>
|
|
137
|
+
</div>
|
|
138
|
+
</template>
|
|
139
|
+
|
|
140
|
+
<script>
|
|
141
|
+
export default {
|
|
142
|
+
data: () => ({ open: false, name: '' })
|
|
143
|
+
}
|
|
144
|
+
</script>
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
🎉 **That's it.** The same `.vue` file works on both runtimes — no `#ifdef`, no wrapper, no shim.
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## ✨ Why teams pick webcake
|
|
152
|
+
|
|
153
|
+
<table>
|
|
154
|
+
<tr>
|
|
155
|
+
<td width="33%" valign="top">
|
|
156
|
+
|
|
157
|
+
### 🎯 True dual-compat
|
|
158
|
+
|
|
159
|
+
One source. Vue 2.7 and Vue 3.x. Tested on both runtimes in CI — every PR, every component.
|
|
160
|
+
|
|
161
|
+
</td>
|
|
162
|
+
<td width="33%" valign="top">
|
|
163
|
+
|
|
164
|
+
### 📦 Ships raw SFC
|
|
165
|
+
|
|
166
|
+
No pre-compiled artifacts. Your bundler compiles `.vue` files once, alongside your app. Zero version lock.
|
|
167
|
+
|
|
168
|
+
</td>
|
|
169
|
+
<td width="33%" valign="top">
|
|
170
|
+
|
|
171
|
+
### 🎨 Token-driven theming
|
|
172
|
+
|
|
173
|
+
Override `--color-primary` and the whole kit rebrands. No SASS, no providers, no JS theme objects.
|
|
174
|
+
|
|
175
|
+
</td>
|
|
176
|
+
</tr>
|
|
177
|
+
<tr>
|
|
178
|
+
<td valign="top">
|
|
179
|
+
|
|
180
|
+
### ♿ Accessible by default
|
|
181
|
+
|
|
182
|
+
Semantic HTML, `:focus-visible` rings, ARIA where it matters. Not retrofitted — designed in.
|
|
183
|
+
|
|
184
|
+
</td>
|
|
185
|
+
<td valign="top">
|
|
186
|
+
|
|
187
|
+
### 🪶 Tree-shakable
|
|
188
|
+
|
|
189
|
+
Named exports only. Import `Button`, leave the rest behind. No `Vue.use(KitchenSink)`.
|
|
190
|
+
|
|
191
|
+
</td>
|
|
192
|
+
<td valign="top">
|
|
193
|
+
|
|
194
|
+
### 📖 Storybook included
|
|
195
|
+
|
|
196
|
+
Every component, every variant, every prop — browsable before you `npm install`.
|
|
197
|
+
|
|
198
|
+
</td>
|
|
199
|
+
</tr>
|
|
200
|
+
</table>
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## 🧩 Components
|
|
205
|
+
|
|
206
|
+
<div align="center">
|
|
207
|
+
|
|
208
|
+
| Forms | Overlays | Layout | Display |
|
|
209
|
+
| :------------------- | :---------- | :------------ | :------ |
|
|
210
|
+
| Button | Dialog | Accordion | Badge |
|
|
211
|
+
| ButtonGroup | AlertDialog | AccordionItem | Tag |
|
|
212
|
+
| Input | Tooltip\* | Sidebar | Divider |
|
|
213
|
+
| Checkbox | | Tabs | Spinner |
|
|
214
|
+
| CheckboxGroup | | Breadcrumb | |
|
|
215
|
+
| Radio | | | |
|
|
216
|
+
| RadioGroup | | | |
|
|
217
|
+
| Select | | | |
|
|
218
|
+
| Switch / SwitchGroup | | | |
|
|
219
|
+
| Toggle / ToggleGroup | | | |
|
|
220
|
+
| Slider | | | |
|
|
221
|
+
| RichCheckboxGroup | | | |
|
|
222
|
+
| RichSwitchGroup | | | |
|
|
223
|
+
|
|
224
|
+
<sub>\* coming soon · _more on the way_</sub>
|
|
225
|
+
|
|
226
|
+
</div>
|
|
227
|
+
|
|
228
|
+
All components follow the same conventions: **validated props**, **declared emits**, **BEM-style hooks** (`ui-button--primary`), and `v-model` where it makes sense.
|
|
229
|
+
|
|
230
|
+
👉 **Want to see them in action?** [Browse the live Storybook →](https://ui.webcake.io)
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## 🎨 Theming
|
|
235
|
+
|
|
236
|
+
Every component reads from CSS custom properties. Drop them on `:root` and the whole kit rebrands:
|
|
237
|
+
|
|
238
|
+
```css
|
|
239
|
+
:root {
|
|
240
|
+
--color-primary: #ff6b9d;
|
|
241
|
+
--color-primary-hover: #ff4d8a;
|
|
242
|
+
--radius-md: 12px;
|
|
243
|
+
--font-sans: 'Inter', system-ui, sans-serif;
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
Dark mode? Already wired — every color token has a `.dark` companion. Toggle a class on `<html>` and you're done.
|
|
248
|
+
|
|
249
|
+
```css
|
|
250
|
+
.dark {
|
|
251
|
+
--color-bg: #0b0b0f;
|
|
252
|
+
--color-fg: #f4f4f5;
|
|
253
|
+
/* …everything else cascades */
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
No SASS variables. No JS theme provider. No runtime patching. Just CSS, the way the platform meant it.
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## 🛡️ The dual-compat guarantee
|
|
262
|
+
|
|
263
|
+
Every component compiles cleanly on both runtimes — enforced by a strict authoring contract:
|
|
264
|
+
|
|
265
|
+
- ✅ **Pure Options API** — no `<script setup>`, no `setup()`, no Composition API imports
|
|
266
|
+
- ✅ **Single root template** (Vue 2 has no fragments)
|
|
267
|
+
- ✅ **`emits` always declared** (Vue 3 needs it for `$attrs` separation)
|
|
268
|
+
- ✅ No Vue-3-only features (`<Teleport>`, `<Suspense>`, multi `v-model`)
|
|
269
|
+
- ✅ No Vue-2-only features (filters, `.native`, `$listeners`)
|
|
270
|
+
|
|
271
|
+
And every commit runs through **four parallel build lanes**:
|
|
272
|
+
|
|
273
|
+
| | Runtime | Bundler | What it catches |
|
|
274
|
+
| :-: | :------ | :---------------------------------- | :------------------------------------ |
|
|
275
|
+
| 🟢 | Vue 3.4 | Vite + `@vitejs/plugin-vue` | Modern compile errors, fragment leaks |
|
|
276
|
+
| 🟣 | Vue 2.7 | webpack 4 + `vue-template-compiler` | Legacy compile errors, banned APIs |
|
|
277
|
+
| 🟡 | Vue 3.2 | Storybook 6.5 | Story-side regressions |
|
|
278
|
+
| 🧪 | Both | Vitest × 2 lanes | Runtime + behavior parity |
|
|
279
|
+
|
|
280
|
+
**If a PR doesn't build on either side, it doesn't ship.** Period.
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## 🏗️ Why ship raw SFC?
|
|
285
|
+
|
|
286
|
+
Most Vue libraries publish pre-compiled `.js` artifacts targeting _one_ Vue runtime. That's how the ecosystem ended up fragmented into `-vue2` and `-vue3` packages.
|
|
287
|
+
|
|
288
|
+
webcake-ui-kit publishes the **source `.vue` files** directly. Your app's bundler — Vite, webpack, whatever you use — compiles them against _your_ Vue version. One source, two outputs, zero version lock-in.
|
|
289
|
+
|
|
290
|
+
> **The tradeoff:** you need a bundler that handles `.vue`. _(You already do.)_
|
|
291
|
+
|
|
292
|
+
This is the entire reason the kit exists. Everything else — the components, the tokens, the Storybook — is downstream of that decision.
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
## 🚦 Compatibility
|
|
297
|
+
|
|
298
|
+
| | Version | Status |
|
|
299
|
+
| :----------------- | :-------------------------------------- | :----------: |
|
|
300
|
+
| Vue 2 | `2.7.x` | ✅ supported |
|
|
301
|
+
| Vue 3 | `3.0+` (tested on `3.4`) | ✅ supported |
|
|
302
|
+
| Bundlers | Vite, webpack 4/5, Rollup, esbuild | ✅ |
|
|
303
|
+
| Node (consumer) | any version your bundler supports | ✅ |
|
|
304
|
+
| Node (contributor) | **14.x** (Vue 2 sandbox uses webpack 4) | ⚠️ pinned |
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
## 🧪 Local development
|
|
309
|
+
|
|
310
|
+
```bash
|
|
311
|
+
npm run preview # Vue 2 + Vue 3 dev servers side by side (HMR on both)
|
|
312
|
+
npm run test:build # Compile-check everything (Vue 2, Vue 3, Storybook) — ~16s
|
|
313
|
+
npm test # Unit suite on both runtimes, in parallel
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
Visit **`localhost:8001`** (Vue 3) and **`localhost:8080`** (Vue 2) side-by-side to spot dual-compat regressions in real time.
|
|
317
|
+
|
|
318
|
+
Full contributor workflow — including the 10-file checklist for adding a component — lives in [CLAUDE.md](./CLAUDE.md).
|
|
319
|
+
|
|
320
|
+
**Environment:** Node 14 · Python ≤ 3.10 (the Vue 2 playground uses webpack 4 with native deps).
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
## 🌐 Resources
|
|
325
|
+
|
|
326
|
+
<div align="center">
|
|
327
|
+
|
|
328
|
+
| | |
|
|
329
|
+
| :---------------------: | :------------------------------------------------------------------------------- |
|
|
330
|
+
| 🌍 **Docs & Storybook** | [ui.webcake.io](https://ui.webcake.io) |
|
|
331
|
+
| 📦 **npm** | [npmjs.com/package/webcake-ui-kit](https://www.npmjs.com/package/webcake-ui-kit) |
|
|
332
|
+
| 🐙 **GitHub** | [pancake-vn/webcake-ui-kit](https://github.com/pancake-vn/webcake-ui-kit) |
|
|
333
|
+
| 🐛 **Issues** | [Report a bug](https://github.com/pancake-vn/webcake-ui-kit/issues) |
|
|
334
|
+
| 💬 **Discussions** | [Ask a question](https://github.com/pancake-vn/webcake-ui-kit/discussions) |
|
|
335
|
+
|
|
336
|
+
</div>
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
## 🤝 Contributing
|
|
341
|
+
|
|
342
|
+
PRs welcome — especially new components, accessibility fixes, and Vue 2/3 parity bug reports.
|
|
343
|
+
|
|
344
|
+
Before opening one:
|
|
345
|
+
|
|
346
|
+
1. Read [CLAUDE.md](./CLAUDE.md) — it documents the dual-compat rules and the 10-file checklist for adding a component.
|
|
347
|
+
2. Run `npm run test:build && npm test` — both must pass on Vue 2 _and_ Vue 3 lanes.
|
|
348
|
+
3. Add a Storybook story and a unit spec. New components without both are not accepted.
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
352
|
+
## 📜 License
|
|
353
|
+
|
|
354
|
+
**ISC** © Webcake Team — use it, fork it, ship it.
|
|
355
|
+
|
|
356
|
+
---
|
|
357
|
+
|
|
358
|
+
<div align="center">
|
|
359
|
+
<sub>Made with 🍰 by <a href="https://github.com/pancake-vn">pancake-vn</a></sub>
|
|
360
|
+
<br />
|
|
361
|
+
<sub>Because nobody should have to rewrite their app to upgrade a UI library.</sub>
|
|
362
|
+
</div>
|
package/package.json
CHANGED
|
@@ -1,14 +1,66 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webcake-ui-kit",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "UI Kit for Vue 2 && 3 - Pure Options API",
|
|
5
5
|
"main": "src/index.js",
|
|
6
|
+
"module": "src/index.js",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"sideEffects": [
|
|
9
|
+
"**/*.css"
|
|
10
|
+
],
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"import": "./src/index.js",
|
|
14
|
+
"default": "./src/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./styles": "./src/styles/index.css",
|
|
17
|
+
"./styles/*": "./src/styles/*",
|
|
18
|
+
"./WkAccordion": "./src/components/accordion/Accordion.vue",
|
|
19
|
+
"./WkAccordionItem": "./src/components/accordion-item/AccordionItem.vue",
|
|
20
|
+
"./WkAlertDialog": "./src/components/alert-dialog/AlertDialog.vue",
|
|
21
|
+
"./WkBadge": "./src/components/badge/Badge.vue",
|
|
22
|
+
"./WkBreadcrumb": "./src/components/breadcrumb/Breadcrumb.vue",
|
|
23
|
+
"./WkButton": "./src/components/button/Button.vue",
|
|
24
|
+
"./WkButtonGroup": "./src/components/button-group/ButtonGroup.vue",
|
|
25
|
+
"./WkCheckbox": "./src/components/checkbox/Checkbox.vue",
|
|
26
|
+
"./WkCheckboxGroup": "./src/components/checkbox-group/CheckboxGroup.vue",
|
|
27
|
+
"./WkDialog": "./src/components/dialog/Dialog.vue",
|
|
28
|
+
"./WkDivider": "./src/components/divider/Divider.vue",
|
|
29
|
+
"./WkInput": "./src/components/input/Input.vue",
|
|
30
|
+
"./WkPagination": "./src/components/pagination/Pagination.vue",
|
|
31
|
+
"./WkRadio": "./src/components/radio/Radio.vue",
|
|
32
|
+
"./WkRadioGroup": "./src/components/radio-group/RadioGroup.vue",
|
|
33
|
+
"./WkRichCheckboxGroup": "./src/components/rich-checkbox-group/RichCheckboxGroup.vue",
|
|
34
|
+
"./WkRichSwitchGroup": "./src/components/rich-switch-group/RichSwitchGroup.vue",
|
|
35
|
+
"./WkSelect": "./src/components/select/Select.vue",
|
|
36
|
+
"./WkSelectOption": "./src/components/select-option/SelectOption.vue",
|
|
37
|
+
"./WkSidebarGroupLabel": "./src/components/sidebar-group-label/SidebarGroupLabel.vue",
|
|
38
|
+
"./WkSidebarItem": "./src/components/sidebar-item/SidebarItem.vue",
|
|
39
|
+
"./WkSlider": "./src/components/slider/Slider.vue",
|
|
40
|
+
"./WkSpinner": "./src/components/spinner/Spinner.vue",
|
|
41
|
+
"./WkSwitch": "./src/components/switch/Switch.vue",
|
|
42
|
+
"./WkSwitchGroup": "./src/components/switch-group/SwitchGroup.vue",
|
|
43
|
+
"./WkTabs": "./src/components/tabs/Tabs.vue",
|
|
44
|
+
"./WkTag": "./src/components/tag/Tag.vue",
|
|
45
|
+
"./WkToggle": "./src/components/toggle/Toggle.vue",
|
|
46
|
+
"./WkToggleGroup": "./src/components/toggle-group/ToggleGroup.vue",
|
|
47
|
+
"./components/*": "./src/components/*",
|
|
48
|
+
"./package.json": "./package.json"
|
|
49
|
+
},
|
|
6
50
|
"files": [
|
|
7
|
-
"src"
|
|
51
|
+
"src",
|
|
52
|
+
"README.md",
|
|
53
|
+
"LICENSE"
|
|
8
54
|
],
|
|
55
|
+
"publishConfig": {
|
|
56
|
+
"access": "public"
|
|
57
|
+
},
|
|
9
58
|
"scripts": {
|
|
10
59
|
"dev": "vite",
|
|
11
60
|
"build": "echo 'No need to build - shipping raw SFC'",
|
|
61
|
+
"sync:exports": "node scripts/sync-exports.js",
|
|
62
|
+
"sync:exports:check": "node scripts/sync-exports.js --check",
|
|
63
|
+
"prepublishOnly": "npm run sync:exports:check && npm run test:build",
|
|
12
64
|
"dev:vue2": "cd playground-vue2 && npm run dev",
|
|
13
65
|
"dev:vue3": "cd playground-vue3 && npm run dev",
|
|
14
66
|
"preview": "concurrently --names vue3,vue2 --prefix-colors cyan,magenta \"npm:dev:vue3\" \"npm:dev:vue2\"",
|
|
@@ -17,10 +69,20 @@
|
|
|
17
69
|
"build:storybook": "cd storybook-vue3 && npm run build-storybook",
|
|
18
70
|
"test:build": "concurrently --kill-others-on-fail --names vue3,vue2,sb --prefix-colors cyan,magenta,yellow \"npm:build:vue3\" \"npm:build:vue2\" \"npm:build:storybook\"",
|
|
19
71
|
"test:storybook": "npm run build:storybook",
|
|
72
|
+
"test:vue3": "cd playground-vue3 && npm test",
|
|
73
|
+
"test:vue2": "cd playground-vue2 && npm test",
|
|
74
|
+
"test": "concurrently --names vue3,vue2 --prefix-colors cyan,magenta \"npm:test:vue3\" \"npm:test:vue2\"",
|
|
20
75
|
"format": "prettier --write .",
|
|
21
76
|
"format:check": "prettier --check .",
|
|
22
77
|
"lint": "eslint . --ext .js,.cjs,.vue",
|
|
23
|
-
"lint:fix": "eslint . --ext .js,.cjs,.vue --fix"
|
|
78
|
+
"lint:fix": "eslint . --ext .js,.cjs,.vue --fix",
|
|
79
|
+
"prepare": "husky install || echo \"(husky skipped)\"",
|
|
80
|
+
"release": "node scripts/release.js",
|
|
81
|
+
"release:patch": "node scripts/release.js patch",
|
|
82
|
+
"release:minor": "node scripts/release.js minor",
|
|
83
|
+
"release:major": "node scripts/release.js major",
|
|
84
|
+
"release:fast": "node scripts/release.js patch --skip-checks",
|
|
85
|
+
"release:dry": "node scripts/release.js patch --dry-run"
|
|
24
86
|
},
|
|
25
87
|
"lint-staged": {
|
|
26
88
|
"*.{js,cjs,vue}": [
|
|
@@ -40,6 +102,7 @@
|
|
|
40
102
|
"eslint": "^8.57.1",
|
|
41
103
|
"eslint-config-prettier": "^9.1.2",
|
|
42
104
|
"eslint-plugin-vue": "^9.33.0",
|
|
105
|
+
"express": "^5.2.1",
|
|
43
106
|
"husky": "^8.0.3",
|
|
44
107
|
"lint-staged": "^13.3.0",
|
|
45
108
|
"prettier": "^3.8.3",
|
|
@@ -54,9 +117,9 @@
|
|
|
54
117
|
"UI Component"
|
|
55
118
|
],
|
|
56
119
|
"author": "Webcake Team",
|
|
57
|
-
"license": "
|
|
120
|
+
"license": "MIT",
|
|
58
121
|
"bugs": {
|
|
59
122
|
"url": "https://github.com/pancake-vn/webcake-ui-kit/issues"
|
|
60
123
|
},
|
|
61
|
-
"homepage": "https://
|
|
124
|
+
"homepage": "https://ui.webcake.io"
|
|
62
125
|
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="['ui-accordion', bordered && 'ui-accordion--bordered']">
|
|
3
|
+
<slot />
|
|
4
|
+
</div>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script>
|
|
8
|
+
export default {
|
|
9
|
+
name: 'Accordion',
|
|
10
|
+
model: { prop: 'value', event: 'change' },
|
|
11
|
+
props: {
|
|
12
|
+
bordered: { type: Boolean, default: false },
|
|
13
|
+
multiple: { type: Boolean, default: false },
|
|
14
|
+
value: { type: [Array, Number, String], default: undefined },
|
|
15
|
+
modelValue: { type: [Array, Number, String], default: undefined },
|
|
16
|
+
defaultOpen: { type: [Array, Number, String], default: () => [] }
|
|
17
|
+
},
|
|
18
|
+
emits: ['change', 'update:modelValue'],
|
|
19
|
+
provide() {
|
|
20
|
+
return {
|
|
21
|
+
accordion: this
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
data() {
|
|
25
|
+
const initial =
|
|
26
|
+
this.modelValue !== undefined ? this.modelValue : this.value !== undefined ? this.value : this.defaultOpen
|
|
27
|
+
return {
|
|
28
|
+
internalKeys: this.normalizeKeys(initial)
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
computed: {
|
|
32
|
+
isControlled() {
|
|
33
|
+
return this.modelValue !== undefined || this.value !== undefined
|
|
34
|
+
},
|
|
35
|
+
openKeys() {
|
|
36
|
+
if (this.modelValue !== undefined) return this.normalizeKeys(this.modelValue)
|
|
37
|
+
if (this.value !== undefined) return this.normalizeKeys(this.value)
|
|
38
|
+
return this.internalKeys
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
methods: {
|
|
42
|
+
normalizeKeys(v) {
|
|
43
|
+
if (Array.isArray(v)) return v.slice()
|
|
44
|
+
if (v === undefined || v === null || v === '') return []
|
|
45
|
+
return [v]
|
|
46
|
+
},
|
|
47
|
+
isOpen(key) {
|
|
48
|
+
return this.openKeys.indexOf(key) !== -1
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
toggle(key) {
|
|
52
|
+
const isOpen = this.isOpen(key)
|
|
53
|
+
let newKeys
|
|
54
|
+
if (this.multiple) {
|
|
55
|
+
newKeys = isOpen ? this.openKeys.filter(k => k !== key) : this.openKeys.concat([key])
|
|
56
|
+
} else {
|
|
57
|
+
newKeys = isOpen ? [] : [key]
|
|
58
|
+
}
|
|
59
|
+
const emitVal = this.multiple ? newKeys : newKeys.length > 0 ? newKeys[0] : null
|
|
60
|
+
if (!this.isControlled) {
|
|
61
|
+
this.internalKeys = newKeys
|
|
62
|
+
}
|
|
63
|
+
this.$emit('change', emitVal)
|
|
64
|
+
this.$emit('update:modelValue', emitVal)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
</script>
|
|
69
|
+
|
|
70
|
+
<style src="./accordion.css" scoped></style>
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
:class="[
|
|
4
|
+
'ui-accordion-item',
|
|
5
|
+
bordered && 'ui-accordion-item--bordered',
|
|
6
|
+
isOpen && 'ui-accordion-item--open',
|
|
7
|
+
disabled && 'ui-accordion-item--disabled'
|
|
8
|
+
]"
|
|
9
|
+
>
|
|
10
|
+
<button
|
|
11
|
+
:id="triggerId"
|
|
12
|
+
type="button"
|
|
13
|
+
class="ui-accordion-item__trigger"
|
|
14
|
+
:disabled="disabled"
|
|
15
|
+
:aria-expanded="isOpen ? 'true' : 'false'"
|
|
16
|
+
:aria-controls="contentId"
|
|
17
|
+
@click="onClick"
|
|
18
|
+
>
|
|
19
|
+
<span class="ui-accordion-item__label-row">
|
|
20
|
+
<span class="ui-accordion-item__label">
|
|
21
|
+
<slot name="label">{{ label }}</slot>
|
|
22
|
+
</span>
|
|
23
|
+
<span v-if="hasAppend" class="ui-accordion-item__append">
|
|
24
|
+
<slot name="append">{{ append }}</slot>
|
|
25
|
+
</span>
|
|
26
|
+
</span>
|
|
27
|
+
<span :class="['ui-accordion-item__icon', isOpen && 'ui-accordion-item__icon--open']">
|
|
28
|
+
<slot name="icon">
|
|
29
|
+
<svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
|
30
|
+
<path
|
|
31
|
+
d="m4 6 4 4 4-4"
|
|
32
|
+
stroke="currentColor"
|
|
33
|
+
stroke-width="1.5"
|
|
34
|
+
stroke-linecap="round"
|
|
35
|
+
stroke-linejoin="round"
|
|
36
|
+
/>
|
|
37
|
+
</svg>
|
|
38
|
+
</slot>
|
|
39
|
+
</span>
|
|
40
|
+
</button>
|
|
41
|
+
<div v-show="isOpen" :id="contentId" class="ui-accordion-item__content" role="region" :aria-labelledby="triggerId">
|
|
42
|
+
<slot />
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
</template>
|
|
46
|
+
|
|
47
|
+
<script>
|
|
48
|
+
let uidCounter = 0
|
|
49
|
+
|
|
50
|
+
export default {
|
|
51
|
+
name: 'AccordionItem',
|
|
52
|
+
inject: {
|
|
53
|
+
accordion: { default: null }
|
|
54
|
+
},
|
|
55
|
+
props: {
|
|
56
|
+
label: { type: String, default: '' },
|
|
57
|
+
value: { type: [String, Number], default: undefined },
|
|
58
|
+
append: { type: String, default: '' },
|
|
59
|
+
disabled: { type: Boolean, default: false }
|
|
60
|
+
},
|
|
61
|
+
data() {
|
|
62
|
+
return {
|
|
63
|
+
uid: `accordion-item-${++uidCounter}`
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
computed: {
|
|
67
|
+
itemKey() {
|
|
68
|
+
return this.value !== undefined ? this.value : this.uid
|
|
69
|
+
},
|
|
70
|
+
triggerId() {
|
|
71
|
+
return `${this.uid}-trigger`
|
|
72
|
+
},
|
|
73
|
+
contentId() {
|
|
74
|
+
return `${this.uid}-content`
|
|
75
|
+
},
|
|
76
|
+
isOpen() {
|
|
77
|
+
return this.accordion ? this.accordion.isOpen(this.itemKey) : false
|
|
78
|
+
},
|
|
79
|
+
bordered() {
|
|
80
|
+
return this.accordion ? this.accordion.bordered : false
|
|
81
|
+
},
|
|
82
|
+
hasAppend() {
|
|
83
|
+
const slots = this.$slots
|
|
84
|
+
return !!this.append || !!(slots && slots['append'])
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
methods: {
|
|
88
|
+
onClick() {
|
|
89
|
+
if (this.disabled) return
|
|
90
|
+
if (this.accordion && typeof this.accordion.toggle === 'function') {
|
|
91
|
+
this.accordion.toggle(this.itemKey)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
</script>
|
|
97
|
+
|
|
98
|
+
<style src="./accordion-item.css" scoped></style>
|