@svgrid/grid 2.2.16 → 2.2.18
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/README.md +1 -1
- package/dist/GridFooter.svelte +12 -11
- package/dist/SvAnchor.svelte +65 -0
- package/dist/SvAnchor.svelte.d.ts +24 -0
- package/dist/SvAspectRatio.svelte +38 -0
- package/dist/SvAspectRatio.svelte.d.ts +16 -0
- package/dist/SvAutoComplete.svelte +52 -7
- package/dist/SvAutoComplete.svelte.d.ts +4 -1
- package/dist/SvBlockquote.svelte +43 -0
- package/dist/SvBlockquote.svelte.d.ts +16 -0
- package/dist/SvCalendar.svelte +33 -2
- package/dist/SvCalendar.svelte.d.ts +8 -1
- package/dist/SvCheckBox.svelte +6 -2
- package/dist/SvCode.svelte +52 -0
- package/dist/SvCode.svelte.d.ts +19 -0
- package/dist/SvCollapsible.svelte +75 -0
- package/dist/SvCollapsible.svelte.d.ts +27 -0
- package/dist/SvColorInput.svelte +11 -17
- package/dist/SvColorInput.svelte.d.ts +2 -0
- package/dist/SvComboBox.svelte +85 -8
- package/dist/SvComboBox.svelte.d.ts +14 -0
- package/dist/SvCountryInput.svelte +2 -2
- package/dist/SvCountryInput.svelte.d.ts +1 -1
- package/dist/SvDropDownList.svelte +154 -51
- package/dist/SvDropDownList.svelte.d.ts +17 -3
- package/dist/SvDurationInput.svelte +59 -41
- package/dist/SvDurationInput.svelte.d.ts +18 -0
- package/dist/SvField.svelte +203 -12
- package/dist/SvField.svelte.d.ts +45 -8
- package/dist/SvForm.svelte +195 -21
- package/dist/SvForm.svelte.d.ts +23 -0
- package/dist/SvGrid.controller.svelte.d.ts +12 -1
- package/dist/SvGrid.controller.svelte.js +87 -7
- package/dist/SvGrid.svelte +383 -181
- package/dist/SvGrid.types.d.ts +123 -2
- package/dist/SvGridChartView.svelte +70 -0
- package/dist/SvGridChartView.svelte.d.ts +11 -0
- package/dist/SvGridDropdown.svelte +9 -2
- package/dist/SvGridSelect.svelte +5 -2
- package/dist/SvGridSelect.svelte.d.ts +1 -1
- package/dist/SvGroup.svelte +41 -0
- package/dist/SvGroup.svelte.d.ts +27 -0
- package/dist/SvHoverCard.svelte +70 -0
- package/dist/SvHoverCard.svelte.d.ts +41 -0
- package/dist/SvKbd.svelte +51 -0
- package/dist/SvKbd.svelte.d.ts +18 -0
- package/dist/SvList.svelte +55 -0
- package/dist/SvList.svelte.d.ts +23 -0
- package/dist/SvListBox.svelte +166 -77
- package/dist/SvListBox.svelte.d.ts +17 -4
- package/dist/SvLoadingOverlay.svelte +53 -0
- package/dist/SvLoadingOverlay.svelte.d.ts +28 -0
- package/dist/SvMark.svelte +36 -0
- package/dist/SvMark.svelte.d.ts +14 -0
- package/dist/SvMaskedInput.svelte +50 -35
- package/dist/SvMaskedInput.svelte.d.ts +17 -2
- package/dist/SvMenuList.svelte +32 -3
- package/dist/SvMenubar.svelte +200 -0
- package/dist/SvMenubar.svelte.d.ts +18 -0
- package/dist/SvMultiSelect.svelte +7 -4
- package/dist/SvMultiSelect.svelte.d.ts +1 -1
- package/dist/SvNumberInput.svelte +79 -42
- package/dist/SvNumberInput.svelte.d.ts +25 -0
- package/dist/SvOtpInput.svelte +2 -2
- package/dist/SvPasswordInput.svelte +51 -31
- package/dist/SvPasswordInput.svelte.d.ts +17 -0
- package/dist/SvPhoneInput.svelte +39 -28
- package/dist/SvPhoneInput.svelte.d.ts +4 -0
- package/dist/SvPopconfirm.svelte +79 -0
- package/dist/SvPopconfirm.svelte.d.ts +42 -0
- package/dist/SvPopover.svelte +87 -29
- package/dist/SvPopover.svelte.d.ts +18 -4
- package/dist/SvRadioGroup.svelte +5 -1
- package/dist/SvResult.svelte +73 -0
- package/dist/SvResult.svelte.d.ts +28 -0
- package/dist/SvSegmented.svelte +114 -0
- package/dist/SvSegmented.svelte.d.ts +29 -0
- package/dist/SvSimpleGrid.svelte +41 -0
- package/dist/SvSimpleGrid.svelte.d.ts +25 -0
- package/dist/SvSlider.svelte +23 -10
- package/dist/SvSpinner.svelte +43 -0
- package/dist/SvSpinner.svelte.d.ts +20 -0
- package/dist/SvStack.svelte +37 -0
- package/dist/SvStack.svelte.d.ts +24 -0
- package/dist/SvSwitchButton.svelte +6 -1
- package/dist/SvTagsInput.svelte +9 -5
- package/dist/SvText.svelte +76 -0
- package/dist/SvText.svelte.d.ts +31 -0
- package/dist/SvTextInput.svelte +75 -43
- package/dist/SvTextInput.svelte.d.ts +28 -1
- package/dist/SvTimePicker.svelte +32 -2
- package/dist/SvTimePicker.svelte.d.ts +8 -9
- package/dist/SvTitle.svelte +57 -0
- package/dist/SvTitle.svelte.d.ts +24 -0
- package/dist/SvToaster.svelte +41 -6
- package/dist/SvToggleButton.svelte +4 -1
- package/dist/SvTooltip.svelte +68 -34
- package/dist/SvTooltip.svelte.d.ts +14 -2
- package/dist/SvTree.svelte +81 -21
- package/dist/SvTree.svelte.d.ts +3 -2
- package/dist/SvTreeSelect.svelte +5 -2
- package/dist/SvTreeSelect.svelte.d.ts +1 -1
- package/dist/SvVisuallyHidden.svelte +49 -0
- package/dist/SvVisuallyHidden.svelte.d.ts +19 -0
- package/dist/ai.d.ts +289 -0
- package/dist/ai.js +1013 -0
- package/dist/board-view.svelte.d.ts +22 -0
- package/dist/board-view.svelte.js +13 -0
- package/dist/build-api.js +36 -6
- package/dist/cdn/GridMenus-0AK9O7qG.js +420 -0
- package/dist/cdn/GridMenus-BjUoCXoD.js +416 -0
- package/dist/cdn/SvDateTimePicker-CYC7gRER.js +2176 -0
- package/dist/cdn/SvDateTimePicker-DtQKd4Ns.js +2198 -0
- package/dist/cdn/SvGridChart-BcLCYvw9.js +1195 -0
- package/dist/cdn/SvGridChart-BhnFdLd0.js +1203 -0
- package/dist/cdn/SvGridChartPanel-Cmx9DHAS.js +561 -0
- package/dist/cdn/SvGridChartPanel-DvjwxLvK.js +577 -0
- package/dist/cdn/SvGridChartView-B40DTJSX.js +54 -0
- package/dist/cdn/SvGridChartView-PwqI4s02.js +53 -0
- package/dist/cdn/SvGridDropdown-DjALc_4f.js +255 -0
- package/dist/cdn/SvGridDropdown-hpnHvOGt.js +254 -0
- package/dist/cdn/chart-T1usDN0o.js +1212 -0
- package/dist/cdn/disclose-version-DoD9AFD_.js +2958 -0
- package/dist/cdn/export-format-JT5pWVT8.js +561 -0
- package/dist/cdn/popover-P-9P2YYn.js +69 -0
- package/dist/cdn/rolldown-runtime-Dy4uBu1J.js +11 -0
- package/dist/cdn/src-BLhdLmoN.js +25707 -0
- package/dist/cdn/src-BwnUVj3T.js +25623 -0
- package/dist/cdn/svgrid.js +9 -32897
- package/dist/cdn/svgrid.svelte-external.js +9 -30052
- package/dist/cell-formatting.d.ts +2 -2
- package/dist/cell-render.js +4 -4
- package/dist/chart-view.svelte.d.ts +25 -0
- package/dist/chart-view.svelte.js +14 -0
- package/dist/createCombobox.svelte.d.ts +5 -0
- package/dist/createCombobox.svelte.js +21 -5
- package/dist/createDropdownList.svelte.d.ts +3 -0
- package/dist/createDropdownList.svelte.js +8 -2
- package/dist/createForm.svelte.d.ts +18 -0
- package/dist/createForm.svelte.js +51 -6
- package/dist/createMenu.svelte.js +27 -0
- package/dist/createPopoverSelect.svelte.d.ts +3 -0
- package/dist/createPopoverSelect.svelte.js +9 -1
- package/dist/createSlider.svelte.d.ts +8 -21
- package/dist/createSlider.svelte.js +34 -0
- package/dist/createTooltip.svelte.d.ts +12 -0
- package/dist/createTooltip.svelte.js +72 -9
- package/dist/editor-contract.d.ts +15 -0
- package/dist/export-provider.d.ts +27 -0
- package/dist/export-provider.js +9 -0
- package/dist/filter-operators.d.ts +6 -0
- package/dist/filter-operators.js +33 -0
- package/dist/form-field.d.ts +45 -2
- package/dist/grid-messages.d.ts +61 -0
- package/dist/grid-messages.js +72 -0
- package/dist/group-display.d.ts +62 -0
- package/dist/group-display.js +78 -0
- package/dist/index.d.ts +36 -4
- package/dist/index.js +43 -2
- package/dist/js-scroller.svelte.d.ts +35 -0
- package/dist/js-scroller.svelte.js +154 -0
- package/dist/list-option.d.ts +46 -0
- package/dist/list-option.js +53 -0
- package/dist/menus.js +25 -11
- package/dist/pivot-view.svelte.d.ts +72 -0
- package/dist/pivot-view.svelte.js +13 -0
- package/dist/positioning.d.ts +111 -0
- package/dist/positioning.js +191 -0
- package/dist/scheduler-model.d.ts +3 -0
- package/dist/scheduler-model.js +22 -5
- package/dist/svgrid-wrapper.types.d.ts +18 -0
- package/dist/toast-store.svelte.d.ts +54 -0
- package/dist/toast-store.svelte.js +65 -15
- package/package.json +9 -1
- package/src/GridFooter.svelte +12 -11
- package/src/SvAnchor.svelte +65 -0
- package/src/SvAspectRatio.svelte +38 -0
- package/src/SvAutoComplete.svelte +52 -7
- package/src/SvBlockquote.svelte +43 -0
- package/src/SvCalendar.svelte +33 -2
- package/src/SvCalendar.test.ts +15 -0
- package/src/SvCheckBox.svelte +6 -2
- package/src/SvCode.svelte +52 -0
- package/src/SvCollapsible.svelte +75 -0
- package/src/SvColorInput.svelte +11 -17
- package/src/SvComboBox.svelte +85 -8
- package/src/SvCountryInput.svelte +2 -2
- package/src/SvDropDownList.svelte +154 -51
- package/src/SvDurationInput.svelte +59 -41
- package/src/SvField.svelte +203 -12
- package/src/SvForm.svelte +195 -21
- package/src/SvForm.test.ts +112 -0
- package/src/SvGrid.controller.svelte.ts +88 -7
- package/src/SvGrid.svelte +383 -181
- package/src/SvGrid.types.ts +125 -1
- package/src/SvGridChartView.svelte +70 -0
- package/src/SvGridDropdown.svelte +9 -2
- package/src/SvGridSelect.svelte +5 -2
- package/src/SvGroup.svelte +41 -0
- package/src/SvHoverCard.svelte +70 -0
- package/src/SvKbd.svelte +51 -0
- package/src/SvList.svelte +55 -0
- package/src/SvListBox.svelte +166 -77
- package/src/SvLoadingOverlay.svelte +53 -0
- package/src/SvMark.svelte +36 -0
- package/src/SvMaskedInput.svelte +50 -35
- package/src/SvMenuList.svelte +32 -3
- package/src/SvMenubar.svelte +200 -0
- package/src/SvMultiSelect.svelte +7 -4
- package/src/SvNumberInput.svelte +79 -42
- package/src/SvOtpInput.svelte +2 -2
- package/src/SvPasswordInput.svelte +51 -31
- package/src/SvPhoneInput.svelte +39 -28
- package/src/SvPopconfirm.svelte +79 -0
- package/src/SvPopover.svelte +87 -29
- package/src/SvRadioGroup.svelte +5 -1
- package/src/SvResult.svelte +73 -0
- package/src/SvSegmented.svelte +114 -0
- package/src/SvSimpleGrid.svelte +41 -0
- package/src/SvSlider.svelte +23 -10
- package/src/SvSpinner.svelte +43 -0
- package/src/SvStack.svelte +37 -0
- package/src/SvSwitchButton.svelte +6 -1
- package/src/SvTagsInput.svelte +9 -5
- package/src/SvText.svelte +76 -0
- package/src/SvTextInput.svelte +75 -43
- package/src/SvTimePicker.svelte +32 -2
- package/src/SvTitle.svelte +57 -0
- package/src/SvToaster.svelte +41 -6
- package/src/SvToaster.test.ts +32 -0
- package/src/SvToggleButton.svelte +4 -1
- package/src/SvTooltip.svelte +68 -34
- package/src/SvTree.svelte +81 -21
- package/src/SvTreeSelect.svelte +5 -2
- package/src/SvVisuallyHidden.svelte +49 -0
- package/src/ai.test.ts +502 -0
- package/src/ai.ts +1391 -0
- package/src/board-view.svelte.ts +33 -0
- package/src/build-api.coverage.test.ts +101 -0
- package/src/build-api.ts +43 -18
- package/src/builtin-editors.grid.test.ts +1 -1
- package/src/cell-formatting.ts +5 -5
- package/src/cell-render.ts +4 -4
- package/src/chart-view.svelte.ts +36 -0
- package/src/createCombobox.svelte.ts +17 -5
- package/src/createDropdownList.svelte.ts +8 -2
- package/src/createForm.svelte.ts +59 -6
- package/src/createMenu.svelte.ts +23 -0
- package/src/createPopoverSelect.svelte.ts +8 -1
- package/src/createSlider.svelte.ts +20 -0
- package/src/createTooltip.svelte.ts +67 -9
- package/src/editor-contract.ts +16 -0
- package/src/export-provider.ts +40 -0
- package/src/filter-operators.ts +37 -0
- package/src/form-field.ts +42 -2
- package/src/grid-messages.test.ts +24 -0
- package/src/grid-messages.ts +137 -0
- package/src/group-display.test.ts +77 -0
- package/src/group-display.ts +117 -0
- package/src/i18n.grid.test.ts +73 -0
- package/src/index.ts +91 -2
- package/src/js-scroller.svelte.ts +173 -0
- package/src/list-option.test.ts +56 -0
- package/src/list-option.ts +81 -0
- package/src/menus.test.ts +32 -0
- package/src/menus.ts +25 -12
- package/src/pivot-view.svelte.ts +90 -0
- package/src/pivot-view.test.ts +38 -0
- package/src/pivot.grid.test.ts +102 -0
- package/src/positioning.test.ts +141 -0
- package/src/positioning.ts +266 -0
- package/src/scheduler-model.test.ts +16 -0
- package/src/scheduler-model.ts +24 -5
- package/src/svgrid-wrapper.types.ts +23 -0
- package/src/svgrid.charting.test.ts +8 -1
- package/src/svgrid.comments-autocomplete.test.ts +7 -2
- package/src/svgrid.context-menu.test.ts +8 -3
- package/src/toast-store.svelte.ts +98 -0
- package/src/toast-store.test.ts +62 -1
- package/src/ui-breadth.test.ts +138 -0
- package/src/ui-buttons.test.ts +39 -0
- package/src/ui-inputs.test.ts +2 -2
- package/src/ui-range.test.ts +9 -0
- package/src/ui-selection.test.ts +36 -0
- package/src/ui-tier1.test.ts +1 -1
- package/src/virtual.test.ts +20 -6
- package/dist/SvGridBoard.svelte +0 -2339
- package/dist/SvGridBoard.svelte.d.ts +0 -31
- package/src/SvGridBoard.svelte +0 -2339
- package/src/board.test.ts +0 -927
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* SvCollapsible - a single show/hide region with an accessible trigger (the
|
|
4
|
+
* standalone form of one accordion item). The header toggles the panel with a
|
|
5
|
+
* rotating chevron; the panel animates its height open/closed and respects
|
|
6
|
+
* `prefers-reduced-motion`.
|
|
7
|
+
*
|
|
8
|
+
* ```svelte
|
|
9
|
+
* <SvCollapsible title="Advanced options" bind:open>
|
|
10
|
+
* ...content...
|
|
11
|
+
* </SvCollapsible>
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
import type { Snippet } from 'svelte'
|
|
15
|
+
import { nextEditorId } from './editor-contract'
|
|
16
|
+
|
|
17
|
+
type Props = {
|
|
18
|
+
/** Header text (ignored when a `header` snippet is given). */
|
|
19
|
+
title?: string
|
|
20
|
+
/** Open state (bindable). */
|
|
21
|
+
open?: boolean
|
|
22
|
+
onOpenChange?: (open: boolean) => void
|
|
23
|
+
disabled?: boolean
|
|
24
|
+
/** Custom header content (replaces `title`). */
|
|
25
|
+
header?: Snippet
|
|
26
|
+
children?: Snippet
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
let { title, open = $bindable(false), onOpenChange, disabled = false, header, children }: Props = $props()
|
|
30
|
+
|
|
31
|
+
const uid = nextEditorId('sv-collapse')
|
|
32
|
+
function toggle() {
|
|
33
|
+
if (disabled) return
|
|
34
|
+
open = !open
|
|
35
|
+
onOpenChange?.(open)
|
|
36
|
+
}
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<div class="sv-collapse" class:is-open={open} class:is-disabled={disabled}>
|
|
40
|
+
<button
|
|
41
|
+
class="sv-collapse__trigger"
|
|
42
|
+
type="button"
|
|
43
|
+
{disabled}
|
|
44
|
+
aria-expanded={open}
|
|
45
|
+
aria-controls={`${uid}-panel`}
|
|
46
|
+
id={`${uid}-trigger`}
|
|
47
|
+
onclick={toggle}
|
|
48
|
+
>
|
|
49
|
+
<span class="sv-collapse__label">{#if header}{@render header()}{:else}{title}{/if}</span>
|
|
50
|
+
<svg class="sv-collapse__chev" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6" /></svg>
|
|
51
|
+
</button>
|
|
52
|
+
<div class="sv-collapse__region" id={`${uid}-panel`} role="region" aria-labelledby={`${uid}-trigger`} inert={!open}>
|
|
53
|
+
<div class="sv-collapse__content">{@render children?.()}</div>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<style>
|
|
58
|
+
.sv-collapse { border: 1px solid var(--sg-border, #e2e8f0); border-radius: 10px; background: var(--sg-bg, #fff); }
|
|
59
|
+
.sv-collapse__trigger {
|
|
60
|
+
display: flex; align-items: center; justify-content: space-between; gap: 10px; width: 100%; box-sizing: border-box;
|
|
61
|
+
padding: 11px 14px; background: none; border: 0; cursor: pointer; font: inherit; font-size: 13.5px; font-weight: 600;
|
|
62
|
+
color: var(--sg-fg, #0f172a); text-align: start;
|
|
63
|
+
}
|
|
64
|
+
.sv-collapse__trigger:hover:not(:disabled) { background: var(--sg-row-hover-bg, #f1f5f9); border-radius: 10px; }
|
|
65
|
+
.sv-collapse__trigger:disabled { opacity: 0.55; cursor: not-allowed; }
|
|
66
|
+
.sv-collapse__trigger:focus-visible { outline: 2px solid var(--sg-focus-ring, var(--sg-accent, #2563eb)); outline-offset: -2px; border-radius: 10px; }
|
|
67
|
+
.sv-collapse__label { min-width: 0; }
|
|
68
|
+
.sv-collapse__chev { flex: none; color: var(--sg-muted, #64748b); transition: transform 0.16s ease; }
|
|
69
|
+
.sv-collapse.is-open .sv-collapse__chev { transform: rotate(180deg); }
|
|
70
|
+
.sv-collapse__region { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 0.18s ease; }
|
|
71
|
+
.sv-collapse.is-open .sv-collapse__region { grid-template-rows: 1fr; }
|
|
72
|
+
.sv-collapse__content { overflow: hidden; padding: 0 14px; min-height: 0; }
|
|
73
|
+
.sv-collapse.is-open .sv-collapse__content { padding-bottom: 13px; }
|
|
74
|
+
@media (prefers-reduced-motion: reduce) { .sv-collapse__region, .sv-collapse__chev { transition: none; } }
|
|
75
|
+
</style>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SvCollapsible - a single show/hide region with an accessible trigger (the
|
|
3
|
+
* standalone form of one accordion item). The header toggles the panel with a
|
|
4
|
+
* rotating chevron; the panel animates its height open/closed and respects
|
|
5
|
+
* `prefers-reduced-motion`.
|
|
6
|
+
*
|
|
7
|
+
* ```svelte
|
|
8
|
+
* <SvCollapsible title="Advanced options" bind:open>
|
|
9
|
+
* ...content...
|
|
10
|
+
* </SvCollapsible>
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
import type { Snippet } from 'svelte';
|
|
14
|
+
type Props = {
|
|
15
|
+
/** Header text (ignored when a `header` snippet is given). */
|
|
16
|
+
title?: string;
|
|
17
|
+
/** Open state (bindable). */
|
|
18
|
+
open?: boolean;
|
|
19
|
+
onOpenChange?: (open: boolean) => void;
|
|
20
|
+
disabled?: boolean;
|
|
21
|
+
/** Custom header content (replaces `title`). */
|
|
22
|
+
header?: Snippet;
|
|
23
|
+
children?: Snippet;
|
|
24
|
+
};
|
|
25
|
+
declare const SvCollapsible: import("svelte").Component<Props, {}, "open">;
|
|
26
|
+
type SvCollapsible = ReturnType<typeof SvCollapsible>;
|
|
27
|
+
export default SvCollapsible;
|
package/dist/SvColorInput.svelte
CHANGED
|
@@ -26,6 +26,8 @@
|
|
|
26
26
|
autoOpen?: boolean
|
|
27
27
|
/** Override the built-in popover strings. */
|
|
28
28
|
messages?: Partial<ColorMessages>
|
|
29
|
+
/** Stretch to the container width (otherwise hugs its content). */
|
|
30
|
+
block?: boolean
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
let {
|
|
@@ -44,8 +46,10 @@
|
|
|
44
46
|
hint,
|
|
45
47
|
dir,
|
|
46
48
|
id,
|
|
49
|
+
loading = false,
|
|
47
50
|
autoOpen = false,
|
|
48
51
|
messages,
|
|
52
|
+
block = false,
|
|
49
53
|
}: Props = $props()
|
|
50
54
|
|
|
51
55
|
const autoId = nextEditorId('sv-color')
|
|
@@ -100,12 +104,11 @@
|
|
|
100
104
|
}
|
|
101
105
|
</script>
|
|
102
106
|
|
|
103
|
-
<SvField id={uid} {label} {hint} {error} {required} {dir}>
|
|
107
|
+
<SvField frame id={uid} {label} {hint} {error} {required} {dir} {size} {invalid} {disabled} {readonly} {loading} {block} width={block ? undefined : 'fit-content'}>
|
|
104
108
|
<button
|
|
105
109
|
bind:this={triggerEl}
|
|
106
|
-
class="sv-
|
|
110
|
+
class="sv-color__trigger"
|
|
107
111
|
class:is-disabled={disabled}
|
|
108
|
-
class:is-invalid={invalid}
|
|
109
112
|
{...col.swatchProps()}
|
|
110
113
|
use:focusOpen
|
|
111
114
|
>
|
|
@@ -153,22 +156,13 @@
|
|
|
153
156
|
{#if name}<input type="hidden" {name} value={col.normalized} />{/if}
|
|
154
157
|
|
|
155
158
|
<style>
|
|
156
|
-
.sv-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
background: var(--sg-input-bg, #fff); color: var(--sg-fg, #0f172a);
|
|
160
|
-
border: 1px solid var(--sg-input-border, var(--sg-border, #cbd5e1)); border-radius: var(--sg-radius, 8px);
|
|
161
|
-
padding: 0 10px; cursor: pointer; font: inherit;
|
|
159
|
+
.sv-color__trigger {
|
|
160
|
+
display: flex; align-items: center; gap: 8px; width: 100%; height: 100%;
|
|
161
|
+
background: none; border: 0; padding: 0 10px; cursor: pointer; font: inherit; color: inherit;
|
|
162
162
|
}
|
|
163
|
-
.sv-
|
|
164
|
-
.sv-color--md { height: 34px; font-size: 13px; }
|
|
165
|
-
.sv-color--lg { height: 40px; font-size: 15px; }
|
|
166
|
-
.sv-color.is-disabled { opacity: 0.6; cursor: not-allowed; }
|
|
167
|
-
.sv-color.is-invalid { border-color: var(--sg-danger, #dc2626); }
|
|
168
|
-
.sv-color.is-invalid:focus-within { box-shadow: 0 0 0 2px color-mix(in srgb, var(--sg-danger, #dc2626) 22%, transparent); }
|
|
169
|
-
.sv-color:focus-visible { outline: 2px solid var(--sg-focus-ring, var(--_accent)); outline-offset: 2px; }
|
|
163
|
+
.sv-color__trigger.is-disabled { cursor: not-allowed; }
|
|
170
164
|
.sv-color__swatch { width: 18px; height: 18px; border-radius: 4px; border: 1px solid rgba(0,0,0,0.15); flex: none; }
|
|
171
|
-
.sv-color__hex { font-variant-numeric: tabular-nums; text-transform: lowercase; }
|
|
165
|
+
.sv-color__hex { font-variant-numeric: tabular-nums; text-transform: lowercase; white-space: nowrap; }
|
|
172
166
|
|
|
173
167
|
:global(.sv-color__panel) {
|
|
174
168
|
z-index: 2147483647; width: 208px; padding: 12px;
|
|
@@ -13,6 +13,8 @@ type Props = SvEditorProps & {
|
|
|
13
13
|
autoOpen?: boolean;
|
|
14
14
|
/** Override the built-in popover strings. */
|
|
15
15
|
messages?: Partial<ColorMessages>;
|
|
16
|
+
/** Stretch to the container width (otherwise hugs its content). */
|
|
17
|
+
block?: boolean;
|
|
16
18
|
};
|
|
17
19
|
declare const SvColorInput: import("svelte").Component<Props, {}, "value">;
|
|
18
20
|
type SvColorInput = ReturnType<typeof SvColorInput>;
|
package/dist/SvComboBox.svelte
CHANGED
|
@@ -8,11 +8,13 @@
|
|
|
8
8
|
* keyboard + ARIA); only portal/measure/scroll render concerns live here.
|
|
9
9
|
*/
|
|
10
10
|
import { anchoredRect, portalToBody, popIn, type AnchoredRect } from './popover'
|
|
11
|
+
import { startPanelResize } from './panel-resize'
|
|
11
12
|
import { createDismissableLayer } from './a11y/dismissable'
|
|
12
|
-
import { groupOptions, type ListOption } from './list-option'
|
|
13
|
+
import { groupOptions, normalizeOptions, type ListOption } from './list-option'
|
|
13
14
|
import SvField from './SvField.svelte'
|
|
14
15
|
import { nextEditorId, resolveMessages, type SvEditorProps } from './editor-contract'
|
|
15
16
|
import { createCombobox } from './createCombobox.svelte'
|
|
17
|
+
import type { Snippet } from 'svelte'
|
|
16
18
|
|
|
17
19
|
/** User-facing strings (localizable via `messages`). */
|
|
18
20
|
type ComboMessages = { noResults: string; loading: string; typeMore: string }
|
|
@@ -24,6 +26,11 @@
|
|
|
24
26
|
onChange?: (value: string | number | null) => void
|
|
25
27
|
placeholder?: string
|
|
26
28
|
autoOpen?: boolean
|
|
29
|
+
/** Show a clear (x) button when a value is selected. */
|
|
30
|
+
clearable?: boolean
|
|
31
|
+
/** Show a bottom drag grip so the user can resize the open panel's height
|
|
32
|
+
* (hidden when the panel flips upward, where there is no room to grow). */
|
|
33
|
+
resizable?: boolean
|
|
27
34
|
/** Load options from a server as the user types (debounced). Disables local
|
|
28
35
|
* filtering; the returned list is shown as-is. */
|
|
29
36
|
loadOptions?: (query: string) => Promise<ListOption[]>
|
|
@@ -33,6 +40,14 @@
|
|
|
33
40
|
debounce?: number
|
|
34
41
|
/** Override the built-in strings (empty-state / loading text). */
|
|
35
42
|
messages?: Partial<ComboMessages>
|
|
43
|
+
/** Custom render for each option (receives the ListOption). */
|
|
44
|
+
item?: Snippet<[ListOption]>
|
|
45
|
+
/** Content pinned above the option list. */
|
|
46
|
+
header?: Snippet
|
|
47
|
+
/** Content pinned below the option list. */
|
|
48
|
+
footer?: Snippet
|
|
49
|
+
/** Shown when the (non-loading) list is empty; overrides the default text. */
|
|
50
|
+
noData?: Snippet
|
|
36
51
|
}
|
|
37
52
|
|
|
38
53
|
let {
|
|
@@ -41,6 +56,9 @@
|
|
|
41
56
|
onChange,
|
|
42
57
|
placeholder = 'Select…',
|
|
43
58
|
disabled = false,
|
|
59
|
+
readonly = false,
|
|
60
|
+
clearable = false,
|
|
61
|
+
resizable = false,
|
|
44
62
|
name,
|
|
45
63
|
size = 'md',
|
|
46
64
|
ariaLabel,
|
|
@@ -51,11 +69,16 @@
|
|
|
51
69
|
hint,
|
|
52
70
|
dir,
|
|
53
71
|
id,
|
|
72
|
+
loading: loadingProp = false,
|
|
54
73
|
autoOpen = false,
|
|
55
74
|
loadOptions,
|
|
56
75
|
minLength = 1,
|
|
57
76
|
debounce = 250,
|
|
58
77
|
messages,
|
|
78
|
+
item,
|
|
79
|
+
header,
|
|
80
|
+
footer,
|
|
81
|
+
noData,
|
|
59
82
|
}: Props = $props()
|
|
60
83
|
|
|
61
84
|
const autoId = nextEditorId('sv-combo')
|
|
@@ -66,6 +89,14 @@
|
|
|
66
89
|
let fieldEl = $state<HTMLDivElement | null>(null)
|
|
67
90
|
let panelEl = $state<HTMLDivElement | null>(null)
|
|
68
91
|
let rect = $state<AnchoredRect>({ top: 0, left: 0, width: 0, openUpward: false, maxHeight: 0, availHeight: 0 })
|
|
92
|
+
// User-chosen panel height (px) once they drag the resize grip; null = auto.
|
|
93
|
+
let userHeight = $state<number | null>(null)
|
|
94
|
+
// Default comfortable cap (px) before the list scrolls; the grip can grow past it.
|
|
95
|
+
const DEFAULT_CAP = 288
|
|
96
|
+
const panelMaxH = $derived(
|
|
97
|
+
resizable && userHeight != null ? Math.min(userHeight, rect.availHeight) : Math.min(rect.availHeight, DEFAULT_CAP),
|
|
98
|
+
)
|
|
99
|
+
const showGrip = $derived(resizable && !rect.openUpward)
|
|
69
100
|
|
|
70
101
|
// Remote data source: fetch options as the query changes (debounced).
|
|
71
102
|
let remoteOptions = $state<ListOption[]>([])
|
|
@@ -73,13 +104,14 @@
|
|
|
73
104
|
let searched = $state(false)
|
|
74
105
|
let debTimer: ReturnType<typeof setTimeout> | undefined
|
|
75
106
|
let reqSeq = 0
|
|
76
|
-
const effectiveOptions = $derived(loadOptions ? remoteOptions : options)
|
|
107
|
+
const effectiveOptions = $derived(normalizeOptions(loadOptions ? remoteOptions : options))
|
|
77
108
|
|
|
78
109
|
const combo = createCombobox({
|
|
79
110
|
options: () => effectiveOptions,
|
|
80
111
|
value: () => value,
|
|
81
112
|
onChange: (v) => onChange?.(v),
|
|
82
113
|
disabled: () => disabled,
|
|
114
|
+
readonly: () => readonly,
|
|
83
115
|
ariaLabel: () => ariaLabel,
|
|
84
116
|
localFilter: () => !loadOptions,
|
|
85
117
|
focusInput: () => inputEl?.focus(),
|
|
@@ -114,8 +146,20 @@
|
|
|
114
146
|
// estimatedHeight only picks the flip direction (up vs down); the panel's
|
|
115
147
|
// real max-height comes from availHeight below, so it takes its natural
|
|
116
148
|
// content height (options + group labels) and scrolls only when it truly
|
|
117
|
-
// overflows the room - never from an estimate that under-counts a row.
|
|
118
|
-
|
|
149
|
+
// overflows the room - never from an estimate that under-counts a row. When
|
|
150
|
+
// the user has dragged the grip, anchor the flip decision to THAT height.
|
|
151
|
+
const est = resizable && userHeight != null ? userHeight : Math.min(combo.filtered.length, 8) * 34 + 12
|
|
152
|
+
rect = anchoredRect(fieldEl.getBoundingClientRect(), { estimatedHeight: est })
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function startResize(e: PointerEvent) {
|
|
156
|
+
if (!panelEl) return
|
|
157
|
+
startPanelResize(e, {
|
|
158
|
+
startHeight: panelEl.clientHeight,
|
|
159
|
+
min: 96,
|
|
160
|
+
max: () => rect.availHeight,
|
|
161
|
+
onHeight: (h) => { userHeight = h; updatePos() },
|
|
162
|
+
})
|
|
119
163
|
}
|
|
120
164
|
|
|
121
165
|
// Position + reposition + outside-click close are render concerns (need the DOM).
|
|
@@ -137,7 +181,7 @@
|
|
|
137
181
|
function focusOpen(node: HTMLInputElement) { if (autoOpen) { node.focus() } }
|
|
138
182
|
</script>
|
|
139
183
|
|
|
140
|
-
<SvField id={uid} {label} {hint} {error} {required} {dir}>
|
|
184
|
+
<SvField id={uid} {label} {hint} {error} {required} {dir} loading={loadingProp || loading}>
|
|
141
185
|
<div bind:this={fieldEl} class="sv-combo sv-combo--{size}" class:is-open={combo.open} class:is-disabled={disabled} class:is-invalid={invalid}>
|
|
142
186
|
<input
|
|
143
187
|
bind:this={inputEl}
|
|
@@ -147,6 +191,11 @@
|
|
|
147
191
|
{...combo.inputProps()}
|
|
148
192
|
use:focusOpen
|
|
149
193
|
/>
|
|
194
|
+
{#if clearable && combo.value != null && !disabled && !readonly}
|
|
195
|
+
<button type="button" class="sv-combo__clear" tabindex="-1" aria-label="Clear" onclick={() => { combo.clear(); inputEl?.focus() }}>
|
|
196
|
+
<svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><path d="M6 6l12 12M18 6L6 18" /></svg>
|
|
197
|
+
</button>
|
|
198
|
+
{/if}
|
|
150
199
|
<button class="sv-combo__chev" {...combo.triggerProps()}>
|
|
151
200
|
<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6" /></svg>
|
|
152
201
|
</button>
|
|
@@ -154,7 +203,8 @@
|
|
|
154
203
|
</SvField>
|
|
155
204
|
|
|
156
205
|
{#if combo.open}
|
|
157
|
-
<div bind:this={panelEl} class="sv-ddl__panel" use:portalToBody use:popIn={{ up: rect.openUpward }} style:position="fixed" style:top={rect.openUpward ? undefined : `${rect.top}px`} style:bottom={rect.openUpward ? `${rect.bottom}px` : undefined} style:left={`${rect.left}px`} style:min-width={`${rect.width}px`} style:max-height={`${
|
|
206
|
+
<div bind:this={panelEl} class="sv-ddl__panel" class:is-resizable={showGrip} use:portalToBody use:popIn={{ up: rect.openUpward }} style:position="fixed" style:top={rect.openUpward ? undefined : `${rect.top}px`} style:bottom={rect.openUpward ? `${rect.bottom}px` : undefined} style:left={`${rect.left}px`} style:min-width={`${rect.width}px`} style:max-height={`${panelMaxH}px`} style:height={resizable && userHeight != null && !rect.openUpward ? `${panelMaxH}px` : undefined} {...combo.listboxProps()}>
|
|
207
|
+
{#if header}<div class="sv-ddl__header">{@render header()}</div>{/if}
|
|
158
208
|
{#if loading}
|
|
159
209
|
<div class="sv-ddl__empty sv-ddl__loading"><svg class="sv-ddl__spin" viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><path d="M21 12a9 9 0 1 1-6.2-8.6" /></svg>{M.loading}</div>
|
|
160
210
|
{:else if loadOptions && !searched && combo.query.trim().length < minLength}
|
|
@@ -162,14 +212,23 @@
|
|
|
162
212
|
{:else if combo.filtered.length}
|
|
163
213
|
{#each groupOptions(combo.filtered) as g (g.group ?? ' ')}
|
|
164
214
|
{#if g.group != null}<div class="sv-ddl__group-label" aria-hidden="true">{g.group}</div>{/if}
|
|
165
|
-
{#each g.options as opt (opt.
|
|
215
|
+
{#each g.options as opt (opt.index)}
|
|
166
216
|
<!-- svelte-ignore a11y_click_events_have_key_events a11y_interactive_supports_focus -->
|
|
167
|
-
<div class="sv-ddl__opt" class:is-active={combo.isActive(opt.index)} class:is-selected={combo.isSelected(opt)} class:is-disabled={opt.disabled} {...combo.optionProps(opt.index)}>{opt.label}</div>
|
|
217
|
+
<div class="sv-ddl__opt" class:is-active={combo.isActive(opt.index)} class:is-selected={combo.isSelected(opt)} class:is-disabled={opt.disabled} {...combo.optionProps(opt.index)}>{#if item}{@render item(opt)}{:else}{opt.label}{/if}</div>
|
|
168
218
|
{/each}
|
|
169
219
|
{/each}
|
|
220
|
+
{:else if noData}
|
|
221
|
+
{@render noData()}
|
|
170
222
|
{:else}
|
|
171
223
|
<div class="sv-ddl__empty">{M.noResults}</div>
|
|
172
224
|
{/if}
|
|
225
|
+
{#if footer}<div class="sv-ddl__footer">{@render footer()}</div>{/if}
|
|
226
|
+
{#if showGrip}
|
|
227
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
228
|
+
<div class="sv-ddl__grip" onpointerdown={startResize} title="Drag to resize" aria-hidden="true">
|
|
229
|
+
<span class="sv-ddl__grip-dots"></span>
|
|
230
|
+
</div>
|
|
231
|
+
{/if}
|
|
173
232
|
</div>
|
|
174
233
|
{/if}
|
|
175
234
|
{#if name}<input type="hidden" {name} value={value ?? ''} />{/if}
|
|
@@ -189,10 +248,28 @@
|
|
|
189
248
|
.sv-combo.is-invalid.is-open, .sv-combo.is-invalid:focus-within { box-shadow: 0 0 0 2px color-mix(in srgb, var(--sg-danger, #dc2626) 22%, transparent); }
|
|
190
249
|
.sv-combo.is-disabled { opacity: 0.6; }
|
|
191
250
|
.sv-combo__input { flex: 1; min-width: 0; border: 0; background: none; outline: none; color: inherit; font: inherit; padding-block: 0; padding-inline: 10px 4px; }
|
|
251
|
+
.sv-combo__clear { display: grid; place-items: center; width: 22px; align-self: center; flex: none; background: none; border: 0; color: var(--sg-muted, #64748b); cursor: pointer; border-radius: 4px; }
|
|
252
|
+
.sv-combo__clear:hover { color: var(--sg-danger, #dc2626); }
|
|
192
253
|
.sv-combo__chev { display: grid; place-items: center; width: 28px; align-self: stretch; background: none; border: 0; color: var(--sg-muted, #64748b); cursor: pointer; }
|
|
193
254
|
:global(.sv-ddl__empty) { padding: 8px 10px; color: var(--sg-muted, #94a3b8); font-size: 13px; }
|
|
255
|
+
:global(.sv-ddl__header) { padding: 8px 10px; border-bottom: 1px solid var(--sg-border, #e2e8f0); font-size: 12.5px; color: var(--sg-muted, #64748b); }
|
|
256
|
+
:global(.sv-ddl__footer) { padding: 8px 10px; border-top: 1px solid var(--sg-border, #e2e8f0); font-size: 12.5px; }
|
|
194
257
|
:global(.sv-ddl__loading) { display: flex; align-items: center; gap: 7px; }
|
|
195
258
|
:global(.sv-ddl__spin) { animation: sv-combo-spin 0.7s linear infinite; }
|
|
196
259
|
@keyframes sv-combo-spin { to { transform: rotate(360deg); } }
|
|
197
260
|
@media (prefers-reduced-motion: reduce) { :global(.sv-ddl__spin) { animation: none; } }
|
|
261
|
+
/* Bottom resize grip (shared "····" handle - see SvDropDownList / panel-resize). */
|
|
262
|
+
:global(.sv-ddl__panel.is-resizable) { padding-bottom: 0; }
|
|
263
|
+
:global(.sv-ddl__grip) {
|
|
264
|
+
position: sticky; bottom: 0; z-index: 1; margin: 2px -4px -4px; height: 15px;
|
|
265
|
+
display: flex; align-items: center; justify-content: center; cursor: ns-resize;
|
|
266
|
+
background: var(--sg-bg, #fff); border-top: 1px solid var(--sg-border, #e2e8f0);
|
|
267
|
+
border-radius: 0 0 10px 10px; touch-action: none;
|
|
268
|
+
}
|
|
269
|
+
:global(.sv-ddl__grip-dots) {
|
|
270
|
+
width: 26px; height: 4px; color: var(--sg-muted, #94a3b8); opacity: 0.6;
|
|
271
|
+
background-image: radial-gradient(currentColor 1px, transparent 1.6px);
|
|
272
|
+
background-size: 6px 4px; background-position: center; background-repeat: repeat-x;
|
|
273
|
+
}
|
|
274
|
+
:global(.sv-ddl__grip:hover .sv-ddl__grip-dots) { opacity: 1; }
|
|
198
275
|
</style>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type ListOption } from './list-option';
|
|
2
2
|
import { type SvEditorProps } from './editor-contract';
|
|
3
|
+
import type { Snippet } from 'svelte';
|
|
3
4
|
/** User-facing strings (localizable via `messages`). */
|
|
4
5
|
type ComboMessages = {
|
|
5
6
|
noResults: string;
|
|
@@ -12,6 +13,11 @@ type Props = SvEditorProps & {
|
|
|
12
13
|
onChange?: (value: string | number | null) => void;
|
|
13
14
|
placeholder?: string;
|
|
14
15
|
autoOpen?: boolean;
|
|
16
|
+
/** Show a clear (x) button when a value is selected. */
|
|
17
|
+
clearable?: boolean;
|
|
18
|
+
/** Show a bottom drag grip so the user can resize the open panel's height
|
|
19
|
+
* (hidden when the panel flips upward, where there is no room to grow). */
|
|
20
|
+
resizable?: boolean;
|
|
15
21
|
/** Load options from a server as the user types (debounced). Disables local
|
|
16
22
|
* filtering; the returned list is shown as-is. */
|
|
17
23
|
loadOptions?: (query: string) => Promise<ListOption[]>;
|
|
@@ -21,6 +27,14 @@ type Props = SvEditorProps & {
|
|
|
21
27
|
debounce?: number;
|
|
22
28
|
/** Override the built-in strings (empty-state / loading text). */
|
|
23
29
|
messages?: Partial<ComboMessages>;
|
|
30
|
+
/** Custom render for each option (receives the ListOption). */
|
|
31
|
+
item?: Snippet<[ListOption]>;
|
|
32
|
+
/** Content pinned above the option list. */
|
|
33
|
+
header?: Snippet;
|
|
34
|
+
/** Content pinned below the option list. */
|
|
35
|
+
footer?: Snippet;
|
|
36
|
+
/** Shown when the (non-loading) list is empty; overrides the default text. */
|
|
37
|
+
noData?: Snippet;
|
|
24
38
|
};
|
|
25
39
|
declare const SvComboBox: import("svelte").Component<Props, {}, "">;
|
|
26
40
|
type SvComboBox = ReturnType<typeof SvComboBox>;
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
let {
|
|
32
|
-
value = null,
|
|
32
|
+
value = $bindable<string | null>(null),
|
|
33
33
|
onChange,
|
|
34
34
|
showDial = false,
|
|
35
35
|
placeholder = 'Select country…',
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
|
|
59
59
|
const ci = createCountryInput({
|
|
60
60
|
value: () => value,
|
|
61
|
-
onChange: (c) => onChange?.(c),
|
|
61
|
+
onChange: (c) => { value = c; onChange?.(c) },
|
|
62
62
|
disabled: () => disabled,
|
|
63
63
|
ariaLabel: () => ariaLabel,
|
|
64
64
|
searchLabel: () => M.search,
|
|
@@ -13,6 +13,6 @@ type Props = SvEditorProps & {
|
|
|
13
13
|
/** Override the built-in strings (search + empty-state). */
|
|
14
14
|
messages?: Partial<CountryMessages>;
|
|
15
15
|
};
|
|
16
|
-
declare const SvCountryInput: import("svelte").Component<Props, {}, "">;
|
|
16
|
+
declare const SvCountryInput: import("svelte").Component<Props, {}, "value">;
|
|
17
17
|
type SvCountryInput = ReturnType<typeof SvCountryInput>;
|
|
18
18
|
export default SvCountryInput;
|