@dosgato/dialog 1.2.8 → 1.3.1
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/Button.svelte +15 -13
- package/dist/ButtonGroup.svelte +44 -40
- package/dist/Checkbox.svelte +13 -12
- package/dist/Container.svelte +50 -46
- package/dist/Dialog.svelte +56 -41
- package/dist/FieldAutocomplete.svelte +77 -70
- package/dist/FieldCheckbox.svelte +25 -22
- package/dist/FieldChoices.svelte +74 -68
- package/dist/FieldChooserLink.svelte +148 -150
- package/dist/FieldDate.svelte +19 -18
- package/dist/FieldDateTime.svelte +36 -34
- package/dist/FieldDualListbox.svelte +80 -79
- package/dist/FieldHidden.svelte +16 -15
- package/dist/FieldIdentifier.svelte +18 -17
- package/dist/FieldMultiple.svelte +71 -74
- package/dist/FieldMultiselect.svelte +81 -72
- package/dist/FieldNumber.svelte +20 -19
- package/dist/FieldRadio.svelte +42 -41
- package/dist/FieldSelect.svelte +45 -45
- package/dist/FieldStandard.svelte +28 -27
- package/dist/FieldText.svelte +27 -24
- package/dist/FieldTextArea.svelte +24 -24
- package/dist/FileIcon.svelte +10 -8
- package/dist/Form.svelte +40 -18
- package/dist/Form.svelte.d.ts +15 -13
- package/dist/FormDialog.svelte +40 -25
- package/dist/FormDialog.svelte.d.ts +23 -17
- package/dist/Icon.svelte +38 -33
- package/dist/InlineMessage.svelte +31 -29
- package/dist/InlineMessages.svelte +10 -7
- package/dist/Input.svelte +40 -39
- package/dist/Listbox.svelte +102 -109
- package/dist/MaxLength.svelte +19 -18
- package/dist/Radio.svelte +18 -15
- package/dist/Switcher.svelte +37 -33
- package/dist/Tab.svelte +23 -21
- package/dist/Tabs.svelte +111 -110
- package/dist/Tooltip.svelte +7 -7
- package/dist/chooser/Chooser.svelte +83 -76
- package/dist/chooser/ChooserPreview.svelte +16 -14
- package/dist/chooser/Details.svelte +6 -4
- package/dist/chooser/Thumbnail.svelte +20 -16
- package/dist/chooser/UploadUI.svelte +78 -69
- package/dist/code/CodeEditor.svelte +63 -66
- package/dist/code/FieldCodeEditor.svelte +21 -19
- package/dist/colorpicker/FieldColorPicker.svelte +36 -35
- package/dist/cropper/FieldCropper.svelte +142 -141
- package/dist/iconpicker/FieldIconPicker.svelte +102 -94
- package/dist/imageposition/FieldImagePosition.svelte +107 -98
- package/dist/tagpicker/FieldTagPicker.svelte +63 -54
- package/dist/tree/LoadIcon.svelte +0 -1
- package/dist/tree/Tree.svelte +198 -192
- package/dist/tree/Tree.svelte.d.ts +5 -5
- package/dist/tree/TreeCell.svelte +10 -6
- package/dist/tree/TreeCell.svelte.d.ts +5 -5
- package/dist/tree/TreeNode.svelte +213 -241
- package/dist/tree/TreeNode.svelte.d.ts +5 -5
- package/package.json +8 -9
package/dist/Button.svelte
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export let
|
|
6
|
-
export let
|
|
7
|
-
export let
|
|
8
|
-
export let
|
|
9
|
-
export let
|
|
10
|
-
export let
|
|
11
|
-
let
|
|
12
|
-
export
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { IconifyIcon } from '@iconify/svelte'
|
|
3
|
+
import Icon from './Icon.svelte'
|
|
4
|
+
|
|
5
|
+
export let type: 'button' | 'submit' = 'button'
|
|
6
|
+
export let disabled = false
|
|
7
|
+
export let compact = false
|
|
8
|
+
export let cancel = false
|
|
9
|
+
export let destructive = false
|
|
10
|
+
export let secondary = false
|
|
11
|
+
export let describedby: string | undefined = undefined
|
|
12
|
+
export let element: HTMLElement | undefined = undefined
|
|
13
|
+
export let icon: IconifyIcon | undefined = undefined
|
|
14
|
+
let className: string | undefined = undefined
|
|
15
|
+
export { className as class }
|
|
13
16
|
</script>
|
|
14
17
|
|
|
15
18
|
<button {disabled} bind:this={element} {type} class="reset {className ?? ''}" class:cancel class:destructive class:secondary class:compact aria-describedby={describedby} on:click><Icon {icon} width="1.3em" inline /><span><slot /></span></button>
|
|
@@ -74,5 +77,4 @@ export { className as class };
|
|
|
74
77
|
background-color: var(--dg-button-delete-hover-bg, rgb(240, 62, 62));
|
|
75
78
|
color: var(--dg-button-delete-hover-text, white);
|
|
76
79
|
}
|
|
77
|
-
|
|
78
80
|
</style>
|
package/dist/ButtonGroup.svelte
CHANGED
|
@@ -1,44 +1,49 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export let
|
|
6
|
-
export let
|
|
7
|
-
export let
|
|
8
|
-
export let
|
|
9
|
-
export let
|
|
10
|
-
export let
|
|
11
|
-
export let
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { modifierKey, type PopupMenuItem } from '@txstate-mws/svelte-components'
|
|
3
|
+
import { createEventDispatcher } from 'svelte'
|
|
4
|
+
|
|
5
|
+
export let name: string | undefined = undefined
|
|
6
|
+
export let choices: PopupMenuItem[]
|
|
7
|
+
export let value = choices[0].value
|
|
8
|
+
export let groupid: string | undefined = undefined
|
|
9
|
+
export let messagesid: string | undefined = undefined
|
|
10
|
+
export let ariaControls: string | undefined = undefined
|
|
11
|
+
export let disabled = false
|
|
12
|
+
export let valid = false
|
|
13
|
+
export let invalid = false
|
|
14
|
+
|
|
15
|
+
const dispatch = createEventDispatcher()
|
|
16
|
+
|
|
17
|
+
const elements: HTMLElement[] = []
|
|
18
|
+
|
|
19
|
+
function update (newVal: string) {
|
|
20
|
+
value = newVal
|
|
21
|
+
dispatch('change', value)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function onClick (choice: PopupMenuItem, idx: number) {
|
|
19
25
|
return () => {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
26
|
+
update(choice.value)
|
|
27
|
+
elements[idx].focus()
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function onKeyDown (choice: PopupMenuItem, idx: number) {
|
|
25
32
|
return e => {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
};
|
|
41
|
-
}
|
|
33
|
+
if (modifierKey(e)) return
|
|
34
|
+
if ((e.key === 'ArrowRight' || e.key === 'ArrowDown') && idx < choices.length - 1) {
|
|
35
|
+
e.preventDefault()
|
|
36
|
+
e.stopPropagation()
|
|
37
|
+
update(choices[idx + 1].value)
|
|
38
|
+
elements[idx + 1].focus()
|
|
39
|
+
} else if ((e.key === 'ArrowLeft' || e.key === 'ArrowUp') && idx > 0) {
|
|
40
|
+
e.preventDefault()
|
|
41
|
+
e.stopPropagation()
|
|
42
|
+
update(choices[idx - 1].value)
|
|
43
|
+
elements[idx - 1].focus()
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
42
47
|
</script>
|
|
43
48
|
|
|
44
49
|
{#if name}
|
|
@@ -72,5 +77,4 @@ function onKeyDown(choice, idx) {
|
|
|
72
77
|
background-color: var(--dialog-btngrp-active-bg, #333333);
|
|
73
78
|
color: var(--dialog-btngrp-active-text, white);
|
|
74
79
|
}
|
|
75
|
-
|
|
76
80
|
</style>
|
package/dist/Checkbox.svelte
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export let
|
|
5
|
-
export let
|
|
6
|
-
export let
|
|
7
|
-
export let
|
|
8
|
-
export let
|
|
9
|
-
export let
|
|
10
|
-
export let
|
|
11
|
-
export let
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { isNotBlank } from 'txstate-utils'
|
|
3
|
+
|
|
4
|
+
export let id: string | undefined = undefined
|
|
5
|
+
export let name: string
|
|
6
|
+
export let value: boolean
|
|
7
|
+
export let onChange: any = undefined
|
|
8
|
+
export let onBlur: any = undefined
|
|
9
|
+
export let descid: string | undefined = undefined
|
|
10
|
+
export let disabled = false
|
|
11
|
+
export let valid = false
|
|
12
|
+
export let invalid = false
|
|
13
|
+
export let inputelement: HTMLInputElement = undefined as any
|
|
12
14
|
</script>
|
|
13
15
|
|
|
14
16
|
<input bind:this={inputelement} {id} type="checkbox" {name} class:valid class:invalid {disabled} aria-describedby={descid} bind:checked={value} on:change={onChange} on:blur={onBlur}>
|
|
@@ -64,5 +66,4 @@ input[type="checkbox"]:disabled {
|
|
|
64
66
|
color: var(--dialog-checkbox-color);
|
|
65
67
|
cursor: not-allowed;
|
|
66
68
|
}
|
|
67
|
-
|
|
68
69
|
</style>
|
package/dist/Container.svelte
CHANGED
|
@@ -2,51 +2,56 @@
|
|
|
2
2
|
The purpose of `<Container>` is to provide common rendering for helptext, screen reader support,
|
|
3
3
|
and `Feedback` messages for its slotted components under a common `<div>` useful for form fields.
|
|
4
4
|
-->
|
|
5
|
-
<script>
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
export let
|
|
21
|
-
/**
|
|
22
|
-
|
|
23
|
-
export let
|
|
24
|
-
export let
|
|
25
|
-
/**
|
|
26
|
-
let
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
let
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
tabContext?.store.
|
|
49
|
-
}
|
|
5
|
+
<script lang="ts">
|
|
6
|
+
import type { Feedback } from '@txstate-mws/svelte-forms'
|
|
7
|
+
import { eq, resize, ScreenReaderOnly } from '@txstate-mws/svelte-components'
|
|
8
|
+
import { getContext, onDestroy } from 'svelte'
|
|
9
|
+
import type { Writable } from 'svelte/store'
|
|
10
|
+
import { randomid } from 'txstate-utils'
|
|
11
|
+
import { DG_DIALOG_FIELD_MULTIPLE } from './FieldMultiple.svelte'
|
|
12
|
+
import InlineMessages from './InlineMessages.svelte'
|
|
13
|
+
import { getDescribedBy, type TabStore, TAB_CONTEXT, TAB_NAME_CONTEXT } from './'
|
|
14
|
+
|
|
15
|
+
export let path: string
|
|
16
|
+
/** A label for the Container `<div>`. */
|
|
17
|
+
export let label: string
|
|
18
|
+
export let messages: Feedback[]
|
|
19
|
+
/** If the input that's being built has an id pass it here so the label can point at it. */
|
|
20
|
+
export let id: string | undefined = undefined
|
|
21
|
+
/** If `descid` is defined then this assumes you've made an outside label referenced to by descid `<div id={descid}`.
|
|
22
|
+
Useful for things like checkboxes and radio buttons that have their own individual labels. */
|
|
23
|
+
export let descid: string | undefined = undefined
|
|
24
|
+
export let helptext: string | undefined = undefined
|
|
25
|
+
/** Syntactic sugar that toggles a '*' to be appended to label. */
|
|
26
|
+
export let required = false
|
|
27
|
+
export let related: true | number = 0
|
|
28
|
+
export let conditional: boolean | undefined = undefined
|
|
29
|
+
/** The `id` of `<div>` messages are rendered in. */
|
|
30
|
+
let messagesid: string | undefined
|
|
31
|
+
|
|
32
|
+
const dgMultipleContext = getContext<{ helptextid: string | undefined } | undefined>(DG_DIALOG_FIELD_MULTIPLE)
|
|
33
|
+
|
|
34
|
+
const helptextid = randomid()
|
|
35
|
+
$: descids = getDescribedBy([helptext ? helptextid : undefined, dgMultipleContext?.helptextid])
|
|
36
|
+
let showhelp = false
|
|
37
|
+
let helpelement: HTMLSpanElement
|
|
38
|
+
let needsShowHelp = false
|
|
39
|
+
function setNeedsShowHelp (..._: any[]) {
|
|
40
|
+
needsShowHelp = (helpelement?.getClientRects().length ?? 0) > 1
|
|
41
|
+
if (!needsShowHelp) showhelp = false
|
|
42
|
+
}
|
|
43
|
+
$: setNeedsShowHelp(helpelement)
|
|
44
|
+
|
|
45
|
+
const tabContext = getContext<{ store: TabStore } | undefined>(TAB_CONTEXT)
|
|
46
|
+
const tabNameStore = getContext<Writable<string> | undefined>(TAB_NAME_CONTEXT)
|
|
47
|
+
$: if (messages.length && messages.some(m => m.type === 'error')) {
|
|
48
|
+
tabContext?.store.notifyErrorPath($tabNameStore!, path)
|
|
49
|
+
} else {
|
|
50
|
+
tabContext?.store.notifyErrorPathGone(path)
|
|
51
|
+
}
|
|
52
|
+
onDestroy(() => {
|
|
53
|
+
tabContext?.store.notifyErrorPathGone(path)
|
|
54
|
+
})
|
|
50
55
|
</script>
|
|
51
56
|
|
|
52
57
|
{#if conditional !== false}
|
|
@@ -180,5 +185,4 @@ onDestroy(() => {
|
|
|
180
185
|
.dialog-field-help-expand:hover {
|
|
181
186
|
text-decoration: none;
|
|
182
187
|
}
|
|
183
|
-
|
|
184
188
|
</style>
|
package/dist/Dialog.svelte
CHANGED
|
@@ -1,41 +1,57 @@
|
|
|
1
|
-
<script context="module"
|
|
1
|
+
<script context="module" lang="ts">
|
|
2
|
+
export const DIALOG_TABS_CONTEXT = {}
|
|
3
|
+
export interface DialogTabContext {
|
|
4
|
+
change: (..._: any) => void
|
|
5
|
+
hasTabs?: boolean
|
|
6
|
+
prevTitle?: string
|
|
7
|
+
nextTitle?: string
|
|
8
|
+
hasRequired?: boolean
|
|
9
|
+
onNext?: () => void
|
|
10
|
+
onPrev?: () => void
|
|
11
|
+
}
|
|
2
12
|
</script>
|
|
3
|
-
<script>
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
export let
|
|
17
|
-
export let
|
|
18
|
-
export let
|
|
19
|
-
export let
|
|
20
|
-
export let
|
|
21
|
-
export let
|
|
22
|
-
export let
|
|
23
|
-
export let
|
|
24
|
-
export let
|
|
25
|
-
export let
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
let
|
|
29
|
-
let
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
let
|
|
33
|
-
let
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
13
|
+
<script lang="ts">
|
|
14
|
+
import type { IconifyIcon } from '@iconify/svelte'
|
|
15
|
+
import arrowLeft from '@iconify-icons/ph/arrow-left-bold'
|
|
16
|
+
import arrowRight from '@iconify-icons/ph/arrow-right-bold'
|
|
17
|
+
import xLight from '@iconify-icons/ph/x-light'
|
|
18
|
+
import arrowsOutSimple from '@iconify-icons/ph/arrows-out-simple'
|
|
19
|
+
import arrowsInSimple from '@iconify-icons/ph/arrows-in-simple'
|
|
20
|
+
import { eq, Modal, ScreenReaderOnly } from '@txstate-mws/svelte-components'
|
|
21
|
+
import { createEventDispatcher, setContext } from 'svelte'
|
|
22
|
+
import { isNotBlank, randomid } from 'txstate-utils'
|
|
23
|
+
import { Button, Icon } from './'
|
|
24
|
+
const dispatch = createEventDispatcher()
|
|
25
|
+
|
|
26
|
+
export let initialfocus: string | undefined = undefined
|
|
27
|
+
export let title = ''
|
|
28
|
+
export let icon: IconifyIcon | undefined = undefined
|
|
29
|
+
export let size: 'tiny' | 'small' | 'normal' | 'large' | 'xl' = 'normal'
|
|
30
|
+
export let cancelText: string | undefined = undefined
|
|
31
|
+
export let continueText: string = 'Ok'
|
|
32
|
+
export let continueIcon: IconifyIcon | undefined = undefined
|
|
33
|
+
export let escapable = isNotBlank(cancelText)
|
|
34
|
+
export let expandable: boolean = false
|
|
35
|
+
export let disabled = false
|
|
36
|
+
export let ignoreTabs = false
|
|
37
|
+
|
|
38
|
+
export let labelid = randomid()
|
|
39
|
+
export let descid = randomid()
|
|
40
|
+
|
|
41
|
+
const ctx: DialogTabContext = { change: onTabChange }
|
|
42
|
+
let hasTabs: boolean | undefined = false
|
|
43
|
+
let prevTitle: string | undefined
|
|
44
|
+
let nextTitle: string | undefined
|
|
45
|
+
let hasRequired: boolean | undefined = false
|
|
46
|
+
let onPrev: (() => void) | undefined
|
|
47
|
+
let onNext: (() => void) | undefined
|
|
48
|
+
let expanded: boolean = false
|
|
49
|
+
function onTabChange () {
|
|
50
|
+
({ hasTabs, prevTitle, nextTitle, hasRequired, onPrev, onNext } = ctx)
|
|
51
|
+
}
|
|
52
|
+
setContext(DIALOG_TABS_CONTEXT, ctx)
|
|
53
|
+
|
|
54
|
+
$: describedby = [title ? labelid : undefined, descid].filter(isNotBlank).join(' ')
|
|
39
55
|
</script>
|
|
40
56
|
|
|
41
57
|
<Modal {escapable} {initialfocus} hidefocus={false} includeselector=".ck-body-wrapper" on:escape>
|
|
@@ -59,7 +75,7 @@ $: describedby = [title ? labelid : undefined, descid].filter(isNotBlank).join('
|
|
|
59
75
|
<footer class="actions">
|
|
60
76
|
<slot name="buttons" {nextTitle} {prevTitle} hasRequired={hasRequired && !ignoreTabs} onPrev={onPrev} onNext={onNext} {describedby}>
|
|
61
77
|
{#if prevTitle && !ignoreTabs}
|
|
62
|
-
<Button class="prev" disabled={!prevTitle} on:click={onPrev}><Icon icon={arrowLeft} inline /> <span class="prev-next" aria-hidden="true">Previous</span><ScreenReaderOnly>Previous Tab ({prevTitle})</ScreenReaderOnly></Button>
|
|
78
|
+
<Button class="prev" disabled={!prevTitle} on:click={() => onPrev?.()}><Icon icon={arrowLeft} inline /> <span class="prev-next" aria-hidden="true">Previous</span><ScreenReaderOnly>Previous Tab ({prevTitle})</ScreenReaderOnly></Button>
|
|
63
79
|
{/if}
|
|
64
80
|
{#if isNotBlank(cancelText)}
|
|
65
81
|
<Button cancel {describedby} on:click={() => dispatch('escape')}>{cancelText}</Button>
|
|
@@ -68,7 +84,7 @@ $: describedby = [title ? labelid : undefined, descid].filter(isNotBlank).join('
|
|
|
68
84
|
<Button class="primary" disabled={disabled || (hasRequired && !ignoreTabs)} {describedby} on:click={() => dispatch('continue')}><Icon icon={continueIcon} inline /> {continueText}</Button>
|
|
69
85
|
{/if}
|
|
70
86
|
{#if nextTitle && !ignoreTabs}
|
|
71
|
-
<Button class="next" disabled={!nextTitle} on:click={onNext}><span class="prev-next" aria-hidden="true">Next</span><ScreenReaderOnly> Next Tab ({nextTitle})</ScreenReaderOnly> <Icon icon={arrowRight} inline /></Button>
|
|
87
|
+
<Button class="next" disabled={!nextTitle} on:click={() => onNext?.()}><span class="prev-next" aria-hidden="true">Next</span><ScreenReaderOnly> Next Tab ({nextTitle})</ScreenReaderOnly> <Icon icon={arrowRight} inline /></Button>
|
|
72
88
|
{/if}
|
|
73
89
|
</slot>
|
|
74
90
|
</footer>
|
|
@@ -169,7 +185,7 @@ $: describedby = [title ? labelid : undefined, descid].filter(isNotBlank).join('
|
|
|
169
185
|
margin-right: 0.5em;
|
|
170
186
|
}
|
|
171
187
|
|
|
172
|
-
:global(.dialog-field-container) {
|
|
188
|
+
.dialog-content :global(.dialog-field-container) {
|
|
173
189
|
background-color: transparent !important;
|
|
174
190
|
border-bottom: 0px !important;
|
|
175
191
|
}
|
|
@@ -197,5 +213,4 @@ $: describedby = [title ? labelid : undefined, descid].filter(isNotBlank).join('
|
|
|
197
213
|
background: none;
|
|
198
214
|
cursor: pointer;
|
|
199
215
|
}
|
|
200
|
-
|
|
201
216
|
</style>
|
|
@@ -1,78 +1,85 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { getDescribedBy } from './'
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
export let
|
|
9
|
-
export let
|
|
10
|
-
export let
|
|
11
|
-
let
|
|
12
|
-
|
|
13
|
-
export
|
|
14
|
-
export let
|
|
15
|
-
export let
|
|
16
|
-
export let
|
|
17
|
-
export let
|
|
18
|
-
export let
|
|
19
|
-
export let
|
|
20
|
-
export let
|
|
21
|
-
export let
|
|
22
|
-
export let
|
|
23
|
-
let
|
|
24
|
-
|
|
25
|
-
let
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
$:
|
|
31
|
-
$:
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { modifierKey, PopupMenu, ScreenReaderOnly, type PopupMenuItem } from '@txstate-mws/svelte-components'
|
|
3
|
+
import { nullableSerialize, nullableDeserialize } from '@txstate-mws/svelte-forms'
|
|
4
|
+
import { isBlank, isNotBlank, randomid } from 'txstate-utils'
|
|
5
|
+
import { getDescribedBy } from './'
|
|
6
|
+
import FieldStandard from './FieldStandard.svelte'
|
|
7
|
+
|
|
8
|
+
export let id: string | undefined = undefined
|
|
9
|
+
export let path: string
|
|
10
|
+
export let label: string = ''
|
|
11
|
+
export let placeholder: string = 'Select' + (label ? ' ' + label : '')
|
|
12
|
+
let className = ''
|
|
13
|
+
export { className as class }
|
|
14
|
+
export let notNull = false
|
|
15
|
+
export let disabled = false
|
|
16
|
+
export let choices: { label?: string, value: string, disabled?: boolean }[]
|
|
17
|
+
export let defaultValue: string | undefined = undefined
|
|
18
|
+
export let conditional: boolean | undefined = undefined
|
|
19
|
+
export let required = false
|
|
20
|
+
export let inputelement: HTMLInputElement = undefined as any
|
|
21
|
+
export let related: true | number = 0
|
|
22
|
+
export let extradescid: string | undefined = undefined
|
|
23
|
+
export let helptext: string | undefined = undefined
|
|
24
|
+
|
|
25
|
+
let inputvalue = ''
|
|
26
|
+
let popupvalue = undefined
|
|
27
|
+
let menuid: string
|
|
28
|
+
|
|
29
|
+
const liveTextId = randomid()
|
|
30
|
+
$: finalserialize = !notNull ? nullableSerialize : v => v
|
|
31
|
+
$: finaldeserialize = !notNull ? nullableDeserialize : v => v
|
|
32
|
+
|
|
33
|
+
$: valueToLabel = Object.fromEntries(choices.map(c => [c.value, c.label || c.value]))
|
|
34
|
+
$: labelToValue = Object.fromEntries(choices.map(c => [c.label || c.value, c.value]))
|
|
35
|
+
$: filteredChoices = choices.filter((item: PopupMenuItem) => {
|
|
36
|
+
return item.label?.toLowerCase().includes(inputvalue.toLowerCase()) || item.value.toLowerCase().includes(inputvalue.toLowerCase())
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
let menushown = false
|
|
40
|
+
let savedVal = defaultValue
|
|
41
|
+
function onKeyUp (setVal: any) {
|
|
37
42
|
return (e) => {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
43
|
+
if (!modifierKey(e)) {
|
|
44
|
+
const val = labelToValue[inputvalue.trim()]
|
|
45
|
+
menushown = !val
|
|
46
|
+
// we need to make sure the form state stays up to date with what's shown in the text field
|
|
47
|
+
// if the text field has only a substring of a valid label the form state value should remain
|
|
48
|
+
// empty, but once the text field has a valid label the form state should be updated
|
|
49
|
+
if (savedVal !== val) {
|
|
50
|
+
savedVal = val
|
|
51
|
+
setVal(val)
|
|
48
52
|
}
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function onchangepopup (setVal: any) {
|
|
52
58
|
return (e) => {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
inputvalue = e.detail.label || e.detail.value
|
|
60
|
+
popupvalue = undefined
|
|
61
|
+
savedVal = e.detail.value
|
|
62
|
+
setVal(e.detail.value)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function reactToValue (value: string, setVal: any) {
|
|
67
|
+
const dsvalue = finaldeserialize(value)
|
|
61
68
|
if (dsvalue !== savedVal) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
69
|
+
const label = valueToLabel[dsvalue]
|
|
70
|
+
|
|
71
|
+
// if the form state value changes from the outside we need to replace the text field content
|
|
72
|
+
// with the new label
|
|
73
|
+
// if the new form state value is undefined, we should let them keep any half-finished typing they
|
|
74
|
+
// might have in the field, but if they have a fully valid entry in the field, it needs to disappear
|
|
75
|
+
// to reflect the new reality that the form value has gone away
|
|
76
|
+
if (label != null || (savedVal && valueToLabel[savedVal])) inputvalue = label ?? ''
|
|
77
|
+
|
|
78
|
+
savedVal = dsvalue
|
|
79
|
+
// if the form state value changes from the outside to an invalid value, we have to clear it out
|
|
80
|
+
if (isNotBlank(dsvalue) && isBlank(label)) setVal(finaldeserialize(''))
|
|
74
81
|
}
|
|
75
|
-
}
|
|
82
|
+
}
|
|
76
83
|
</script>
|
|
77
84
|
|
|
78
85
|
<FieldStandard bind:id {label} {path} {required} {defaultValue} {conditional} {related} {helptext} serialize={finalserialize} deserialize={finaldeserialize} let:value let:setVal let:valid let:invalid let:id let:onBlur let:messagesid let:helptextid>
|
|
@@ -1,26 +1,29 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export
|
|
8
|
-
export let
|
|
9
|
-
export let
|
|
10
|
-
export let
|
|
11
|
-
export let
|
|
12
|
-
export let
|
|
13
|
-
export let
|
|
14
|
-
export let
|
|
15
|
-
export let
|
|
16
|
-
export let
|
|
17
|
-
export let
|
|
18
|
-
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { randomid } from 'txstate-utils'
|
|
3
|
+
import FieldStandard from './FieldStandard.svelte'
|
|
4
|
+
import Checkbox from './Checkbox.svelte'
|
|
5
|
+
import { getDescribedBy } from './'
|
|
6
|
+
let className = ''
|
|
7
|
+
export { className as class }
|
|
8
|
+
export let id: string | undefined = undefined
|
|
9
|
+
export let path: string
|
|
10
|
+
export let label: string = ''
|
|
11
|
+
export let boxLabel: string
|
|
12
|
+
export let defaultValue: boolean | undefined = undefined
|
|
13
|
+
export let conditional: boolean | undefined = undefined
|
|
14
|
+
export let required = false
|
|
15
|
+
export let inputelement: HTMLInputElement = undefined as any
|
|
16
|
+
export let related: true | number = 0
|
|
17
|
+
export let extradescid: string | undefined = undefined
|
|
18
|
+
export let helptext: string | undefined = undefined
|
|
19
|
+
|
|
20
|
+
function onChange (setVal: (val: any) => void) {
|
|
19
21
|
return function () {
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
22
|
+
setVal(this.checked)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const descid = randomid()
|
|
24
27
|
</script>
|
|
25
28
|
|
|
26
29
|
<FieldStandard bind:id {path} {descid} {label} {defaultValue} {conditional} {related} {helptext} {required} let:value let:messagesid let:helptextid let:valid let:invalid let:id let:onBlur let:setVal>
|