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.
Files changed (66) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +358 -8
  3. package/package.json +68 -5
  4. package/src/components/accordion/Accordion.vue +70 -0
  5. package/src/components/accordion/accordion.css +5 -0
  6. package/src/components/accordion-item/AccordionItem.vue +98 -0
  7. package/src/components/accordion-item/accordion-item.css +143 -0
  8. package/src/components/alert-dialog/AlertDialog.vue +82 -0
  9. package/src/components/alert-dialog/alert-dialog.css +33 -0
  10. package/src/components/badge/Badge.vue +2 -2
  11. package/src/components/badge/badge.css +1 -4
  12. package/src/components/breadcrumb/Breadcrumb.vue +85 -0
  13. package/src/components/breadcrumb/breadcrumb.css +90 -0
  14. package/src/components/button/Button.vue +77 -10
  15. package/src/components/button/button.css +258 -24
  16. package/src/components/button-group/ButtonGroup.vue +25 -0
  17. package/src/components/button-group/button-group.css +30 -0
  18. package/src/components/checkbox/Checkbox.vue +55 -0
  19. package/src/components/checkbox/checkbox.css +86 -0
  20. package/src/components/checkbox-group/CheckboxGroup.vue +50 -0
  21. package/src/components/checkbox-group/checkbox-group.css +35 -0
  22. package/src/components/dialog/Dialog.vue +355 -0
  23. package/src/components/dialog/dialog.css +255 -0
  24. package/src/components/divider/Divider.vue +35 -0
  25. package/src/components/divider/divider.css +38 -0
  26. package/src/components/input/Input.vue +99 -0
  27. package/src/components/input/input.css +123 -0
  28. package/src/components/pagination/Pagination.vue +211 -0
  29. package/src/components/pagination/pagination.css +13 -0
  30. package/src/components/radio/Radio.vue +74 -0
  31. package/src/components/radio/radio.css +89 -0
  32. package/src/components/radio-group/RadioGroup.vue +70 -0
  33. package/src/components/radio-group/radio_group.css +11 -0
  34. package/src/components/rich-checkbox-group/RichCheckboxGroup.vue +59 -0
  35. package/src/components/rich-checkbox-group/rich-checkbox-group.css +54 -0
  36. package/src/components/rich-switch-group/RichSwitchGroup.vue +49 -0
  37. package/src/components/rich-switch-group/rich_switch_group.css +45 -0
  38. package/src/components/select/Select.vue +262 -0
  39. package/src/components/select/select.css +207 -0
  40. package/src/components/select-option/SelectOption.vue +82 -0
  41. package/src/components/select-option/select_option.css +60 -0
  42. package/src/components/sidebar-group-label/SidebarGroupLabel.vue +68 -0
  43. package/src/components/sidebar-group-label/sidebar_group_label.css +61 -0
  44. package/src/components/sidebar-item/SidebarItem.vue +110 -0
  45. package/src/components/sidebar-item/sidebar_item.css +142 -0
  46. package/src/components/slider/Slider.vue +255 -0
  47. package/src/components/slider/slider.css +89 -0
  48. package/src/components/spinner/Spinner.vue +47 -0
  49. package/src/components/spinner/spinner.css +48 -0
  50. package/src/components/switch/Switch.vue +32 -0
  51. package/src/components/switch/switch.css +46 -0
  52. package/src/components/switch-group/SwitchGroup.vue +32 -0
  53. package/src/components/switch-group/switch_group.css +28 -0
  54. package/src/components/tabs/Tabs.vue +57 -0
  55. package/src/components/tabs/tabs.css +118 -0
  56. package/src/components/tag/Tag.vue +47 -0
  57. package/src/components/tag/tag.css +115 -0
  58. package/src/components/toggle/Toggle.vue +112 -0
  59. package/src/components/toggle/toggle.css +174 -0
  60. package/src/components/toggle-group/ToggleGroup.vue +57 -0
  61. package/src/components/toggle-group/toggle-group.css +68 -0
  62. package/src/icons/LoaderIcon.vue +22 -0
  63. package/src/index.js +29 -2
  64. package/src/styles/border_radius.css +3 -3
  65. package/src/styles/color_general.css +21 -14
  66. package/src/styles/shadow.css +2 -2
@@ -0,0 +1,355 @@
1
+ <template>
2
+ <div v-if="hasOpened" v-show="isVisible" class="ui-dialog-root" :style="rootStyle">
3
+ <transition name="ui-dialog-fade">
4
+ <div v-if="isOpen && mask" class="ui-dialog-mask" :style="maskStyle"></div>
5
+ </transition>
6
+ <transition name="ui-dialog-zoom" appear @after-leave="onAfterLeave">
7
+ <div
8
+ v-if="isOpen"
9
+ ref="wrap"
10
+ class="ui-dialog-wrap"
11
+ :class="wrapCls"
12
+ tabindex="-1"
13
+ role="dialog"
14
+ aria-modal="true"
15
+ @mousedown.self="onWrapMousedown"
16
+ @mouseup.self="onWrapMouseup"
17
+ @keydown.esc="onEscape"
18
+ >
19
+ <div class="ui-dialog-content" :style="contentStyle">
20
+ <div :class="['ui-dialog', isFullscreen && 'ui-dialog--fullscreen']">
21
+ <div v-if="showHeader" :class="['ui-dialog-header', headerDivider && 'ui-dialog-header--divided']">
22
+ <div class="ui-dialog-header__row">
23
+ <slot name="header">
24
+ <div v-if="hasTitle" class="ui-dialog-header__content">
25
+ <div class="ui-dialog-header__title">
26
+ <slot name="title">{{ title }}</slot>
27
+ </div>
28
+ <div v-if="hasSubText" class="ui-dialog-header__sub-text">
29
+ <slot name="sub-text">{{ subText }}</slot>
30
+ </div>
31
+ </div>
32
+ <div v-else class="ui-dialog-header__content ui-dialog-header__content--empty"></div>
33
+ </slot>
34
+
35
+ <div class="ui-dialog-header__actions">
36
+ <button
37
+ v-if="minimizable"
38
+ type="button"
39
+ class="ui-dialog-header__icon-btn"
40
+ :aria-label="minimized ? 'Restore' : 'Minimize'"
41
+ @click="toggleMinimize"
42
+ >
43
+ <svg
44
+ v-if="!minimized"
45
+ viewBox="0 0 20 20"
46
+ fill="none"
47
+ xmlns="http://www.w3.org/2000/svg"
48
+ aria-hidden="true"
49
+ >
50
+ <path d="M5 10h10" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" />
51
+ </svg>
52
+ <svg v-else viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
53
+ <rect x="4" y="5" width="12" height="10" rx="1.5" stroke="currentColor" stroke-width="1.75" />
54
+ </svg>
55
+ </button>
56
+ <button
57
+ v-if="fullscreen"
58
+ type="button"
59
+ class="ui-dialog-header__icon-btn"
60
+ :aria-label="isFullscreen ? 'Exit fullscreen' : 'Fullscreen'"
61
+ @click="toggleFullscreen"
62
+ >
63
+ <svg
64
+ v-if="!isFullscreen"
65
+ xmlns="http://www.w3.org/2000/svg"
66
+ width="24"
67
+ height="24"
68
+ viewBox="0 0 24 24"
69
+ fill="none"
70
+ stroke="currentColor"
71
+ stroke-width="1.75"
72
+ stroke-linecap="round"
73
+ stroke-linejoin="round"
74
+ class="lucide lucide-expand-icon lucide-expand"
75
+ >
76
+ <path d="m15 15 6 6" />
77
+ <path d="m15 9 6-6" />
78
+ <path d="M21 16v5h-5" />
79
+ <path d="M21 8V3h-5" />
80
+ <path d="M3 16v5h5" />
81
+ <path d="m3 21 6-6" />
82
+ <path d="M3 8V3h5" />
83
+ <path d="M9 9 3 3" />
84
+ </svg>
85
+ <svg
86
+ v-else
87
+ xmlns="http://www.w3.org/2000/svg"
88
+ width="24"
89
+ height="24"
90
+ viewBox="0 0 24 24"
91
+ fill="none"
92
+ stroke="currentColor"
93
+ stroke-width="1.75"
94
+ stroke-linecap="round"
95
+ stroke-linejoin="round"
96
+ class="lucide lucide-shrink-icon lucide-shrink"
97
+ >
98
+ <path d="m15 15 6 6m-6-6v4.8m0-4.8h4.8" />
99
+ <path d="M9 19.8V15m0 0H4.2M9 15l-6 6" />
100
+ <path d="M15 4.2V9m0 0h4.8M15 9l6-6" />
101
+ <path d="M9 4.2V9m0 0H4.2M9 9 3 3" />
102
+ </svg>
103
+ </button>
104
+ <button
105
+ v-if="closable"
106
+ type="button"
107
+ class="ui-dialog-header__icon-btn"
108
+ aria-label="Close"
109
+ @click="handleCancel"
110
+ >
111
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none">
112
+ <path
113
+ d="M14.4841 4.48408C14.7688 4.19932 15.2312 4.19932 15.516 4.48408C15.8007 4.76883 15.8007 5.23122 15.516 5.51598L11.0319 10L15.516 14.4841C15.8007 14.7688 15.8007 15.2312 15.516 15.516C15.2312 15.8007 14.7688 15.8007 14.4841 15.516L10 11.0319L5.51598 15.516C5.23122 15.8007 4.76883 15.8007 4.48408 15.516C4.19932 15.2312 4.19932 14.7688 4.48408 14.4841L8.96813 10L4.48408 5.51598C4.19932 5.23122 4.19932 4.76883 4.48408 4.48408C4.76883 4.19932 5.23122 4.19932 5.51598 4.48408L10 8.96813L14.4841 4.48408Z"
114
+ fill="#171717"
115
+ />
116
+ </svg>
117
+ </button>
118
+ </div>
119
+ </div>
120
+ </div>
121
+
122
+ <div v-show="!minimized" class="ui-dialog-body">
123
+ <slot />
124
+ </div>
125
+
126
+ <div
127
+ v-if="footer && !minimized"
128
+ :class="[
129
+ 'ui-dialog-footer',
130
+ `ui-dialog-footer--align-${footerAlign}`,
131
+ footerDivider && 'ui-dialog-footer--divided'
132
+ ]"
133
+ >
134
+ <div class="ui-dialog-footer__inner">
135
+ <slot name="footer">
136
+ <Button :variant="cancelVariant" @click="handleCancel">{{ cancelText }}</Button>
137
+ <Button :variant="okVariant" :loading="confirmLoading" @click="handleOk">{{ okText }}</Button>
138
+ </slot>
139
+ </div>
140
+ </div>
141
+ </div>
142
+ </div>
143
+ </div>
144
+ </transition>
145
+ </div>
146
+ </template>
147
+
148
+ <script>
149
+ import Button from '../button/Button.vue'
150
+
151
+ export default {
152
+ name: 'Dialog',
153
+ components: { Button },
154
+ model: { prop: 'open', event: 'change' },
155
+ props: {
156
+ open: { type: Boolean, default: false },
157
+ modelValue: { type: Boolean, default: undefined },
158
+ title: { type: String, default: '' },
159
+ subText: { type: String, default: '' },
160
+ closable: { type: Boolean, default: true },
161
+ showHeader: { type: Boolean, default: true },
162
+ headerDivider: { type: Boolean, default: true },
163
+ footer: { type: Boolean, default: true },
164
+ footerAlign: {
165
+ type: String,
166
+ default: 'right',
167
+ validator: v => ['right', 'fill'].includes(v)
168
+ },
169
+ footerDivider: { type: Boolean, default: true },
170
+ okText: { type: String, default: 'OK' },
171
+ cancelText: { type: String, default: 'Cancel' },
172
+ okVariant: { type: String, default: 'primary' },
173
+ cancelVariant: { type: String, default: 'outline' },
174
+ confirmLoading: { type: Boolean, default: false },
175
+ width: { type: [Number, String], default: '' },
176
+ centered: { type: Boolean, default: false },
177
+ mask: { type: Boolean, default: true },
178
+ maskClosable: { type: Boolean, default: true },
179
+ keyboard: { type: Boolean, default: true },
180
+ zIndex: { type: [Number, String], default: 1000 },
181
+ minimizable: { type: Boolean, default: false },
182
+ fullscreen: { type: Boolean, default: false },
183
+ blur: { type: [Boolean, Number, String], default: false }
184
+ },
185
+ emits: ['change', 'update:modelValue', 'ok', 'cancel', 'after-close'],
186
+ data() {
187
+ return {
188
+ hasOpened: false,
189
+ isVisible: false,
190
+ minimized: false,
191
+ isFullscreen: false
192
+ }
193
+ },
194
+ computed: {
195
+ isOpen() {
196
+ return this.modelValue !== undefined ? this.modelValue : this.open
197
+ },
198
+ rootStyle() {
199
+ return { zIndex: this.zIndex }
200
+ },
201
+ maskStyle() {
202
+ if (!this.blur) return {}
203
+ const val =
204
+ this.blur === true
205
+ ? '8px'
206
+ : typeof this.blur === 'number' || !isNaN(Number(this.blur))
207
+ ? `${this.blur}px`
208
+ : this.blur
209
+ return { backdropFilter: `blur(${val})`, WebkitBackdropFilter: `blur(${val})` }
210
+ },
211
+ contentStyle() {
212
+ if (this.isFullscreen) return {}
213
+ if (!this.width) return {}
214
+ const w = typeof this.width === 'number' || !isNaN(Number(this.width)) ? `${this.width}px` : this.width
215
+ return { width: w }
216
+ },
217
+ wrapCls() {
218
+ return [
219
+ this.centered && !this.isFullscreen ? 'ui-dialog-wrap--centered' : null,
220
+ this.isFullscreen ? 'ui-dialog-wrap--fullscreen' : null
221
+ ].filter(Boolean)
222
+ },
223
+ hasTitleSlot() {
224
+ return !!this.$slots['title']
225
+ },
226
+ hasTitle() {
227
+ return !!this.title || this.hasTitleSlot
228
+ },
229
+ hasSubTextSlot() {
230
+ return !!this.$slots['sub-text']
231
+ },
232
+ hasSubText() {
233
+ return !!this.subText || this.hasSubTextSlot
234
+ },
235
+ hasHeaderActions() {
236
+ return this.minimizable || this.fullscreen || !!this.$slots['header-actions']
237
+ }
238
+ },
239
+ watch: {
240
+ isOpen: {
241
+ handler(v) {
242
+ if (v) {
243
+ this.isVisible = true
244
+ this.onOpen()
245
+ } else {
246
+ this.minimized = false
247
+ this.isFullscreen = false
248
+ this.onClose()
249
+ }
250
+ }
251
+ }
252
+ },
253
+ mounted() {
254
+ this._prevFocus = null
255
+ this._prevOverflow = ''
256
+ this._prevPadding = ''
257
+ //Đẩy dialog ra ngoài body
258
+ if (typeof document !== 'undefined' && this.$el && this.$el.parentNode !== document.body) {
259
+ document.body.appendChild(this.$el)
260
+ }
261
+ if (typeof this.$on === 'function') {
262
+ // eslint-disable-next-line vue/no-deprecated-events-api
263
+ this.$on('hook:beforeDestroy', this.cleanup)
264
+ }
265
+ if (this.isOpen) {
266
+ this.isVisible = true
267
+ this.onOpen()
268
+ }
269
+ },
270
+ beforeUnmount() {
271
+ this.cleanup()
272
+ },
273
+ methods: {
274
+ setOpen(v) {
275
+ this.$emit('change', v)
276
+ this.$emit('update:modelValue', v)
277
+ },
278
+ handleOk(e) {
279
+ this.$emit('ok', e)
280
+ },
281
+ handleCancel(e) {
282
+ this.$emit('cancel', e)
283
+ this.setOpen(false)
284
+ },
285
+ onWrapMousedown(e) {
286
+ this._mousedownOnWrap = true
287
+ },
288
+ onWrapMouseup(e) {
289
+ if (this.maskClosable && this._mousedownOnWrap) {
290
+ this.handleCancel(e)
291
+ }
292
+ this._mousedownOnWrap = false
293
+ },
294
+ onEscape(e) {
295
+ if (this.keyboard) this.handleCancel(e)
296
+ },
297
+ toggleMinimize() {
298
+ this.minimized = !this.minimized
299
+ if (this.minimized) this.isFullscreen = false
300
+ },
301
+ toggleFullscreen() {
302
+ this.isFullscreen = !this.isFullscreen
303
+ if (this.isFullscreen) this.minimized = false
304
+ },
305
+ onOpen() {
306
+ this.hasOpened = true
307
+ this.lockBody()
308
+ if (typeof document !== 'undefined') {
309
+ this._prevFocus = document.activeElement
310
+ }
311
+ this.$nextTick(() => {
312
+ if (this.$refs.wrap && this.$refs.wrap.focus) {
313
+ this.$refs.wrap.focus()
314
+ }
315
+ })
316
+ },
317
+ onClose() {
318
+ this.unlockBody()
319
+ if (this._prevFocus && typeof this._prevFocus.focus === 'function') {
320
+ this._prevFocus.focus()
321
+ }
322
+ this._prevFocus = null
323
+ },
324
+ onAfterLeave() {
325
+ if (!this.isOpen) {
326
+ this.isVisible = false
327
+ }
328
+ this.$emit('after-close')
329
+ },
330
+ lockBody() {
331
+ if (typeof document === 'undefined' || typeof window === 'undefined') return
332
+ const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth
333
+ this._prevOverflow = document.body.style.overflow
334
+ this._prevPadding = document.body.style.paddingRight
335
+ document.body.style.overflow = 'hidden'
336
+ if (scrollbarWidth > 0) {
337
+ document.body.style.paddingRight = `${scrollbarWidth}px`
338
+ }
339
+ },
340
+ unlockBody() {
341
+ if (typeof document === 'undefined') return
342
+ document.body.style.overflow = this._prevOverflow || ''
343
+ document.body.style.paddingRight = this._prevPadding || ''
344
+ },
345
+ cleanup() {
346
+ this.unlockBody()
347
+ if (this.$el && this.$el.parentNode === document.body) {
348
+ document.body.removeChild(this.$el)
349
+ }
350
+ }
351
+ }
352
+ }
353
+ </script>
354
+
355
+ <style src="./dialog.css" scoped></style>
@@ -0,0 +1,255 @@
1
+ /* ── overlay ──────────────────────────────────────────────────────────── */
2
+ .ui-dialog-root {
3
+ position: fixed;
4
+ inset: 0;
5
+ }
6
+
7
+ .ui-dialog-mask {
8
+ position: absolute;
9
+ inset: 0;
10
+ background: var(--backdrop);
11
+ }
12
+
13
+ .ui-dialog-wrap {
14
+ position: absolute;
15
+ inset: 0;
16
+ display: flex;
17
+ flex-direction: column;
18
+ align-items: center;
19
+ overflow: auto;
20
+ outline: none;
21
+ padding: 100px 16px 16px;
22
+ -webkit-overflow-scrolling: touch;
23
+ }
24
+
25
+ .ui-dialog-wrap {
26
+ padding: 24px;
27
+ }
28
+
29
+ @media (max-width: 767px) {
30
+ .ui-dialog-wrap {
31
+ padding: 8px;
32
+ }
33
+ }
34
+
35
+ .ui-dialog-wrap--centered {
36
+ justify-content: center;
37
+ padding: 16px;
38
+ }
39
+
40
+ .ui-dialog-wrap--fullscreen {
41
+ padding: 0;
42
+ overflow: hidden;
43
+ align-items: stretch;
44
+ }
45
+
46
+ .ui-dialog-content {
47
+ flex-shrink: 0;
48
+ pointer-events: auto;
49
+ }
50
+
51
+ .ui-dialog-wrap--fullscreen .ui-dialog-content {
52
+ flex: 1;
53
+ width: 100%;
54
+ height: 100%;
55
+ }
56
+
57
+ /* ── shell ────────────────────────────────────────────────────────────── */
58
+ .ui-dialog {
59
+ display: flex;
60
+ flex-direction: column;
61
+ background: var(--card);
62
+ border: 1px solid var(--border-primary);
63
+ border-radius: var(--rounded-xl);
64
+ box-shadow: var(--shadow-lg);
65
+ overflow: hidden;
66
+ max-height: 100%; /* Allow internal scrolling if content is taller than wrapper */
67
+ }
68
+
69
+ .ui-dialog-content {
70
+ width: min(640px, calc(100vw - 32px));
71
+ }
72
+
73
+ @media (max-width: 767px) {
74
+ .ui-dialog-content {
75
+ width: min(320px, calc(100vw - 32px));
76
+ }
77
+ }
78
+
79
+ .ui-dialog--fullscreen {
80
+ width: 100%;
81
+ height: 100%;
82
+ border-radius: 0;
83
+ border-left: none;
84
+ border-right: none;
85
+ }
86
+
87
+ /* ── header ───────────────────────────────────────────────────────────── */
88
+ .ui-dialog-header {
89
+ display: flex;
90
+ flex-direction: column;
91
+ justify-content: center;
92
+ width: 100%;
93
+ min-height: 56px;
94
+ padding: var(--spacing-sm) var(--spacing-md);
95
+ background: transparent;
96
+ flex-shrink: 0;
97
+ }
98
+
99
+ .ui-dialog-header--divided {
100
+ border-bottom: 1px solid var(--border-primary);
101
+ }
102
+
103
+ .ui-dialog-header__row {
104
+ display: flex;
105
+ align-items: center;
106
+ justify-content: space-between;
107
+ gap: var(--spacing-sm);
108
+ width: 100%;
109
+ }
110
+
111
+ .ui-dialog-header__content {
112
+ display: flex;
113
+ flex: 1 1 0;
114
+ flex-direction: column;
115
+ align-items: flex-start;
116
+ gap: var(--spacing-2xs);
117
+ min-width: 0;
118
+ }
119
+
120
+ .ui-dialog-header__content--breadcrumb {
121
+ flex-direction: row;
122
+ align-items: center;
123
+ gap: var(--spacing-2xs);
124
+ }
125
+
126
+ .ui-dialog-header__content--empty {
127
+ flex: 1 1 0;
128
+ }
129
+
130
+ .ui-dialog-header__title {
131
+ width: 100%;
132
+ font-family: var(--heading-4-font-family);
133
+ font-size: var(--heading-4-font-size);
134
+ line-height: var(--heading-4-line-height);
135
+ letter-spacing: var(--heading-4-letter-spacing);
136
+ font-weight: var(--heading-4-font-weight);
137
+ color: var(--primary-fg);
138
+ }
139
+
140
+ .ui-dialog-header__sub-text {
141
+ width: 100%;
142
+ font-family: var(--paragraph-small-font-family);
143
+ font-size: var(--paragraph-small-font-size);
144
+ line-height: var(--paragraph-small-line-height);
145
+ letter-spacing: var(--paragraph-small-letter-spacing);
146
+ font-weight: var(--paragraph-font-weight);
147
+ color: var(--muted-fg);
148
+ }
149
+
150
+ .ui-dialog-header__actions {
151
+ display: inline-flex;
152
+ align-items: center;
153
+ gap: var(--spacing-xs);
154
+ flex-shrink: 0;
155
+ }
156
+
157
+ .ui-dialog-header__icon-btn {
158
+ display: inline-flex;
159
+ align-items: center;
160
+ justify-content: center;
161
+ flex-shrink: 0;
162
+ min-width: 32px;
163
+ min-height: 32px;
164
+ padding: var(--spacing-6);
165
+ margin: 0;
166
+ background: var(--ghost);
167
+ color: var(--primary-fg);
168
+ border: 0;
169
+ border-radius: var(--rounded-xl);
170
+ cursor: pointer;
171
+ transition: background-color 0.15s ease;
172
+ -webkit-appearance: none;
173
+ appearance: none;
174
+ }
175
+
176
+ .ui-dialog-header__icon-btn svg {
177
+ display: block;
178
+ width: 20px;
179
+ height: 20px;
180
+ }
181
+
182
+ .ui-dialog-header__icon-btn:hover {
183
+ background: var(--ghost-hover);
184
+ }
185
+
186
+ .ui-dialog-header__icon-btn:focus-visible {
187
+ outline: none;
188
+ box-shadow: var(--shadow-focus-ring);
189
+ }
190
+
191
+ /* ── body ─────────────────────────────────────────────────────────────── */
192
+ .ui-dialog-body {
193
+ padding: var(--spacing-md);
194
+ font-family: var(--paragraph-small-font-family);
195
+ font-size: var(--paragraph-small-font-size);
196
+ line-height: var(--paragraph-small-line-height);
197
+ color: var(--secondary-fg);
198
+ overflow-y: auto;
199
+ flex: 1 1 auto;
200
+ }
201
+
202
+ /* ── footer ───────────────────────────────────────────────────────────── */
203
+ .ui-dialog-footer {
204
+ display: flex;
205
+ flex-direction: column;
206
+ width: 100%;
207
+ padding: var(--spacing-md);
208
+ background: var(--accent-0);
209
+ }
210
+
211
+ .ui-dialog-footer--divided {
212
+ border-top: 1px solid var(--border-primary);
213
+ }
214
+
215
+ .ui-dialog-footer__inner {
216
+ width: 100%;
217
+ gap: var(--spacing-xs);
218
+ }
219
+
220
+ .ui-dialog-footer--align-right .ui-dialog-footer__inner {
221
+ display: flex;
222
+ align-items: center;
223
+ justify-content: flex-end;
224
+ }
225
+
226
+ .ui-dialog-footer--align-fill .ui-dialog-footer__inner {
227
+ display: grid;
228
+ grid-auto-flow: column;
229
+ grid-auto-columns: 1fr;
230
+ align-items: center;
231
+ }
232
+
233
+ /* ── transitions ──────────────────────────────────────────────────────── */
234
+ .ui-dialog-fade-enter-active,
235
+ .ui-dialog-fade-leave-active {
236
+ transition: opacity 0.2s ease;
237
+ }
238
+ .ui-dialog-fade-enter,
239
+ .ui-dialog-fade-enter-from,
240
+ .ui-dialog-fade-leave-to {
241
+ opacity: 0;
242
+ }
243
+
244
+ .ui-dialog-zoom-enter-active,
245
+ .ui-dialog-zoom-leave-active {
246
+ transition:
247
+ opacity 0.2s ease,
248
+ transform 0.2s ease;
249
+ }
250
+ .ui-dialog-zoom-enter,
251
+ .ui-dialog-zoom-enter-from,
252
+ .ui-dialog-zoom-leave-to {
253
+ opacity: 0;
254
+ transform: scale(0.96);
255
+ }
@@ -0,0 +1,35 @@
1
+ <template>
2
+ <div
3
+ class="ui-divider"
4
+ :class="['ui-divider--' + direction, 'ui-divider--spacing-' + spacing]"
5
+ role="separator"
6
+ :aria-orientation="direction"
7
+ />
8
+ </template>
9
+
10
+ <script>
11
+ export default {
12
+ name: 'Divider',
13
+
14
+ props: {
15
+ direction: {
16
+ type: String,
17
+ default: 'horizontal',
18
+ validator: function (v) {
19
+ return ['horizontal', 'vertical'].indexOf(v) !== -1
20
+ }
21
+ },
22
+ spacing: {
23
+ type: String,
24
+ default: 'none',
25
+ validator: function (v) {
26
+ return ['none', 'regular', 'spacious'].indexOf(v) !== -1
27
+ }
28
+ }
29
+ },
30
+
31
+ emits: []
32
+ }
33
+ </script>
34
+
35
+ <style src="./divider.css" scoped></style>
@@ -0,0 +1,38 @@
1
+ .ui-divider {
2
+ flex-shrink: 0;
3
+ background-color: var(--border-primary);
4
+ }
5
+
6
+ /* Horizontal */
7
+ .ui-divider--horizontal {
8
+ display: block;
9
+ width: 100%;
10
+ height: 1px;
11
+ }
12
+
13
+ .ui-divider--horizontal.ui-divider--spacing-regular {
14
+ margin-top: var(--spacing-2xs);
15
+ margin-bottom: var(--spacing-2xs);
16
+ }
17
+
18
+ .ui-divider--horizontal.ui-divider--spacing-spacious {
19
+ margin-top: var(--spacing-7p5);
20
+ margin-bottom: var(--spacing-7p5);
21
+ }
22
+
23
+ /* Vertical */
24
+ .ui-divider--vertical {
25
+ display: inline-block;
26
+ width: 1px;
27
+ align-self: stretch;
28
+ }
29
+
30
+ .ui-divider--vertical.ui-divider--spacing-regular {
31
+ margin-left: var(--spacing-2xs);
32
+ margin-right: var(--spacing-2xs);
33
+ }
34
+
35
+ .ui-divider--vertical.ui-divider--spacing-spacious {
36
+ margin-left: var(--spacing-7p5);
37
+ margin-right: var(--spacing-7p5);
38
+ }