@bagelink/vue 1.9.67 → 1.9.71
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/dist/components/Filter.vue.d.ts +3 -2
- package/dist/components/Filter.vue.d.ts.map +1 -1
- package/dist/index.cjs +88 -88
- package/dist/index.mjs +5963 -5947
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/components/Filter.vue +51 -22
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<script setup lang="ts" generic="T extends Record<string, any>">
|
|
2
2
|
import type { Option } from '@bagelink/vue'
|
|
3
3
|
import type { ComparisonOperator, LogicalOperator, QueryConditions } from '../utils/queryFilter'
|
|
4
|
-
import { Btn, DateInput, Dropdown, Icon, SelectInput, TextInput, useI18n } from '@bagelink/vue'
|
|
5
|
-
import { computed } from 'vue'
|
|
4
|
+
import { Btn, DateInput, Dropdown, Icon, SelectInput, TextInput, useI18n, useDebounceFn } from '@bagelink/vue'
|
|
5
|
+
import { computed, ref, useAttrs } from 'vue'
|
|
6
6
|
|
|
7
7
|
type OptionsSource = Option[] | ((query: string) => Promise<Option[]>)
|
|
8
8
|
|
|
@@ -25,11 +25,28 @@ const props = defineProps<{
|
|
|
25
25
|
|
|
26
26
|
const emit = defineEmits<{
|
|
27
27
|
change: [value: QueryConditions<T>]
|
|
28
|
+
save: [value: QueryConditions<T>]
|
|
28
29
|
}>()
|
|
29
30
|
|
|
30
31
|
const model = defineModel<QueryConditions<T>>({ default: () => [] })
|
|
31
32
|
|
|
33
|
+
// Internal working copy — may contain incomplete conditions for UI purposes
|
|
34
|
+
const internalModel = ref<QueryConditions<T>>([...model.value] as QueryConditions<T>)
|
|
35
|
+
|
|
32
36
|
const { $t } = useI18n()
|
|
37
|
+
const attrs = useAttrs()
|
|
38
|
+
const hasSaveListener = computed(() => !!attrs.onSave)
|
|
39
|
+
|
|
40
|
+
function isComplete(c: { field: string, op: ComparisonOperator, value: any }) {
|
|
41
|
+
return c.field && c.op && (c.op === 'pr' || (c.value !== '' && c.value !== null && c.value !== undefined))
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const debouncedFlush = useDebounceFn(() => {
|
|
45
|
+
const complete = internalModel.value.filter(isComplete) as QueryConditions<T>
|
|
46
|
+
console.log('[Filter] flushing - internal:', internalModel.value, '| complete:', complete)
|
|
47
|
+
model.value = complete
|
|
48
|
+
emit('change', complete)
|
|
49
|
+
}, 400)
|
|
33
50
|
|
|
34
51
|
let conditionIdCounter = 0
|
|
35
52
|
function generateId() {
|
|
@@ -76,7 +93,7 @@ const currentTexts = computed(() => ({
|
|
|
76
93
|
const conditionIds = new Map<number, string>()
|
|
77
94
|
|
|
78
95
|
const conditions = computed(() => {
|
|
79
|
-
const arr =
|
|
96
|
+
const arr = internalModel.value || []
|
|
80
97
|
return arr.map((cond, index) => {
|
|
81
98
|
// Get or create stable ID for this index
|
|
82
99
|
if (!conditionIds.has(index)) {
|
|
@@ -142,7 +159,7 @@ function parseValue(value: string | number | boolean | null): string | number |
|
|
|
142
159
|
}
|
|
143
160
|
|
|
144
161
|
function updateConditionAtIndex(index: number, updates: Partial<{ field: string, op: ComparisonOperator, value: string | number | boolean | null, connector: LogicalOperator }>) {
|
|
145
|
-
const newModel = [...
|
|
162
|
+
const newModel = [...internalModel.value]
|
|
146
163
|
const existing = newModel[index]
|
|
147
164
|
if (!existing) return
|
|
148
165
|
|
|
@@ -153,8 +170,8 @@ function updateConditionAtIndex(index: number, updates: Partial<{ field: string,
|
|
|
153
170
|
if (updates.connector !== undefined) updated.connector = updates.connector
|
|
154
171
|
|
|
155
172
|
newModel[index] = updated
|
|
156
|
-
|
|
157
|
-
|
|
173
|
+
internalModel.value = newModel as QueryConditions<T>
|
|
174
|
+
debouncedFlush()
|
|
158
175
|
}
|
|
159
176
|
|
|
160
177
|
function addCondition() {
|
|
@@ -165,28 +182,28 @@ function addCondition() {
|
|
|
165
182
|
value: '' as any,
|
|
166
183
|
connector: model.value.length > 0 ? 'and' as LogicalOperator : undefined,
|
|
167
184
|
}
|
|
168
|
-
const newModel = [...
|
|
169
|
-
|
|
170
|
-
|
|
185
|
+
const newModel = [...internalModel.value, newCondition]
|
|
186
|
+
internalModel.value = newModel as QueryConditions<T>
|
|
187
|
+
console.log('[Filter] addCondition - skipping flush (incomplete)')
|
|
171
188
|
}
|
|
172
189
|
|
|
173
190
|
function removeCondition(index: number) {
|
|
174
|
-
const newModel = [...
|
|
191
|
+
const newModel = [...internalModel.value]
|
|
175
192
|
newModel.splice(index, 1)
|
|
176
|
-
// Clear connector on new first item
|
|
177
193
|
if (newModel.length > 0 && newModel[0].connector) {
|
|
178
194
|
newModel[0] = { ...newModel[0], connector: undefined }
|
|
179
195
|
}
|
|
180
|
-
// Clean up ID mapping
|
|
181
196
|
conditionIds.delete(index)
|
|
182
|
-
|
|
183
|
-
|
|
197
|
+
internalModel.value = newModel as QueryConditions<T>
|
|
198
|
+
debouncedFlush()
|
|
184
199
|
}
|
|
185
200
|
|
|
186
201
|
function clearAll() {
|
|
187
202
|
conditionIds.clear()
|
|
188
|
-
|
|
189
|
-
|
|
203
|
+
internalModel.value = [] as unknown as QueryConditions<T>
|
|
204
|
+
model.value = [] as unknown as QueryConditions<T>
|
|
205
|
+
console.log('[Filter] clearAll')
|
|
206
|
+
emit('change', [] as unknown as QueryConditions<T>)
|
|
190
207
|
}
|
|
191
208
|
|
|
192
209
|
function getFieldType(fieldValue: string): string {
|
|
@@ -245,9 +262,11 @@ function onConnectorChange(id: string, connector: LogicalOperator) {
|
|
|
245
262
|
<TransitionGroup name="condition">
|
|
246
263
|
<div
|
|
247
264
|
v-for="(condition, index) in conditions" :key="condition.id"
|
|
248
|
-
class="grid
|
|
265
|
+
class="grid gap-025 align-items-center pt-025" :class="{
|
|
249
266
|
'mt-025': index > 0 && condition.connector === 'or',
|
|
250
267
|
'pt-075 border-top-or': index > 0 && condition.connector === 'or',
|
|
268
|
+
'first-filter-row': index === 0,
|
|
269
|
+
'filter-row': index > 0,
|
|
251
270
|
}"
|
|
252
271
|
>
|
|
253
272
|
<!-- Connector (AND/OR) -->
|
|
@@ -260,7 +279,7 @@ function onConnectorChange(id: string, connector: LogicalOperator) {
|
|
|
260
279
|
@update:model-value="(v: LogicalOperator) => onConnectorChange(condition.id, v)"
|
|
261
280
|
/>
|
|
262
281
|
</div>
|
|
263
|
-
<div v-else />
|
|
282
|
+
<!-- <div v-else /> -->
|
|
264
283
|
|
|
265
284
|
<!-- Field selector -->
|
|
266
285
|
<SelectInput
|
|
@@ -324,10 +343,16 @@ function onConnectorChange(id: string, connector: LogicalOperator) {
|
|
|
324
343
|
|
|
325
344
|
<div class="flex gap-1 space-between">
|
|
326
345
|
<Btn icon="add" flat thin :value="currentTexts.buttons.addCondition" @click="addCondition" />
|
|
327
|
-
<
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
346
|
+
<div class="flex gap-05">
|
|
347
|
+
<Btn
|
|
348
|
+
v-if="conditions.length > 0" icon="delete_sweep" flat thin color="gray"
|
|
349
|
+
:value="currentTexts.buttons.clearAll" @click="clearAll"
|
|
350
|
+
/>
|
|
351
|
+
<Btn
|
|
352
|
+
v-if="hasSaveListener" icon="save" thin color="primary" :value="$t('filter.buttons.save')"
|
|
353
|
+
@click="emit('save', internalModel.filter(isComplete))"
|
|
354
|
+
/>
|
|
355
|
+
</div>
|
|
331
356
|
</div>
|
|
332
357
|
</div>
|
|
333
358
|
</Dropdown>
|
|
@@ -347,6 +372,10 @@ function onConnectorChange(id: string, connector: LogicalOperator) {
|
|
|
347
372
|
font-size: 12px !important;
|
|
348
373
|
}
|
|
349
374
|
|
|
375
|
+
.first-filter-row {
|
|
376
|
+
grid-template-columns: minmax(90px, 0.5fr) minmax(170px, 0.75fr) minmax(120px, 0.5fr) auto;
|
|
377
|
+
}
|
|
378
|
+
|
|
350
379
|
.filter-row {
|
|
351
380
|
grid-template-columns: 50px minmax(90px, 0.5fr) minmax(170px, 0.75fr) minmax(120px, 0.5fr) auto;
|
|
352
381
|
}
|