runeforge 0.0.40 → 0.0.42
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.
|
@@ -102,6 +102,7 @@
|
|
|
102
102
|
const allowRead = $derived(read.enabled ?? true);
|
|
103
103
|
const allowUpdate = $derived(update.enabled ?? true);
|
|
104
104
|
const allowDelete = $derived(deletion.enabled ?? true);
|
|
105
|
+
const allowCreate = $derived(creation.enabled ?? true);
|
|
105
106
|
const deleteLabel = $derived(deletion.label ?? strings.delete);
|
|
106
107
|
const updateLabel = $derived(update.label ?? strings.edit);
|
|
107
108
|
const readLabel = $derived(read.label ?? strings.view);
|
|
@@ -353,15 +354,17 @@
|
|
|
353
354
|
</Button>
|
|
354
355
|
{/if}
|
|
355
356
|
|
|
356
|
-
{
|
|
357
|
-
|
|
358
|
-
<
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
357
|
+
{#if allowCreate}
|
|
358
|
+
{@const CreateIcon = icons.create}
|
|
359
|
+
<Button variant="primary" onclick={measuring ? undefined : handleCreate}>
|
|
360
|
+
<CreateIcon class="size-5" />
|
|
361
|
+
{#if creation.label}
|
|
362
|
+
<span>{creation.label}</span>
|
|
363
|
+
{:else}
|
|
364
|
+
<span>{strings.create}<span class="hidden sm:inline"> {labelOne}</span></span>
|
|
365
|
+
{/if}
|
|
366
|
+
</Button>
|
|
367
|
+
{/if}
|
|
365
368
|
{/snippet}
|
|
366
369
|
|
|
367
370
|
{#snippet actionsCell(item: T)}
|
|
@@ -415,7 +418,6 @@
|
|
|
415
418
|
<SearchInput config={search} />
|
|
416
419
|
{/if}
|
|
417
420
|
|
|
418
|
-
{@const CreateIcon = icons.create}
|
|
419
421
|
<Button
|
|
420
422
|
variant="ghost"
|
|
421
423
|
class="btn-square"
|
|
@@ -433,17 +435,20 @@
|
|
|
433
435
|
class="dropdown dropdown-end w-56 rounded-box border border-base-content/10 bg-base-100 p-1 shadow-lg"
|
|
434
436
|
bind:this={actionsPopoverEl}
|
|
435
437
|
>
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
438
|
+
{#if allowCreate}
|
|
439
|
+
{@const CreateIcon = icons.create}
|
|
440
|
+
<Button
|
|
441
|
+
variant="ghost"
|
|
442
|
+
class="btn-sm w-full justify-start"
|
|
443
|
+
onclick={() => {
|
|
444
|
+
actionsPopoverEl?.hidePopover();
|
|
445
|
+
handleCreate();
|
|
446
|
+
}}
|
|
447
|
+
>
|
|
448
|
+
<CreateIcon class="size-4" />
|
|
449
|
+
{creation.label || `${strings.create} ${labelOne}`}
|
|
450
|
+
</Button>
|
|
451
|
+
{/if}
|
|
447
452
|
|
|
448
453
|
{#if allowDelete}
|
|
449
454
|
<Button
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { SvelteMap } from 'svelte/reactivity';
|
|
3
3
|
import { getStrings } from '../../i18n/context.js';
|
|
4
|
+
import { getIconSet } from '../../icons/context.js';
|
|
5
|
+
import { defaultIconSet } from '../../icons/sets/default.js';
|
|
6
|
+
import Button from './Button.svelte';
|
|
4
7
|
import type { SearchResolver, SelectOption } from '../../types/attribute.js';
|
|
5
8
|
|
|
6
9
|
const strings = getStrings();
|
|
10
|
+
const icons = $derived(getIconSet() ?? defaultIconSet);
|
|
7
11
|
|
|
8
12
|
let {
|
|
9
13
|
name,
|
|
@@ -14,6 +18,12 @@
|
|
|
14
18
|
placeholder = strings.selectPlaceholder,
|
|
15
19
|
error = '',
|
|
16
20
|
disabled = false,
|
|
21
|
+
// When passed, the dropdown's top row selects every option instead of
|
|
22
|
+
// clearing the selection (labelled `strings.selectAll` instead of
|
|
23
|
+
// `placeholder`) — clearing moves to the trigger's own × button instead.
|
|
24
|
+
// Left unset, existing callers keep today's behavior unchanged: top row
|
|
25
|
+
// clears, no × button.
|
|
26
|
+
onSelectAll,
|
|
17
27
|
}: {
|
|
18
28
|
name?: string;
|
|
19
29
|
value?: string[];
|
|
@@ -23,6 +33,7 @@
|
|
|
23
33
|
placeholder?: string;
|
|
24
34
|
error?: string;
|
|
25
35
|
disabled?: boolean;
|
|
36
|
+
onSelectAll?: () => void;
|
|
26
37
|
} = $props();
|
|
27
38
|
|
|
28
39
|
const popId = $props.id();
|
|
@@ -87,6 +98,17 @@
|
|
|
87
98
|
function onToggle(e: Event) {
|
|
88
99
|
if ((e as ToggleEvent).newState === 'closed') query = '';
|
|
89
100
|
}
|
|
101
|
+
|
|
102
|
+
const hasSelection = $derived(value.length > 0);
|
|
103
|
+
|
|
104
|
+
function clearFromTrigger(e: MouseEvent) {
|
|
105
|
+
// Stop the click from also reaching the popover-trigger button
|
|
106
|
+
// underneath (they're overlapping siblings, not nested) so clearing
|
|
107
|
+
// doesn't toggle the dropdown open at the same time.
|
|
108
|
+
e.preventDefault();
|
|
109
|
+
e.stopPropagation();
|
|
110
|
+
clear();
|
|
111
|
+
}
|
|
90
112
|
</script>
|
|
91
113
|
|
|
92
114
|
<div class="relative w-full">
|
|
@@ -94,18 +116,34 @@
|
|
|
94
116
|
<input type="hidden" {name} value={JSON.stringify(value)} />
|
|
95
117
|
{/if}
|
|
96
118
|
|
|
97
|
-
<
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
119
|
+
<div class="relative">
|
|
120
|
+
<button
|
|
121
|
+
type="button"
|
|
122
|
+
class="select select-bordered w-full text-left font-normal"
|
|
123
|
+
class:select-error={!!error}
|
|
124
|
+
class:opacity-40={value.length === 0}
|
|
125
|
+
class:pr-8={hasSelection}
|
|
126
|
+
{disabled}
|
|
127
|
+
popovertarget={popId}
|
|
128
|
+
style="anchor-name:{anchorName}"
|
|
129
|
+
title={selectedLabels.join(', ')}
|
|
130
|
+
>
|
|
131
|
+
{buttonLabel}
|
|
132
|
+
</button>
|
|
133
|
+
|
|
134
|
+
{#if hasSelection && !disabled}
|
|
135
|
+
{@const Icon = icons.clear}
|
|
136
|
+
<Button
|
|
137
|
+
variant="ghost"
|
|
138
|
+
class="btn-xs btn-square btn-circle absolute top-1/2 right-6 -translate-y-1/2"
|
|
139
|
+
aria-label={strings.selectClear}
|
|
140
|
+
title={strings.selectClear}
|
|
141
|
+
onclick={clearFromTrigger}
|
|
142
|
+
>
|
|
143
|
+
<Icon class="size-3" />
|
|
144
|
+
</Button>
|
|
145
|
+
{/if}
|
|
146
|
+
</div>
|
|
109
147
|
|
|
110
148
|
<div
|
|
111
149
|
popover="auto"
|
|
@@ -129,9 +167,9 @@
|
|
|
129
167
|
<button
|
|
130
168
|
type="button"
|
|
131
169
|
class="w-full rounded-btn px-3 py-2 text-left text-sm text-base-content/40 hover:bg-base-200"
|
|
132
|
-
onclick={clear}
|
|
170
|
+
onclick={onSelectAll ?? clear}
|
|
133
171
|
>
|
|
134
|
-
{placeholder}
|
|
172
|
+
{onSelectAll ? strings.selectAll : placeholder}
|
|
135
173
|
</button>
|
|
136
174
|
</li>
|
|
137
175
|
{#if searching}
|
|
@@ -8,6 +8,7 @@ type $$ComponentProps = {
|
|
|
8
8
|
placeholder?: string;
|
|
9
9
|
error?: string;
|
|
10
10
|
disabled?: boolean;
|
|
11
|
+
onSelectAll?: () => void;
|
|
11
12
|
};
|
|
12
13
|
declare const MultiSelect: import("svelte").Component<$$ComponentProps, {}, "value">;
|
|
13
14
|
type MultiSelect = ReturnType<typeof MultiSelect>;
|
package/dist/i18n/en.js
CHANGED
package/dist/i18n/es.js
CHANGED
|
@@ -13,6 +13,8 @@ export const es = {
|
|
|
13
13
|
selectSearching: 'Buscando...',
|
|
14
14
|
selectNoResults: 'Sin resultados',
|
|
15
15
|
selectedCount: (count) => `${count} seleccionado${count === 1 ? '' : 's'}`,
|
|
16
|
+
selectAll: 'Seleccionar todo',
|
|
17
|
+
selectClear: 'Limpiar selección',
|
|
16
18
|
view: 'Ver',
|
|
17
19
|
edit: 'Editar',
|
|
18
20
|
delete: 'Eliminar',
|
package/dist/i18n/types.d.ts
CHANGED