@dosgato/dialog 1.2.7 → 1.3.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.
Files changed (60) hide show
  1. package/dist/Button.svelte +15 -13
  2. package/dist/ButtonGroup.svelte +44 -40
  3. package/dist/Checkbox.svelte +13 -12
  4. package/dist/Container.svelte +50 -46
  5. package/dist/Dialog.svelte +56 -41
  6. package/dist/FieldAutocomplete.svelte +77 -70
  7. package/dist/FieldCheckbox.svelte +25 -22
  8. package/dist/FieldChoices.svelte +74 -68
  9. package/dist/FieldChooserLink.svelte +148 -150
  10. package/dist/FieldDate.svelte +19 -18
  11. package/dist/FieldDateTime.svelte +36 -34
  12. package/dist/FieldDualListbox.svelte +80 -79
  13. package/dist/FieldHidden.svelte +16 -15
  14. package/dist/FieldIdentifier.svelte +18 -17
  15. package/dist/FieldMultiple.svelte +71 -74
  16. package/dist/FieldMultiselect.svelte +86 -59
  17. package/dist/FieldMultiselect.svelte.d.ts +13 -1
  18. package/dist/FieldNumber.svelte +20 -19
  19. package/dist/FieldRadio.svelte +42 -41
  20. package/dist/FieldSelect.svelte +45 -45
  21. package/dist/FieldStandard.svelte +28 -27
  22. package/dist/FieldText.svelte +27 -24
  23. package/dist/FieldTextArea.svelte +24 -24
  24. package/dist/FileIcon.svelte +10 -8
  25. package/dist/Form.svelte +40 -18
  26. package/dist/Form.svelte.d.ts +15 -13
  27. package/dist/FormDialog.svelte +40 -25
  28. package/dist/FormDialog.svelte.d.ts +23 -17
  29. package/dist/Icon.svelte +38 -33
  30. package/dist/InlineMessage.svelte +31 -29
  31. package/dist/InlineMessages.svelte +10 -7
  32. package/dist/Input.svelte +40 -39
  33. package/dist/Listbox.svelte +102 -109
  34. package/dist/MaxLength.svelte +19 -18
  35. package/dist/Radio.svelte +18 -15
  36. package/dist/Switcher.svelte +37 -33
  37. package/dist/Tab.svelte +23 -21
  38. package/dist/Tabs.svelte +111 -110
  39. package/dist/Tooltip.svelte +7 -7
  40. package/dist/chooser/Chooser.svelte +83 -76
  41. package/dist/chooser/ChooserPreview.svelte +16 -14
  42. package/dist/chooser/Details.svelte +6 -4
  43. package/dist/chooser/Thumbnail.svelte +20 -16
  44. package/dist/chooser/UploadUI.svelte +78 -69
  45. package/dist/code/CodeEditor.svelte +63 -66
  46. package/dist/code/FieldCodeEditor.svelte +21 -19
  47. package/dist/colorpicker/FieldColorPicker.svelte +36 -35
  48. package/dist/cropper/FieldCropper.svelte +142 -141
  49. package/dist/iconpicker/FieldIconPicker.svelte +102 -94
  50. package/dist/imageposition/FieldImagePosition.svelte +107 -98
  51. package/dist/tagpicker/FieldTagPicker.svelte +104 -38
  52. package/dist/tagpicker/FieldTagPicker.svelte.d.ts +7 -0
  53. package/dist/tree/LoadIcon.svelte +0 -1
  54. package/dist/tree/Tree.svelte +198 -192
  55. package/dist/tree/Tree.svelte.d.ts +5 -5
  56. package/dist/tree/TreeCell.svelte +10 -6
  57. package/dist/tree/TreeCell.svelte.d.ts +5 -5
  58. package/dist/tree/TreeNode.svelte +213 -241
  59. package/dist/tree/TreeNode.svelte.d.ts +5 -5
  60. package/package.json +9 -10
@@ -1,15 +1,18 @@
1
- <script>import Icon from './Icon.svelte';
2
- export let type = 'button';
3
- export let disabled = false;
4
- export let compact = false;
5
- export let cancel = false;
6
- export let destructive = false;
7
- export let secondary = false;
8
- export let describedby = undefined;
9
- export let element = undefined;
10
- export let icon = undefined;
11
- let className = undefined;
12
- export { className as class };
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>
@@ -1,44 +1,49 @@
1
- <script>import { modifierKey } from '@txstate-mws/svelte-components';
2
- import { createEventDispatcher } from 'svelte';
3
- export let name = undefined;
4
- export let choices;
5
- export let value = choices[0].value;
6
- export let groupid = undefined;
7
- export let messagesid = undefined;
8
- export let ariaControls = undefined;
9
- export let disabled = false;
10
- export let valid = false;
11
- export let invalid = false;
12
- const dispatch = createEventDispatcher();
13
- const elements = [];
14
- function update(newVal) {
15
- value = newVal;
16
- dispatch('change', value);
17
- }
18
- function onClick(choice, idx) {
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
- update(choice.value);
21
- elements[idx].focus();
22
- };
23
- }
24
- function onKeyDown(choice, idx) {
26
+ update(choice.value)
27
+ elements[idx].focus()
28
+ }
29
+ }
30
+
31
+ function onKeyDown (choice: PopupMenuItem, idx: number) {
25
32
  return e => {
26
- if (modifierKey(e))
27
- return;
28
- if ((e.key === 'ArrowRight' || e.key === 'ArrowDown') && idx < choices.length - 1) {
29
- e.preventDefault();
30
- e.stopPropagation();
31
- update(choices[idx + 1].value);
32
- elements[idx + 1].focus();
33
- }
34
- else if ((e.key === 'ArrowLeft' || e.key === 'ArrowUp') && idx > 0) {
35
- e.preventDefault();
36
- e.stopPropagation();
37
- update(choices[idx - 1].value);
38
- elements[idx - 1].focus();
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>
@@ -1,14 +1,16 @@
1
- <script>import { isNotBlank } from 'txstate-utils';
2
- export let id = undefined;
3
- export let name;
4
- export let value;
5
- export let onChange = undefined;
6
- export let onBlur = undefined;
7
- export let descid = undefined;
8
- export let disabled = false;
9
- export let valid = false;
10
- export let invalid = false;
11
- export let inputelement = undefined;
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>
@@ -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>import { eq, resize, ScreenReaderOnly } from '@txstate-mws/svelte-components';
6
- import { randomid } from 'txstate-utils';
7
- import { getContext, onDestroy } from 'svelte';
8
- import { DG_DIALOG_FIELD_MULTIPLE } from './FieldMultiple.svelte';
9
- import InlineMessages from './InlineMessages.svelte';
10
- import { getDescribedBy, TAB_CONTEXT, TAB_NAME_CONTEXT } from './';
11
- export let path;
12
- /** A label for the Container `<div>`. */
13
- export let label;
14
- export let messages;
15
- /** If the input that's being built has an id pass it here so the label can point at it. */
16
- export let id = undefined;
17
- /** If `descid` is defined then this assumes you've made an outside label referenced to by descid `<div id={descid}`.
18
- Useful for things like checkboxes and radio buttons that have their own individual labels. */
19
- export let descid = undefined;
20
- export let helptext = undefined;
21
- /** Syntactic sugar that toggles a '*' to be appended to label. */
22
- export let required = false;
23
- export let related = 0;
24
- export let conditional = undefined;
25
- /** The `id` of `<div>` messages are rendered in. */
26
- let messagesid;
27
- const dgMultipleContext = getContext(DG_DIALOG_FIELD_MULTIPLE);
28
- const helptextid = randomid();
29
- $: descids = getDescribedBy([helptext ? helptextid : undefined, dgMultipleContext?.helptextid]);
30
- let showhelp = false;
31
- let helpelement;
32
- let needsShowHelp = false;
33
- function setNeedsShowHelp(..._) {
34
- needsShowHelp = (helpelement?.getClientRects().length ?? 0) > 1;
35
- if (!needsShowHelp)
36
- showhelp = false;
37
- }
38
- $: setNeedsShowHelp(helpelement);
39
- const tabContext = getContext(TAB_CONTEXT);
40
- const tabNameStore = getContext(TAB_NAME_CONTEXT);
41
- $: if (messages.length && messages.some(m => m.type === 'error')) {
42
- tabContext?.store.notifyErrorPath($tabNameStore, path);
43
- }
44
- else {
45
- tabContext?.store.notifyErrorPathGone(path);
46
- }
47
- onDestroy(() => {
48
- tabContext?.store.notifyErrorPathGone(path);
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>
@@ -1,41 +1,57 @@
1
- <script context="module">export const DIALOG_TABS_CONTEXT = {};
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>import arrowLeft from '@iconify-icons/ph/arrow-left-bold';
4
- import arrowRight from '@iconify-icons/ph/arrow-right-bold';
5
- import xLight from '@iconify-icons/ph/x-light';
6
- import arrowsOutSimple from '@iconify-icons/ph/arrows-out-simple';
7
- import arrowsInSimple from '@iconify-icons/ph/arrows-in-simple';
8
- import { eq, Modal, ScreenReaderOnly } from '@txstate-mws/svelte-components';
9
- import { createEventDispatcher, setContext } from 'svelte';
10
- import { isNotBlank, randomid } from 'txstate-utils';
11
- import { Button, Icon } from './';
12
- const dispatch = createEventDispatcher();
13
- export let initialfocus = undefined;
14
- export let title = '';
15
- export let icon = undefined;
16
- export let size = 'normal';
17
- export let cancelText = undefined;
18
- export let continueText = 'Ok';
19
- export let continueIcon = undefined;
20
- export let escapable = isNotBlank(cancelText);
21
- export let expandable = false;
22
- export let disabled = false;
23
- export let ignoreTabs = false;
24
- export let labelid = randomid();
25
- export let descid = randomid();
26
- const ctx = { change: onTabChange };
27
- let hasTabs = false;
28
- let prevTitle;
29
- let nextTitle;
30
- let hasRequired = false;
31
- let onPrev;
32
- let onNext;
33
- let expanded = false;
34
- function onTabChange() {
35
- ({ hasTabs, prevTitle, nextTitle, hasRequired, onPrev, onNext } = ctx);
36
- }
37
- setContext(DIALOG_TABS_CONTEXT, ctx);
38
- $: describedby = [title ? labelid : undefined, descid].filter(isNotBlank).join(' ');
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>import { nullableSerialize, nullableDeserialize } from '@txstate-mws/svelte-forms';
2
- import FieldStandard from './FieldStandard.svelte';
3
- import { isBlank, isNotBlank, randomid } from 'txstate-utils';
4
- import { modifierKey, PopupMenu, ScreenReaderOnly } from '@txstate-mws/svelte-components';
5
- import { getDescribedBy } from './';
6
- import { onMount } from 'svelte';
7
- export let id = undefined;
8
- export let path;
9
- export let label = '';
10
- export let placeholder = 'Select' + (label ? ' ' + label : '');
11
- let className = '';
12
- export { className as class };
13
- export let notNull = false;
14
- export let disabled = false;
15
- export let choices;
16
- export let defaultValue = undefined;
17
- export let conditional = undefined;
18
- export let required = false;
19
- export let inputelement = undefined;
20
- export let related = 0;
21
- export let extradescid = undefined;
22
- export let helptext = undefined;
23
- let inputvalue = '';
24
- let popupvalue = undefined;
25
- let menuid;
26
- const liveTextId = randomid();
27
- $: finalserialize = !notNull ? nullableSerialize : v => v;
28
- $: finaldeserialize = !notNull ? nullableDeserialize : v => v;
29
- $: valueToLabel = Object.fromEntries(choices.map(c => [c.value, c.label || c.value]));
30
- $: labelToValue = Object.fromEntries(choices.map(c => [c.label || c.value, c.value]));
31
- $: filteredChoices = choices.filter((item) => {
32
- return item.label?.toLowerCase().includes(inputvalue.toLowerCase()) || item.value.toLowerCase().includes(inputvalue.toLowerCase());
33
- });
34
- let menushown = false;
35
- let savedVal = defaultValue;
36
- function onKeyUp(setVal) {
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
- if (!modifierKey(e)) {
39
- const val = labelToValue[inputvalue.trim()];
40
- menushown = !val;
41
- // we need to make sure the form state stays up to date with what's shown in the text field
42
- // if the text field has only a substring of a valid label the form state value should remain
43
- // empty, but once the text field has a valid label the form state should be updated
44
- if (savedVal !== val) {
45
- savedVal = val;
46
- setVal(val);
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
- function onchangepopup(setVal) {
53
+ }
54
+ }
55
+ }
56
+
57
+ function onchangepopup (setVal: any) {
52
58
  return (e) => {
53
- inputvalue = e.detail.label || e.detail.value;
54
- popupvalue = undefined;
55
- savedVal = e.detail.value;
56
- setVal(e.detail.value);
57
- };
58
- }
59
- function reactToValue(value, setVal) {
60
- const dsvalue = finaldeserialize(value);
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
- const label = valueToLabel[dsvalue];
63
- // if the form state value changes from the outside we need to replace the text field content
64
- // with the new label
65
- // if the new form state value is undefined, we should let them keep any half-finished typing they
66
- // might have in the field, but if they have a fully valid entry in the field, it needs to disappear
67
- // to reflect the new reality that the form value has gone away
68
- if (label != null || (savedVal && valueToLabel[savedVal]))
69
- inputvalue = label ?? '';
70
- savedVal = dsvalue;
71
- // if the form state value changes from the outside to an invalid value, we have to clear it out
72
- if (isNotBlank(dsvalue) && isBlank(label))
73
- setVal(finaldeserialize(''));
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>import { randomid } from 'txstate-utils';
2
- import FieldStandard from './FieldStandard.svelte';
3
- import Checkbox from './Checkbox.svelte';
4
- import { getDescribedBy } from './';
5
- let className = '';
6
- export { className as class };
7
- export let id = undefined;
8
- export let path;
9
- export let label = '';
10
- export let boxLabel;
11
- export let defaultValue = undefined;
12
- export let conditional = undefined;
13
- export let required = false;
14
- export let inputelement = undefined;
15
- export let related = 0;
16
- export let extradescid = undefined;
17
- export let helptext = undefined;
18
- function onChange(setVal) {
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
- setVal(this.checked);
21
- };
22
- }
23
- const descid = randomid();
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>