@bagelink/vue 1.15.301 → 1.15.303

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bagelink/vue",
3
3
  "type": "module",
4
- "version": "1.15.301",
4
+ "version": "1.15.303",
5
5
  "description": "Bagel core sdk packages",
6
6
  "author": {
7
7
  "name": "Bagel Studio",
@@ -65,6 +65,7 @@ function toggle() {
65
65
  <template>
66
66
  <div class="accordion-item txt-start" :class="[{ flat }]">
67
67
  <button
68
+ type="button"
68
69
  :aria-expanded="isOpen ? 'true' : 'false'" class="accordion-head"
69
70
  :aria-controls="`accordion-body-${id}`" @click="toggle()"
70
71
  >
@@ -652,6 +652,7 @@ function onConnectorChange(id: string, connector: LogicalOperator) {
652
652
  .and-or-select {
653
653
  --bgl-input-font-size: 12px !important;
654
654
  --input-background-color: transparent !important;
655
+ min-width: 60px !important;
655
656
  }
656
657
 
657
658
  .between-inputs {
@@ -706,11 +707,11 @@ max-height: none;
706
707
  }
707
708
 
708
709
  .filter-query-inline .filter-row {
709
- grid-template-columns: 50px minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr) auto;
710
+ grid-template-columns: 60px minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr) auto;
710
711
  }
711
712
 
712
713
  .filter-query-inline .first-filter-row {
713
- grid-template-columns: 50px minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr) auto;
714
+ grid-template-columns: 60px minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr) auto;
714
715
  }
715
716
 
716
717
  .filter-query-inline .first-filter-field {
@@ -167,7 +167,7 @@ watch(() => props.modelValue, () => {
167
167
 
168
168
  <template>
169
169
  <div
170
- class="bagel-input code-editor-container ltr" :class="[shellClass, { 'mb-2': label && !singleLine, 'has-value': hasCodeValue, 'single-line': singleLine }]"
170
+ class="bagel-input code-editor-container ltr" :class="[shellClass, { '': label && !singleLine, 'has-value': hasCodeValue, 'single-line': singleLine }]"
171
171
  :style="[{ height: maxHeight }, shellStyle]"
172
172
  >
173
173
  <label v-if="label" class="label">{{ label }}</label>
@@ -225,6 +225,12 @@ watch(() => props.modelValue, () => {
225
225
  outline: solid 1px var(--bgl-border-color, #4f575f);
226
226
  box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.13);
227
227
  }
228
+ .code-editor-grandpa textarea.code-input{
229
+ box-shadow: none !important;
230
+ background: transparent !important;
231
+ border-radius: 0 !important;
232
+
233
+ }
228
234
 
229
235
  .editor-content-papa {
230
236
  /* Stack pre + textarea in one cell so both share the content-sized box */
@@ -0,0 +1,120 @@
1
+ <script setup lang="ts">
2
+ import { computed, onBeforeUnmount, ref, watch } from 'vue'
3
+ import { Dropdown, EmptyState, Icon, TabsNav, TextInput } from '@bagelink/vue'
4
+ import { FONT_AWESOME_BRANDS_ICONS, FONT_AWESOME_ICONS, MATERIAL_ICONS } from '../../Icon/constants'
5
+
6
+ defineProps<{
7
+ modelValue?: string
8
+ label?: string
9
+ placeholder?: string
10
+ }>()
11
+
12
+ const emit = defineEmits<{
13
+ 'update:modelValue': [value: string | undefined]
14
+ }>()
15
+
16
+ const dropdown = ref<InstanceType<typeof Dropdown> | null>(null)
17
+ const search = ref('')
18
+ const activeTab = ref<'material' | 'fa' | 'brands'>('material')
19
+ const visibleCount = ref(80)
20
+ const tabsGroup = `icon-picker-${Math.random().toString(36).slice(2)}`
21
+ let batchTimer: ReturnType<typeof setTimeout> | undefined
22
+
23
+ const tabs = [
24
+ { label: 'Material', value: 'material' },
25
+ { label: 'FA', value: 'fa' },
26
+ { label: 'Brands', value: 'brands' },
27
+ ]
28
+
29
+ const iconSets = {
30
+ material: MATERIAL_ICONS,
31
+ fa: FONT_AWESOME_ICONS,
32
+ brands: FONT_AWESOME_BRANDS_ICONS,
33
+ }
34
+
35
+ const filteredIcons = computed(() => {
36
+ const query = search.value.trim().toLowerCase()
37
+ const icons = iconSets[activeTab.value]
38
+ return query ? icons.filter(icon => icon.includes(query)) : icons
39
+ })
40
+
41
+ const visibleIcons = computed(() => filteredIcons.value.slice(0, visibleCount.value))
42
+
43
+ function loadMore() {
44
+ if (visibleCount.value >= filteredIcons.value.length) return
45
+ batchTimer = setTimeout(() => {
46
+ visibleCount.value = Math.min(visibleCount.value + 80, filteredIcons.value.length)
47
+ loadMore()
48
+ }, 16)
49
+ }
50
+
51
+ function resetAndLoad() {
52
+ if (batchTimer) clearTimeout(batchTimer)
53
+ visibleCount.value = 80
54
+ loadMore()
55
+ }
56
+
57
+ function select(icon: string) {
58
+ emit('update:modelValue', icon)
59
+ dropdown.value?.hide()
60
+ search.value = ''
61
+ }
62
+
63
+ function clear() {
64
+ emit('update:modelValue', undefined)
65
+ }
66
+
67
+ watch([activeTab, search], resetAndLoad)
68
+ onBeforeUnmount(() => {
69
+ if (batchTimer) clearTimeout(batchTimer)
70
+ })
71
+ </script>
72
+
73
+ <template>
74
+ <div class="bagel-input">
75
+ <label v-if="label" class="block txt12 medium pb-025">{{ label }}</label>
76
+ <Dropdown
77
+ ref="dropdown"
78
+ placement="bottom-start"
79
+ :auto-hide="true"
80
+ @show="resetAndLoad"
81
+ @hide="search = ''"
82
+ >
83
+ <template #trigger="{ shown, show, hide }">
84
+ <div class="icon-picker-trigger flex gap-05 w-100p bg-input px-075 rounded hover" @click="shown ? hide() : show()">
85
+ <span class="square-20 flex-center flex-shrink-0">
86
+ <Icon v-if="modelValue" :icon="modelValue" :size="1.1" />
87
+ <span v-else class="txt11 opacity-4">—</span>
88
+ </span>
89
+ <span class="txt12 flex-grow opacity-6 ellipsis-1">{{ modelValue || placeholder || 'Choose an icon' }}</span>
90
+ <Icon v-if="modelValue" icon="close" :size="0.9" class="opacity-5 hover-opacity-10" @click.stop="clear" />
91
+ <Icon :icon="shown ? 'expand_less' : 'expand_more'" :size="1" class="opacity-4" />
92
+ </div>
93
+ </template>
94
+
95
+ <div class="w-300px overflow-hidden">
96
+ <TabsNav v-model="activeTab" :tabs="tabs" :group="tabsGroup" flat class="round-none w-100p mx-0 txt-center" />
97
+ <TextInput v-model="search" icon-start="search" placeholder="Search icons" class="mb-0" />
98
+ <div class="grid grid-wrap-7 gap-025 p-05 overflow max-h-300px">
99
+ <div
100
+ v-for="icon in visibleIcons"
101
+ :key="icon"
102
+ class="square-40 flex-center hover rounded relative overflow-hidden"
103
+ :class="modelValue === icon ? 'bg-primary-light color-primary' : 'bg-box'"
104
+ :title="icon"
105
+ @click="select(icon)"
106
+ >
107
+ <Icon :icon="icon" :size="1.2" />
108
+ </div>
109
+ </div>
110
+ <EmptyState v-if="visibleIcons.length === 0" compact icon="none" description="No icons found" />
111
+ </div>
112
+ </Dropdown>
113
+ </div>
114
+ </template>
115
+
116
+ <style scoped>
117
+ .icon-picker-trigger {
118
+ height: var(--bgl-input-height);
119
+ }
120
+ </style>
@@ -7,6 +7,7 @@ export { default as ColorInput } from './ColorInput.vue'
7
7
  export { default as DateInput } from './DateInput.vue'
8
8
  export { default as DatePicker } from './DatePicker.vue'
9
9
  export { default as EmailInput } from './EmailInput.vue'
10
+ export { default as IconPickerInput } from './IconPickerInput.vue'
10
11
  export { default as MarkdownEditor } from './MarkdownEditor.vue'
11
12
  export { default as NumberInput } from './NumberInput.vue'
12
13
  export { default as OTP } from './OTP.vue'
@@ -434,6 +434,9 @@ padding-inline: 0.75rem;
434
434
  .pageContent--border {
435
435
  padding-top: 1rem;
436
436
  }
437
+ .pageContent--border:has(.pageContentFull) {
438
+ padding: 0rem;
439
+ }
437
440
  .pageContent--card {
438
441
  padding-top: 0.25rem;
439
442
  }
@@ -445,6 +448,9 @@ padding-top: 0;
445
448
  .pageContent--m-border {
446
449
  padding-top: 0.25rem;
447
450
  }
451
+ .pageContent:has(.p-0) {
452
+ padding-block: 0rem !important;
453
+ }
448
454
  .pageContent--m-card {
449
455
  padding-top: 0.25rem;
450
456
  }
@@ -7,6 +7,7 @@ import CodeEditor from '../components/form/inputs/CodeEditor/Index.vue'
7
7
  import ColorInput from '../components/form/inputs/ColorInput.vue'
8
8
  import DateInput from '../components/form/inputs/DateInput.vue'
9
9
  import EmailInput from '../components/form/inputs/EmailInput.vue'
10
+ import IconPickerInput from '../components/form/inputs/IconPickerInput.vue'
10
11
  import NumberInput from '../components/form/inputs/NumberInput.vue'
11
12
  import PasswordInput from '../components/form/inputs/PasswordInput.vue'
12
13
  import RadioGroup from '../components/form/inputs/RadioGroup.vue'
@@ -283,6 +284,7 @@ function getFieldComponent(fieldOrType: FieldBuilder | string) {
283
284
  array: ArrayInput,
284
285
  upload: UploadInput,
285
286
  color: ColorInput,
287
+ icon: IconPickerInput,
286
288
  range: RangeInput,
287
289
  }
288
290
 
@@ -371,6 +371,10 @@ export const $ = {
371
371
  return new Field('color', parseArgs(labelOrConfig, config))
372
372
  },
373
373
 
374
+ icon(labelOrConfig?: string | BaseFieldConfig, config?: BaseFieldConfig): FieldBuilder<string> {
375
+ return new Field('icon', parseArgs(labelOrConfig, config))
376
+ },
377
+
374
378
  range(
375
379
  labelOrConfig?: string | (BaseFieldConfig & { min?: number, max?: number, step?: number, multiRange?: boolean }),
376
380
  config?: BaseFieldConfig & { min?: number, max?: number, step?: number, multiRange?: boolean }
@@ -1031,6 +1035,9 @@ function createFieldFromProperty(
1031
1035
  case 'multiselect':
1032
1036
  field = $.multiselect(xOptions ?? resolvedProp.enum ?? [], config)
1033
1037
  break
1038
+ case 'icon':
1039
+ field = $.icon(config)
1040
+ break
1034
1041
  case 'file':
1035
1042
  case 'upload':
1036
1043
  field = $.upload(config)