@bagelink/vue 0.0.431 → 0.0.437

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,302 +1,299 @@
1
1
  <template>
2
- <Dropdown
3
- @click.stop
4
- @hide="updateOpen(false)"
5
- ref="dropdown"
6
- placement="bottom-start"
7
- class="bagel-input selectinput"
8
- >
9
- <label>
10
- {{ label }}
11
- <button
12
- @keydown="openOptions"
13
- @click="updateOpen(true)"
14
- :disabled="disabled"
15
- type="button"
16
- class="selectinput-btn"
17
- :class="{ isEmpty: selectedItems.length === 0 }"
18
- >
19
- <p>{{ selectedLabel }}</p>
20
- <Icon
21
- v-if="!disabled"
22
- v-bind="{ icon: open ? 'unfold_less' : 'unfold_more' }"
23
- />
24
- </button>
25
- <input
26
- tabindex="-1"
27
- style="width: 0; height: 0; position: absolute; opacity: 0; z-index: -1"
28
- v-if="required"
29
- @input="updateOpen(true)"
30
- :value="selectedItems"
31
- required
32
- />
33
- </label>
34
- <template #popper>
35
- <Card
36
- class="selectinput-options p-05"
37
- :style="{ width: fullWidth ? '100%' : 'auto' }"
38
- >
39
- <TextInput
40
- v-if="searchable"
41
- ref="searchInput"
42
- dense
43
- :placeholder="'Search'"
44
- icon="search"
45
- v-model="search"
46
- />
47
- <div
48
- class="selectinput-option hover gap-1"
49
- v-for="(option, i) in filteredOptions"
50
- :key="`${option}${i}`"
51
- @click="select(option)"
52
- :class="{ selected: isSelected(option) }"
53
- >
54
- <Icon v-if="isSelected(option)" icon="check" />
55
- <Icon
56
- class="opacity-3"
57
- v-if="!isSelected(option)"
58
- icon="fiber_manual_record"
59
- />
60
- <span>
61
- {{ getLabel(option) }}
62
- </span>
63
- </div>
64
- <slot name="last" />
65
- </Card>
66
- </template>
67
- </Dropdown>
2
+ <Dropdown
3
+ @click.stop
4
+ @hide="updateOpen(false)"
5
+ ref="dropdown"
6
+ placement="bottom-start"
7
+ class="bagel-input selectinput"
8
+ >
9
+ <label>
10
+ {{ label }}
11
+ <button
12
+ @keydown="openOptions"
13
+ @click="updateOpen(true)"
14
+ :disabled="disabled"
15
+ type="button"
16
+ class="selectinput-btn"
17
+ :class="{ isEmpty: selectedItems.length === 0 }"
18
+ >
19
+ <p>{{ selectedLabel }}</p>
20
+ <Icon
21
+ v-if="!disabled"
22
+ v-bind="{ icon: open ? 'unfold_less' : 'unfold_more' }"
23
+ />
24
+ </button>
25
+ <input
26
+ tabindex="-1"
27
+ style="width: 0; height: 0; position: absolute; opacity: 0; z-index: -1"
28
+ v-if="required"
29
+ @input="updateOpen(true)"
30
+ :value="selectedItems"
31
+ required
32
+ >
33
+ </label>
34
+ <template #popper>
35
+ <Card
36
+ class="selectinput-options p-05"
37
+ :style="{ width: fullWidth ? '100%' : 'auto' }"
38
+ >
39
+ <TextInput
40
+ v-if="searchable"
41
+ ref="searchInput"
42
+ dense
43
+ :placeholder="'Search'"
44
+ icon="search"
45
+ v-model="search"
46
+ />
47
+ <div
48
+ class="selectinput-option hover gap-1"
49
+ v-for="(option, i) in filteredOptions"
50
+ :key="`${option}${i}`"
51
+ @click="select(option)"
52
+ :class="{ selected: isSelected(option) }"
53
+ >
54
+ <Icon v-if="isSelected(option)" icon="check" />
55
+ <Icon
56
+ class="opacity-3"
57
+ v-if="!isSelected(option)"
58
+ icon="fiber_manual_record"
59
+ />
60
+ <span>
61
+ {{ getLabel(option) }}
62
+ </span>
63
+ </div>
64
+ <slot name="last" />
65
+ </Card>
66
+ </template>
67
+ </Dropdown>
68
68
  </template>
69
69
 
70
70
  <script lang="ts" setup>
71
- import { watch } from "vue";
72
- import { Dropdown } from "floating-vue";
73
- import "floating-vue/style.css";
74
- import { TextInput, Card, Icon } from "@bagelink/vue";
71
+ import { watch } from 'vue';
72
+ import { Dropdown } from 'floating-vue';
73
+ import 'floating-vue/style.css';
74
+ import { TextInput, Card, Icon } from '@bagelink/vue';
75
75
 
76
76
  type Option =
77
- | string
78
- | number
79
- | Record<string, any>
80
- | { label: string; value: string | number };
77
+ | string
78
+ | number
79
+ | Record<string, any>
80
+ | { label: string; value: string | number };
81
81
 
82
82
  const searchInput = $ref<HTMLInputElement | null>(null);
83
83
 
84
84
  const props = defineProps<{
85
- options: Option[];
86
- placeholder?: string;
87
- disabled?: boolean;
88
- modelValue?: Option;
89
- searchable?: boolean;
90
- required?: boolean;
91
- label?: string;
92
- fullWidth?: boolean;
93
- multiselect?: boolean;
85
+ options: Option[];
86
+ placeholder?: string;
87
+ disabled?: boolean;
88
+ modelValue?: Option;
89
+ searchable?: boolean;
90
+ required?: boolean;
91
+ label?: string;
92
+ fullWidth?: boolean;
93
+ multiselect?: boolean;
94
94
  }>();
95
95
 
96
96
  let selectedItems = $ref<Option[]>([]);
97
- let search = $ref("");
97
+ let search = $ref('');
98
98
 
99
99
  const dropdown = $ref<InstanceType<typeof Dropdown> | null>(null);
100
100
 
101
101
  let open = $ref(false);
102
102
 
103
103
  function openOptions() {
104
- dropdown?.show();
105
- // updateOpen(true);
104
+ dropdown?.show();
105
+ // updateOpen(true);
106
106
  }
107
107
 
108
108
  function updateOpen(visible: boolean) {
109
- open = visible;
110
- if (!open) search = "";
111
- else {
112
- setTimeout(
113
- () => (searchInput as any)?.$el?.querySelector("input")?.focus(),
114
- 100
115
- );
116
- }
109
+ open = visible;
110
+ if (!open) search = '';
111
+ else {
112
+ setTimeout(
113
+ () => (searchInput as any)?.$el?.querySelector('input')?.focus(),
114
+ 100,
115
+ );
116
+ }
117
117
  }
118
118
 
119
119
  const selectedLabel = $computed(() => {
120
- if (selectedItems.length === 0) return props.placeholder || "Select";
121
- if (selectedItems.length > 4) {
122
- const str = selectedItems
123
- .slice(0, 4)
124
- .map((item) => getLabel(item))
125
- .join(", ");
126
- return `${str}... +${selectedItems.length - 4}`;
127
- }
128
- return selectedItems.map((item) => getLabel(item)).join(", ");
120
+ if (selectedItems.length === 0) return props.placeholder || 'Select';
121
+ if (selectedItems.length > 4) {
122
+ const str = selectedItems
123
+ .slice(0, 4)
124
+ .map((item) => getLabel(item))
125
+ .join(', ');
126
+ return `${str}... +${selectedItems.length - 4}`;
127
+ }
128
+ return selectedItems.map((item) => getLabel(item)).join(', ');
129
129
  });
130
130
 
131
- const emit = defineEmits(["update:modelValue"]);
131
+ const emit = defineEmits(['update:modelValue']);
132
132
 
133
133
  const getLabel = (option: Option) => {
134
- if (!option) return "";
135
- if (typeof option === "string") return option;
136
- if (typeof option === "number") return `${option}`;
137
- return option.label;
134
+ if (!option) return '';
135
+ if (typeof option === 'string') return option;
136
+ if (typeof option === 'number') return `${option}`;
137
+ return option.label;
138
138
  };
139
139
 
140
- const getValue = (option: Option) => {
141
- if (!option) return "";
142
- if (typeof option === "string") return option;
143
- if (typeof option === "number") return option;
144
- return option.value;
140
+ const getValue = (option?: Option) => {
141
+ if (!option) return undefined;
142
+ if (typeof option === 'string') return option;
143
+ if (typeof option === 'number') return option;
144
+ return option.value;
145
145
  };
146
146
 
147
- const isSelected = (option: Option) =>
148
- !!selectedItems.find((item) => getValue(option) === getValue(item));
149
-
150
- const filteredOptions = $computed(() =>
151
- props.options.filter((option) => {
152
- const searchTerm = search
153
- .split(/\s+/)
154
- .filter(Boolean)
155
- .map((t) => new RegExp(t, "gi"));
156
- return (
157
- Boolean(option) &&
158
- (searchTerm.every((s) => getLabel(option).match(s)) ||
159
- searchTerm.length === 0)
160
- );
161
- })
162
- );
147
+ const isSelected = (option: Option) => !!selectedItems.find((item) => getValue(option) === getValue(item));
148
+
149
+ const filteredOptions = $computed(() => props.options.filter((option) => {
150
+ const searchTerm = search
151
+ .split(/\s+/)
152
+ .filter(Boolean)
153
+ .map((t) => new RegExp(t, 'gi'));
154
+ return (
155
+ Boolean(option) &&
156
+ (searchTerm.every((s) => getLabel(option).match(s)) ||
157
+ searchTerm.length === 0)
158
+ );
159
+ }));
163
160
 
164
161
  const select = (option: Option) => {
165
- const existingIndex = selectedItems.findIndex(
166
- (item) => getValue(item) === getValue(option)
167
- );
168
- if (existingIndex > -1) selectedItems.splice(existingIndex, 1);
169
- else if (props.multiselect) {
170
- const current = [...selectedItems];
171
- current.push(option);
172
-
173
- selectedItems = current;
174
- } else selectedItems.splice(0, selectedItems.length, option);
175
-
176
- if (!props.multiselect) dropdown?.hide();
177
- emitUpdate();
162
+ const existingIndex = selectedItems.findIndex(
163
+ (item) => getValue(item) === getValue(option),
164
+ );
165
+ if (existingIndex > -1) selectedItems.splice(existingIndex, 1);
166
+ else if (props.multiselect) {
167
+ const current = [...selectedItems];
168
+ current.push(option);
169
+
170
+ selectedItems = current;
171
+ } else selectedItems.splice(0, selectedItems.length, option);
172
+
173
+ if (!props.multiselect) dropdown?.hide();
174
+ emitUpdate();
178
175
  };
179
176
 
180
177
  function emitUpdate() {
181
- if (props.multiselect) {
182
- emit("update:modelValue", selectedItems.map(getValue).filter(Boolean));
183
- } else {
184
- selectedItems.splice(1, selectedItems.length - 1);
185
- const [item] = selectedItems;
186
- emit("update:modelValue", item ? getValue(item) : null);
187
- }
178
+ if (props.multiselect) {
179
+ emit('update:modelValue', selectedItems.map(getValue).filter(Boolean));
180
+ } else {
181
+ // selectedItems.splice(1, selectedItems.length - 1);
182
+ const [item] = selectedItems;
183
+ emit('update:modelValue', getValue(item));
184
+ }
188
185
  }
189
186
 
190
187
  function compareArrays(arr1: Option[], arr2: Option[]) {
191
- const arr1Values = [...arr1].map((a) => getValue(a)).filter(Boolean);
192
- const arr2Values = [...arr2].map((a) => getValue(a)).filter(Boolean);
193
- const isSame = arr1Values.every((item: Option) => arr2Values.includes(item));
194
- return isSame;
188
+ const arr1Values = [...arr1].map((a) => getValue(a)).filter(Boolean);
189
+ const arr2Values = [...arr2].map((a) => getValue(a)).filter(Boolean);
190
+ const isSame = arr1Values.every((item: Option) => arr2Values.includes(item));
191
+ return isSame;
195
192
  }
196
193
 
197
194
  watch(
198
- () => props.modelValue,
199
- (newVal: Option | Option[]) => {
200
- if (!props.multiselect) {
201
- const newOption =
202
- props.options.find((o) => getValue(o) === newVal) || newVal;
203
- if (newOption && !isSelected(newOption)) selectedItems = [newOption];
204
- } else {
205
- const isSame = compareArrays([newVal].flat(), selectedItems);
206
- if (!isSame) {
207
- selectedItems.splice(0, selectedItems.length, ...[newVal].flat());
208
- }
209
- }
210
- },
211
- { immediate: true }
195
+ () => props.modelValue,
196
+ (newVal: Option | Option[]) => {
197
+ if (!props.multiselect) {
198
+ const newOption =
199
+ props.options.find((o) => getValue(o) === newVal) || newVal;
200
+ if (newOption && !isSelected(newOption)) selectedItems = [newOption];
201
+ } else {
202
+ const isSame = compareArrays([newVal].flat(), selectedItems);
203
+ if (!isSame) {
204
+ selectedItems.splice(0, selectedItems.length, ...[newVal].flat());
205
+ }
206
+ }
207
+ },
208
+ { immediate: true },
212
209
  );
213
210
 
214
211
  watch(
215
- () => props.options,
216
- () => {
217
- selectedItems.forEach((option, i) => {
218
- const exists = props.options.find(
219
- (o) => getValue(o) === getValue(option)
220
- );
221
- if (!exists) selectedItems.splice(i, 1);
222
- else selectedItems.splice(i, 1, exists);
223
- });
224
- // const original = JSON.stringify(props.options.map(getValue));
225
- // const newSelection = JSON.stringify(selectedItems.map(getValue));
226
- // if (original !== newSelection) emitUpdate();
227
- },
228
- { deep: true, immediate: true }
212
+ () => props.options,
213
+ () => {
214
+ selectedItems.forEach((option, i) => {
215
+ const exists = props.options.find(
216
+ (o) => getValue(o) === getValue(option),
217
+ );
218
+ if (!exists) selectedItems.splice(i, 1);
219
+ else selectedItems.splice(i, 1, exists);
220
+ });
221
+ // const original = JSON.stringify(props.options.map(getValue));
222
+ // const newSelection = JSON.stringify(selectedItems.map(getValue));
223
+ // if (original !== newSelection) emitUpdate();
224
+ },
225
+ { deep: true, immediate: true },
229
226
  );
230
227
  </script>
231
228
 
232
229
  <style scoped>
233
230
  .selectinput {
234
- width: 100%;
231
+ width: 100%;
235
232
  }
236
233
 
237
234
  .selectinput-option {
238
- padding: 6px 12px;
239
- cursor: pointer;
240
- border-radius: 5px;
241
- transition: all 0.2s;
242
- display: grid;
243
- grid-template-columns: 10px 1fr;
244
- justify-content: space-between;
245
- width: 100%;
246
- font-size: var(--input-font-size);
235
+ padding: 6px 12px;
236
+ cursor: pointer;
237
+ border-radius: 5px;
238
+ transition: all 0.2s;
239
+ display: grid;
240
+ grid-template-columns: 10px 1fr;
241
+ justify-content: space-between;
242
+ width: 100%;
243
+ font-size: var(--input-font-size);
247
244
  }
248
245
 
249
246
  .selectinput-options {
250
- max-height: 300px;
251
- overflow-y: auto;
247
+ max-height: 300px;
248
+ overflow-y: auto;
252
249
  }
253
250
 
254
251
  .selectinput-option:hover {
255
- background: var(--bgl-gray-20);
252
+ background: var(--bgl-gray-20);
256
253
  }
257
254
  .isEmpty p {
258
- opacity: 0.3;
255
+ opacity: 0.3;
259
256
  }
260
257
  </style>
261
258
 
262
259
  <style>
263
260
  .bagel-input label {
264
- font-size: var(--label-font-size);
261
+ font-size: var(--label-font-size);
265
262
  }
266
263
 
267
264
  .selectinput-btn {
268
- display: flex;
269
- justify-content: space-between;
270
- align-items: center;
271
- height: var(--input-height);
272
- border-radius: var(--input-border-radius);
273
- border: none;
274
- background: var(--input-bg);
275
- padding: 0.7rem;
276
- color: var(--input-color);
277
- width: 100%;
278
- font-family: inherit;
279
- font-size: var(--input-font-size);
265
+ display: flex;
266
+ justify-content: space-between;
267
+ align-items: center;
268
+ height: var(--input-height);
269
+ border-radius: var(--input-border-radius);
270
+ border: none;
271
+ background: var(--input-bg);
272
+ padding: 0.7rem;
273
+ color: var(--input-color);
274
+ width: 100%;
275
+ font-family: inherit;
276
+ font-size: var(--input-font-size);
280
277
  }
281
278
 
282
279
  .selectinput-btn:disabled {
283
- color: var(--input-disabled-color);
284
- background-color: transparent;
280
+ color: var(--input-disabled-color);
281
+ background-color: transparent;
285
282
  }
286
283
 
287
284
  .selectinput-btn:focus {
288
- outline: none;
289
- box-shadow: inset 0 0 10px #00000012;
285
+ outline: none;
286
+ box-shadow: inset 0 0 10px #00000012;
290
287
  }
291
288
 
292
289
  .v-popper__arrow-container {
293
- display: none;
290
+ display: none;
294
291
  }
295
292
 
296
293
  .v-popper--theme-dropdown .v-popper__inner {
297
- border: none;
298
- /* background: transparent; if anyone is changing this please talk to me first*/
299
- border-radius: var(--card-border-radius);
300
- color: var(--input-color);
294
+ border: none;
295
+ /* background: transparent; if anyone is changing this please talk to me first*/
296
+ border-radius: var(--card-border-radius);
297
+ color: var(--input-color);
301
298
  }
302
299
  </style>
@@ -16,13 +16,6 @@
16
16
  --transition-ease: cubic-bezier(0.1, 0.5, 0.33, 1);
17
17
  }
18
18
 
19
- body {
20
- max-width: 100vw;
21
- height: 100vh;
22
- padding: 0;
23
- margin: 0;
24
- }
25
-
26
19
  .grid>* {
27
20
  min-height: 0;
28
21
  }
@@ -31,7 +24,66 @@ body {
31
24
  box-sizing: border-box;
32
25
  }
33
26
 
34
- @media (min-width: 992px) {}
27
+
28
+ html {
29
+ -ms-text-size-adjust: 100%;
30
+ -webkit-text-size-adjust: 100%;
31
+ height: 100%;
32
+ background-attachment: scroll;
33
+ }
34
+
35
+ body {
36
+ margin: 0;
37
+ min-height: 100%;
38
+ background-color: var(--bgl-bg);
39
+ font-family: var(--bgl-font);
40
+ font-size: 18px;
41
+ font-weight: 400;
42
+ line-height: 1.65;
43
+ width: auto;
44
+ height: auto;
45
+ }
46
+
47
+ a {
48
+ background-color: transparent;
49
+ cursor: pointer;
50
+ display: inline-block;
51
+ color: inherit;
52
+ }
53
+
54
+ a:active,
55
+ a:hover {
56
+ outline: 0;
57
+ }
58
+
59
+ b,
60
+ strong {
61
+ font-weight: bold;
62
+ }
63
+
64
+ hr {
65
+ box-sizing: content-box;
66
+ }
67
+
68
+ img,
69
+ video,
70
+ canvas,
71
+ audio,
72
+ iframe,
73
+ embed,
74
+ object {
75
+ max-width: 100%;
76
+ vertical-align: middle;
77
+ border: 0;
78
+ }
79
+
80
+ input,
81
+ button,
82
+ textarea,
83
+ select {
84
+ font: inherit;
85
+ }
86
+
35
87
 
36
88
  @media screen and (max-width: 910px) {
37
89