@bagelink/vue 1.8.9 → 1.8.14
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/AddToCalendar.vue.d.ts +9 -12
- package/dist/components/AddToCalendar.vue.d.ts.map +1 -1
- package/dist/components/Filter.vue.d.ts +5 -4
- package/dist/components/Filter.vue.d.ts.map +1 -1
- package/dist/components/calendar/Index.vue.d.ts +1 -1
- package/dist/components/calendar/views/WeekView.vue.d.ts +1 -1
- package/dist/components/calendar/views/WeekView.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/Upload/UploadInput.vue.d.ts.map +1 -1
- package/dist/index.cjs +24 -23
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +4696 -4535
- package/dist/style.css +1 -1
- package/dist/types/BagelForm.d.ts +0 -1
- package/dist/types/BagelForm.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/calendar/types.d.ts +8 -0
- package/dist/utils/calendar/types.d.ts.map +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/queryFilter.d.ts +12 -8
- package/dist/utils/queryFilter.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/AddToCalendar.vue +230 -45
- package/src/components/Filter.vue +124 -112
- package/src/components/form/inputs/Upload/UploadInput.vue +10 -20
- package/src/index.ts +2 -1
- package/src/types/BagelForm.ts +61 -61
- package/src/types/index.ts +36 -35
- package/src/utils/calendar/types.ts +9 -0
- package/src/utils/index.ts +1 -1
- package/src/utils/queryFilter.ts +30 -22
|
@@ -1,25 +1,18 @@
|
|
|
1
1
|
<script setup lang="ts" generic="T extends Record<string, any>">
|
|
2
2
|
import type { Option } from '@bagelink/vue'
|
|
3
|
-
import type { ComparisonOperator } from '
|
|
3
|
+
import type { ComparisonOperator, LogicalOperator, QueryConditions } from './queryFilter'
|
|
4
4
|
import { Btn, DateInput, Dropdown, Icon, SelectInput, TextInput } from '@bagelink/vue'
|
|
5
5
|
import { computed } from 'vue'
|
|
6
6
|
|
|
7
7
|
type OptionsSource = Option[] | ((query: string) => Promise<Option[]>)
|
|
8
8
|
type Language = 'he' | 'en'
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
type QueryObject<T = Record<string, any>> = Record<string, any> & T
|
|
12
|
-
interface Condition {
|
|
13
|
-
pr?: boolean
|
|
14
|
-
[operator: string]: any
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
interface FilterCondition {
|
|
10
|
+
interface UICondition {
|
|
18
11
|
id: string
|
|
19
12
|
field: string
|
|
20
13
|
operator: ComparisonOperator
|
|
21
14
|
value: string
|
|
22
|
-
connector:
|
|
15
|
+
connector: LogicalOperator | ''
|
|
23
16
|
}
|
|
24
17
|
|
|
25
18
|
const props = defineProps<{
|
|
@@ -33,10 +26,15 @@ const props = defineProps<{
|
|
|
33
26
|
}>()
|
|
34
27
|
|
|
35
28
|
const emit = defineEmits<{
|
|
36
|
-
change: [value:
|
|
29
|
+
change: [value: QueryConditions<T>]
|
|
37
30
|
}>()
|
|
38
31
|
|
|
39
|
-
const model = defineModel<
|
|
32
|
+
const model = defineModel<QueryConditions<T>>({ default: () => [] })
|
|
33
|
+
|
|
34
|
+
let conditionIdCounter = 0
|
|
35
|
+
function generateId() {
|
|
36
|
+
return `cond_${++conditionIdCounter}_${Date.now()}`
|
|
37
|
+
}
|
|
40
38
|
|
|
41
39
|
// Localization data
|
|
42
40
|
const texts = {
|
|
@@ -113,45 +111,27 @@ const texts = {
|
|
|
113
111
|
// Get current language texts
|
|
114
112
|
const currentTexts = computed(() => texts[props.language || 'en'])
|
|
115
113
|
|
|
116
|
-
//
|
|
117
|
-
const
|
|
118
|
-
const obj = model.value
|
|
119
|
-
if (Object.keys(obj).filter(k => !k.startsWith('_')).length === 0) {
|
|
120
|
-
return [] as FilterCondition[]
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const result: FilterCondition[] = []
|
|
124
|
-
const useOr = (obj as any)._or === true
|
|
125
|
-
|
|
126
|
-
for (const [field, value] of Object.entries(obj)) {
|
|
127
|
-
if (field.startsWith('_')) continue
|
|
114
|
+
// Map model conditions to UI conditions with stable IDs
|
|
115
|
+
const conditionIds = new Map<number, string>()
|
|
128
116
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
117
|
+
const conditions = computed(() => {
|
|
118
|
+
const arr = model.value || []
|
|
119
|
+
return arr.map((cond, index) => {
|
|
120
|
+
// Get or create stable ID for this index
|
|
121
|
+
if (!conditionIds.has(index)) {
|
|
122
|
+
conditionIds.set(index, generateId())
|
|
135
123
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
const val = (cond as any)[op]
|
|
145
|
-
condition.value = val === null ? 'null' : String(val)
|
|
146
|
-
}
|
|
147
|
-
} else if (value !== undefined) {
|
|
148
|
-
condition.value = value === null ? 'null' : String(value)
|
|
124
|
+
const id = conditionIds.get(index)!
|
|
125
|
+
|
|
126
|
+
const uiCond: UICondition = {
|
|
127
|
+
id,
|
|
128
|
+
field: cond.field as string,
|
|
129
|
+
operator: cond.op,
|
|
130
|
+
value: cond.value === null ? 'null' : cond.value === undefined ? '' : String(cond.value),
|
|
131
|
+
connector: index > 0 ? (cond.connector || 'and') : '',
|
|
149
132
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
return result
|
|
133
|
+
return uiCond
|
|
134
|
+
})
|
|
155
135
|
})
|
|
156
136
|
|
|
157
137
|
const allOperatorOptions = computed(() => [
|
|
@@ -191,43 +171,60 @@ const booleanOptions = computed(() => [
|
|
|
191
171
|
{ label: currentTexts.value.boolean.false, value: 'false' },
|
|
192
172
|
])
|
|
193
173
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
} else if (operator === 'pr') {
|
|
207
|
-
(newModel as any)[field] = { pr: true }
|
|
208
|
-
} else {
|
|
209
|
-
(newModel as any)[field] = { [operator]: parsedValue }
|
|
210
|
-
}
|
|
174
|
+
function parseValue(value: string): string | number | boolean | null {
|
|
175
|
+
if (value === 'true') return true
|
|
176
|
+
if (value === 'false') return false
|
|
177
|
+
if (value === 'null') return null
|
|
178
|
+
if (!Number.isNaN(Number(value)) && value.trim() !== '') return Number(value)
|
|
179
|
+
return value
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function updateConditionAtIndex(index: number, updates: Partial<{ field: string, op: ComparisonOperator, value: string, connector: LogicalOperator }>) {
|
|
183
|
+
const newModel = [...model.value]
|
|
184
|
+
const existing = newModel[index]
|
|
185
|
+
if (!existing) return
|
|
211
186
|
|
|
187
|
+
const updated = { ...existing }
|
|
188
|
+
if (updates.field !== undefined) updated.field = updates.field
|
|
189
|
+
if (updates.op !== undefined) updated.op = updates.op
|
|
190
|
+
if (updates.value !== undefined) updated.value = parseValue(updates.value)
|
|
191
|
+
if (updates.connector !== undefined) updated.connector = updates.connector
|
|
192
|
+
|
|
193
|
+
newModel[index] = updated
|
|
212
194
|
model.value = newModel
|
|
213
195
|
emit('change', newModel)
|
|
214
196
|
}
|
|
215
197
|
|
|
216
198
|
function addCondition() {
|
|
217
|
-
const field = props.fields[0]?.value || '
|
|
218
|
-
|
|
199
|
+
const field = props.fields[0]?.value || 'field'
|
|
200
|
+
const newCondition = {
|
|
201
|
+
field,
|
|
202
|
+
op: 'eq' as ComparisonOperator,
|
|
203
|
+
value: '' as any,
|
|
204
|
+
connector: model.value.length > 0 ? 'and' as LogicalOperator : undefined,
|
|
205
|
+
}
|
|
206
|
+
const newModel = [...model.value, newCondition]
|
|
207
|
+
model.value = newModel
|
|
208
|
+
emit('change', newModel)
|
|
219
209
|
}
|
|
220
210
|
|
|
221
|
-
function removeCondition(
|
|
222
|
-
const newModel =
|
|
223
|
-
|
|
211
|
+
function removeCondition(index: number) {
|
|
212
|
+
const newModel = [...model.value]
|
|
213
|
+
newModel.splice(index, 1)
|
|
214
|
+
// Clear connector on new first item
|
|
215
|
+
if (newModel.length > 0 && newModel[0].connector) {
|
|
216
|
+
newModel[0] = { ...newModel[0], connector: undefined }
|
|
217
|
+
}
|
|
218
|
+
// Clean up ID mapping
|
|
219
|
+
conditionIds.delete(index)
|
|
224
220
|
model.value = newModel
|
|
225
221
|
emit('change', newModel)
|
|
226
222
|
}
|
|
227
223
|
|
|
228
224
|
function clearAll() {
|
|
229
|
-
|
|
230
|
-
|
|
225
|
+
conditionIds.clear()
|
|
226
|
+
model.value = []
|
|
227
|
+
emit('change', [])
|
|
231
228
|
}
|
|
232
229
|
|
|
233
230
|
function getFieldType(fieldValue: string): string {
|
|
@@ -242,35 +239,28 @@ const activeFiltersCount = computed(() => {
|
|
|
242
239
|
return conditions.value.filter(c => Boolean(c.field) && (c.operator === 'pr' || Boolean(c.value))).length
|
|
243
240
|
})
|
|
244
241
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
Reflect.deleteProperty(newModel, oldField)
|
|
249
|
-
|
|
250
|
-
let parsedValue: any = condition.value
|
|
251
|
-
if (condition.value === 'true') parsedValue = true
|
|
252
|
-
else if (condition.value === 'false') parsedValue = false
|
|
253
|
-
else if (condition.value === 'null') parsedValue = null
|
|
254
|
-
else if (!Number.isNaN(Number(condition.value)) && condition.value.trim() !== '') parsedValue = Number(condition.value)
|
|
255
|
-
|
|
256
|
-
if (condition.operator === 'eq') {
|
|
257
|
-
(newModel as any)[newField] = parsedValue
|
|
258
|
-
} else if (condition.operator === 'pr') {
|
|
259
|
-
(newModel as any)[newField] = { pr: true }
|
|
260
|
-
} else {
|
|
261
|
-
(newModel as any)[newField] = { [condition.operator]: parsedValue }
|
|
262
|
-
}
|
|
242
|
+
function getConditionIndex(id: string): number {
|
|
243
|
+
return conditions.value.findIndex(c => c.id === id)
|
|
244
|
+
}
|
|
263
245
|
|
|
264
|
-
|
|
265
|
-
|
|
246
|
+
function onFieldChange(id: string, newField: string) {
|
|
247
|
+
const index = getConditionIndex(id)
|
|
248
|
+
if (index >= 0) updateConditionAtIndex(index, { field: newField })
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function onOperatorChange(id: string, operator: ComparisonOperator) {
|
|
252
|
+
const index = getConditionIndex(id)
|
|
253
|
+
if (index >= 0) updateConditionAtIndex(index, { op: operator })
|
|
266
254
|
}
|
|
267
255
|
|
|
268
|
-
function
|
|
269
|
-
|
|
256
|
+
function onValueChange(id: string, value: string) {
|
|
257
|
+
const index = getConditionIndex(id)
|
|
258
|
+
if (index >= 0) updateConditionAtIndex(index, { value })
|
|
270
259
|
}
|
|
271
260
|
|
|
272
|
-
function
|
|
273
|
-
|
|
261
|
+
function onConnectorChange(id: string, connector: LogicalOperator) {
|
|
262
|
+
const index = getConditionIndex(id)
|
|
263
|
+
if (index >= 0) updateConditionAtIndex(index, { connector })
|
|
274
264
|
}
|
|
275
265
|
</script>
|
|
276
266
|
|
|
@@ -293,21 +283,31 @@ function onValueChange(field: string, operator: ComparisonOperator, value: strin
|
|
|
293
283
|
<TransitionGroup name="condition">
|
|
294
284
|
<div
|
|
295
285
|
v-for="(condition, index) in conditions" :key="condition.id"
|
|
296
|
-
class="grid filter-row gap-025 align-items-center
|
|
286
|
+
class="grid filter-row gap-025 align-items-center pt-025"
|
|
287
|
+
:class="{
|
|
288
|
+
'mt-025': index > 0 && condition.connector === 'or',
|
|
289
|
+
'pt-075 border-top-or': index > 0 && condition.connector === 'or',
|
|
290
|
+
}"
|
|
297
291
|
>
|
|
298
|
-
<!-- Connector (AND/OR)
|
|
299
|
-
<div v-if="index > 0" class="min-w-
|
|
300
|
-
<
|
|
301
|
-
|
|
302
|
-
|
|
292
|
+
<!-- Connector (AND/OR) -->
|
|
293
|
+
<div v-if="index > 0" class="min-w-60px">
|
|
294
|
+
<SelectInput
|
|
295
|
+
:model-value="condition.connector || 'and'"
|
|
296
|
+
:options="[
|
|
297
|
+
{ label: currentTexts.connectors.and, value: 'and' },
|
|
298
|
+
{ label: currentTexts.connectors.or, value: 'or' },
|
|
299
|
+
]"
|
|
300
|
+
class="m-0 and-or-select txt-12"
|
|
301
|
+
@update:model-value="(v: LogicalOperator) => onConnectorChange(condition.id, v)"
|
|
302
|
+
/>
|
|
303
303
|
</div>
|
|
304
|
-
<div v-else class="
|
|
304
|
+
<div v-else class="" />
|
|
305
305
|
|
|
306
306
|
<!-- Field selector -->
|
|
307
307
|
<SelectInput
|
|
308
308
|
:model-value="condition.field" :options="fields"
|
|
309
309
|
:placeholder="currentTexts.placeholders.selectField" class="m-0 light-input borderHover"
|
|
310
|
-
@update:model-value="(v: string) => onFieldChange(condition.
|
|
310
|
+
@update:model-value="(v: string) => onFieldChange(condition.id, v)"
|
|
311
311
|
/>
|
|
312
312
|
|
|
313
313
|
<!-- Operator selector -->
|
|
@@ -315,7 +315,7 @@ function onValueChange(field: string, operator: ComparisonOperator, value: strin
|
|
|
315
315
|
:model-value="condition.operator"
|
|
316
316
|
:options="getOperatorsForType(getFieldType(condition.field), !!getFieldOptions(condition.field))"
|
|
317
317
|
class="m-0 light-input borderHover"
|
|
318
|
-
@update:model-value="(v: ComparisonOperator) => onOperatorChange(condition.
|
|
318
|
+
@update:model-value="(v: ComparisonOperator) => onOperatorChange(condition.id, v)"
|
|
319
319
|
/>
|
|
320
320
|
|
|
321
321
|
<!-- Value input - type-specific -->
|
|
@@ -325,31 +325,31 @@ function onValueChange(field: string, operator: ComparisonOperator, value: strin
|
|
|
325
325
|
:options="getFieldOptions(condition.field)!"
|
|
326
326
|
:placeholder="currentTexts.placeholders.selectOption"
|
|
327
327
|
class="m-0 light-input borderHover" searchable
|
|
328
|
-
@update:model-value="(v: string) => onValueChange(condition.
|
|
328
|
+
@update:model-value="(v: string) => onValueChange(condition.id, v)"
|
|
329
329
|
/>
|
|
330
330
|
<SelectInput
|
|
331
331
|
v-else-if="getFieldType(condition.field) === 'boolean'"
|
|
332
332
|
:model-value="condition.value" :options="booleanOptions"
|
|
333
333
|
:placeholder="currentTexts.placeholders.selectOption"
|
|
334
334
|
class="m-0 light-input borderHover"
|
|
335
|
-
@update:model-value="(v: string) => onValueChange(condition.
|
|
335
|
+
@update:model-value="(v: string) => onValueChange(condition.id, v)"
|
|
336
336
|
/>
|
|
337
337
|
<DateInput
|
|
338
338
|
v-else-if="getFieldType(condition.field) === 'date'"
|
|
339
339
|
:model-value="condition.value" :placeholder="currentTexts.placeholders.selectDate"
|
|
340
340
|
class="m-0 light-input borderHover"
|
|
341
|
-
@update:model-value="(v: any) => onValueChange(condition.
|
|
341
|
+
@update:model-value="(v: any) => onValueChange(condition.id, String(v))"
|
|
342
342
|
/>
|
|
343
343
|
<TextInput
|
|
344
344
|
v-else-if="getFieldType(condition.field) === 'number'"
|
|
345
345
|
:model-value="condition.value" placeholder="0" type="number"
|
|
346
346
|
class="m-0 light-input borderHover"
|
|
347
|
-
@update:model-value="(v: string) => onValueChange(condition.
|
|
347
|
+
@update:model-value="(v: string) => onValueChange(condition.id, v)"
|
|
348
348
|
/>
|
|
349
349
|
<TextInput
|
|
350
350
|
v-else :model-value="condition.value"
|
|
351
351
|
:placeholder="currentTexts.placeholders.enterValue" class="m-0 light-input borderHover"
|
|
352
|
-
@update:model-value="(v: string) => onValueChange(condition.
|
|
352
|
+
@update:model-value="(v: string) => onValueChange(condition.id, v)"
|
|
353
353
|
/>
|
|
354
354
|
</template>
|
|
355
355
|
<div v-else />
|
|
@@ -357,7 +357,7 @@ function onValueChange(field: string, operator: ComparisonOperator, value: strin
|
|
|
357
357
|
<!-- Remove button -->
|
|
358
358
|
<Btn
|
|
359
359
|
icon="close" thin flat size="small" class="m_bg-gray-40 m_px-3 m_mx-auto"
|
|
360
|
-
@click="removeCondition(
|
|
360
|
+
@click="removeCondition(index)"
|
|
361
361
|
/>
|
|
362
362
|
</div>
|
|
363
363
|
</TransitionGroup>
|
|
@@ -375,8 +375,20 @@ function onValueChange(field: string, operator: ComparisonOperator, value: strin
|
|
|
375
375
|
</template>
|
|
376
376
|
|
|
377
377
|
<style scoped>
|
|
378
|
+
.and-or-select {
|
|
379
|
+
--input-font-size: 12px !important;
|
|
380
|
+
--input-background-color: transparent !important;
|
|
381
|
+
}
|
|
382
|
+
.and-or-select .selectinput-btn {
|
|
383
|
+
border: none;
|
|
384
|
+
width: 100%;
|
|
385
|
+
box-shadow: none;
|
|
386
|
+
padding: 0.25rem !important;
|
|
387
|
+
font-size: 12px !important;
|
|
388
|
+
}
|
|
389
|
+
|
|
378
390
|
.filter-row {
|
|
379
|
-
grid-template-columns:
|
|
391
|
+
grid-template-columns: 50px minmax(90px, 0.5fr) minmax(170px, 0.75fr) minmax(120px, 0.5fr) auto;
|
|
380
392
|
}
|
|
381
393
|
|
|
382
394
|
/* Transition animations */
|
|
@@ -124,27 +124,17 @@ function fileName(pathKey: string) {
|
|
|
124
124
|
>
|
|
125
125
|
<slot name="files" :files="pathKeys" :fileQueue>
|
|
126
126
|
<div v-if="multiple" class="bgl-multi-preview">
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
<p class="m-0">
|
|
137
|
-
{{ fileName(path_key) }}
|
|
138
|
-
</p>
|
|
139
|
-
<Btn thin flat icon="delete" color="red" @click="removeFile(path_key)" />
|
|
140
|
-
</div>
|
|
141
|
-
</template>
|
|
142
|
-
<!-- File count indicator when showFileList is false and multiple files -->
|
|
143
|
-
<div v-if="showFileList === false && pathKeys.length > 0" class="flex column gap-05 pt-1">
|
|
144
|
-
<p class="color-primary">
|
|
145
|
-
{{ pathKeys.length }} file{{ pathKeys.length > 1 ? 's' : '' }} uploaded
|
|
127
|
+
<div
|
|
128
|
+
v-for="path_key in pathKeys" :key="path_key"
|
|
129
|
+
v-lightbox="{ src: pathKeyToURL(path_key), download: true }"
|
|
130
|
+
class="multi-image-item-preview" :class="{ 'bgl_fill-image': fill }"
|
|
131
|
+
>
|
|
132
|
+
<Image v-if="isImage(path_key)" :pathKey="path_key" class="multi-preview" />
|
|
133
|
+
<Icon v-else icon="description" class="multi-preview" />
|
|
134
|
+
<p class="m-0">
|
|
135
|
+
{{ fileName(path_key) }}
|
|
146
136
|
</p>
|
|
147
|
-
<Btn
|
|
137
|
+
<Btn thin flat icon="delete" color="red" @click="removeFile(path_key)" />
|
|
148
138
|
</div>
|
|
149
139
|
<div
|
|
150
140
|
v-for="file in fileQueue" :key="file.name" class="multi-image-item-preview"
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import './styles/bagel.css'
|
|
2
|
+
|
|
1
3
|
export * from './components'
|
|
2
4
|
export * from './components/form/useBagelFormState'
|
|
3
5
|
export * from './composables'
|
|
@@ -14,7 +16,6 @@ export * from './types'
|
|
|
14
16
|
export * from './utils'
|
|
15
17
|
export * from './utils/allCountries'
|
|
16
18
|
export * from './utils/BagelFormUtils'
|
|
17
|
-
import './styles/bagel.css'
|
|
18
19
|
|
|
19
20
|
export * from './utils/calendar/dateUtils'
|
|
20
21
|
export * from './utils/constants'
|
package/src/types/BagelForm.ts
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
// Local type definitions for internal use only
|
|
2
|
-
type ArrayAttrs = any
|
|
3
|
-
interface Option { label: string, value: any }
|
|
4
2
|
import type { Paths, Get, IterableElement, OmitIndexSignature } from 'type-fest'
|
|
5
3
|
import type { ToString } from 'type-fest/source/internal'
|
|
6
4
|
import type { LiteralStringUnion } from 'type-fest/source/literal-union'
|
|
7
5
|
import type { PathsOptions, DefaultPathsOptions } from 'type-fest/source/paths'
|
|
8
6
|
import type { VNode } from 'vue'
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
|
15
|
-
|
|
8
|
+
type ArrayAttrs = any
|
|
9
|
+
interface Option { label: string, value: any }
|
|
10
|
+
|
|
11
|
+
export type AttributeValue
|
|
12
|
+
= | string
|
|
13
|
+
| number
|
|
14
|
+
| boolean
|
|
15
|
+
| undefined
|
|
16
|
+
| { [key: string]: any }
|
|
16
17
|
|
|
17
18
|
export type AttributeFn<T, P extends Path<T>> = (
|
|
18
19
|
field: SmartFieldVal<T, P>,
|
|
@@ -23,25 +24,25 @@ export interface Attributes<T, P extends Path<T>> {
|
|
|
23
24
|
[key: string]: AttributeValue | AttributeFn<T, P>
|
|
24
25
|
}
|
|
25
26
|
|
|
26
|
-
export type BagelFieldOptions<T, P extends Path<T>>
|
|
27
|
-
| string
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
27
|
+
export type BagelFieldOptions<T, P extends Path<T>>
|
|
28
|
+
= | string
|
|
29
|
+
| (
|
|
30
|
+
| {
|
|
31
|
+
label?: string
|
|
32
|
+
value: string | number
|
|
33
|
+
}
|
|
34
|
+
| string
|
|
35
|
+
| number
|
|
36
|
+
| boolean
|
|
37
|
+
| { [key: string]: any }
|
|
38
|
+
)[]
|
|
39
|
+
| ((val?: SmartFieldVal<T, P>, rowData?: T) => Option[] | ((query: string) => Promise<Option[]>))
|
|
40
|
+
| ((query: string, val?: SmartFieldVal<T, P>, rowData?: T) => Promise<Option[]>)
|
|
41
|
+
|
|
42
|
+
export type VIfType<T, P extends Path<T>>
|
|
43
|
+
= | string
|
|
35
44
|
| boolean
|
|
36
|
-
|
|
|
37
|
-
)[]
|
|
38
|
-
| ((val?: SmartFieldVal<T, P>, rowData?: T) => Option[] | ((query: string) => Promise<Option[]>))
|
|
39
|
-
| ((query: string, val?: SmartFieldVal<T, P>, rowData?: T) => Promise<Option[]>)
|
|
40
|
-
|
|
41
|
-
export type VIfType<T, P extends Path<T>> =
|
|
42
|
-
| string
|
|
43
|
-
| boolean
|
|
44
|
-
| ((val?: SmartFieldVal<T, P>, rowData?: T) => boolean)
|
|
45
|
+
| ((val?: SmartFieldVal<T, P>, rowData?: T) => boolean)
|
|
45
46
|
|
|
46
47
|
export type ValidationFn<T, P extends Path<T>> = (
|
|
47
48
|
val?: SmartFieldVal<T, P>,
|
|
@@ -58,14 +59,14 @@ export type _Path<
|
|
|
58
59
|
> = ToString<Paths<OmitIndexSignature<T>, PO>>
|
|
59
60
|
|
|
60
61
|
// Utility type for open-ended object paths
|
|
61
|
-
export type OpenEndedPath<T>
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
62
|
+
export type OpenEndedPath<T>
|
|
63
|
+
= keyof T extends infer K
|
|
64
|
+
? K extends keyof T
|
|
65
|
+
? T[K] extends { [key: string]: any }
|
|
66
|
+
? `${K & string}.${string}`
|
|
67
|
+
: never
|
|
68
|
+
: never
|
|
69
|
+
: never
|
|
69
70
|
|
|
70
71
|
// Helper type to get paths for index signature properties
|
|
71
72
|
type IndexSignaturePaths<T> = {
|
|
@@ -77,40 +78,40 @@ type IndexSignaturePaths<T> = {
|
|
|
77
78
|
}[keyof T]
|
|
78
79
|
|
|
79
80
|
// Enhanced Path type that allows flexibility for nested open-ended objects
|
|
80
|
-
export type Path<T, PO extends PathsOptions = DefaultPathsOptions>
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
export type Path<T, PO extends PathsOptions = DefaultPathsOptions>
|
|
82
|
+
= FieldVal<T, _Path<T, PO>> extends Array<any>
|
|
83
|
+
? LiteralStringUnion<_Path<T, PO>>
|
|
84
|
+
: _Path<T, PO> | IndexSignaturePaths<T> | `${keyof T & string}.more_info.${string}`
|
|
84
85
|
|
|
85
86
|
// Smart field value type that preserves type information when possible
|
|
86
|
-
export type SmartFieldVal<T, P extends Path<T>>
|
|
87
|
-
P extends string
|
|
87
|
+
export type SmartFieldVal<T, P extends Path<T>>
|
|
88
|
+
= P extends string
|
|
88
89
|
? P extends keyof T
|
|
89
90
|
? T[P]
|
|
90
91
|
: any
|
|
91
92
|
: FieldVal<T, P>
|
|
92
93
|
|
|
93
94
|
// Smart bagel field options that preserve type information
|
|
94
|
-
export type SmartBagelFieldOptions<T, P extends Path<T>>
|
|
95
|
-
| string
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
95
|
+
export type SmartBagelFieldOptions<T, P extends Path<T>>
|
|
96
|
+
= | string
|
|
97
|
+
| (
|
|
98
|
+
| {
|
|
99
|
+
label?: string
|
|
100
|
+
value: string | number
|
|
101
|
+
}
|
|
102
|
+
| string
|
|
103
|
+
| number
|
|
104
|
+
| boolean
|
|
105
|
+
| { [key: string]: any }
|
|
106
|
+
)[]
|
|
107
|
+
| ((val?: SmartFieldVal<T, P>, rowData?: T) => Option[] | ((query: string) => Promise<Option[]>))
|
|
108
|
+
| ((query: string, val?: SmartFieldVal<T, P>, rowData?: T) => Promise<Option[]>)
|
|
108
109
|
|
|
109
110
|
// Smart VIf type that preserves type information
|
|
110
|
-
export type SmartVIfType<T, P extends Path<T>>
|
|
111
|
-
| string
|
|
112
|
-
|
|
113
|
-
|
|
111
|
+
export type SmartVIfType<T, P extends Path<T>>
|
|
112
|
+
= | string
|
|
113
|
+
| boolean
|
|
114
|
+
| ((val?: SmartFieldVal<T, P>, rowData?: T) => boolean)
|
|
114
115
|
|
|
115
116
|
// Smart validation function that preserves type information
|
|
116
117
|
export type SmartValidationFn<T, P extends Path<T>> = (
|
|
@@ -138,8 +139,8 @@ export type SmartUpdateFn<T, P extends Path<T>> = (
|
|
|
138
139
|
|
|
139
140
|
/** The value type at path P in object T. */
|
|
140
141
|
// Fall back to unknown if type resolution fails
|
|
141
|
-
export type FieldVal<T, P extends Path<T>>
|
|
142
|
-
unknown extends Get<T, P> ? unknown : Get<T, P>
|
|
142
|
+
export type FieldVal<T, P extends Path<T>>
|
|
143
|
+
= unknown extends Get<T, P> ? unknown : Get<T, P>
|
|
143
144
|
|
|
144
145
|
/** If path P in T is an array, this gives the array's element type. */
|
|
145
146
|
export type ArrayFieldVal<T, P extends Path<T>> = IterableElement<Get<T, P>>
|
|
@@ -297,5 +298,4 @@ export interface UploadInputProps {
|
|
|
297
298
|
dropPlaceholder?: string
|
|
298
299
|
noFilePlaceholder?: string
|
|
299
300
|
btnPlaceholder?: string
|
|
300
|
-
showFileList?: boolean
|
|
301
301
|
}
|