firstly 0.3.0 → 0.4.0
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/CHANGELOG.md +52 -0
- package/esm/SqlDatabase/FF_LogToConsole.js +9 -14
- package/esm/carbone/CarboneController.js +2 -1
- package/esm/changeLog/index.d.ts +0 -5
- package/esm/core/helper.d.ts +2 -0
- package/esm/core/helper.js +3 -0
- package/esm/core/index.d.ts +0 -0
- package/esm/core/index.js +5 -0
- package/esm/core/tailwind.d.ts +21 -0
- package/esm/core/tailwind.js +22 -0
- package/esm/core/tryCatch.d.ts +44 -0
- package/esm/core/tryCatch.js +34 -0
- package/esm/cron/server/index.js +1 -1
- package/esm/feedback/FeedbackController.js +3 -2
- package/esm/feedback/index.d.ts +7 -2
- package/esm/feedback/index.js +1 -2
- package/esm/feedback/server/index.d.ts +0 -5
- package/esm/feedback/server/index.js +1 -1
- package/esm/formats/strings.js +2 -2
- package/esm/index.d.ts +16 -0
- package/esm/index.js +13 -0
- package/esm/svelte/FF_Repo.svelte.d.ts +0 -2
- package/esm/svelte/FF_Repo.svelte.js +1 -17
- package/esm/svelte/helpers/debounce.js +1 -1
- package/esm/svelte/index.d.ts +2 -24
- package/esm/svelte/index.js +2 -22
- package/esm/{ui → svelte/ui}/Icon.svelte +1 -1
- package/esm/virtual/StateDemoEnum.d.ts +3 -3
- package/esm/virtual/StateDemoEnum.js +3 -3
- package/esm/virtual/UIEntity.js +1 -2
- package/package.json +6 -24
- package/esm/bin/cmd.d.ts +0 -1
- package/esm/bin/cmd.js +0 -638
- package/esm/feedback/ui/DialogIssue.svelte +0 -149
- package/esm/feedback/ui/DialogIssue.svelte.d.ts +0 -22
- package/esm/feedback/ui/DialogIssues.svelte +0 -114
- package/esm/feedback/ui/DialogIssues.svelte.d.ts +0 -22
- package/esm/feedback/ui/DialogMilestones.svelte +0 -43
- package/esm/feedback/ui/DialogMilestones.svelte.d.ts +0 -20
- package/esm/feedback/ui/Feedback.svelte +0 -16
- package/esm/feedback/ui/Feedback.svelte.d.ts +0 -18
- package/esm/internals/FF_Entity.d.ts +0 -2
- package/esm/internals/FF_Fields.d.ts +0 -11
- package/esm/internals/FF_Fields.js +0 -144
- package/esm/internals/cellsBuildor.d.ts +0 -47
- package/esm/internals/cellsBuildor.js +0 -141
- package/esm/internals/helper.d.ts +0 -49
- package/esm/internals/helper.js +0 -162
- package/esm/internals/index.d.ts +0 -78
- package/esm/internals/index.js +0 -45
- package/esm/internals/storeItem.d.ts +0 -19
- package/esm/internals/storeItem.js +0 -190
- package/esm/internals/storeList.d.ts +0 -34
- package/esm/internals/storeList.js +0 -108
- package/esm/internals/theme.d.ts +0 -4
- package/esm/internals/theme.js +0 -4
- package/esm/server/index.d.ts +0 -52
- package/esm/server/index.js +0 -87
- package/esm/svelte/FF_Cell.svelte +0 -103
- package/esm/svelte/FF_Cell.svelte.d.ts +0 -33
- package/esm/svelte/FF_Cell_Caption.svelte +0 -20
- package/esm/svelte/FF_Cell_Caption.svelte.d.ts +0 -31
- package/esm/svelte/FF_Cell_Display.svelte +0 -61
- package/esm/svelte/FF_Cell_Display.svelte.d.ts +0 -29
- package/esm/svelte/FF_Cell_Edit.svelte +0 -104
- package/esm/svelte/FF_Cell_Edit.svelte.d.ts +0 -32
- package/esm/svelte/FF_Cell_Error.svelte +0 -20
- package/esm/svelte/FF_Cell_Error.svelte.d.ts +0 -31
- package/esm/svelte/FF_Cell_Hint.svelte +0 -20
- package/esm/svelte/FF_Cell_Hint.svelte.d.ts +0 -31
- package/esm/svelte/FF_Config.svelte +0 -29
- package/esm/svelte/FF_Config.svelte.d.ts +0 -9
- package/esm/svelte/FF_Form.svelte +0 -155
- package/esm/svelte/FF_Form.svelte.d.ts +0 -37
- package/esm/svelte/FF_Grid.svelte +0 -257
- package/esm/svelte/FF_Grid.svelte.d.ts +0 -37
- package/esm/svelte/FF_Layout.svelte +0 -62
- package/esm/svelte/FF_Layout.svelte.d.ts +0 -31
- package/esm/svelte/actions/intersection.d.ts +0 -6
- package/esm/svelte/actions/intersection.js +0 -17
- package/esm/svelte/customField.d.ts +0 -69
- package/esm/svelte/customField.js +0 -4
- package/esm/svelte/dialog/DialogManagement.svelte +0 -98
- package/esm/svelte/dialog/DialogManagement.svelte.d.ts +0 -18
- package/esm/svelte/dialog/DialogPrimitive.svelte +0 -156
- package/esm/svelte/dialog/DialogPrimitive.svelte.d.ts +0 -38
- package/esm/svelte/dialog/dialog.d.ts +0 -58
- package/esm/svelte/dialog/dialog.js +0 -130
- package/esm/svelte/ff_Config.svelte.d.ts +0 -91
- package/esm/svelte/ff_Config.svelte.js +0 -111
- package/esm/svelte/firstly.css +0 -14
- package/esm/svelte/helpers.d.ts +0 -30
- package/esm/svelte/helpers.js +0 -38
- package/esm/svelte/tryCatch.d.ts +0 -12
- package/esm/svelte/tryCatch.js +0 -18
- package/esm/sveltekit/server/index.d.ts +0 -5
- package/esm/sveltekit/server/index.js +0 -24
- package/esm/ui/Button.svelte +0 -90
- package/esm/ui/Button.svelte.d.ts +0 -11
- package/esm/ui/Clipboardable.svelte +0 -25
- package/esm/ui/Clipboardable.svelte.d.ts +0 -12
- package/esm/ui/Field.svelte +0 -391
- package/esm/ui/Field.svelte.d.ts +0 -40
- package/esm/ui/FieldGroup.svelte +0 -117
- package/esm/ui/FieldGroup.svelte.d.ts +0 -44
- package/esm/ui/Grid.svelte +0 -262
- package/esm/ui/Grid.svelte.d.ts +0 -57
- package/esm/ui/Grid2.svelte +0 -290
- package/esm/ui/Grid2.svelte.d.ts +0 -57
- package/esm/ui/GridLoading.svelte +0 -58
- package/esm/ui/GridLoading.svelte.d.ts +0 -23
- package/esm/ui/GridPaginate.svelte +0 -69
- package/esm/ui/GridPaginate.svelte.d.ts +0 -23
- package/esm/ui/GridPaginate2.svelte +0 -25
- package/esm/ui/GridPaginate2.svelte.d.ts +0 -7
- package/esm/ui/Loading.svelte +0 -16
- package/esm/ui/Loading.svelte.d.ts +0 -31
- package/esm/ui/Tooltip.svelte +0 -45
- package/esm/ui/Tooltip.svelte.d.ts +0 -32
- package/esm/ui/dialog/DialogForm.svelte +0 -76
- package/esm/ui/dialog/DialogForm.svelte.d.ts +0 -21
- package/esm/ui/dialog/DialogManagement.svelte +0 -96
- package/esm/ui/dialog/DialogManagement.svelte.d.ts +0 -26
- package/esm/ui/dialog/DialogPrimitive.svelte +0 -90
- package/esm/ui/dialog/DialogPrimitive.svelte.d.ts +0 -38
- package/esm/ui/dialog/FormEditAction.svelte +0 -62
- package/esm/ui/dialog/FormEditAction.svelte.d.ts +0 -31
- package/esm/ui/dialog/dialog.d.ts +0 -60
- package/esm/ui/dialog/dialog.js +0 -100
- package/esm/ui/index.d.ts +0 -6
- package/esm/ui/index.js +0 -20
- package/esm/ui/internals/FieldContainer.svelte +0 -39
- package/esm/ui/internals/FieldContainer.svelte.d.ts +0 -18
- package/esm/ui/internals/Input.svelte +0 -143
- package/esm/ui/internals/Input.svelte.d.ts +0 -37
- package/esm/ui/internals/Textarea.svelte +0 -66
- package/esm/ui/internals/Textarea.svelte.d.ts +0 -33
- package/esm/ui/internals/select/MultiSelectMelt.svelte +0 -260
- package/esm/ui/internals/select/MultiSelectMelt.svelte.d.ts +0 -32
- package/esm/ui/internals/select/Select2.svelte +0 -88
- package/esm/ui/internals/select/Select2.svelte.d.ts +0 -12
- package/esm/ui/internals/select/SelectMelt.svelte +0 -289
- package/esm/ui/internals/select/SelectMelt.svelte.d.ts +0 -40
- package/esm/ui/internals/select/SelectRadio.svelte +0 -43
- package/esm/ui/internals/select/SelectRadio.svelte.d.ts +0 -27
- package/esm/ui/link/Link.svelte +0 -33
- package/esm/ui/link/Link.svelte.d.ts +0 -33
- package/esm/ui/link/LinkPlus.svelte +0 -63
- package/esm/ui/link/LinkPlus.svelte.d.ts +0 -9
- package/esm/utils/tailwind.d.ts +0 -2
- package/esm/utils/tailwind.js +0 -3
- package/esm/utils/transition.d.ts +0 -9
- package/esm/utils/transition.js +0 -33
- /package/esm/{internals → core}/BaseEnum.d.ts +0 -0
- /package/esm/{internals → core}/BaseEnum.js +0 -0
- /package/esm/{internals → core}/FF_Entity.js +0 -0
- /package/esm/{internals → core}/common.d.ts +0 -0
- /package/esm/{internals → core}/common.js +0 -0
- /package/esm/{utils → core}/types.d.ts +0 -0
- /package/esm/{utils → core}/types.js +0 -0
- /package/esm/{ui → svelte/ui}/Icon.svelte.d.ts +0 -0
- /package/esm/{ui → svelte/ui}/LibIcon.d.ts +0 -0
- /package/esm/{ui → svelte/ui}/LibIcon.js +0 -0
|
@@ -1,260 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { createCombobox, createSync, type ComboboxOptionProps } from '@melt-ui/svelte'
|
|
3
|
-
import { createEventDispatcher, onMount } from 'svelte'
|
|
4
|
-
import { fly } from 'svelte/transition'
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
LibIcon_Check,
|
|
8
|
-
LibIcon_Cross,
|
|
9
|
-
LibIcon_MultiCheck,
|
|
10
|
-
LibIcon_Search,
|
|
11
|
-
tw,
|
|
12
|
-
type BaseItem,
|
|
13
|
-
type FF_Icon,
|
|
14
|
-
} from '../../../internals'
|
|
15
|
-
import Icon from '../../Icon.svelte'
|
|
16
|
-
|
|
17
|
-
export let id: string
|
|
18
|
-
export let disabled: boolean = false
|
|
19
|
-
export let placeholder: string = ''
|
|
20
|
-
export let items: BaseItem[] = []
|
|
21
|
-
let totalCount: number | undefined = undefined
|
|
22
|
-
|
|
23
|
-
export let loadOptions:
|
|
24
|
-
| ((str: string) => Promise<{ items: BaseItem[]; totalCount: number }>)
|
|
25
|
-
| undefined = undefined
|
|
26
|
-
export let values: (string | null)[] | undefined = undefined
|
|
27
|
-
export let clearable = false
|
|
28
|
-
|
|
29
|
-
const dispatch = createEventDispatcher()
|
|
30
|
-
|
|
31
|
-
function dispatchSelectedValues(_data: BaseItem[] | undefined) {
|
|
32
|
-
values = _data?.map((_data) => _data.id)
|
|
33
|
-
dispatch('selected', _data)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
onMount(async () => {
|
|
37
|
-
if (loadOptions) {
|
|
38
|
-
const lo = await loadOptions('')
|
|
39
|
-
items = lo.items
|
|
40
|
-
totalCount = lo.totalCount
|
|
41
|
-
filteredItems = items
|
|
42
|
-
}
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
const getDefaultValues = (_selectedValue: (string | null)[] | undefined) => {
|
|
46
|
-
if (!items) {
|
|
47
|
-
return []
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const f = items.filter((c) => (_selectedValue ?? []).includes(String(c.id)))
|
|
51
|
-
if (f) {
|
|
52
|
-
return f.map((c) => toOption(c))
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return []
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const toOption = (
|
|
59
|
-
item: BaseItem,
|
|
60
|
-
): ComboboxOptionProps<BaseItem> & {
|
|
61
|
-
icon?: FF_Icon
|
|
62
|
-
} => ({
|
|
63
|
-
value: item,
|
|
64
|
-
label: item.caption,
|
|
65
|
-
// icon: item.icon,
|
|
66
|
-
// disabled: item.disabled,
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
const {
|
|
70
|
-
elements: { menu, input, option },
|
|
71
|
-
states: { open, inputValue, touchedInput, selected: localSelected },
|
|
72
|
-
helpers: { isSelected },
|
|
73
|
-
} = createCombobox<BaseItem, true>({
|
|
74
|
-
forceVisible: true,
|
|
75
|
-
multiple: true,
|
|
76
|
-
disabled,
|
|
77
|
-
ids: { label: id },
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
const clearSelection = () => {
|
|
81
|
-
sync.selected(undefined)
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
let debounceTimer: ReturnType<typeof setTimeout>
|
|
85
|
-
const debounce = (callback: () => void) => {
|
|
86
|
-
clearTimeout(debounceTimer)
|
|
87
|
-
debounceTimer = setTimeout(
|
|
88
|
-
callback,
|
|
89
|
-
// debounce only if we have a load option
|
|
90
|
-
loadOptions ? 444 : 0,
|
|
91
|
-
)
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const sync = createSync({ selected: localSelected })
|
|
95
|
-
$: items &&
|
|
96
|
-
sync.selected(getDefaultValues(values), (v) => {
|
|
97
|
-
const list = (v ?? []).map((c) => c.value.id)
|
|
98
|
-
|
|
99
|
-
// Create a map to count occurrences of each element
|
|
100
|
-
// TODO: switch to: Use SvelteMap instead svelte/prefer-svelte-reactivity
|
|
101
|
-
// eslint-disable-next-line
|
|
102
|
-
const countMap: Map<string | null, number> = new Map()
|
|
103
|
-
|
|
104
|
-
list.forEach((item) => {
|
|
105
|
-
countMap.set(item, (countMap.get(item) || 0) + 1)
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
// Filter the list to include only elements that occur exactly once
|
|
109
|
-
const uniqueList: (string | null)[] = list.filter((item) => countMap.get(item) === 1)
|
|
110
|
-
|
|
111
|
-
const newIds = uniqueList.sort().join(',')
|
|
112
|
-
const oldSelectedValues = (values ?? []).sort().join(',')
|
|
113
|
-
|
|
114
|
-
if (newIds !== oldSelectedValues) {
|
|
115
|
-
dispatchSelectedValues(
|
|
116
|
-
v === undefined
|
|
117
|
-
? undefined
|
|
118
|
-
: v.filter((c) => uniqueList.includes(c.value.id)).map((c) => c.value),
|
|
119
|
-
)
|
|
120
|
-
}
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
const labelToDisplayInInput = (_localSelected: typeof $localSelected) => {
|
|
124
|
-
if (_localSelected === undefined || _localSelected.length === 0) {
|
|
125
|
-
return ''
|
|
126
|
-
}
|
|
127
|
-
if (_localSelected.length === 1) {
|
|
128
|
-
return _localSelected[0].label ?? ''
|
|
129
|
-
}
|
|
130
|
-
return `${_localSelected.length} éléments`
|
|
131
|
-
}
|
|
132
|
-
$: $inputValue = labelToDisplayInInput($localSelected)
|
|
133
|
-
|
|
134
|
-
const iconToDisplayInInput = (_localSelected: typeof $localSelected): FF_Icon => {
|
|
135
|
-
if (_localSelected === undefined || _localSelected.length === 0) {
|
|
136
|
-
return { data: LibIcon_Search }
|
|
137
|
-
}
|
|
138
|
-
if (_localSelected.length === 1) {
|
|
139
|
-
return _localSelected[0].value.icon ?? { data: LibIcon_Search }
|
|
140
|
-
}
|
|
141
|
-
return { data: LibIcon_MultiCheck }
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const isChecked = (_localSelected: typeof $localSelected, _item: BaseItem) => {
|
|
145
|
-
const f = (_localSelected ?? []).filter((c) => c.value?.id === _item.id)
|
|
146
|
-
if (f.length > 0) {
|
|
147
|
-
return true
|
|
148
|
-
}
|
|
149
|
-
return false
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
let filteredItems = items
|
|
153
|
-
const calcFilteredItems = (touched: boolean, str: string, values: any) => {
|
|
154
|
-
if (touched && !str.endsWith(' éléments')) {
|
|
155
|
-
debounce(async () => {
|
|
156
|
-
const normalizedInput = str.toLowerCase()
|
|
157
|
-
|
|
158
|
-
// In a Multi select we can't filter to the server.
|
|
159
|
-
// If we do I don't knwo what to set to $inputValue. and and list gets shorter... So what do we do about items that are selected but not in the list anymore (because of the filter) ?
|
|
160
|
-
// if (loadOptions) {
|
|
161
|
-
// const lo = await loadOptions(normalizedInput)
|
|
162
|
-
// items = lo.items
|
|
163
|
-
// totalCount = lo.totalCount
|
|
164
|
-
// filteredItems = items
|
|
165
|
-
// } else {
|
|
166
|
-
filteredItems = items.filter((item) => {
|
|
167
|
-
return item.caption?.toLowerCase().includes(normalizedInput)
|
|
168
|
-
})
|
|
169
|
-
// }
|
|
170
|
-
})
|
|
171
|
-
} else {
|
|
172
|
-
filteredItems = items
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
$: calcFilteredItems($touchedInput, $inputValue, values)
|
|
177
|
-
</script>
|
|
178
|
-
|
|
179
|
-
<div class="input flex min-w-0 items-center">
|
|
180
|
-
<div class="relative">
|
|
181
|
-
{#if iconToDisplayInInput($localSelected)}
|
|
182
|
-
{@const ico = iconToDisplayInInput($localSelected)}
|
|
183
|
-
<Icon data={ico?.data} class={tw(['relative', ico?.class])} style={ico?.style} size={ico?.size}
|
|
184
|
-
></Icon>
|
|
185
|
-
{/if}
|
|
186
|
-
</div>
|
|
187
|
-
<!-- {id} -->
|
|
188
|
-
<input
|
|
189
|
-
{...$input}
|
|
190
|
-
use:$input.action
|
|
191
|
-
class="-mr-5 -ml-8 h-full min-w-0 flex-grow bg-transparent px-10"
|
|
192
|
-
{placeholder}
|
|
193
|
-
/>
|
|
194
|
-
<div class="pointer-events-none relative right-0 flex gap-2">
|
|
195
|
-
{#if clearable && $localSelected && $localSelected.length > 0}
|
|
196
|
-
<button on:click={clearSelection} class="pointer-events-auto">
|
|
197
|
-
<Icon data={LibIcon_Cross}></Icon>
|
|
198
|
-
</button>
|
|
199
|
-
{/if}
|
|
200
|
-
<!-- {#if $open}
|
|
201
|
-
<Icon data={LibIcon_ChevronUp}></Icon>
|
|
202
|
-
{:else}
|
|
203
|
-
<Icon data={LibIcon_ChevronDown}></Icon>
|
|
204
|
-
{/if} -->
|
|
205
|
-
</div>
|
|
206
|
-
</div>
|
|
207
|
-
|
|
208
|
-
{#if $open}
|
|
209
|
-
<ul
|
|
210
|
-
class="z-50 flex max-h-[300px] flex-col overflow-hidden rounded-lg border border-base-content/20"
|
|
211
|
-
{...$menu}
|
|
212
|
-
use:$menu.action
|
|
213
|
-
transition:fly={{ duration: 150, y: -5 }}
|
|
214
|
-
>
|
|
215
|
-
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
|
216
|
-
<div class="flex max-h-full flex-col gap-0 overflow-y-auto bg-base-100 py-2" tabindex="0">
|
|
217
|
-
{#each filteredItems as item, index (index)}
|
|
218
|
-
<li
|
|
219
|
-
{...$option(toOption(item))}
|
|
220
|
-
use:$option.action
|
|
221
|
-
class="relative flex cursor-pointer scroll-my-2 items-center rounded-md px-1
|
|
222
|
-
py-2
|
|
223
|
-
data-[disabled]:opacity-50
|
|
224
|
-
data-[highlighted]:bg-primary
|
|
225
|
-
data-[highlighted]:text-primary-content"
|
|
226
|
-
>
|
|
227
|
-
{#if isChecked($localSelected, item)}
|
|
228
|
-
<Icon data={LibIcon_Check} class="w-6"></Icon>
|
|
229
|
-
{:else}
|
|
230
|
-
<!-- just to book the place -->
|
|
231
|
-
<span class="w-6"></span>
|
|
232
|
-
{/if}
|
|
233
|
-
{#if item.icon?.data}
|
|
234
|
-
<Icon
|
|
235
|
-
data={item.icon.data}
|
|
236
|
-
class={tw(['flex-shrink-0', item.icon.class])}
|
|
237
|
-
style={item.icon.style}
|
|
238
|
-
size={item.icon.size}
|
|
239
|
-
></Icon>
|
|
240
|
-
{/if}
|
|
241
|
-
<div class="pl-2 {item.class}">
|
|
242
|
-
<span class="font-medium">{item.caption}</span>
|
|
243
|
-
</div>
|
|
244
|
-
</li>
|
|
245
|
-
{:else}
|
|
246
|
-
<li class="relative cursor-pointer rounded-md py-1 pl-8 pr-4">Aucun résultat</li>
|
|
247
|
-
{/each}
|
|
248
|
-
</div>
|
|
249
|
-
{#if totalCount}
|
|
250
|
-
<div class="z-50 bg-base-300 text-center text-xs">
|
|
251
|
-
{#if items.length < totalCount}
|
|
252
|
-
({items.length} / {totalCount})
|
|
253
|
-
{:else}
|
|
254
|
-
<!-- yes, items.length can be bigger if the selected item is not in the limit -->
|
|
255
|
-
({items.length})
|
|
256
|
-
{/if}
|
|
257
|
-
</div>
|
|
258
|
-
{/if}
|
|
259
|
-
</ul>
|
|
260
|
-
{/if}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { type BaseItem } from '../../../internals';
|
|
2
|
-
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
3
|
-
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
4
|
-
$$bindings?: Bindings;
|
|
5
|
-
} & Exports;
|
|
6
|
-
(internal: unknown, props: Props & {
|
|
7
|
-
$$events?: Events;
|
|
8
|
-
$$slots?: Slots;
|
|
9
|
-
}): Exports & {
|
|
10
|
-
$set?: any;
|
|
11
|
-
$on?: any;
|
|
12
|
-
};
|
|
13
|
-
z_$$bindings?: Bindings;
|
|
14
|
-
}
|
|
15
|
-
declare const MultiSelectMelt: $$__sveltets_2_IsomorphicComponent<{
|
|
16
|
-
id: string;
|
|
17
|
-
disabled?: boolean;
|
|
18
|
-
placeholder?: string;
|
|
19
|
-
items?: BaseItem[];
|
|
20
|
-
loadOptions?: ((str: string) => Promise<{
|
|
21
|
-
items: BaseItem[];
|
|
22
|
-
totalCount: number;
|
|
23
|
-
}>) | undefined;
|
|
24
|
-
values?: (string | null)[] | undefined;
|
|
25
|
-
clearable?: boolean;
|
|
26
|
-
}, {
|
|
27
|
-
selected: CustomEvent<any>;
|
|
28
|
-
} & {
|
|
29
|
-
[evt: string]: CustomEvent<any>;
|
|
30
|
-
}, {}, {}, string>;
|
|
31
|
-
type MultiSelectMelt = InstanceType<typeof MultiSelectMelt>;
|
|
32
|
-
export default MultiSelectMelt;
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import Svelecte from 'svelecte'
|
|
3
|
-
|
|
4
|
-
import { LibIcon_Search, type BaseItem } from '../../../internals'
|
|
5
|
-
import Icon from '../../Icon.svelte'
|
|
6
|
-
|
|
7
|
-
interface Props {
|
|
8
|
-
value?: string | undefined
|
|
9
|
-
clearable?: boolean
|
|
10
|
-
items?: BaseItem[] | undefined
|
|
11
|
-
placeholder?: string | undefined
|
|
12
|
-
|
|
13
|
-
onChange?: (value: string | undefined) => void
|
|
14
|
-
|
|
15
|
-
multiple?: boolean
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
let {
|
|
19
|
-
value = $bindable(undefined),
|
|
20
|
-
clearable = false,
|
|
21
|
-
items = [],
|
|
22
|
-
placeholder = '',
|
|
23
|
-
multiple = false,
|
|
24
|
-
onChange,
|
|
25
|
-
}: Props = $props()
|
|
26
|
-
</script>
|
|
27
|
-
|
|
28
|
-
<Svelecte
|
|
29
|
-
i18n={{
|
|
30
|
-
nomatch: 'Aucun résultat',
|
|
31
|
-
}}
|
|
32
|
-
options={items}
|
|
33
|
-
bind:value
|
|
34
|
-
{clearable}
|
|
35
|
-
{placeholder}
|
|
36
|
-
{multiple}
|
|
37
|
-
{onChange}
|
|
38
|
-
>
|
|
39
|
-
{#snippet prepend()}
|
|
40
|
-
{value}
|
|
41
|
-
<Icon data={LibIcon_Search} class="mr-2 ml-3"></Icon>
|
|
42
|
-
{/snippet}
|
|
43
|
-
|
|
44
|
-
{#snippet option(opt, inputValue)}
|
|
45
|
-
{@const item = opt as BaseItem}
|
|
46
|
-
<div class="flex items-center">
|
|
47
|
-
<Icon data={item.icon?.data} class="mr-2"></Icon>
|
|
48
|
-
{item.caption}
|
|
49
|
-
</div>
|
|
50
|
-
{/snippet}
|
|
51
|
-
</Svelecte>
|
|
52
|
-
|
|
53
|
-
<style>
|
|
54
|
-
:global(.svelecte) {
|
|
55
|
-
--sv-min-height: 3rem;
|
|
56
|
-
--sv-bg: var(--color-base-100, #fff);
|
|
57
|
-
--sv-disabled-bg: #eee;
|
|
58
|
-
--sv-border: 1px solid #414a54;
|
|
59
|
-
--sv-border-radius: var(--radius-field, 4px);
|
|
60
|
-
--sv-general-padding: 4px;
|
|
61
|
-
--sv-control-bg: var(--sv-bg);
|
|
62
|
-
--sv-item-wrap-padding: 3px 3px 3px 6px;
|
|
63
|
-
--sv-item-selected-bg: var(--color-base-200, #efefef);
|
|
64
|
-
--sv-item-btn-color: var(--color-base-content, #000);
|
|
65
|
-
--sv-item-btn-color-hover: #777; /* same as icon-color-hover in default theme */
|
|
66
|
-
--sv-item-btn-bg: var(--color-base-100, #efefef);
|
|
67
|
-
--sv-item-btn-bg-hover: var(--color-base-200, #ddd);
|
|
68
|
-
--sv-icon-color: var(--color-base-content, #efefef);
|
|
69
|
-
--sv-icon-color-hover: #777;
|
|
70
|
-
--sv-icon-bg: transparent;
|
|
71
|
-
--sv-icon-size: 20px;
|
|
72
|
-
--sv-separator-bg: var(--color-neutral-content, #ccc);
|
|
73
|
-
--sv-btn-border: 0;
|
|
74
|
-
--sv-placeholder-color: #ccccd6;
|
|
75
|
-
--sv-dropdown-bg: var(--sv-bg);
|
|
76
|
-
--sv-dropdown-offset: 1px;
|
|
77
|
-
--sv-dropdown-border: 1px solid rgba(0, 0, 0, 0.15);
|
|
78
|
-
--sv-dropdown-width: auto;
|
|
79
|
-
--sv-dropdown-shadow: 0 6px 12px #0000002d;
|
|
80
|
-
--sv-dropdown-height: 320px;
|
|
81
|
-
--sv-dropdown-active-bg: var(--color-primary, #f2f5f8);
|
|
82
|
-
--sv-dropdown-selected-bg: var(--color-neutral);
|
|
83
|
-
--sv-create-kbd-border: var(--border, 1px) solid var(--color-base-200, #efefef);
|
|
84
|
-
--sv-create-kbd-bg: var(--color-base-100, #fff);
|
|
85
|
-
--sv-create-disabled-bg: var(--color-error, #fcbaba);
|
|
86
|
-
--sv-loader-border: var(--border, 2px) solid var(--color-base-200, #ccc);
|
|
87
|
-
}
|
|
88
|
-
</style>
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { type BaseItem } from '../../../internals';
|
|
2
|
-
interface Props {
|
|
3
|
-
value?: string | undefined;
|
|
4
|
-
clearable?: boolean;
|
|
5
|
-
items?: BaseItem[] | undefined;
|
|
6
|
-
placeholder?: string | undefined;
|
|
7
|
-
onChange?: (value: string | undefined) => void;
|
|
8
|
-
multiple?: boolean;
|
|
9
|
-
}
|
|
10
|
-
declare const Select2: import("svelte").Component<Props, {}, "value">;
|
|
11
|
-
type Select2 = ReturnType<typeof Select2>;
|
|
12
|
-
export default Select2;
|
|
@@ -1,289 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { createCombobox, createSync, type ComboboxOptionProps } from '@melt-ui/svelte'
|
|
3
|
-
import { createEventDispatcher, onMount, tick } from 'svelte'
|
|
4
|
-
import { fly } from 'svelte/transition'
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
Button,
|
|
8
|
-
LibIcon_Add,
|
|
9
|
-
LibIcon_Check,
|
|
10
|
-
LibIcon_Cross,
|
|
11
|
-
LibIcon_Search,
|
|
12
|
-
tw,
|
|
13
|
-
type BaseItem,
|
|
14
|
-
type FF_Icon,
|
|
15
|
-
} from '../../../internals'
|
|
16
|
-
import Icon from '../../Icon.svelte'
|
|
17
|
-
|
|
18
|
-
export let id: string
|
|
19
|
-
export let disabled: boolean = false
|
|
20
|
-
export let placeholder: string = ''
|
|
21
|
-
export let items: BaseItem[] = []
|
|
22
|
-
let totalCount: number | undefined = undefined
|
|
23
|
-
|
|
24
|
-
export let focus: boolean = false
|
|
25
|
-
const focusNow = (node: any) => {
|
|
26
|
-
if (focus) {
|
|
27
|
-
tick().then(() => {
|
|
28
|
-
node.focus()
|
|
29
|
-
})
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export let loadOptions:
|
|
34
|
-
| ((str: string) => Promise<{ items: BaseItem[]; totalCount: number }>)
|
|
35
|
-
| undefined = undefined
|
|
36
|
-
export let value: string | null | undefined = undefined
|
|
37
|
-
export let clearable = false
|
|
38
|
-
export let createOptionWhenNoResult = false
|
|
39
|
-
export let default_select_if_one_item = false
|
|
40
|
-
export let createRequest: ((args: { input: string; id: string }) => void) | undefined = undefined
|
|
41
|
-
|
|
42
|
-
const dispatch = createEventDispatcher()
|
|
43
|
-
|
|
44
|
-
function dispatchSelectedValue(_data: BaseItem | undefined) {
|
|
45
|
-
dispatch('selected', _data)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function dispatchIssue(msg: 'VALUE_NOT_IN_ITEMS') {
|
|
49
|
-
dispatch('issue', msg)
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
let lastSearch: string | undefined = undefined
|
|
53
|
-
const localLoadOptions = async (str: string) => {
|
|
54
|
-
if (str === lastSearch) {
|
|
55
|
-
return
|
|
56
|
-
}
|
|
57
|
-
lastSearch = str
|
|
58
|
-
if (loadOptions) {
|
|
59
|
-
const lo = await loadOptions(str)
|
|
60
|
-
items = lo.items
|
|
61
|
-
totalCount = lo.totalCount
|
|
62
|
-
filteredItems = items
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
onMount(async () => {
|
|
67
|
-
localLoadOptions('')
|
|
68
|
-
|
|
69
|
-
// after we load items
|
|
70
|
-
sync.selected(getDefaultValue(value))
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
const getDefaultValue = (_selectedValue: string | null | undefined) => {
|
|
74
|
-
if (!items) {
|
|
75
|
-
return
|
|
76
|
-
}
|
|
77
|
-
const found = items.find((c) => String(c?.id) === String(_selectedValue))
|
|
78
|
-
if (found) {
|
|
79
|
-
return toOption(found)
|
|
80
|
-
} else {
|
|
81
|
-
if (value !== null && value !== undefined && items.length > 0) {
|
|
82
|
-
dispatchIssue('VALUE_NOT_IN_ITEMS')
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const toOption = (
|
|
88
|
-
item: BaseItem,
|
|
89
|
-
): ComboboxOptionProps<BaseItem> & {
|
|
90
|
-
icon?: FF_Icon
|
|
91
|
-
} => ({
|
|
92
|
-
value: item,
|
|
93
|
-
label: item.caption,
|
|
94
|
-
// icon: item.icon,
|
|
95
|
-
// disabled: item.disabled,
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
const {
|
|
99
|
-
elements: { menu, input, option },
|
|
100
|
-
states: { open, inputValue, touchedInput, selected: localSelected },
|
|
101
|
-
// helpers: { isSelected },
|
|
102
|
-
} = createCombobox<BaseItem>({
|
|
103
|
-
forceVisible: true,
|
|
104
|
-
disabled,
|
|
105
|
-
ids: { label: id },
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
const clearSelection = () => {
|
|
109
|
-
sync.selected(undefined)
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
let debounceTimer: ReturnType<typeof setTimeout>
|
|
113
|
-
const debounce = (callback: () => void) => {
|
|
114
|
-
clearTimeout(debounceTimer)
|
|
115
|
-
debounceTimer = setTimeout(
|
|
116
|
-
callback,
|
|
117
|
-
// debounce only if we have a load option
|
|
118
|
-
loadOptions ? 444 : 0,
|
|
119
|
-
)
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const sync = createSync({ selected: localSelected })
|
|
123
|
-
$: items &&
|
|
124
|
-
sync.selected(getDefaultValue(value), (v) => {
|
|
125
|
-
// Only if different
|
|
126
|
-
if (v?.value?.id !== value) {
|
|
127
|
-
dispatchSelectedValue(v?.value)
|
|
128
|
-
}
|
|
129
|
-
value = v?.value?.id
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
// Helper to strip HTML tags from caption for display in input
|
|
133
|
-
const stripHtml = (html: string): string => {
|
|
134
|
-
const tmp = document.createElement('div')
|
|
135
|
-
tmp.innerHTML = html
|
|
136
|
-
return tmp.textContent || tmp.innerText || ''
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
$: if (!$open) {
|
|
140
|
-
$inputValue = $localSelected?.label ? stripHtml($localSelected.label) : ''
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
$: filteredItems = items
|
|
144
|
-
|
|
145
|
-
$: {
|
|
146
|
-
if (items.length === 1 && default_select_if_one_item) {
|
|
147
|
-
sync.selected(toOption(items[0]))
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const calcFilteredItems = (touched: boolean, str: string, value: any) => {
|
|
152
|
-
if (touched) {
|
|
153
|
-
debounce(async () => {
|
|
154
|
-
const normalizedInput = str.toLowerCase()
|
|
155
|
-
updateFilteredItems(normalizedInput)
|
|
156
|
-
})
|
|
157
|
-
} else {
|
|
158
|
-
updateFilteredItems('')
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
const updateFilteredItems = async (normalizedInput: string) => {
|
|
163
|
-
if (loadOptions) {
|
|
164
|
-
await localLoadOptions(normalizedInput)
|
|
165
|
-
} else {
|
|
166
|
-
filteredItems = items.filter((item) => {
|
|
167
|
-
return item.caption?.toLowerCase().includes(normalizedInput)
|
|
168
|
-
})
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
$: calcFilteredItems($touchedInput, $inputValue, value)
|
|
173
|
-
</script>
|
|
174
|
-
|
|
175
|
-
<div class="input flex w-full min-w-0 items-center {disabled && 'opacity-40'}">
|
|
176
|
-
<div class="relative">
|
|
177
|
-
{#if $localSelected?.value?.icon?.data}
|
|
178
|
-
<Icon
|
|
179
|
-
data={$localSelected.value.icon.data}
|
|
180
|
-
class={tw(['relative', $localSelected.value.icon.class])}
|
|
181
|
-
style={$localSelected.value.icon.style}
|
|
182
|
-
size={$localSelected.value.icon.size}
|
|
183
|
-
></Icon>
|
|
184
|
-
{:else}
|
|
185
|
-
<Icon data={LibIcon_Search} class="relative"></Icon>
|
|
186
|
-
{/if}
|
|
187
|
-
</div>
|
|
188
|
-
<!-- {id} -->
|
|
189
|
-
<input
|
|
190
|
-
{...$input}
|
|
191
|
-
use:$input.action
|
|
192
|
-
class="-mr-5 -ml-8 h-full min-w-0 flex-grow bg-transparent px-10"
|
|
193
|
-
{placeholder}
|
|
194
|
-
use:focusNow
|
|
195
|
-
/>
|
|
196
|
-
<div class="pointer-events-none relative right-0 flex gap-2">
|
|
197
|
-
{#if clearable && $localSelected}
|
|
198
|
-
<button on:click={clearSelection} class="pointer-events-auto">
|
|
199
|
-
<Icon data={LibIcon_Cross}></Icon>
|
|
200
|
-
</button>
|
|
201
|
-
{/if}
|
|
202
|
-
<!-- {#if $open}
|
|
203
|
-
<Icon data={LibIcon_ChevronUp}></Icon>
|
|
204
|
-
{:else}
|
|
205
|
-
<Icon data={LibIcon_ChevronDown}></Icon>
|
|
206
|
-
{/if} -->
|
|
207
|
-
</div>
|
|
208
|
-
</div>
|
|
209
|
-
|
|
210
|
-
{#if $open}
|
|
211
|
-
<ul
|
|
212
|
-
class="z-50 flex max-h-[300px] flex-col overflow-hidden rounded-lg border border-base-content/20"
|
|
213
|
-
{...$menu}
|
|
214
|
-
use:$menu.action
|
|
215
|
-
transition:fly={{ duration: 150, y: -5 }}
|
|
216
|
-
>
|
|
217
|
-
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
|
218
|
-
<div class="flex max-h-full flex-col gap-0 overflow-y-auto bg-base-100 py-2" tabindex="0">
|
|
219
|
-
{#each filteredItems as item, index (index)}
|
|
220
|
-
<li
|
|
221
|
-
{...$option(toOption(item))}
|
|
222
|
-
use:$option.action
|
|
223
|
-
class="relative flex cursor-pointer scroll-my-2 items-start rounded-md px-1
|
|
224
|
-
py-2
|
|
225
|
-
data-[disabled]:opacity-50
|
|
226
|
-
data-[highlighted]:bg-primary
|
|
227
|
-
data-[highlighted]:text-primary-content"
|
|
228
|
-
>
|
|
229
|
-
<div class="flex items-center">
|
|
230
|
-
{#if $localSelected?.value?.id === item.id}
|
|
231
|
-
<Icon data={LibIcon_Check} class="w-6"></Icon>
|
|
232
|
-
{:else}
|
|
233
|
-
<!-- just to book the place -->
|
|
234
|
-
<span class="w-6"></span>
|
|
235
|
-
{/if}
|
|
236
|
-
{#if item.icon?.data}
|
|
237
|
-
<Icon
|
|
238
|
-
data={item.icon.data}
|
|
239
|
-
class={tw(['flex-shrink-0', item.icon.class])}
|
|
240
|
-
style={item.icon.style}
|
|
241
|
-
size={item.icon.size}
|
|
242
|
-
></Icon>
|
|
243
|
-
{/if}
|
|
244
|
-
</div>
|
|
245
|
-
<div class="pl-2">
|
|
246
|
-
<span class="font-medium">{@html item.caption}</span>
|
|
247
|
-
</div>
|
|
248
|
-
</li>
|
|
249
|
-
{:else}
|
|
250
|
-
{#if createOptionWhenNoResult}
|
|
251
|
-
{#if $inputValue}
|
|
252
|
-
<div class="p-4">
|
|
253
|
-
<Button
|
|
254
|
-
class="w-full"
|
|
255
|
-
onclick={async () => {
|
|
256
|
-
createRequest?.({ input: $inputValue, id })
|
|
257
|
-
$open = false
|
|
258
|
-
}}
|
|
259
|
-
>
|
|
260
|
-
<div class="flex items-center gap-2">
|
|
261
|
-
<Icon data={LibIcon_Add}></Icon>
|
|
262
|
-
{#if $inputValue}
|
|
263
|
-
Créer "{$inputValue}"
|
|
264
|
-
{/if}
|
|
265
|
-
</div>
|
|
266
|
-
</Button>
|
|
267
|
-
</div>
|
|
268
|
-
{:else}
|
|
269
|
-
<li class="relative cursor-pointer rounded-md py-1 pl-8 pr-4 text-sm">
|
|
270
|
-
Il faut tenter de rechercher avant de créer un nouvel élément
|
|
271
|
-
</li>
|
|
272
|
-
{/if}
|
|
273
|
-
{:else}
|
|
274
|
-
<li class="relative cursor-pointer rounded-md py-1 pl-8 pr-4">Aucun résultat</li>
|
|
275
|
-
{/if}
|
|
276
|
-
{/each}
|
|
277
|
-
</div>
|
|
278
|
-
{#if totalCount}
|
|
279
|
-
<div class="z-50 bg-base-300 text-center text-xs">
|
|
280
|
-
{#if items.length < totalCount}
|
|
281
|
-
({items.length} / {totalCount})
|
|
282
|
-
{:else}
|
|
283
|
-
<!-- yes, items.length can be bigger if the selected item is not in the limit -->
|
|
284
|
-
({items.length})
|
|
285
|
-
{/if}
|
|
286
|
-
</div>
|
|
287
|
-
{/if}
|
|
288
|
-
</ul>
|
|
289
|
-
{/if}
|