@bagelink/vue 0.0.354 → 0.0.358

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.
@@ -1,9 +1,16 @@
1
1
  <template>
2
- <div v-if="editor">
3
- <Btn :flat="!editor.isActive(item.name, item.option)" @click="item.command" thin v-for="item in config"
4
- v-tooltip="item.name" :key="item.name" :icon="item.icon" :disabled="item.disabled?.()" />
5
- </div>
6
- <editor-content :editor="editor" />
2
+ <div v-if="editor">
3
+ <Btn
4
+ :flat="!editor.isActive(item.name, item.option)"
5
+ @click="item.command"
6
+ thin
7
+ v-for="item in config"
8
+ v-tooltip="item.name"
9
+ :key="item.name"
10
+ :icon="item.icon"
11
+ :disabled="item.disabled?.()" />
12
+ </div>
13
+ <editor-content :editor="editor" />
7
14
  </template>
8
15
 
9
16
  <script setup lang="ts">
@@ -18,144 +25,143 @@ let editor = $ref<Editor>();
18
25
  const props = defineProps<{ modelValue: string }>();
19
26
 
20
27
  const focus = () => {
21
- if (!editor) throw new Error('editor is not defined');
22
- return editor.chain().focus();
28
+ if (!editor) throw new Error('editor is not defined');
29
+ return editor.chain().focus();
23
30
  };
24
31
 
25
- const config: { name: string, command: any, icon: MaterialIcons, option?: Record<string, any>, disabled?: () => boolean }[] = [
26
- {
27
- name: 'bold',
28
- command: () => focus()?.toggleBold().run(),
29
- icon: 'format_bold',
30
- disabled: () => !editor?.can().chain().focus().toggleBold()
31
- .run(),
32
- },
33
- {
34
- name: 'italic',
35
- command: () => focus().toggleItalic().run(),
36
- icon: 'format_italic',
37
- disabled: () => !editor?.can().chain().focus().toggleItalic()
38
- .run(),
39
- },
40
- {
41
- name: 'strike',
42
- command: () => focus().toggleStrike().run(),
43
- icon: 'format_strikethrough',
44
- disabled: () => !editor?.can().chain().focus().toggleStrike()
45
- .run(),
46
- },
47
- {
48
- name: 'code',
49
- command: () => focus().toggleCode().run(),
50
- icon: 'code',
51
- },
52
- {
53
- name: 'clearMarks',
54
- command: () => focus().unsetAllMarks(),
55
- icon: 'clear',
56
-
57
- },
58
- {
59
- name: 'clearNodes',
60
- command: () => focus().clearNodes().run(),
61
- icon: 'clear',
62
- },
63
- {
64
- name: 'paragraph',
65
- command: () => focus().setParagraph().run(),
66
- icon: 'format_paragraph',
67
- },
68
- {
69
- name: 'heading',
70
- command: () => focus().toggleHeading({ level: 1 }).run(),
71
- icon: 'format_h1',
72
- option: { level: 1 },
73
- },
74
- {
75
- name: 'heading',
76
- command: () => focus().toggleHeading({ level: 2 }).run(),
77
- icon: 'format_h2',
78
- option: { level: 2 },
79
- },
80
- {
81
- name: 'heading',
82
- command: () => focus().toggleHeading({ level: 3 }).run(),
83
- icon: 'format_h3',
84
- option: { level: 3 },
85
- },
86
- {
87
- name: 'heading',
88
- command: () => focus().toggleHeading({ level: 4 }).run(),
89
- icon: 'format_h4',
90
- option: { level: 4 },
91
- },
92
- {
93
- name: 'heading',
94
- command: () => focus().toggleHeading({ level: 5 }).run(),
95
- icon: 'format_h5',
96
- option: { level: 5 },
97
- },
98
- {
99
- name: 'heading',
100
- command: () => focus().toggleHeading({ level: 6 }).run(),
101
- icon: 'format_h6',
102
- option: { level: 6 },
103
- },
104
- {
105
- name: 'bulletList',
106
- command: () => focus().toggleBulletList().run(),
107
- icon: 'format_list_bulleted',
108
- },
109
- {
110
- name: 'orderedList',
111
- command: () => focus().toggleOrderedList().run(),
112
- icon: 'format_list_numbered',
113
- },
114
- {
115
- name: 'codeBlock',
116
- command: () => focus().toggleCodeBlock().run(),
117
- icon: 'code',
118
- },
119
- {
120
- name: 'blockquote',
121
- command: () => focus().toggleBlockquote().run(),
122
- icon: 'format_quote',
123
- },
124
- {
125
- name: 'horizontalRule',
126
- command: () => focus().setHorizontalRule().run(),
127
- icon: 'horizontal_rule',
128
- },
129
- {
130
- name: 'hardBreak',
131
- command: () => focus().setHardBreak().run(),
132
- icon: 'keyboard_return',
133
-
134
- },
135
- {
136
- name: 'undo',
137
- command: () => focus().undo().run(),
138
- icon: 'undo',
139
- disabled: () => !editor?.can().chain().focus().undo()
140
- .run(),
141
- },
142
- {
143
- name: 'redo',
144
- command: () => focus().redo().run(),
145
- icon: 'redo',
146
- disabled: () => !editor?.can().chain().focus().redo()
147
- .run(),
148
- },
32
+ const config: {
33
+ name: string;
34
+ command: any;
35
+ icon: MaterialIcons;
36
+ option?: Record<string, any>;
37
+ disabled?: () => boolean;
38
+ }[] = [
39
+ {
40
+ name: 'bold',
41
+ command: () => focus()?.toggleBold().run(),
42
+ icon: 'format_bold',
43
+ disabled: () => !editor?.can().chain().focus().toggleBold().run(),
44
+ },
45
+ {
46
+ name: 'italic',
47
+ command: () => focus().toggleItalic().run(),
48
+ icon: 'format_italic',
49
+ disabled: () => !editor?.can().chain().focus().toggleItalic().run(),
50
+ },
51
+ {
52
+ name: 'strike',
53
+ command: () => focus().toggleStrike().run(),
54
+ icon: 'format_strikethrough',
55
+ disabled: () => !editor?.can().chain().focus().toggleStrike().run(),
56
+ },
57
+ {
58
+ name: 'code',
59
+ command: () => focus().toggleCode().run(),
60
+ icon: 'code',
61
+ },
62
+ {
63
+ name: 'clearMarks',
64
+ command: () => focus().unsetAllMarks(),
65
+ icon: 'clear',
66
+ },
67
+ {
68
+ name: 'clearNodes',
69
+ command: () => focus().clearNodes().run(),
70
+ icon: 'clear',
71
+ },
72
+ {
73
+ name: 'paragraph',
74
+ command: () => focus().setParagraph().run(),
75
+ icon: 'format_paragraph',
76
+ },
77
+ {
78
+ name: 'heading',
79
+ command: () => focus().toggleHeading({ level: 1 }).run(),
80
+ icon: 'format_h1',
81
+ option: { level: 1 },
82
+ },
83
+ {
84
+ name: 'heading',
85
+ command: () => focus().toggleHeading({ level: 2 }).run(),
86
+ icon: 'format_h2',
87
+ option: { level: 2 },
88
+ },
89
+ {
90
+ name: 'heading',
91
+ command: () => focus().toggleHeading({ level: 3 }).run(),
92
+ icon: 'format_h3',
93
+ option: { level: 3 },
94
+ },
95
+ {
96
+ name: 'heading',
97
+ command: () => focus().toggleHeading({ level: 4 }).run(),
98
+ icon: 'format_h4',
99
+ option: { level: 4 },
100
+ },
101
+ {
102
+ name: 'heading',
103
+ command: () => focus().toggleHeading({ level: 5 }).run(),
104
+ icon: 'format_h5',
105
+ option: { level: 5 },
106
+ },
107
+ {
108
+ name: 'heading',
109
+ command: () => focus().toggleHeading({ level: 6 }).run(),
110
+ icon: 'format_h6',
111
+ option: { level: 6 },
112
+ },
113
+ {
114
+ name: 'bulletList',
115
+ command: () => focus().toggleBulletList().run(),
116
+ icon: 'format_list_bulleted',
117
+ },
118
+ {
119
+ name: 'orderedList',
120
+ command: () => focus().toggleOrderedList().run(),
121
+ icon: 'format_list_numbered',
122
+ },
123
+ {
124
+ name: 'codeBlock',
125
+ command: () => focus().toggleCodeBlock().run(),
126
+ icon: 'code',
127
+ },
128
+ {
129
+ name: 'blockquote',
130
+ command: () => focus().toggleBlockquote().run(),
131
+ icon: 'format_quote',
132
+ },
133
+ {
134
+ name: 'horizontalRule',
135
+ command: () => focus().setHorizontalRule().run(),
136
+ icon: 'horizontal_rule',
137
+ },
138
+ {
139
+ name: 'hardBreak',
140
+ command: () => focus().setHardBreak().run(),
141
+ icon: 'keyboard_return',
142
+ },
143
+ {
144
+ name: 'undo',
145
+ command: () => focus().undo().run(),
146
+ icon: 'undo',
147
+ disabled: () => !editor?.can().chain().focus().undo().run(),
148
+ },
149
+ {
150
+ name: 'redo',
151
+ command: () => focus().redo().run(),
152
+ icon: 'redo',
153
+ disabled: () => !editor?.can().chain().focus().redo().run(),
154
+ },
149
155
  ];
150
156
 
151
157
  const emit = defineEmits(['update:modelValue']);
152
158
 
153
159
  onMounted(() => {
154
- editor = new Editor({
155
- extensions: [StarterKit],
156
- content: props.modelValue,
157
- onUpdate: ({ editor }) => emit('update:modelValue', editor.getHTML()),
158
- });
160
+ editor = new Editor({
161
+ extensions: [StarterKit],
162
+ content: props.modelValue,
163
+ onUpdate: ({ editor }) => emit('update:modelValue', editor.getHTML()),
164
+ });
159
165
  });
160
166
 
161
167
  onBeforeUnmount(() => editor?.destroy());
@@ -163,13 +169,13 @@ onBeforeUnmount(() => editor?.destroy());
163
169
 
164
170
  <style>
165
171
  /* Basic editor styles */
166
- .tiptap>*+* {
167
- margin-top: 0.75em;
172
+ .tiptap > * + * {
173
+ margin-top: 0.75em;
168
174
  }
169
175
 
170
176
  .tiptap ul,
171
177
  .tiptap ol {
172
- padding: 0 1rem;
178
+ padding: 0 1rem;
173
179
  }
174
180
 
175
181
  .tiptap h1,
@@ -178,42 +184,47 @@ onBeforeUnmount(() => editor?.destroy());
178
184
  .tiptap h4,
179
185
  .tiptap h5,
180
186
  .tiptap h6 {
181
- line-height: 1.1;
187
+ line-height: 1.1;
182
188
  }
183
189
 
184
190
  .tiptap code {
185
- background-color: rgba(97, 97, 97, 0.1);
186
- color: #616161;
191
+ background-color: rgba(97, 97, 97, 0.1);
192
+ color: #616161;
187
193
  }
188
194
 
189
195
  .tiptap pre {
190
- background: #0d0d0d;
191
- color: #fff;
192
- font-family: 'JetBrainsMono', monospace;
193
- padding: 0.75rem 1rem;
194
- border-radius: 0.5rem;
196
+ background: #0d0d0d;
197
+ color: #fff;
198
+ font-family: 'JetBrainsMono', monospace;
199
+ padding: 0.75rem 1rem;
200
+ border-radius: 0.5rem;
195
201
  }
196
202
 
197
203
  .tiptap pre code {
198
- color: inherit;
199
- padding: 0;
200
- background: none;
201
- font-size: 0.8rem;
204
+ color: inherit;
205
+ padding: 0;
206
+ background: none;
207
+ font-size: 0.8rem;
202
208
  }
203
209
 
204
210
  .tiptap img {
205
- max-width: 100%;
206
- height: auto;
211
+ max-width: 100%;
212
+ height: auto;
207
213
  }
208
214
 
209
215
  .tiptap blockquote {
210
- padding-left: 1rem;
211
- border-left: 2px solid rgba(13, 13, 13, 0.1);
216
+ padding-left: 1rem;
217
+ border-left: 2px solid rgba(13, 13, 13, 0.1);
212
218
  }
213
219
 
214
220
  .tiptap hr {
215
- border: none;
216
- border-top: 2px solid rgba(13, 13, 13, 0.1);
217
- margin: 2rem 0;
221
+ border: none;
222
+ border-top: 2px solid rgba(13, 13, 13, 0.1);
223
+ margin: 2rem 0;
224
+ }
225
+
226
+ .tiptap {
227
+ min-height: 500px;
228
+ background: var(--input-bg);
218
229
  }
219
230
  </style>
@@ -3,8 +3,7 @@
3
3
  @hide="updateOpen(false)"
4
4
  ref="dropdown"
5
5
  placement="bottom-start"
6
- class="bagel-input selectinput"
7
- >
6
+ class="bagel-input selectinput">
8
7
  <label>
9
8
  {{ label }}
10
9
  <button
@@ -12,44 +11,39 @@
12
11
  :disabled="disabled"
13
12
  type="button"
14
13
  class="selectinput-btn"
15
- :class="{isEmpty: selectedItems.length ===0}"
16
- >
14
+ :class="{ isEmpty: selectedItems.length === 0 }">
17
15
  <p>{{ selectedLabel }}</p>
18
16
  <Icon v-bind="{ icon: open ? 'unfold_less' : 'unfold_more' }" />
19
17
  </button>
20
18
  <input
21
19
  style="width: 0; height: 0; position: absolute; opacity: 0; z-index: -1"
22
20
  v-if="required"
23
- v-model="selectedItems"
24
- required
25
- >
21
+ @input="updateOpen(true)"
22
+ :value="selectedItems"
23
+ required />
26
24
  </label>
27
25
  <template #popper="{ hide }">
28
26
  <Card
29
27
  class="selectinput-options p-05"
30
- :style="{ width: fullWidth ? '100%' : 'auto' }"
31
- >
28
+ :style="{ width: fullWidth ? '100%' : 'auto' }">
32
29
  <TextInput
33
30
  v-if="searchable"
34
31
  ref="searchInput"
35
32
  dense
36
33
  :placeholder="'Search'"
37
34
  icon="search"
38
- v-model="search"
39
- />
35
+ v-model="search" />
40
36
  <div
41
37
  class="selectinput-option hover gap-1"
42
38
  v-for="(option, i) in filteredOptions"
43
39
  :key="`${option}${i}`"
44
40
  @click="select(option)"
45
- :class="{ selected: isSelected(option) }"
46
- >
41
+ :class="{ selected: isSelected(option) }">
47
42
  <Icon v-if="isSelected(option)" icon="check" />
48
43
  <Icon
49
44
  class="opacity-3"
50
45
  v-if="!isSelected(option)"
51
- icon="fiber_manual_record"
52
- />
46
+ icon="fiber_manual_record" />
53
47
  <span>
54
48
  {{ getLabel(option) }}
55
49
  </span>
@@ -99,7 +93,7 @@ function updateOpen(visible: boolean) {
99
93
  else {
100
94
  setTimeout(
101
95
  () => (searchInput as any)?.$el?.querySelector('input')?.focus(),
102
- 100,
96
+ 100
103
97
  );
104
98
  }
105
99
  }
@@ -130,18 +124,23 @@ const getValue = (option: Option) => {
130
124
  return option.value;
131
125
  };
132
126
 
133
- const isSelected = (option: Option) => !!selectedItems.find((item) => getValue(option) === getValue(item));
127
+ const isSelected = (option: Option) =>
128
+ !!selectedItems.find((item) => getValue(option) === getValue(item));
134
129
 
135
- const filteredOptions = $computed(() => props.options.filter((option) => {
136
- const searchTerm = new RegExp(search, 'gi');
137
- return (
138
- Boolean(option) &&
130
+ const filteredOptions = $computed(() =>
131
+ props.options.filter((option) => {
132
+ const searchTerm = new RegExp(search, 'gi');
133
+ return (
134
+ Boolean(option) &&
139
135
  (getLabel(option).match(searchTerm) || getValue(option).match(searchTerm))
140
- );
141
- }));
136
+ );
137
+ })
138
+ );
142
139
 
143
140
  const select = (option: Option) => {
144
- const existingIndex = selectedItems.findIndex((item) => getValue(item) === getValue(option));
141
+ const existingIndex = selectedItems.findIndex(
142
+ (item) => getValue(item) === getValue(option)
143
+ );
145
144
  if (existingIndex > -1) selectedItems.splice(existingIndex, 1);
146
145
  else if (props.multiselect) {
147
146
  selectedItems.push(option);
@@ -163,7 +162,9 @@ function emitUpdate() {
163
162
  }
164
163
 
165
164
  function compareArrays(arr1: Option[], arr2: Option[]) {
166
- const isSame = arr1.every((item: Option) => arr2.map((a) => getValue(a)).includes(getValue(item)));
165
+ const isSame = arr1.every((item: Option) =>
166
+ arr2.map((a) => getValue(a)).includes(getValue(item))
167
+ );
167
168
  return isSame;
168
169
  }
169
170
 
@@ -172,25 +173,32 @@ watch(
172
173
  (newVal: Option | Option[]) => {
173
174
  if (!newVal) return;
174
175
  if (!props.multiselect) {
175
- if (!isSelected(newVal)) selectedItems.splice(0, selectedItems.length, newVal);
176
+ if (!isSelected(newVal))
177
+ selectedItems.splice(0, selectedItems.length, newVal);
176
178
  } else {
177
179
  const isSame = compareArrays([newVal].flat(), selectedItems);
178
- if (!isSame) selectedItems.splice(0, selectedItems.length, [newVal].flat());
180
+ if (!isSame)
181
+ selectedItems.splice(0, selectedItems.length, [newVal].flat());
179
182
  }
180
183
  },
181
- { immediate: true },
184
+ { immediate: true }
182
185
  );
183
186
 
184
- watch(() => props.options, () => {
185
- const original = JSON.stringify(selectedItems);
186
- [...selectedItems].forEach((option, i) => {
187
- const exists = props.options.find((o) => getValue(o) === getValue(option));
188
- if (!exists) selectedItems.splice(i, 1);
189
- else selectedItems.splice(i, 1, exists);
190
- });
191
- const newSelection = JSON.stringify(selectedItems);
192
- if (original !== newSelection) emitUpdate();
193
- });
187
+ watch(
188
+ () => props.options,
189
+ () => {
190
+ const original = JSON.stringify(selectedItems);
191
+ [...selectedItems].forEach((option, i) => {
192
+ const exists = props.options.find(
193
+ (o) => getValue(o) === getValue(option)
194
+ );
195
+ if (!exists) selectedItems.splice(i, 1);
196
+ else selectedItems.splice(i, 1, exists);
197
+ });
198
+ const newSelection = JSON.stringify(selectedItems);
199
+ if (original !== newSelection) emitUpdate();
200
+ }
201
+ );
194
202
  </script>
195
203
 
196
204
  <style scoped>
@@ -218,7 +226,7 @@ watch(() => props.options, () => {
218
226
  .selectinput-option:hover {
219
227
  background: var(--bgl-gray-20);
220
228
  }
221
- .isEmpty p{
229
+ .isEmpty p {
222
230
  opacity: 0.3;
223
231
  }
224
232
  </style>
@@ -1,19 +1,38 @@
1
1
  <template>
2
2
  <TabsNav :tabs="tabs" :group="group" class="mb-05" />
3
3
  <div v-if="currentTab">
4
- <slot :name="currentTab" />
4
+ <template v-if="slots[currentTab]">
5
+ <slot :name="currentTab" />
6
+ </template>
7
+ <template v-else-if="currentTab">
8
+ <component :is="tabComponent" />
9
+ </template>
5
10
  </div>
6
11
  </template>
7
12
 
8
13
  <script setup lang="ts">
9
14
  import { TabsNav, type Tab } from '@bagelink/vue';
15
+ import { defineProps, useSlots, h, defineComponent } from 'vue';
10
16
  import { useTabs } from './tabsManager';
11
17
 
12
- defineProps<{
13
- tabs: Tab[];
14
- modelValue?: string;
18
+ const props = defineProps<{
19
+ tabs: Tab[];
20
+ modelValue?: string;
15
21
  }>();
16
22
 
23
+ const slots = useSlots();
17
24
  const group = Math.random().toString(36).substring(7);
18
25
  const { currentTab } = useTabs(group);
26
+
27
+ const tabValue = (tab: Tab) => (typeof tab === 'string' ? tab : tab.id);
28
+
29
+ const tabComponent = defineComponent({
30
+ render() {
31
+ const currentTabIndex = props.tabs.findIndex(
32
+ (tab) => tabValue(tab) === currentTab.value
33
+ );
34
+ const slotChildren = slots?.default?.()?.[1]?.children;
35
+ return h('div', slotChildren?.[currentTabIndex]);
36
+ },
37
+ });
19
38
  </script>
@@ -13,17 +13,18 @@ export * from './BtnOptions';
13
13
  export * from './BagelForm';
14
14
 
15
15
  export type Tab = {
16
- label: string;
17
- id: string;
18
- icon?: MaterialIcons;
16
+ label: string;
17
+ id: string;
18
+ icon?: MaterialIcons;
19
19
  } | string
20
20
 
21
21
  export type ThemeType = |
22
- 'light'
23
- | 'red'
24
- | 'gray'
25
- | 'gray-light'
26
- | 'black'
27
- | 'green'
28
- | 'primary'
29
- | 'blue' // ! blue does nothing
22
+ 'light'
23
+ | 'white'
24
+ | 'red'
25
+ | 'gray'
26
+ | 'gray-light'
27
+ | 'black'
28
+ | 'green'
29
+ | 'primary'
30
+ | 'blue' // ! blue does nothing