@bagelink/vue 1.8.71 → 1.8.76

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.
@@ -0,0 +1,358 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * Dialog - Native dialog wrapper with animations
4
+ *
5
+ * Uses native <dialog> element for:
6
+ * - Automatic focus trap
7
+ * - ESC key handling
8
+ * - Backdrop via ::backdrop
9
+ * - Browser-managed z-index stacking
10
+ */
11
+ import type { DialogWidth, DialogPosition } from './dialogTypes'
12
+ import { ref, computed, onMounted, watch } from 'vue'
13
+ import { DIALOG_WIDTHS } from './dialogTypes'
14
+
15
+ const props = withDefaults(defineProps<{
16
+ open: boolean
17
+ title?: string
18
+ width?: DialogWidth
19
+ position?: DialogPosition
20
+ dismissable?: boolean
21
+ }>(), {
22
+ width: 'm',
23
+ position: 'center',
24
+ dismissable: true
25
+ })
26
+
27
+ const emit = defineEmits<{
28
+ 'update:open': [value: boolean]
29
+ 'close': []
30
+ }>()
31
+
32
+ const dialogRef = ref<HTMLDialogElement | null>(null)
33
+ const isClosing = ref(false)
34
+
35
+ const widthStyle = computed(() => DIALOG_WIDTHS[props.width])
36
+
37
+ const positionClass = computed(() => {
38
+ if (props.position === 'left') return 'dialog-left'
39
+ if (props.position === 'right') return 'dialog-right'
40
+ return 'dialog-center'
41
+ })
42
+
43
+ // Handle open/close
44
+ watch(() => props.open, (isOpen) => {
45
+ if (isOpen) {
46
+ dialogRef.value?.showModal()
47
+ isClosing.value = false
48
+ } else {
49
+ closeWithAnimation()
50
+ }
51
+ })
52
+
53
+ onMounted(() => {
54
+ if (props.open) {
55
+ dialogRef.value?.showModal()
56
+ }
57
+ })
58
+
59
+ function closeWithAnimation() {
60
+ if (isClosing.value) return
61
+ isClosing.value = true
62
+ }
63
+
64
+ function onAnimationEnd() {
65
+ if (isClosing.value) {
66
+ dialogRef.value?.close()
67
+ isClosing.value = false
68
+ emit('close')
69
+ }
70
+ }
71
+
72
+ function onBackdropClick(e: MouseEvent) {
73
+ // Only close if clicking directly on the dialog backdrop (not content)
74
+ if (e.target === dialogRef.value && props.dismissable) {
75
+ emit('update:open', false)
76
+ }
77
+ }
78
+
79
+ function onCancel(e: Event) {
80
+ // Native ESC key triggers cancel event
81
+ if (!props.dismissable) {
82
+ e.preventDefault()
83
+ return
84
+ }
85
+ emit('update:open', false)
86
+ }
87
+
88
+ function close() {
89
+ emit('update:open', false)
90
+ }
91
+
92
+ defineExpose({ close })
93
+ </script>
94
+
95
+ <template>
96
+ <dialog
97
+ ref="dialogRef" :class="[positionClass, { 'is-closing': isClosing }]"
98
+ :style="{ '--dialog-width': widthStyle }" @click="onBackdropClick" @cancel="onCancel"
99
+ @animationend="onAnimationEnd"
100
+ >
101
+ <div class="dialog-content" @click.stop>
102
+ <!-- Header -->
103
+ <header v-if="title || dismissable" class="dialog-header">
104
+ <h2 v-if="title" class="dialog-title">
105
+ {{ title }}
106
+ </h2>
107
+ <button v-if="dismissable" type="button" class="dialog-close" aria-label="Close" @click="close">
108
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
109
+ <path d="M18 6L6 18M6 6l12 12" />
110
+ </svg>
111
+ </button>
112
+ </header>
113
+
114
+ <!-- Body -->
115
+ <div class="dialog-body">
116
+ <slot />
117
+ </div>
118
+
119
+ <!-- Footer -->
120
+ <footer v-if="$slots.footer" class="dialog-footer">
121
+ <slot name="footer" />
122
+ </footer>
123
+ </div>
124
+ </dialog>
125
+ </template>
126
+
127
+ <style scoped>
128
+ dialog {
129
+ border: none;
130
+ border-radius: var(--bgl-card-radius, 12px);
131
+ padding: 0;
132
+ max-width: var(--dialog-width);
133
+ width: calc(100% - 2rem);
134
+ max-height: calc(100vh - 2rem);
135
+ background: var(--bgl-popup-bg, #fff);
136
+ color: var(--bgl-text, #1a1a1a);
137
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12);
138
+ overflow: hidden;
139
+ }
140
+
141
+ dialog::backdrop {
142
+ background: var(--bgl-dark-bg, rgba(0, 0, 0, 0.5));
143
+ opacity: 0;
144
+ transition: opacity 0.2s ease-out;
145
+ }
146
+
147
+ dialog[open]::backdrop {
148
+ opacity: 1;
149
+ }
150
+
151
+ /* Center position (default) */
152
+ dialog.dialog-center {
153
+ margin: auto;
154
+ }
155
+
156
+ dialog.dialog-center[open] {
157
+ animation: dialog-fade-in 0.2s ease-out;
158
+ }
159
+
160
+ dialog.dialog-center.is-closing {
161
+ animation: dialog-fade-out 0.15s ease-in forwards;
162
+ }
163
+
164
+ @keyframes dialog-fade-in {
165
+ from {
166
+ opacity: 0;
167
+ transform: scale(0.95) translateY(10px);
168
+ }
169
+
170
+ to {
171
+ opacity: 1;
172
+ transform: scale(1) translateY(0);
173
+ }
174
+ }
175
+
176
+ @keyframes dialog-fade-out {
177
+ from {
178
+ opacity: 1;
179
+ transform: scale(1) translateY(0);
180
+ }
181
+
182
+ to {
183
+ opacity: 0;
184
+ transform: scale(0.95) translateY(10px);
185
+ }
186
+ }
187
+
188
+ /* Right position */
189
+ dialog.dialog-right {
190
+ margin: 0;
191
+ margin-inline-start: auto;
192
+ margin-inline-end: 1rem;
193
+ margin-top: 1rem;
194
+ margin-bottom: 1rem;
195
+ height: calc(100vh - 2rem);
196
+ max-height: calc(100vh - 2rem);
197
+ border-radius: var(--bgl-card-radius, 12px);
198
+ }
199
+
200
+ dialog.dialog-right[open] {
201
+ animation: dialog-slide-in-right 0.25s ease-out;
202
+ }
203
+
204
+ dialog.dialog-right.is-closing {
205
+ animation: dialog-slide-out-right 0.2s ease-in forwards;
206
+ }
207
+
208
+ @keyframes dialog-slide-in-right {
209
+ from {
210
+ opacity: 0;
211
+ transform: translateX(100%);
212
+ }
213
+
214
+ to {
215
+ opacity: 1;
216
+ transform: translateX(0);
217
+ }
218
+ }
219
+
220
+ @keyframes dialog-slide-out-right {
221
+ from {
222
+ opacity: 1;
223
+ transform: translateX(0);
224
+ }
225
+
226
+ to {
227
+ opacity: 0;
228
+ transform: translateX(100%);
229
+ }
230
+ }
231
+
232
+ /* Left position */
233
+ dialog.dialog-left {
234
+ margin: 0;
235
+ margin-inline-end: auto;
236
+ margin-inline-start: 1rem;
237
+ margin-top: 1rem;
238
+ margin-bottom: 1rem;
239
+ height: calc(100vh - 2rem);
240
+ max-height: calc(100vh - 2rem);
241
+ border-radius: var(--bgl-card-radius, 12px);
242
+ }
243
+
244
+ dialog.dialog-left[open] {
245
+ animation: dialog-slide-in-left 0.25s ease-out;
246
+ }
247
+
248
+ dialog.dialog-left.is-closing {
249
+ animation: dialog-slide-out-left 0.2s ease-in forwards;
250
+ }
251
+
252
+ @keyframes dialog-slide-in-left {
253
+ from {
254
+ opacity: 0;
255
+ transform: translateX(-100%);
256
+ }
257
+
258
+ to {
259
+ opacity: 1;
260
+ transform: translateX(0);
261
+ }
262
+ }
263
+
264
+ @keyframes dialog-slide-out-left {
265
+ from {
266
+ opacity: 1;
267
+ transform: translateX(0);
268
+ }
269
+
270
+ to {
271
+ opacity: 0;
272
+ transform: translateX(-100%);
273
+ }
274
+ }
275
+
276
+ /* Content structure */
277
+ .dialog-content {
278
+ display: flex;
279
+ flex-direction: column;
280
+ height: 100%;
281
+ max-height: inherit;
282
+ }
283
+
284
+ .dialog-header {
285
+ display: flex;
286
+ align-items: center;
287
+ justify-content: space-between;
288
+ padding: 1rem 1.5rem;
289
+ border-bottom: 1px solid var(--bgl-border-color, #e5e5e5);
290
+ flex-shrink: 0;
291
+ }
292
+
293
+ .dialog-title {
294
+ margin: 0;
295
+ font-size: 1.125rem;
296
+ font-weight: 600;
297
+ }
298
+
299
+ .dialog-close {
300
+ display: flex;
301
+ align-items: center;
302
+ justify-content: center;
303
+ width: 32px;
304
+ height: 32px;
305
+ border: none;
306
+ background: transparent;
307
+ border-radius: 6px;
308
+ cursor: pointer;
309
+ color: var(--bgl-text-secondary, #666);
310
+ transition: background 0.15s ease, color 0.15s ease;
311
+ }
312
+
313
+ .dialog-close:hover {
314
+ background: var(--bgl-gray-tint, #f0f0f0);
315
+ color: var(--bgl-text, #1a1a1a);
316
+ }
317
+
318
+ .dialog-body {
319
+ flex: 1;
320
+ padding: 1.5rem;
321
+ overflow-y: auto;
322
+ }
323
+
324
+ .dialog-footer {
325
+ display: flex;
326
+ align-items: center;
327
+ justify-content: flex-end;
328
+ gap: 0.75rem;
329
+ padding: 1rem 1.5rem;
330
+ border-top: 1px solid var(--bgl-border-color, #e5e5e5);
331
+ flex-shrink: 0;
332
+ }
333
+
334
+ /* Full width */
335
+ dialog[style*="--dialog-width: 100%"] {
336
+ max-width: calc(100vw - 2rem);
337
+ }
338
+
339
+ dialog.dialog-left[style*="--dialog-width: 100%"],
340
+ dialog.dialog-right[style*="--dialog-width: 100%"] {
341
+ max-width: calc(100vw - 2rem);
342
+ width: calc(100vw - 2rem);
343
+ }
344
+
345
+ /* Mobile adjustments */
346
+ @media screen and (max-width: 640px) {
347
+
348
+ dialog.dialog-left,
349
+ dialog.dialog-right {
350
+ margin: 0;
351
+ width: 100%;
352
+ max-width: 100%;
353
+ height: 100vh;
354
+ max-height: 100vh;
355
+ border-radius: 0;
356
+ }
357
+ }
358
+ </style>
@@ -266,6 +266,16 @@ export const $ = {
266
266
  return new Field('richtext', parseArgs(labelOrConfig, config))
267
267
  },
268
268
 
269
+ json(
270
+ labelOrConfig?: string | (BaseFieldConfig & { language?: string, height?: string }),
271
+ config?: BaseFieldConfig & { language?: string, height?: string }
272
+ ): FieldBuilder<Record<string, any>> {
273
+ const parsed = parseArgs(labelOrConfig, config)
274
+ // Default language to 'json' for CodeEditor
275
+ if (!parsed.language) parsed.language = 'json'
276
+ return new Field('json', parsed)
277
+ },
278
+
269
279
  checkbox(labelOrConfig?: string | BaseFieldConfig, config?: BaseFieldConfig): FieldBuilder<boolean> {
270
280
  return new Field('checkbox', parseArgs(labelOrConfig, config))
271
281
  },
@@ -519,6 +529,7 @@ class Schema implements SchemaDefinition {
519
529
  datetime: 'string',
520
530
  textarea: 'string',
521
531
  richtext: 'string',
532
+ json: 'object',
522
533
  checkbox: 'boolean',
523
534
  toggle: 'boolean',
524
535
  radio: 'string',
@@ -628,6 +639,11 @@ interface JSONSchemaProperty {
628
639
  'maximum'?: number
629
640
  'minLength'?: number
630
641
  'maxLength'?: number
642
+ '$ref'?: string
643
+ 'anyOf'?: JSONSchemaProperty[]
644
+ 'oneOf'?: JSONSchemaProperty[]
645
+ 'allOf'?: JSONSchemaProperty[]
646
+ 'additionalProperties'?: boolean | JSONSchemaProperty
631
647
  'x-ui'?: {
632
648
  fieldType?: string
633
649
  placeholder?: string
@@ -650,6 +666,8 @@ interface JSONSchemaObject {
650
666
  'title'?: string
651
667
  'properties'?: Record<string, JSONSchemaProperty>
652
668
  'required'?: string[]
669
+ '$defs'?: Record<string, JSONSchemaProperty>
670
+ 'definitions'?: Record<string, JSONSchemaProperty>
653
671
  'x-ui'?: {
654
672
  condition?: string
655
673
  class?: string
@@ -679,7 +697,7 @@ export function fromJSONSchema(jsonSchema: JSONSchemaObject): SchemaDefinition {
679
697
 
680
698
  if (jsonSchema.properties) {
681
699
  for (const [key, prop] of Object.entries(jsonSchema.properties)) {
682
- fields[key] = createFieldFromProperty(key, prop, requiredSet.has(key))
700
+ fields[key] = createFieldFromProperty(key, prop, requiredSet.has(key), jsonSchema)
683
701
  }
684
702
  }
685
703
 
@@ -696,23 +714,101 @@ export function fromJSONSchema(jsonSchema: JSONSchemaObject): SchemaDefinition {
696
714
  return schema
697
715
  }
698
716
 
717
+ /**
718
+ * Resolve a $ref pointer to its definition
719
+ */
720
+ function resolveRef(ref: string, rootSchema: JSONSchemaObject): JSONSchemaProperty | undefined {
721
+ // Handle local refs like "#/$defs/WaLanguage" or "#/definitions/WaLanguage"
722
+ const match = ref.match(/^#\/(\$defs|definitions)\/(.+)$/)
723
+ if (!match) return undefined
724
+
725
+ const [, defsKey, defName] = match
726
+ const defs = defsKey === '$defs' ? rootSchema.$defs : rootSchema.definitions
727
+ return defName ? defs?.[defName] : undefined
728
+ }
729
+
730
+ /**
731
+ * Resolve anyOf/oneOf to a primary type (ignoring null for nullable fields)
732
+ */
733
+ function resolveUnionType(prop: JSONSchemaProperty, _rootSchema: JSONSchemaObject): JSONSchemaProperty {
734
+ const unionTypes = prop.anyOf || prop.oneOf
735
+ if (!unionTypes || unionTypes.length === 0) return prop
736
+
737
+ // Filter out null types to find the "real" type
738
+ const nonNullTypes = unionTypes.filter(t => t.type !== 'null')
739
+
740
+ if (nonNullTypes.length === 1) {
741
+ // Single non-null type - merge with parent prop (preserving title, default, etc.)
742
+ const resolved = nonNullTypes[0]
743
+ return {
744
+ ...resolved,
745
+ 'title': prop.title || resolved.title,
746
+ 'description': prop.description || resolved.description,
747
+ 'default': prop.default !== undefined ? prop.default : resolved.default,
748
+ 'x-ui': { ...resolved['x-ui'], ...prop['x-ui'] },
749
+ }
750
+ }
751
+
752
+ // Multiple non-null types - try to pick the most useful one
753
+ // Prefer object > array > string > number > boolean
754
+ const typeOrder = ['object', 'array', 'string', 'number', 'integer', 'boolean']
755
+ const sorted = nonNullTypes.sort((a, b) => {
756
+ const aIdx = typeOrder.indexOf(a.type || 'string')
757
+ const bIdx = typeOrder.indexOf(b.type || 'string')
758
+ return aIdx - bIdx
759
+ })
760
+
761
+ const resolved = sorted[0]
762
+ return {
763
+ ...resolved,
764
+ 'title': prop.title || resolved.title,
765
+ 'description': prop.description || resolved.description,
766
+ 'default': prop.default !== undefined ? prop.default : resolved.default,
767
+ 'x-ui': { ...resolved['x-ui'], ...prop['x-ui'] },
768
+ }
769
+ }
770
+
699
771
  /**
700
772
  * Create a field builder from a JSONSchema property
701
773
  */
702
774
  function createFieldFromProperty(
703
775
  key: string,
704
776
  prop: JSONSchemaProperty,
705
- isRequired: boolean
777
+ isRequired: boolean,
778
+ rootSchema: JSONSchemaObject
706
779
  ): FieldBuilder {
707
- const xUi = prop['x-ui'] || {}
708
- const fieldType = xUi.fieldType || inferFieldType(prop)
780
+ // Resolve $ref if present
781
+ let resolvedProp = prop
782
+ if (prop.$ref) {
783
+ const refDef = resolveRef(prop.$ref, rootSchema)
784
+ if (refDef) {
785
+ // Merge ref definition with property (property values take precedence)
786
+ resolvedProp = {
787
+ ...refDef,
788
+ 'type': prop.type ?? refDef.type,
789
+ 'enum': prop.enum ?? refDef.enum,
790
+ 'title': prop.title ?? refDef.title,
791
+ 'description': prop.description ?? refDef.description,
792
+ 'default': prop.default !== undefined ? prop.default : refDef.default,
793
+ 'x-ui': { ...refDef['x-ui'], ...prop['x-ui'] },
794
+ }
795
+ }
796
+ }
797
+
798
+ // Resolve anyOf/oneOf
799
+ if (resolvedProp.anyOf || resolvedProp.oneOf) {
800
+ resolvedProp = resolveUnionType(resolvedProp, rootSchema)
801
+ }
802
+
803
+ const xUi = resolvedProp['x-ui'] || {}
804
+ const fieldType = xUi.fieldType || inferFieldType(resolvedProp)
709
805
 
710
806
  // Build base config
711
807
  const config: BaseFieldConfig & Record<string, any> = {}
712
808
 
713
- if (prop.title) config.label = prop.title
714
- if (prop.description) config.helpText = prop.description
715
- if (prop.default !== undefined) config.default = prop.default
809
+ if (resolvedProp.title) config.label = resolvedProp.title
810
+ if (resolvedProp.description) config.helpText = resolvedProp.description
811
+ if (resolvedProp.default !== undefined) config.default = resolvedProp.default
716
812
  if (isRequired) config.required = true
717
813
 
718
814
  // UI hints from x-ui
@@ -724,10 +820,10 @@ function createFieldFromProperty(
724
820
  if (xUi.cols) config.cols = xUi.cols
725
821
 
726
822
  // Numeric/string constraints
727
- if (prop.minimum !== undefined) config.min = prop.minimum
728
- if (prop.maximum !== undefined) config.max = prop.maximum
729
- if (prop.minLength !== undefined) config.min = prop.minLength
730
- if (prop.maxLength !== undefined) config.max = prop.maxLength
823
+ if (resolvedProp.minimum !== undefined) config.min = resolvedProp.minimum
824
+ if (resolvedProp.maximum !== undefined) config.max = resolvedProp.maximum
825
+ if (resolvedProp.minLength !== undefined) config.min = resolvedProp.minLength
826
+ if (resolvedProp.maxLength !== undefined) config.max = resolvedProp.maxLength
731
827
 
732
828
  // Create the appropriate field builder
733
829
  let field: FieldBuilder
@@ -763,6 +859,9 @@ function createFieldFromProperty(
763
859
  case 'richtext':
764
860
  field = $.richtext(config)
765
861
  break
862
+ case 'json':
863
+ field = $.json(config)
864
+ break
766
865
  case 'checkbox':
767
866
  field = $.checkbox(config)
768
867
  break
@@ -770,16 +869,16 @@ function createFieldFromProperty(
770
869
  field = $.toggle(config)
771
870
  break
772
871
  case 'radio':
773
- field = $.radio(prop.enum || [], config)
872
+ field = $.radio(resolvedProp.enum || [], config)
774
873
  break
775
874
  case 'select':
776
- field = $.select(prop.enum || [], config)
875
+ field = $.select(resolvedProp.enum || [], config)
777
876
  break
778
877
  case 'multiselect':
779
- field = $.multiselect(prop.enum || [], config)
878
+ field = $.multiselect(resolvedProp.enum || [], config)
780
879
  break
781
880
  case 'array':
782
- field = $.array(prop.title || key, undefined, {
881
+ field = $.array(resolvedProp.title || key, undefined, {
783
882
  ...config,
784
883
  allowAdd: xUi.allowAdd,
785
884
  allowDelete: xUi.allowDelete,
@@ -837,6 +936,7 @@ function inferFieldType(prop: JSONSchemaProperty): string {
837
936
  case 'number':
838
937
  case 'integer': return 'number'
839
938
  case 'array': return 'array'
939
+ case 'object': return 'json' // Objects rendered with CodeEditor
840
940
  default: return 'text'
841
941
  }
842
942
  }
@@ -1,11 +1,14 @@
1
1
  import type { App, InjectionKey, Plugin } from 'vue'
2
+ import type { PluginOptions as ToastOptions } from 'vue-toastification'
2
3
  import { inject } from 'vue'
3
4
  import Toast, {
4
- type PluginOptions as ToastOptions,
5
+
5
6
  POSITION,
6
- useToast as useVueToast,
7
+ useToast as useVueToast
7
8
  } from 'vue-toastification'
9
+ import CustomToast from '../components/Toast.vue'
8
10
  import 'vue-toastification/dist/index.css'
11
+ import '../styles/toast-overrides.css'
9
12
 
10
13
  export interface ToastApi {
11
14
  success: (message: string, options?: any) => void
@@ -39,20 +42,22 @@ export const ToastPlugin: Plugin<BagelToastOptions[]> = {
39
42
  install: (app: App, options: BagelToastOptions = {}) => {
40
43
  const defaultOptions: ToastOptions = {
41
44
  position: POSITION.TOP_RIGHT,
42
- timeout: 3000,
45
+ timeout: 5000,
43
46
  closeOnClick: true,
44
47
  pauseOnFocusLoss: true,
45
48
  pauseOnHover: true,
46
49
  draggable: true,
47
50
  draggablePercent: 0.6,
48
51
  showCloseButtonOnHover: false,
49
- hideProgressBar: false,
50
- closeButton: 'button',
51
- icon: true,
52
+ hideProgressBar: true,
53
+ closeButton: false,
54
+ icon: false,
52
55
  rtl: false,
53
56
  transition: 'Vue-Toastification__fade',
54
57
  maxToasts: 5,
55
58
  newestOnTop: true,
59
+ toastClassName: 'custom-toast-wrapper',
60
+ bodyClassName: 'custom-toast-body',
56
61
  ...options,
57
62
  }
58
63
 
@@ -63,23 +68,53 @@ export const ToastPlugin: Plugin<BagelToastOptions[]> = {
63
68
  const api: ToastApi = {
64
69
  success: (message: string, opts?: any) => {
65
70
  const toast = useVueToast()
66
- return toast.success(message, opts)
71
+ return toast({
72
+ component: CustomToast,
73
+ props: {
74
+ message,
75
+ type: 'success',
76
+ },
77
+ }, opts)
67
78
  },
68
79
  error: (message: string, opts?: any) => {
69
80
  const toast = useVueToast()
70
- return toast.error(message, opts)
81
+ return toast({
82
+ component: CustomToast,
83
+ props: {
84
+ message,
85
+ type: 'error',
86
+ },
87
+ }, opts)
71
88
  },
72
89
  info: (message: string, opts?: any) => {
73
90
  const toast = useVueToast()
74
- return toast.info(message, opts)
91
+ return toast({
92
+ component: CustomToast,
93
+ props: {
94
+ message,
95
+ type: 'info',
96
+ },
97
+ }, opts)
75
98
  },
76
99
  warning: (message: string, opts?: any) => {
77
100
  const toast = useVueToast()
78
- return toast.warning(message, opts)
101
+ return toast({
102
+ component: CustomToast,
103
+ props: {
104
+ message,
105
+ type: 'warning',
106
+ },
107
+ }, opts)
79
108
  },
80
109
  show: (message: string, opts?: any) => {
81
110
  const toast = useVueToast()
82
- return toast(message, opts)
111
+ return toast({
112
+ component: CustomToast,
113
+ props: {
114
+ message,
115
+ type: 'info',
116
+ },
117
+ }, opts)
83
118
  },
84
119
  clear: () => {
85
120
  const toast = useVueToast()
@@ -9,6 +9,7 @@
9
9
  @import "colors.css";
10
10
  @import "mobileColors.css";
11
11
  @import "appearance.css";
12
+ @import "base-colors.css";
12
13
  @import "theme.css";
13
14
  @import "dark.css";
14
15
  @import "./fonts/Ploni.css";