@bagelink/vue 0.0.268 → 0.0.276

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 (49) hide show
  1. package/dist/components/Accordion.vue.d.ts +10 -0
  2. package/dist/components/Accordion.vue.d.ts.map +1 -0
  3. package/dist/components/AccordionItem.vue.d.ts +2 -0
  4. package/dist/components/AccordionItem.vue.d.ts.map +1 -1
  5. package/dist/components/Btn.vue.d.ts +3 -3
  6. package/dist/components/ComboBox.vue.d.ts +32 -0
  7. package/dist/components/ComboBox.vue.d.ts.map +1 -0
  8. package/dist/components/ModalForm.vue.d.ts.map +1 -1
  9. package/dist/components/Popover.vue.d.ts +10 -0
  10. package/dist/components/Popover.vue.d.ts.map +1 -0
  11. package/dist/components/Title.vue.d.ts +1 -1
  12. package/dist/components/form/BglField.vue.d.ts.map +1 -1
  13. package/dist/components/form/inputs/DateInput.vue.d.ts.map +1 -1
  14. package/dist/components/form/inputs/SelectInput.vue.d.ts.map +1 -1
  15. package/dist/components/form/inputs/TextInput.vue.d.ts.map +1 -1
  16. package/dist/components/form/inputs/index.d.ts +0 -1
  17. package/dist/components/form/inputs/index.d.ts.map +1 -1
  18. package/dist/components/index.d.ts +3 -0
  19. package/dist/components/index.d.ts.map +1 -1
  20. package/dist/index.cjs +12380 -10473
  21. package/dist/index.mjs +12658 -10751
  22. package/dist/plugins/bagel.d.ts.map +1 -1
  23. package/dist/plugins/modal.d.ts +1 -1
  24. package/dist/plugins/modal.d.ts.map +1 -1
  25. package/dist/style.css +309 -277
  26. package/dist/types/BagelForm.d.ts +1 -1
  27. package/dist/types/BagelForm.d.ts.map +1 -1
  28. package/dist/utils/clickOutside.d.ts +7 -0
  29. package/dist/utils/clickOutside.d.ts.map +1 -0
  30. package/package.json +3 -2
  31. package/src/components/Accordion.vue +15 -0
  32. package/src/components/AccordionItem.vue +48 -24
  33. package/src/components/ComboBox.vue +132 -0
  34. package/src/components/ModalForm.vue +7 -35
  35. package/src/components/form/BglField.vue +22 -7
  36. package/src/components/form/BglFieldSet.vue +13 -0
  37. package/src/components/form/BglForm.vue +5 -22
  38. package/src/components/form/inputs/DateInput.vue +6 -2
  39. package/src/components/form/inputs/SelectInput.vue +2 -9
  40. package/src/components/form/inputs/TextInput.vue +12 -8
  41. package/src/components/form/inputs/index.ts +0 -1
  42. package/src/components/index.ts +3 -0
  43. package/src/plugins/bagel.ts +14 -2
  44. package/src/plugins/modal.ts +1 -1
  45. package/src/styles/layout.css +191 -188
  46. package/src/styles/text.css +40 -43
  47. package/src/types/BagelForm.ts +20 -20
  48. package/src/utils/clickOutside.ts +15 -0
  49. package/src/components/form/inputs/TextArea.vue +0 -81
@@ -20,7 +20,7 @@ export type BaseBagelField<T = Record<string, any>> = {
20
20
  } | string | number | Record<string, any>)[];
21
21
  defaultValue?: any;
22
22
  transform?: (val?: any, rowData?: Record<string, any>) => any;
23
- onUpdate?: (val: any, fieldData?: any, rowData?: Record<string, any>) => void;
23
+ onUpdate?: (val: any, rowData?: Record<string, any>) => void;
24
24
  'v-if'?: string | boolean | ((val: any, row: T) => boolean);
25
25
  };
26
26
  export interface InputBagelField<T> extends BaseBagelField<T> {
@@ -1 +1 @@
1
- {"version":3,"file":"BagelForm.d.ts","sourceRoot":"","sources":["../../src/types/BagelForm.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAEvD,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAEhG,MAAM,MAAM,WAAW,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,KAAK,cAAc,CAAC;AAE1F,MAAM,WAAW,UAAU,CAAC,CAAC,GAAG,GAAG;IACjC,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,GAAG,WAAW,CAAC,CAAC,CAAC,CAAA;CAC/C;AAED,MAAM,MAAM,cAAc,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI;IACpD,GAAG,CAAC,EAAE,GAAG,CAAC;IACV,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IACtB,KAAK,CAAC,EAAE,cAAc,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;IACxC,KAAK,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,GAAG,CAAC;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC;IAC1G,YAAY,CAAC,EAAE,GAAG,CAAC;IACnB,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,GAAG,CAAC;IAC9D,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,SAAS,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,CAAC;IAC9E,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC;CAC7D,CAAA;AAED,MAAM,WAAW,eAAe,CAAC,CAAC,CAAE,SAAQ,cAAc,CAAC,CAAC,CAAC;IAC3D,GAAG,EAAE,MAAM,GAAG,OAAO,SAAS,CAAC;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB,CAAC,CAAC,CAAE,SAAQ,cAAc,CAAC,CAAC,CAAC;IAC5D,GAAG,EAAE,QAAQ,GAAG,OAAO,WAAW,CAAC;IACnC,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,MAAM,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,cAAc,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC;AAE1G,MAAM,MAAM,cAAc,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC"}
1
+ {"version":3,"file":"BagelForm.d.ts","sourceRoot":"","sources":["../../src/types/BagelForm.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAEvD,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAEhG,MAAM,MAAM,WAAW,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,KAAK,cAAc,CAAC;AAE1F,MAAM,WAAW,UAAU,CAAC,CAAC,GAAG,GAAG;IAClC,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,GAAG,WAAW,CAAC,CAAC,CAAC,CAAA;CAC9C;AAED,MAAM,MAAM,cAAc,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI;IACrD,GAAG,CAAC,EAAE,GAAG,CAAC;IACV,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IACtB,KAAK,CAAC,EAAE,cAAc,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;IACxC,KAAK,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,GAAG,CAAC;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC;IAC1G,YAAY,CAAC,EAAE,GAAG,CAAC;IACnB,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,GAAG,CAAC;IAC9D,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,CAAC;IAC7D,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC;CAC5D,CAAA;AAED,MAAM,WAAW,eAAe,CAAC,CAAC,CAAE,SAAQ,cAAc,CAAC,CAAC,CAAC;IAC5D,GAAG,EAAE,MAAM,GAAG,OAAO,SAAS,CAAC;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,gBAAgB,CAAC,CAAC,CAAE,SAAQ,cAAc,CAAC,CAAC,CAAC;IAC7D,GAAG,EAAE,QAAQ,GAAG,OAAO,WAAW,CAAC;IACnC,EAAE,EAAE,MAAM,CAAC;CACX;AAED,MAAM,MAAM,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,cAAc,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC;AAE1G,MAAM,MAAM,cAAc,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { DirectiveBinding } from 'vue';
2
+ declare const _default: {
3
+ beforeMount(el: any, binding: DirectiveBinding): void;
4
+ unmounted(el: any): void;
5
+ };
6
+ export default _default;
7
+ //# sourceMappingURL=clickOutside.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clickOutside.d.ts","sourceRoot":"","sources":["../../src/utils/clickOutside.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,KAAK,CAAC;;oBAG3B,GAAG,WAAW,gBAAgB;kBAQhC,GAAG;;AATlB,wBAYE"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bagelink/vue",
3
3
  "type": "module",
4
- "version": "0.0.268",
4
+ "version": "0.0.276",
5
5
  "description": "Bagel core sdk packages",
6
6
  "author": {
7
7
  "name": "Neveh Allon",
@@ -52,7 +52,7 @@
52
52
  ],
53
53
  "devDependencies": {
54
54
  "@vue-macros/reactivity-transform": "^0.4.3",
55
- "vue": "^3.4.15"
55
+ "vue": "^3.4.19"
56
56
  },
57
57
  "peerDependencies": {
58
58
  "@bagelink/sdk": "*",
@@ -113,6 +113,7 @@
113
113
  "access": "public"
114
114
  },
115
115
  "dependencies": {
116
+ "floating-vue": "^5.2.2",
116
117
  "type-fest": "^4.10.2",
117
118
  "vue-multiselect": "3.0.0-beta.3"
118
119
  },
@@ -0,0 +1,15 @@
1
+ <template>
2
+ <div>
3
+ <slot />
4
+ </div>
5
+ </template>
6
+
7
+ <script setup lang="ts">
8
+ import { reactive, provide } from 'vue';
9
+
10
+ const state = reactive({
11
+ openItem: null as string | null,
12
+ });
13
+
14
+ provide('accordionState', state);
15
+ </script>
@@ -1,13 +1,14 @@
1
1
  <template>
2
2
  <div class="accordion-item">
3
- <div class="accordion-head" @click="toggle()">
4
- {{ label }}
5
- <div class="accordion-icon" :class="{open}" >
3
+ <button @click="toggle()" :aria-expanded="open ? 'true' : 'false'" class="accordion-head"
4
+ :aria-controls="`accordion-body-${id}`">
5
+ <span class="accordion-label">{{ label }}</span>
6
+ <div class="accordion-icon" :class="{ open }">
6
7
  <MaterialIcon icon="expand_more" />
7
8
  </div>
8
- </div>
9
+ </button>
9
10
  <Transition name="expand">
10
- <div v-if="open" class="accordion-body">
11
+ <div v-if="open" class="accordion-body" :id="`accordion-body-${id}`" :aria-hidden="open ? 'false' : 'true'">
11
12
  <slot />
12
13
  </div>
13
14
  </Transition>
@@ -16,57 +17,80 @@
16
17
 
17
18
  <script lang="ts" setup>
18
19
  import { MaterialIcon } from '@bagelink/vue';
20
+ import { watch, inject } from 'vue';
19
21
 
20
- defineProps<{
21
- label: string,
22
+ const props = defineProps<{
23
+ label: string,
24
+ id?: string,
22
25
  }>();
23
-
24
26
  let open = $ref(false);
25
27
 
28
+ const accordionState = inject('accordionState') as { openItem: string | null };
29
+ const id = props.id || Math.random().toString(36).substring(7);
30
+
31
+ watch(() => accordionState.openItem, (currentOpenId) => {
32
+ if (currentOpenId !== id) {
33
+ open = false;
34
+ }
35
+ }, { immediate: true });
36
+
26
37
  function toggle() {
27
38
  open = !open;
28
- console.log('toggle', open);
39
+ if (open) accordionState.openItem = id;
40
+ else if (accordionState.openItem === id) accordionState.openItem = null;
29
41
  }
30
42
  </script>
31
43
 
32
44
  <style scoped>
33
45
  .accordion-item {
34
- border-bottom: 1px solid var(--border-color);
35
- transition: all 0.2s ease;
36
- cursor: pointer;
37
- overflow: hidden;
46
+ border-bottom: 1px solid var(--border-color);
47
+ transition: all 0.2s;
48
+ cursor: pointer;
49
+ overflow: hidden;
38
50
  }
39
51
 
40
52
  .accordion-head {
41
- height: var( --input-height);
42
- display: flex;
43
- align-items: center;
44
- justify-content: space-between;
53
+ height: var(--input-height);
54
+ background: transparent;
55
+ display: flex;
56
+ width: 100%;
57
+ align-items: center;
58
+ justify-content: space-between;
45
59
  }
46
60
 
47
61
  .accordion-icon {
48
- transition: all 0.2s ease;
62
+ transition: all 0.2s ease;
49
63
  }
64
+
50
65
  .accordion-icon.open {
51
- transform: rotate(180deg);
66
+ transform: rotate(180deg);
52
67
  }
68
+
69
+ .accordion-label {
70
+ font-weight: bold;
71
+ }
72
+
73
+ .accordion-head:hover .accordion-label {
74
+ text-decoration: underline;
75
+ }
76
+
77
+ .accordion-body {}
53
78
  </style>
54
79
 
55
80
  <style>
56
81
  .expand-enter-active,
57
82
  .expand-leave-active {
58
- transition: all 0.5s;
83
+ transition: all 0.5s;
84
+ transition-delay: 0ms;
59
85
  }
60
86
 
61
87
  .expand-enter-from,
62
88
  .expand-leave-to {
63
- max-height: 0;
64
- opacity: 0.5;
89
+ max-height: 0;
65
90
  }
66
91
 
67
92
  .expand-enter-to,
68
93
  .expand-leave-from {
69
- max-height: 100vh;
70
- opacity: 1;
94
+ max-height: 300px;
71
95
  }
72
96
  </style>
@@ -0,0 +1,132 @@
1
+ <template>
2
+ <Dropdown placement="auto-start" class="bagel-input combobox">
3
+ <Btn class="combobox-btn" border color="black" @click="toggle"
4
+ v-bind="{ 'icon.end': open ? 'unfold_less' : 'unfold_more' }">
5
+ {{
6
+ valueToLabel(selectedItem) ||
7
+ placeholder || 'Select' }}
8
+ </Btn>
9
+ <template #popper="{ hide }">
10
+ <Card border thin class="combobox-options">
11
+ <TextInput v-if="searchable" ref="searchInput" dense :placeholder="'Search'" icon="search" v-model="search" />
12
+ <div class="combobox-option" v-for="(option, i) in filteredOptions" :key="`${option}${i}`" @click="() => {
13
+ select(option)
14
+ hide();
15
+ }" :class="{ selected: option === selectedItem }">
16
+ <span>
17
+ {{ label(option) }}
18
+ </span>
19
+ <Icon v-if="isSelected(option)" icon="check" />
20
+ </div>
21
+ </Card>
22
+ </template>
23
+ </Dropdown>
24
+ </template>
25
+
26
+ <script lang="ts" setup>
27
+ import { Dropdown } from 'floating-vue';
28
+ import 'floating-vue/style.css';
29
+ import {
30
+ TextInput, Btn, Card, Icon,
31
+ } from '@bagelink/vue';
32
+
33
+ type Option = string | number | Record<string, any> | { label: string, value: string | number };
34
+ let open = $ref(false);
35
+ let selectedItem = $ref<Option>();
36
+
37
+ const searchInput = $ref<HTMLInputElement | null>(null);
38
+
39
+ const props = defineProps<{
40
+ options: Option[];
41
+ placeholder?: string;
42
+ disabled?: boolean;
43
+ modelValue?: Option;
44
+ searchable?: boolean;
45
+ }>();
46
+ let search = $ref('');
47
+
48
+ const toggle = () => {
49
+ open = !open;
50
+ if (!open) search = '';
51
+ if (open) setTimeout(() => (searchInput as any)?.$el?.querySelector('input')?.focus(), 100);
52
+ };
53
+
54
+ const valueToLabel = (value?: Option) => {
55
+ if (!value) return '';
56
+ const option = props.options.find((option) => {
57
+ if (typeof option === 'string' || typeof option === 'number') return option === value;
58
+ return option.value === value;
59
+ });
60
+ if (!option) return value;
61
+ return label(option);
62
+ };
63
+
64
+ const emit = defineEmits(['update:modelValue']);
65
+
66
+ const label = (option: Option) => {
67
+ if (typeof option === 'string') return option;
68
+ if (typeof option === 'number') return `${option}`;
69
+ return option.label;
70
+ };
71
+
72
+ const isSelected = (option: Option) => {
73
+ if (typeof option === 'string' || typeof option === 'number') return option === selectedItem;
74
+ return option.value === selectedItem;
75
+ };
76
+
77
+ const filteredOptions = $computed(() => props.options.filter((option) => {
78
+ const searchTerm = new RegExp(search, 'gi');
79
+ if (typeof option === 'string') return option.match(searchTerm);
80
+ if (typeof option === 'number') return `${option}`.match(searchTerm);
81
+ return option.label.match(searchTerm);
82
+ }));
83
+
84
+ const select = (option: Option) => {
85
+ if (typeof option === 'string') selectedItem = option;
86
+ else if (typeof option === 'number') selectedItem = option;
87
+ else selectedItem = option.value;
88
+ emit('update:modelValue', selectedItem);
89
+ open = false;
90
+ };
91
+ </script>
92
+
93
+ <style scoped>
94
+ .combobox {
95
+ width: 100%;
96
+ }
97
+
98
+ .combobox-option {
99
+ padding: 6px 12px;
100
+ cursor: pointer;
101
+ border-radius: 5px;
102
+ transition: all 0.2s;
103
+ display: flex;
104
+ justify-content: space-between;
105
+ width: 300px;
106
+ }
107
+
108
+ .combobox-options {
109
+ max-height: 300px;
110
+ overflow-y: auto;
111
+ }
112
+
113
+ .combobox-option:hover {
114
+ background: var(--bgl-gray-20);
115
+ }
116
+ </style>
117
+
118
+ <style>
119
+ .combobox-btn .bgl_btn-flex {
120
+ justify-content: space-between;
121
+ }
122
+
123
+ .v-popper__arrow-container {
124
+ display: none;
125
+ }
126
+
127
+ .v-popper--theme-dropdown .v-popper__inner {
128
+ border: none;
129
+ background: transparent;
130
+ border-radius: var(--card-border-radius);
131
+ }
132
+ </style>
@@ -1,41 +1,13 @@
1
1
  <template>
2
- <Modal
3
- @onUpdate:isModalVisible="props['onUpdate:isModalVisible']"
4
- :side="side"
5
- ref="modal"
6
- :dismissable="dismissable"
7
- :title="title"
8
- >
9
- <BagelForm
10
- ref="form"
11
- v-model="formData"
12
- :schema="computedFormSchema"
13
- />
14
- <template
15
- #footer
16
- v-if="onDelete || onSubmit"
17
- >
2
+ <Modal @onUpdate:isModalVisible="props['onUpdate:isModalVisible']" :side="side" ref="modal" :dismissable="dismissable"
3
+ :title="title">
4
+ <BagelForm @submit="runSubmit" ref="form" v-model="formData" :schema="computedFormSchema" />
5
+ <template #footer v-if="onDelete || onSubmit">
18
6
  <div>
19
- <Btn
20
- thin
21
- flat
22
- value="Cancel"
23
- @click="closeModal"
24
- />
25
- <Btn
26
- thin
27
- icon="delete"
28
- v-if="onDelete"
29
- flat
30
- value="Delete"
31
- @click="runDelete"
32
- color="red"
33
- />
7
+ <Btn thin flat value="Cancel" @click="closeModal" />
8
+ <Btn thin icon="delete" v-if="onDelete" flat value="Delete" @click="runDelete" color="red" />
34
9
  </div>
35
- <Btn
36
- value="Submit"
37
- @click="runSubmit"
38
- />
10
+ <Btn value="Submit" @click="runSubmit" />
39
11
  </template>
40
12
  </Modal>
41
13
  </template>
@@ -1,17 +1,32 @@
1
1
  <template>
2
- <component :required="field.required" v-bind="bindAttrs(field?.attrs || {}, fieldData, modelValue)"
3
- :class="classify(fieldData, modelValue, field.class, field.attrs?.class)" v-if="vIf" :is="is" :label="field.label"
4
- :id="field.id" :placeholder="field.placeholder || field.label" v-model="fieldData" :defaultValue="field.defaultValue"
5
- :options="field.options" :helptext="field.helptext"
6
- @update:modelValue="($event: any) => field?.onUpdate?.($event, denullify(fieldData, field.id), formData)">
2
+ <component
3
+ :required="field.required"
4
+ v-bind="bindAttrs(field?.attrs || {}, fieldData, modelValue)"
5
+ :class="classify(fieldData, modelValue, field.class, field.attrs?.class)"
6
+ v-if="vIf"
7
+ :is="is"
8
+ :label="field.label"
9
+ :id="field.id"
10
+ :placeholder="field.placeholder || field.label"
11
+ v-model="fieldData"
12
+ :defaultValue="field.defaultValue"
13
+ :options="field.options"
14
+ :helptext="field.helptext"
15
+ @update:modelValue="($event: any) => field?.onUpdate?.($event, formData)"
16
+ >
7
17
  {{ field.transform?.(fieldData, modelValue) || fieldData || '' }}
8
- <BglField v-model="formData" v-for="(child, ii) in field.children" :key="child.id || ii" :field="child" />
18
+ <BglField
19
+ v-model="formData"
20
+ v-for="(child, ii) in field.children"
21
+ :key="child.id || ii"
22
+ :field="child"
23
+ />
9
24
  </component>
10
25
  </template>
11
26
 
12
27
  <script lang="ts" setup>
13
28
  import {
14
- type Field, bindAttrs, classify, SelectInput, TextInput, ToggleInput, CheckInput, denullify,
29
+ type Field, bindAttrs, classify, SelectInput, TextInput, ToggleInput, CheckInput,
15
30
  } from '@bagelink/vue';
16
31
 
17
32
  const props = withDefaults(defineProps<{
@@ -0,0 +1,13 @@
1
+ <template>
2
+ <fieldset ref="fieldSet">
3
+ <slot />
4
+ </fieldset>
5
+ </template>
6
+ <script lang="ts" setup>
7
+ import { defineExpose } from 'vue';
8
+
9
+ const fieldSet = $ref<HTMLFieldSetElement | null>(null);
10
+ const isDirty = $ref(false);
11
+ const validateForm = () => fieldSet?.reportValidity?.();
12
+ defineExpose({ validateForm, isDirty });
13
+ </script>
@@ -1,29 +1,12 @@
1
1
  <template>
2
2
  <template v-if="id">
3
- <BglField
4
- v-for="(field, i) in schema"
5
- :key="field.id || `${i}p`"
6
- :field="field"
7
- v-model="data"
8
- />
3
+ <BglField v-for="(field, i) in schema" :key="field.id || `${i}p`" :field="field" v-model="data" />
9
4
  </template>
10
- <form
11
- v-else
12
- ref="form"
13
- @submit.prevent="runSubmit"
14
- >
15
- <Title
16
- tag="h4"
17
- :label="label"
18
- v-if="label"
19
- />
20
- <BglField
21
- v-for="(field, i) in schema"
22
- :key="field.id || `${i}p`"
23
- :field="field"
24
- v-model="data"
25
- />
5
+ <form v-else ref="form" @submit.prevent="runSubmit">
6
+ <Title tag="h4" :label="label" v-if="label" />
7
+ <BglField v-for="(field, i) in schema" :key="field.id || `${i}p`" :field="field" v-model="data" />
26
8
  <slot name="submit" />
9
+ <input type="submit" hidden v-if="onSubmit" />
27
10
  </form>
28
11
  </template>
29
12
 
@@ -43,7 +43,7 @@ const props = withDefaults(
43
43
 
44
44
  const emit = defineEmits(['update:modelValue']);
45
45
 
46
- let date = $computed<string | Date>({
46
+ const date = $computed<string | Date>({
47
47
  get: () => props.modelValue || '',
48
48
  set: (val) => {
49
49
  const d = typeof val === 'string' ? new Date(val) : val;
@@ -56,7 +56,11 @@ let date = $computed<string | Date>({
56
56
  });
57
57
 
58
58
  onMounted(() => {
59
- if (props.defaultValue) date = props.defaultValue;
59
+ if (
60
+ props.defaultValue && date === ''
61
+ ) {
62
+ Object.assign(date, { date: props.defaultValue });
63
+ }
60
64
  });
61
65
  </script>
62
66
 
@@ -16,13 +16,7 @@
16
16
  v-model="seletValue"
17
17
  v-bind="extraProps"
18
18
  />
19
- <input
20
- v-model="seletValue"
21
- type="hidden"
22
- :name="id"
23
- :required
24
- v-bind="extraProps"
25
- >
19
+ <!-- <input v-model="dataValue" type="hidden" :name="id" :required v-bind="extraProps"> -->
26
20
  </label>
27
21
  </div>
28
22
  </template>
@@ -58,7 +52,6 @@ const seletValue = $computed({
58
52
  set: (val?: Option) => {
59
53
  dataValue = val?.value;
60
54
  emit('update:modelValue', dataValue);
61
- setTimeout(() => multiselect?.deactivate(), 1);
62
55
  },
63
56
  });
64
57
 
@@ -203,7 +196,7 @@ fieldset[disabled] .multiselect {
203
196
  }
204
197
 
205
198
  .multiselect--active .multiselect__input {
206
- margin-top: -0.6rem;
199
+ margin-top: -0.6rem;
207
200
  }
208
201
 
209
202
  .multiselect__input::placeholder {
@@ -2,15 +2,13 @@
2
2
  <div
3
3
  class="bagel-input text-input"
4
4
  :class="{
5
- dense, small, shrink, toggleEdit, editMode, code,
5
+ dense, small, shrink, toggleEdit, editMode, code,
6
6
  textInputIconWrap: icon,
7
7
  txtInputIconStart: iconStart,
8
8
  }"
9
9
  :title="title"
10
10
  >
11
- <label
12
- :for="id"
13
- >
11
+ <label :for="id">
14
12
  {{ label }}
15
13
  <input
16
14
  v-if="!multiline && !autoheight && !code"
@@ -19,7 +17,8 @@
19
17
  :id="id"
20
18
  v-model="inputVal"
21
19
  :type="type"
22
- :rows="1" ref="input"
20
+ :rows="1"
21
+ ref="input"
23
22
  :placeholder="placeholder || label"
24
23
  :disabled="!editMode"
25
24
  :required="required"
@@ -33,7 +32,8 @@
33
32
  :id="id"
34
33
  v-model="inputVal"
35
34
  :type="type"
36
- :rows="rows" ref="input"
35
+ :rows="rows"
36
+ ref="input"
37
37
  :placeholder="placeholder || label"
38
38
  :disabled="!editMode"
39
39
  :required="required"
@@ -45,7 +45,8 @@
45
45
  </label>
46
46
 
47
47
  <MaterialIcon
48
- class="iconStart" v-if="iconStart"
48
+ class="iconStart"
49
+ v-if="iconStart"
49
50
  :icon="iconStart"
50
51
  />
51
52
  <MaterialIcon
@@ -53,7 +54,10 @@
53
54
  :icon="icon"
54
55
  />
55
56
  <Btn
56
- class="toggleEditBtn" v-if="toggleEdit" thin @click="toggleEditAction"
57
+ class="toggleEditBtn"
58
+ v-if="toggleEdit"
59
+ thin
60
+ @click="toggleEditAction"
57
61
  :icon="editMode ? 'check'
58
62
  : 'edit'"
59
63
  flat
@@ -5,7 +5,6 @@ export { default as SelectInput } from './SelectInput.vue';
5
5
  export { default as RichTextEditor } from './RichTextEditor.vue';
6
6
  export { default as TableField } from './TableField.vue';
7
7
  export { default as TextInput } from './TextInput.vue';
8
- export { default as TextArea } from './TextArea.vue';
9
8
  export { default as Checkbox } from './Checkbox.vue';
10
9
  export { default as ColorPicker } from './ColorPicker.vue';
11
10
  export { default as DatePicker } from './DatePicker.vue';
@@ -1,6 +1,7 @@
1
1
  export { default as LangText } from './LangText.vue';
2
2
  export { default as RTXEditor } from './RTXEditor.vue';
3
3
  export { default as MaterialIcon } from './MaterialIcon.vue';
4
+ export { default as Icon } from './MaterialIcon.vue';
4
5
  export { default as NavBar } from './NavBar.vue';
5
6
  export { default as Btn } from './Btn.vue';
6
7
  export { default as Modal } from './Modal.vue';
@@ -18,6 +19,8 @@ export { default as DataPreview } from './DataPreview.vue';
18
19
  export { default as Card } from './Card.vue';
19
20
  export { default as Avatar } from './Avatar.vue';
20
21
  export { default as Title } from './Title.vue';
22
+ export { default as Accordion } from './Accordion.vue';
23
+ export { default as ComboBox } from './ComboBox.vue';
21
24
 
22
25
  export * from './charts';
23
26
  export * from './form';
@@ -1,6 +1,9 @@
1
+ // import { vTooltip } from 'floating-vue';
2
+ import FloatingVue from 'floating-vue';
1
3
  import { inject } from 'vue';
2
4
  import type { InjectionKey, Plugin } from 'vue';
3
5
  import { Bagel } from '@bagelink/sdk';
6
+ import clickOutside from '../utils/clickOutside';
4
7
 
5
8
  export const bagelInjectionKey = Symbol('bagel') as InjectionKey<Bagel>;
6
9
  export const i18nTInjectionKey = Symbol('bagel') as InjectionKey<
@@ -29,11 +32,20 @@ export interface BagelOptions {
29
32
  // eslint-disable-next-line no-unused-vars
30
33
  i18nT?: (key: string) => string
31
34
  }
32
-
33
35
  export const BagelVue: Plugin = {
34
36
  install: (app, options: BagelOptions) => {
35
37
  const bagel = new Bagel({ host: options.host, onError: options.onError });
36
-
38
+ app.directive('click-outside', clickOutside);
39
+
40
+ app.use(FloatingVue, {
41
+ themes: {
42
+ 'bgl-theme': {
43
+ triggers: ['click'],
44
+ autoHide: true,
45
+ placement: 'bottom',
46
+ },
47
+ },
48
+ });
37
49
  app.config.globalProperties.$bagel = bagel;
38
50
  app.provide(bagelInjectionKey, bagel);
39
51
  app.config.globalProperties.$i18T = options?.i18nT || ((key?: string) => key);
@@ -17,7 +17,7 @@ export interface ModalFormOptions {
17
17
  side?: boolean;
18
18
  title?: string;
19
19
  dismissable?: boolean;
20
- schema: BglFormSchemaT<any> | (() => BglFormSchemaT);
20
+ schema: BglFormSchemaT<any> | (() => BglFormSchemaT) | BglFormSchemaT
21
21
  onSubmit?: (formData: any) => Promise<any>;
22
22
  onDelete?: (id: string) => Promise<void>;
23
23
  onError?: ((err: any) => void);