@bagelink/vue 1.12.31 → 1.12.36

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 (50) hide show
  1. package/dist/components/AddToCalendar.vue.d.ts.map +1 -1
  2. package/dist/components/FilterQuery.vue.d.ts +30 -0
  3. package/dist/components/FilterQuery.vue.d.ts.map +1 -0
  4. package/dist/components/Modal.vue.d.ts.map +1 -1
  5. package/dist/components/QueryFilter.vue.d.ts +30 -0
  6. package/dist/components/QueryFilter.vue.d.ts.map +1 -0
  7. package/dist/components/calendar/Index.vue.d.ts.map +1 -1
  8. package/dist/components/calendar/views/AgendaView.vue.d.ts.map +1 -1
  9. package/dist/components/calendar/views/MonthView.vue.d.ts.map +1 -1
  10. package/dist/components/calendar/views/WeekView.vue.d.ts.map +1 -1
  11. package/dist/components/form/inputs/ArrayInput.vue.d.ts.map +1 -1
  12. package/dist/components/form/inputs/RadioGroup.vue.d.ts.map +1 -1
  13. package/dist/components/form/inputs/SelectInput.vue.d.ts.map +1 -1
  14. package/dist/components/index.d.ts.map +1 -1
  15. package/dist/components/layout/AppContent.vue.d.ts.map +1 -1
  16. package/dist/components/layout/AppSidebar.vue.d.ts.map +1 -1
  17. package/dist/components/layout/TabsNav.vue.d.ts.map +1 -1
  18. package/dist/dialog/Dialog.vue.d.ts.map +1 -1
  19. package/dist/form-flow/form-flow.d.ts.map +1 -1
  20. package/dist/i18n/index.d.ts.map +1 -1
  21. package/dist/index.cjs +91 -91
  22. package/dist/index.mjs +13416 -13060
  23. package/dist/style.css +1 -1
  24. package/dist/utils/BagelFormUtils.d.ts.map +1 -1
  25. package/dist/utils/calendar/dateUtils.d.ts.map +1 -1
  26. package/package.json +2 -2
  27. package/src/components/AddToCalendar.vue +12 -10
  28. package/src/components/{Filter.vue → FilterQuery.vue} +5 -5
  29. package/src/components/Modal.vue +3 -1
  30. package/src/components/calendar/Index.vue +39 -18
  31. package/src/components/calendar/views/AgendaView.vue +190 -213
  32. package/src/components/calendar/views/MonthView.vue +9 -2
  33. package/src/components/calendar/views/WeekView.vue +14 -6
  34. package/src/components/form/inputs/ArrayInput.vue +16 -3
  35. package/src/components/form/inputs/RadioGroup.vue +19 -28
  36. package/src/components/form/inputs/SelectInput.vue +31 -5
  37. package/src/components/index.ts +1 -1
  38. package/src/components/layout/AppContent.vue +16 -14
  39. package/src/components/layout/AppSidebar.vue +6 -5
  40. package/src/components/layout/TabsNav.vue +123 -31
  41. package/src/dialog/Dialog.vue +2 -0
  42. package/src/form-flow/form-flow.ts +2 -0
  43. package/src/i18n/locales/en.json +25 -0
  44. package/src/i18n/locales/es.json +19 -0
  45. package/src/i18n/locales/fr.json +19 -1
  46. package/src/i18n/locales/he.json +25 -0
  47. package/src/i18n/locales/it.json +19 -0
  48. package/src/i18n/locales/ru.json +19 -0
  49. package/src/utils/BagelFormUtils.ts +1 -0
  50. package/src/utils/calendar/dateUtils.ts +2 -2
@@ -38,6 +38,11 @@ interface PropTypes {
38
38
  searchPlaceholder?: string
39
39
  error?: string
40
40
  underlined?: boolean
41
+ size?: 'xs' | 's' | 'm' | 'l' | 'xl'
42
+ outline?: boolean
43
+ border?: boolean
44
+ thin?: boolean
45
+ round?: boolean
41
46
  }
42
47
 
43
48
  const searchInput = ref<HTMLElement | undefined>()
@@ -56,6 +61,17 @@ const selected = ref(false)
56
61
  const open = ref(false)
57
62
  const selectPlaceholder = computed(() => resolveI18n(props.placeholder) ?? $t('select.placeholder'))
58
63
 
64
+ const btnClasses = computed(() => ({
65
+ 'selectinput-btn--xs': props.size === 'xs',
66
+ 'selectinput-btn--s': props.size === 's',
67
+ 'selectinput-btn--l': props.size === 'l',
68
+ 'selectinput-btn--xl': props.size === 'xl',
69
+ 'selectinput-btn--round': props.round,
70
+ 'selectinput-btn--thin': props.thin,
71
+ 'outline': props.outline,
72
+ 'border': props.border,
73
+ }))
74
+
59
75
  const selectedLabel = computed((): string => {
60
76
  if (selectedItemCount.value === 0) { return selectPlaceholder.value }
61
77
  if (selectedItemCount.value > 4) {
@@ -73,6 +89,7 @@ const { results, isLoading } = useSearch<Option>({
73
89
  searchTerm: () => searchTerm.value,
74
90
  serverSearch: isAsyncSource(props.options) ? props.options : undefined,
75
91
  items: () => (Array.isArray(props.options) ? props.options : []),
92
+ keysToSearch: ['label'],
76
93
  minChars: isAsyncSource(props.options) ? 0 : 2,
77
94
  })
78
95
 
@@ -275,7 +292,7 @@ onMounted(() => {
275
292
  />
276
293
  <button
277
294
  v-else ref="triggerBtn" :disabled="disabled" type="button" class="selectinput-btn"
278
- :class="{ isEmpty: selectedItemCount === 0 }" @click="open = !open"
295
+ :class="[{ isEmpty: selectedItemCount === 0 }, btnClasses]" @click="open = !open"
279
296
  @keydown.down.prevent="navigate('down')" @keydown.up.prevent="navigate('up')"
280
297
  >
281
298
  <Icon v-if="icon" :icon="icon" />
@@ -320,10 +337,12 @@ onMounted(() => {
320
337
  <Icon v-if="isSelected(option)" :size="1.1" icon="select_check_box" />
321
338
  <Icon v-if="!isSelected(option)" class="opacity-3" icon="check_box_outline_blank" :size="1.1" />
322
339
  </template>
323
- <Icon v-if="getOptionIcon(option)" :icon="getOptionIcon(option)!" :size="1" />
324
- <span class="block">
325
- {{ getLabel(option) }}
326
- </span>
340
+ <div class="flex gap-05">
341
+ <Icon v-if="getOptionIcon(option)" :icon="getOptionIcon(option)!" :size="1" />
342
+ <span class="block">
343
+ {{ getLabel(option) }}
344
+ </span>
345
+ </div>
327
346
  </div>
328
347
  <p v-if="results.length === 0" class="selectinput-option opacity-3 pointer-events-none">
329
348
  No options found
@@ -422,6 +441,13 @@ onMounted(() => {
422
441
  text-overflow: ellipsis;
423
442
  }
424
443
 
444
+ .selectinput-btn.selectinput-btn--xs { height: calc(var(--input-height) * 0.6); padding: 0 0.4rem; font-size: 0.75em; }
445
+ .selectinput-btn.selectinput-btn--s { height: calc(var(--input-height) * 0.75); padding: 0 0.5rem; font-size: 0.875em; }
446
+ .selectinput-btn.selectinput-btn--l { height: calc(var(--input-height) * 1.2); padding: 0 1rem; font-size: 1.1em; }
447
+ .selectinput-btn.selectinput-btn--xl { height: calc(var(--input-height) * 1.5); padding: 0 1.25rem; font-size: 1.2em; }
448
+ .selectinput-btn.selectinput-btn--round { border-radius: 999px; }
449
+ .selectinput-btn.selectinput-btn--thin { height: calc(var(--input-height) * 0.75); padding: 0 0.5rem; }
450
+
425
451
  .selectinput .bagel-input.mb-0 input {
426
452
  /* background: transparent !important; */
427
453
  }
@@ -19,7 +19,7 @@ export { Draggable, useDraggable, vDraggable } from './draggable'
19
19
  export { default as DragOver } from './DragOver.vue'
20
20
  export { default as Dropdown } from './Dropdown.vue'
21
21
  export { default as FieldSetVue } from './FieldSetVue.vue'
22
- export { default as Filter } from './Filter.vue'
22
+ export { default as FilterQuery } from './FilterQuery.vue'
23
23
  export { default as Flag } from './Flag.vue'
24
24
  export * from './form'
25
25
  export { default as Icon } from './Icon/Icon.vue'
@@ -29,11 +29,7 @@ const menuState = inject('menuState', {
29
29
  const sidebarCardStyle = inject('sidebarCardStyle', { value: false })
30
30
 
31
31
  // Computed property to check if sidebar has card style
32
- const hasSidebarCard = computed(() => {
33
- // Check if there's an AppSidebar with card class in the DOM
34
- const sidebar = document.querySelector('.app-sidebar .card')
35
- return sidebar !== null || sidebarCardStyle?.value
36
- })
32
+ const hasSidebarCard = computed(() => sidebarCardStyle?.value ?? false)
37
33
  </script>
38
34
 
39
35
  <template>
@@ -44,12 +40,8 @@ const hasSidebarCard = computed(() => {
44
40
  >
45
41
  <!-- Header -->
46
42
  <header
47
- class="app-header flex align-items-center space-between py-1 m_pt-025 m_pb-05 min-h60px w-100p m_flex-wrap"
48
- :class="{
49
- 'border-bottom': border,
50
- 'px-1': !hasSidebarCard,
51
- 'm_px-1': hasSidebarCard,
52
- }"
43
+ class="app-header flex align-items-center space-between py-1 m_pt-025 m_pb-05 min-h60px w-100p m_flex-wrap px-1 m_px-05"
44
+ :class="{ 'border-bottom': border }"
53
45
  >
54
46
  <!-- Left Side -->
55
47
  <div class="flex align-items-center gap-col-075 m_flex-wrap m_pe-075">
@@ -84,9 +76,7 @@ const hasSidebarCard = computed(() => {
84
76
 
85
77
  <!-- Page Content -->
86
78
  <main
87
- class="pageContent flex-grow overflow pt-1 pb-05 w-100p m_p-05 m_scrollbar-gutter-auto m_vw100" :class="{
88
- 'px-1': !hasSidebarCard,
89
- }"
79
+ class="pageContent flex-grow overflow pt-1 pb-05 px-1 w-100p m_p-05 m_scrollbar-gutter-auto m_vw100"
90
80
  >
91
81
  <slot name="content">
92
82
  <!-- Default slot for content without explicit template -->
@@ -114,6 +104,18 @@ const hasSidebarCard = computed(() => {
114
104
  transition: all 0.15s ease-in;
115
105
  overflow: hidden;
116
106
  }
107
+ body:has(.cardWrapSide) .pageContent,
108
+ body:has(.cardWrapSide) .app-header {
109
+ padding-inline: 0 !important;
110
+ }
111
+
112
+ @media screen and (max-width: 910px) {
113
+
114
+ body:has(.cardWrapSide) .pageContent,
115
+ body:has(.cardWrapSide) .app-header {
116
+ padding-inline: 0.5rem !important;
117
+ }
118
+ }
117
119
  </style>
118
120
 
119
121
  <style scoped>
@@ -168,8 +168,8 @@ const sidebarStyles = computed(() => {
168
168
  <!-- Logo/Brand -->
169
169
  <router-link
170
170
  to="/" class="decoration-none flex siderbarLogoWrap" :class="{
171
- 'gap-05': menuState.isOpen.value,
172
- 'gap-0': !menuState.isOpen.value,
171
+ 'gap-05 ps-05': menuState.isOpen.value,
172
+ 'gap-0 pe-05 mx-auto': !menuState.isOpen.value,
173
173
  }"
174
174
  >
175
175
  <img
@@ -206,12 +206,13 @@ const sidebarStyles = computed(() => {
206
206
  v-for="link in props.footerLinks" :key="link.to || link.label"
207
207
  :title="!menuState.isOpen.value && !menuState.isMobile.value ? resolveI18n(link.label) : ''"
208
208
  :style="{
209
+ backgroundColor: isActiveRoute(link) ? props.activeColor : props.bgColor,
209
210
  color: isActiveRoute(link) ? 'white' : props.textColor,
210
211
  }"
211
- fullWidth
212
- alignTxt="start"
213
- flat :icon="link.icon" class="flex-shrink-0 px-1" :to="link.to" @click="link.action"
212
+ fullWidth alignTxt="start" class="flex-shrink-0 px-1" :class="{ 'nav-btn-active': isActiveRoute(link) }"
213
+ :to="link.to || '/'" @click="link.action"
214
214
  >
215
+ <Icon :name="link.icon" size="1.2" />
215
216
  <span class="nav-text">
216
217
  {{ resolveI18n(link.label) }}
217
218
  </span>
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import type { Tab } from '@bagelink/vue'
2
+ import type { Tab, IconType } from '@bagelink/vue'
3
3
  import { Icon } from '@bagelink/vue'
4
4
  import { nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
5
5
  import { useTabs } from './tabsManager'
@@ -12,6 +12,16 @@ const props = defineProps<{
12
12
  group: string
13
13
  flat?: boolean
14
14
  vertical?: boolean
15
+ icon?: IconType
16
+ iconEnd?: IconType
17
+ iconSize?: number | string
18
+ iconMobileSize?: number | string
19
+ thin?: boolean
20
+ size?: 'xs' | 's' | 'm' | 'l' | 'xl' | 'extra-small' | 'small' | 'medium' | 'large' | 'extra-large'
21
+ fullWidth?: boolean
22
+ fullWidthMobile?: boolean
23
+ alignTxt?: 'center' | 'start' | 'end'
24
+ alignTxtMobile?: 'center' | 'start' | 'end'
15
25
  }>()
16
26
 
17
27
  const emit = defineEmits(['update:modelValue'])
@@ -22,12 +32,12 @@ currentTab.value
22
32
  : props.tabs[0].value
23
33
 
24
34
  const tabsWrap = ref<HTMLElement | undefined>(undefined)
25
- const tabs = ref<HTMLElement[]>([])
35
+ const tabEls = ref<HTMLElement[]>([])
26
36
 
27
37
  function updateIndicator() {
28
38
  nextTick(() => {
29
39
  if (!tabsWrap.value) { return }
30
- const activeTab = tabs.value.find(tab => tab.classList.contains('active'))
40
+ const activeTab = tabEls.value.find(tab => tab.classList.contains('active'))
31
41
  if (activeTab) {
32
42
  // Wait a bit more to ensure CSS is fully loaded and elements are properly sized
33
43
  setTimeout(() => {
@@ -68,7 +78,7 @@ watch(
68
78
  )
69
79
 
70
80
  onMounted(() => {
71
- tabs.value = Array.from(tabsWrap.value?.querySelectorAll('.bgl_tab') || [])
81
+ tabEls.value = Array.from(tabsWrap.value?.querySelectorAll('.bgl_tab') || [])
72
82
 
73
83
  // Wait for the next frame to ensure all CSS and layout calculations are done
74
84
  requestAnimationFrame(() => {
@@ -79,7 +89,7 @@ onMounted(() => {
79
89
  })
80
90
 
81
91
  watch(
82
- () => tabs.value,
92
+ () => tabEls.value,
83
93
  () => {
84
94
  nextTick(() => { updateIndicator() })
85
95
  },
@@ -91,14 +101,33 @@ onBeforeUnmount(() => {
91
101
  </script>
92
102
 
93
103
  <template>
94
- <div ref="tabsWrap" class="grid auto-flow-columns relative fit-content bgl_tabs_wrap overflow-hidden" :class="{ 'bgl_flat-tabs': flat, 'bgl_vertical-tabs': vertical }">
95
- <slot name="tabs" v-bind="{ selectTab, isActive, tabLabel, tabs }">
96
- <button v-for="(tab, i) in props.tabs" :key="i" type="button" :class="{ active: isActive(tab) }" class="bgl_tab relative z-1" @click="selectTab(tab)">
97
- <Icon v-if="typeof tab !== 'string' && tab.icon" :icon="tab.icon" />
98
- {{ tabLabel(tab) }}
99
- </button>
104
+ <div ref="tabsWrap" class="grid auto-flow-columns relative fit-content bgl_tabs_wrap overflow-hidden" :class="{ 'bgl_flat-tabs': flat, 'bgl_vertical-tabs': vertical }">
105
+ <slot name="tabs" v-bind="{ selectTab, isActive, tabLabel, tabs: tabEls }">
106
+ <button v-for="(tab, i) in props.tabs" :key="i" type="button" :class="[
107
+ { active: isActive(tab) },
108
+ {
109
+ 'bgl_tab-thin': thin,
110
+ 'bgl_tab-xs': size === 'xs' || size === 'extra-small',
111
+ 'bgl_tab-s': size === 's' || size === 'small',
112
+ 'bgl_tab-l': size === 'l' || size === 'large',
113
+ 'bgl_tab-xl': size === 'xl' || size === 'extra-large',
114
+ 'w-100p justify-center': fullWidth,
115
+ 'w-auto m_w-100p': fullWidthMobile,
116
+ 'bgl_tab-align-center': alignTxt === 'center',
117
+ 'bgl_tab-align-start': alignTxt === 'start',
118
+ 'bgl_tab-align-end': alignTxt === 'end',
119
+ 'bgl_tab-align-center-mobile': alignTxtMobile === 'center',
120
+ 'bgl_tab-align-start-mobile': alignTxtMobile === 'start',
121
+ 'bgl_tab-align-end-mobile': alignTxtMobile === 'end',
122
+ }
123
+ ]" class="bgl_tab relative z-1" @click="selectTab(tab)">
124
+ <Icon v-if="icon" :icon="icon" :size="iconSize" :mobile-size="iconMobileSize" />
125
+ <Icon v-else-if="typeof tab !== 'string' && tab.icon" :icon="tab.icon" :size="iconSize" :mobile-size="iconMobileSize" />
126
+ {{ tabLabel(tab) }}
127
+ <Icon v-if="iconEnd" :icon="iconEnd" :size="iconSize" :mobile-size="iconMobileSize" />
128
+ </button>
100
129
  </slot>
101
- </div>
130
+ </div>
102
131
  </template>
103
132
 
104
133
  <style>
@@ -123,7 +152,7 @@ onBeforeUnmount(() => {
123
152
  <style scoped>
124
153
  .bgl_tabs_wrap {
125
154
  background: var(--bgl_tabs-background);
126
- border-radius: calc(var(--bgl_tabs-border-radius) * 1.4);
155
+ border-radius: calc(var(--bgl_tabs-border-radius) * 1.4);
127
156
  padding-inline: var(--bgl_tabs-inline-padding);
128
157
  padding-block: var(--bgl_tabs-block-padding);
129
158
  box-shadow: var(--bgl_tabs-shadow);
@@ -134,15 +163,16 @@ onBeforeUnmount(() => {
134
163
  border: none;
135
164
  background: transparent;
136
165
  cursor: pointer;
137
- font-size: var(--bgl_tabs-font-size);
166
+ font-size: inherit;
138
167
  font-family: inherit;
168
+ height: calc(var(--btn-height) - var(--bgl_tabs-block-padding) * 2);
139
169
  padding-inline: var(--bgl_tab-inline-padding);
140
- padding-block: var(--bgl_tab-block-padding);
170
+ padding-block: 0;
141
171
  border-radius: var(--bgl_tab-border-radius);
142
172
  transition: var(--bgl-transition);
143
173
  color: inherit;
144
174
  display: flex;
145
- align-items: center;
175
+ align-items: center;
146
176
  gap: var(--bgl_tab-gap);
147
177
  }
148
178
 
@@ -154,21 +184,22 @@ onBeforeUnmount(() => {
154
184
  content: '';
155
185
  position: absolute;
156
186
  top: var(--bgl_tabs-block-padding);
157
- bottom: var(--bgl_tabs-block-padding);
187
+ bottom: var(--bgl_tabs-block-padding);
158
188
  left: var(--indicator-left, 0);
159
189
  width: var(--indicator-width, 0);
160
190
  background: var(--bgl_tabs-indicator-color);
161
- border-radius: var(--bgl_tabs-border-radius);
191
+ border-radius: var(--bgl_tabs-border-radius);
162
192
  transition: var(--bgl-transition);
163
193
  z-index: 0;
164
194
  /* Hide indicator initially until position is calculated */
165
195
  opacity: var(--indicator-opacity, 0);
166
196
  }
197
+
167
198
  .bgl_flat-tabs.bgl_tabs_wrap {
168
199
  background: transparent;
169
200
  box-shadow: none;
170
201
  }
171
- .bgl_flat-tabs.bgl_tabs_wrap::before{
202
+ .bgl_flat-tabs.bgl_tabs_wrap::before {
172
203
  background: transparent;
173
204
  border-bottom: 1px solid var(--bgl-tabs-flat-indicator-color);
174
205
  border-radius: 0;
@@ -176,36 +207,95 @@ onBeforeUnmount(() => {
176
207
  bottom: unset;
177
208
 
178
209
  }
179
- .bgl_flat-tabs .active.bgl_tab{
210
+ .bgl_flat-tabs .active.bgl_tab {
180
211
  color: var(--bgl-primary)
181
212
  }
213
+
182
214
  .bgl_flat-tabs .bgl_tab:hover {
183
215
  background: rgba(255, 255, 255, .1);
184
216
  }
185
- .bgl_vertical-tabs{
217
+ .bgl_tab-thin {
218
+ padding-inline: calc(var(--bgl_tab-inline-padding) / 2);
219
+ height: calc(var(--btn-height) * 0.7 - var(--bgl_tabs-block-padding) * 2);
220
+ }
221
+
222
+ .bgl_tab-xs {
223
+ padding-inline: calc(var(--bgl_tab-inline-padding) / 3);
224
+ font-size: calc(var(--input-font-size) * 0.6);
225
+ height: calc(var(--btn-height) * 0.5 - var(--bgl_tabs-block-padding) * 2);
226
+ }
227
+
228
+ .bgl_tab-s {
229
+ padding-inline: calc(var(--bgl_tab-inline-padding) / 1.5);
230
+ height: calc(var(--btn-height) * 0.7 - var(--bgl_tabs-block-padding) * 2);
231
+ }
232
+
233
+ .bgl_tab-l {
234
+ padding-inline: calc(var(--bgl_tab-inline-padding) * 1.3);
235
+ font-size: calc(var(--input-font-size) * 1.1);
236
+ height: calc(var(--btn-height) * 1.2 - var(--bgl_tabs-block-padding) * 2);
237
+ }
238
+
239
+ .bgl_tab-xl {
240
+ padding-inline: calc(var(--bgl_tab-inline-padding) * 1.6);
241
+ font-size: calc(var(--input-font-size) * 1.3);
242
+ height: calc(var(--btn-height) * 1.5 - var(--bgl_tabs-block-padding) * 2);
243
+ }
244
+
245
+ .bgl_tab-align-start {
246
+ justify-content: flex-start !important;
247
+ }
248
+
249
+ .bgl_tab-align-end {
250
+ justify-content: flex-end !important;
251
+ }
252
+
253
+ .bgl_tab-align-center {
254
+ justify-content: center !important;
255
+ }
256
+
257
+ .bgl_tab-align-start-mobile,
258
+ .bgl_tab-align-end-mobile {
259
+ justify-content: center !important;
260
+ }
261
+
262
+ .bgl_vertical-tabs {
186
263
  grid-auto-flow: row;
187
264
  align-items: start;
188
265
  justify-items: start;
189
266
  gap: 1rem
190
267
  }
191
- .bgl_vertical-tabs .bgl_tab{
268
+ .bgl_vertical-tabs .bgl_tab {
192
269
  padding-inline: 0;
193
270
  border-radius: 0;
194
271
  border-bottom: 1px solid transparent;
195
272
  }
196
- .bgl_vertical-tabs .bgl_tab:hover{
273
+ .bgl_vertical-tabs .bgl_tab:hover {
197
274
  background: transparent;
198
275
  border-bottom: 1px solid var(--bgl-tabs-flat-indicator-color);
199
276
 
200
277
  }
201
- .bgl_vertical-tabs .bgl_tab.active{
278
+ .bgl_vertical-tabs .bgl_tab.active {
202
279
  border-bottom: 1px solid var(--bgl-tabs-flat-indicator-color);
203
280
  }
204
- .bgl_vertical-tabs.bgl_tabs_wrap::before{
281
+ .bgl_vertical-tabs.bgl_tabs_wrap::before {
205
282
  border: none;
206
283
  }
284
+
207
285
  @media screen and (max-width: 910px) {
208
- .bgl_vertical-tabs{
286
+ .bgl_tab-align-start-mobile {
287
+ justify-content: flex-start !important;
288
+ }
289
+
290
+ .bgl_tab-align-end-mobile {
291
+ justify-content: flex-end !important;
292
+ }
293
+
294
+ .bgl_tab-align-center-mobile {
295
+ justify-content: center !important;
296
+ }
297
+
298
+ .bgl_vertical-tabs {
209
299
  grid-auto-flow: column;
210
300
  overflow: auto;
211
301
  max-width: 100vw;
@@ -214,15 +304,17 @@ onBeforeUnmount(() => {
214
304
  gap: 1rem;
215
305
  position: relative;
216
306
  }
307
+
217
308
  .bgl_vertical-tabs::-webkit-scrollbar {
218
309
  display: none;
219
310
  }
220
- .bgl_vertical-tabs .bgl_tab{
311
+ .bgl_vertical-tabs .bgl_tab {
221
312
  white-space: nowrap;
222
313
  }
223
- .bgl_tab {
224
- gap: 0.25rem;
225
- padding: 0.25rem 0.5rem;
226
- }
314
+
315
+ .bgl_tab {
316
+ gap: 0.25rem;
317
+ padding: 0.25rem 0.5rem;
318
+ }
227
319
  }
228
320
  </style>
@@ -1,5 +1,6 @@
1
1
  <!-- prettier-ignore-start -->
2
2
  <!-- eslint-disable -->
3
+ <!-- eslint-disable vue/multi-word-component-names -->
3
4
  <script setup lang="ts">
4
5
  import type { DialogWidth, DialogPosition } from './dialogTypes'
5
6
  import { Btn } from '@bagelink/vue'
@@ -171,6 +172,7 @@ dialog {
171
172
  grid-template-rows: auto 1fr auto;
172
173
  overflow: hidden;
173
174
  border-radius: var(--bgl-card-radius, 12px);
175
+ height: 100%;
174
176
  }
175
177
 
176
178
  .height-100-2 {
@@ -404,6 +404,7 @@ export const $ = {
404
404
  collapsible?: boolean
405
405
  min?: number
406
406
  max?: number
407
+ simple?: boolean
407
408
  }),
408
409
  maybeConfig?: BaseFieldConfig & {
409
410
  allowAdd?: boolean
@@ -412,6 +413,7 @@ export const $ = {
412
413
  collapsible?: boolean
413
414
  min?: number
414
415
  max?: number
416
+ simple?: boolean
415
417
  }
416
418
  ): FieldBuilder<any[]> {
417
419
  // Label-first: $.array('Items', schema) or $.array('Items', schema, { min: 1 })
@@ -463,5 +463,30 @@
463
463
  "phone": "Phone"
464
464
  }
465
465
  }
466
+ },
467
+ "calendar": {
468
+ "today": "Today",
469
+ "views": {
470
+ "week": "Week",
471
+ "month": "Month",
472
+ "day": "Day",
473
+ "agenda": "Agenda"
474
+ },
475
+ "agenda": {
476
+ "time": "Time",
477
+ "event": "Event",
478
+ "eventsCount": "{n} event | {n} events",
479
+ "noEvents": "No events"
480
+ }
481
+ },
482
+ "addToCalendar": {
483
+ "addTo": "Add to {name}",
484
+ "addToCalendar": "Add to Calendar",
485
+ "google": "Google Calendar",
486
+ "apple": "Apple Calendar",
487
+ "outlook": "Outlook",
488
+ "office365": "Office 365",
489
+ "yahoo": "Yahoo Calendar",
490
+ "ics": "Calendar (ICS file)"
466
491
  }
467
492
  }
@@ -248,5 +248,24 @@
248
248
  "deleteInviteConfirm": "¿Eliminar la invitación?",
249
249
  "deleteInviteError": "Error al eliminar la invitación",
250
250
  "removeUserConfirm": "¿Eliminar a {email}?"
251
+ },
252
+ "calendar": {
253
+ "today": "Hoy",
254
+ "views": {
255
+ "week": "Semana",
256
+ "month": "Mes",
257
+ "day": "Día",
258
+ "agenda": "Agenda"
259
+ },
260
+ "agenda": {
261
+ "time": "Hora",
262
+ "event": "Evento",
263
+ "eventsCount": "{n} evento | {n} eventos",
264
+ "noEvents": "Sin eventos"
265
+ }
266
+ },
267
+ "addToCalendar": {
268
+ "addTo": "Agregar a {name}",
269
+ "addToCalendar": "Agregar al calendario"
251
270
  }
252
271
  }
@@ -247,6 +247,24 @@
247
247
  "inviteError": "Erreur lors de l'envoi de l'invitation",
248
248
  "deleteInviteConfirm": "Supprimer l'invitation ?",
249
249
  "deleteInviteError": "Erreur lors de la suppression de l'invitation",
250
- "removeUserConfirm": "Retirer {email} ?"
250
+ "removeUserConfirm": "Retirer {email} ?" },
251
+ "calendar": {
252
+ "today": "Aujourd'hui",
253
+ "views": {
254
+ "week": "Semaine",
255
+ "month": "Mois",
256
+ "day": "Jour",
257
+ "agenda": "Agenda"
258
+ },
259
+ "agenda": {
260
+ "time": "Heure",
261
+ "event": "Événement",
262
+ "eventsCount": "{n} événement | {n} événements",
263
+ "noEvents": "Aucun événement"
264
+ }
265
+ },
266
+ "addToCalendar": {
267
+ "addTo": "Ajouter à {name}",
268
+ "addToCalendar": "Ajouter au calendrier"
251
269
  }
252
270
  }
@@ -484,5 +484,30 @@
484
484
  "phone": "טלפון"
485
485
  }
486
486
  }
487
+ },
488
+ "calendar": {
489
+ "today": "היום",
490
+ "views": {
491
+ "week": "שבוע",
492
+ "month": "חודש",
493
+ "day": "יום",
494
+ "agenda": "סדר יום"
495
+ },
496
+ "agenda": {
497
+ "time": "שעה",
498
+ "event": "אירוע",
499
+ "eventsCount": "אירוע אחד | {n} אירועים",
500
+ "noEvents": "אין אירועים"
501
+ }
502
+ },
503
+ "addToCalendar": {
504
+ "addTo": "הוסף ל{name}",
505
+ "addToCalendar": "הוסף ליומן",
506
+ "google": "יומן Google",
507
+ "apple": "יומן Apple",
508
+ "outlook": "Outlook",
509
+ "office365": "Office 365",
510
+ "yahoo": "יומן Yahoo",
511
+ "ics": "יומן (קובץ ICS)"
487
512
  }
488
513
  }
@@ -248,5 +248,24 @@
248
248
  "deleteInviteConfirm": "Eliminare l'invito?",
249
249
  "deleteInviteError": "Errore durante l'eliminazione dell'invito",
250
250
  "removeUserConfirm": "Rimuovere {email}?"
251
+ },
252
+ "calendar": {
253
+ "today": "Oggi",
254
+ "views": {
255
+ "week": "Settimana",
256
+ "month": "Mese",
257
+ "day": "Giorno",
258
+ "agenda": "Agenda"
259
+ },
260
+ "agenda": {
261
+ "time": "Ora",
262
+ "event": "Evento",
263
+ "eventsCount": "{n} evento | {n} eventi",
264
+ "noEvents": "Nessun evento"
265
+ }
266
+ },
267
+ "addToCalendar": {
268
+ "addTo": "Aggiungi a {name}",
269
+ "addToCalendar": "Aggiungi al calendario"
251
270
  }
252
271
  }
@@ -248,5 +248,24 @@
248
248
  "deleteInviteConfirm": "Удалить приглашение?",
249
249
  "deleteInviteError": "Ошибка при удалении приглашения",
250
250
  "removeUserConfirm": "Удалить {email}?"
251
+ },
252
+ "calendar": {
253
+ "today": "Сегодня",
254
+ "views": {
255
+ "week": "Неделя",
256
+ "month": "Месяц",
257
+ "day": "День",
258
+ "agenda": "Повестка"
259
+ },
260
+ "agenda": {
261
+ "time": "Время",
262
+ "event": "Событие",
263
+ "eventsCount": "{n} событие | {n} события | {n} событий",
264
+ "noEvents": "Нет событий"
265
+ }
266
+ },
267
+ "addToCalendar": {
268
+ "addTo": "Добавить в {name}",
269
+ "addToCalendar": "Добавить в календарь"
251
270
  }
252
271
  }
@@ -523,6 +523,7 @@ export interface ArrayAttrs<T, P extends Path<T>> extends Attributes<T, P> {
523
523
  add?: boolean
524
524
  schema?: MaybeRefOrGetter<BglFormSchemaT<ArrayFieldVal<T, P>>>
525
525
  type?: ArrayType
526
+ simple?: boolean
526
527
  }
527
528
 
528
529
  export interface ArrayFieldOptions<T, K extends Path<T>> extends InputOptions<T, K>, ArrayAttrs<T, K> {}
@@ -1,8 +1,8 @@
1
1
  import type { TimeUnit } from '../../types/timeAgoT'
2
- import { timeDelta, formatDate, fmtDate, handleTimezone, getDatePartsMap } from '@bagelink/utils'
2
+ import { timeDelta, formatDate, fmtDate, handleTimezone, getDatePartsMap, utc, local } from '@bagelink/utils'
3
3
  import { getI18n } from '../../i18n'
4
4
 
5
- export { fmtDate, formatDate, getDatePartsMap, handleTimezone, timeDelta }
5
+ export { fmtDate, formatDate, getDatePartsMap, handleTimezone, timeDelta, utc, local }
6
6
  export type { DateTimeAcceptedFormats, FormatDateOptions } from '@bagelink/utils'
7
7
 
8
8
  type TimeAgoLang = 'en' | 'es' | 'fr' | 'he' | 'it' | 'ru'