@dosgato/dialog 0.0.46 → 0.0.47

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 (55) hide show
  1. package/dist/ButtonGroup.svelte +1 -0
  2. package/dist/Checkbox.svelte +1 -4
  3. package/dist/Checkbox.svelte.d.ts +0 -2
  4. package/dist/Container.svelte +41 -6
  5. package/dist/Container.svelte.d.ts +2 -0
  6. package/dist/Dialog.svelte +2 -2
  7. package/dist/FieldAutocomplete.svelte +4 -2
  8. package/dist/FieldAutocomplete.svelte.d.ts +2 -0
  9. package/dist/FieldCheckbox.svelte +5 -2
  10. package/dist/FieldCheckbox.svelte.d.ts +2 -0
  11. package/dist/FieldChoices.svelte +5 -2
  12. package/dist/FieldChoices.svelte.d.ts +2 -0
  13. package/dist/FieldChooserLink.svelte +4 -2
  14. package/dist/FieldChooserLink.svelte.d.ts +2 -0
  15. package/dist/FieldCodeEditor.svelte +4 -2
  16. package/dist/FieldCodeEditor.svelte.d.ts +2 -0
  17. package/dist/FieldDate.svelte +4 -2
  18. package/dist/FieldDate.svelte.d.ts +2 -0
  19. package/dist/FieldDateTime.svelte +4 -2
  20. package/dist/FieldDateTime.svelte.d.ts +2 -0
  21. package/dist/FieldDualListbox.svelte +9 -5
  22. package/dist/FieldDualListbox.svelte.d.ts +3 -0
  23. package/dist/FieldMultiple.svelte +11 -3
  24. package/dist/FieldMultiple.svelte.d.ts +3 -0
  25. package/dist/FieldMultiselect.svelte +7 -3
  26. package/dist/FieldMultiselect.svelte.d.ts +3 -0
  27. package/dist/FieldNumber.svelte +4 -2
  28. package/dist/FieldNumber.svelte.d.ts +2 -0
  29. package/dist/FieldRadio.svelte +3 -1
  30. package/dist/FieldRadio.svelte.d.ts +2 -0
  31. package/dist/FieldSelect.svelte +4 -2
  32. package/dist/FieldSelect.svelte.d.ts +2 -0
  33. package/dist/FieldStandard.svelte +2 -1
  34. package/dist/FieldStandard.svelte.d.ts +1 -0
  35. package/dist/FieldText.svelte +4 -2
  36. package/dist/FieldText.svelte.d.ts +2 -0
  37. package/dist/FieldTextArea.svelte +4 -2
  38. package/dist/FieldTextArea.svelte.d.ts +2 -0
  39. package/dist/Input.svelte +2 -1
  40. package/dist/Input.svelte.d.ts +1 -0
  41. package/dist/Listbox.svelte +1 -0
  42. package/dist/Radio.svelte +2 -1
  43. package/dist/Radio.svelte.d.ts +1 -0
  44. package/dist/Switcher.svelte +4 -2
  45. package/dist/Switcher.svelte.d.ts +2 -0
  46. package/dist/Tabs.svelte +1 -0
  47. package/dist/chooser/Chooser.svelte +32 -18
  48. package/dist/chooser/Details.svelte +54 -12
  49. package/dist/helpers.d.ts +1 -1
  50. package/dist/helpers.js +1 -1
  51. package/dist/tree/Tree.svelte +14 -8
  52. package/dist/tree/TreeNode.svelte +3 -3
  53. package/dist/tree/treestore.d.ts +3 -1
  54. package/dist/tree/treestore.js +21 -12
  55. package/package.json +2 -2
@@ -44,6 +44,7 @@ function onKeyDown(choice, idx) {
44
44
  {#if name}
45
45
  <input type="hidden" {name} {value}>
46
46
  {/if}
47
+ <!-- svelte-ignore a11y-no-noninteractive-element-to-interactive-role -->
47
48
  <ul class="dialog-btn-group" class:disabled class:valid class:invalid aria-disabled={disabled} role="radiogroup" aria-labelledby={groupid} on:blur>
48
49
  {#each choices as choice, i}
49
50
  {@const selected = choice.value === value}
@@ -5,16 +5,13 @@ export let value;
5
5
  export let onChange = undefined;
6
6
  export let onBlur = undefined;
7
7
  export let descid = undefined;
8
- export let messagesid = undefined;
9
8
  export let disabled = false;
10
9
  export let valid = false;
11
10
  export let invalid = false;
12
11
  export let inputelement = undefined;
13
- export let helptextid = undefined;
14
- $: descby = [descid, messagesid, helptextid].filter(isNotBlank).join(' ');
15
12
  </script>
16
13
 
17
- <input bind:this={inputelement} {id} type="checkbox" {name} class:valid class:invalid {disabled} aria-describedby={descby} bind:checked={value} on:change={onChange} on:blur={onBlur}>
14
+ <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}>
18
15
 
19
16
  <style>
20
17
  input, input:before, input:after {
@@ -7,12 +7,10 @@ declare const __propDef: {
7
7
  onChange?: any;
8
8
  onBlur?: any;
9
9
  descid?: string | undefined;
10
- messagesid?: string | undefined;
11
10
  disabled?: boolean | undefined;
12
11
  valid?: boolean | undefined;
13
12
  invalid?: boolean | undefined;
14
13
  inputelement?: HTMLInputElement | undefined;
15
- helptextid?: string | undefined;
16
14
  };
17
15
  events: {
18
16
  [evt: string]: CustomEvent<any>;
@@ -1,17 +1,26 @@
1
1
  <script>import { eq } from '@txstate-mws/svelte-components';
2
- import InlineMessages from './InlineMessages.svelte';
3
2
  import { randomid } from 'txstate-utils';
3
+ import { getContext } from 'svelte';
4
+ import { DG_DIALOG_FIELD_MULTIPLE } from './FieldMultiple.svelte';
5
+ import InlineMessages from './InlineMessages.svelte';
6
+ import { getDescribedBy } from './';
4
7
  export let id = undefined;
5
8
  export let descid = undefined;
6
9
  export let label;
7
10
  export let helptext = undefined;
8
11
  export let messages;
9
12
  export let required = false;
13
+ export let related = 0;
14
+ export let conditional = undefined;
10
15
  let messagesid;
11
- const helptextid = helptext ? randomid() : undefined;
16
+ const dgMultipleContext = getContext(DG_DIALOG_FIELD_MULTIPLE);
17
+ const helptextid = randomid();
18
+ $: descids = getDescribedBy([helptext ? helptextid : undefined, dgMultipleContext?.helptextid]);
19
+ let showhelp = false;
12
20
  </script>
13
21
 
14
- <div use:eq class="dialog-field-container">
22
+ {#if conditional !== false}
23
+ <div use:eq class="dialog-field-container" data-related={Array.from({ length: related === true ? 1 : related }, (_, i) => i + 1).join(' ')}>
15
24
  {#if descid == null}
16
25
  <label class="dialog-field-label" for={id}>{label}{#if required}&nbsp;*{/if}</label>
17
26
  {:else}
@@ -19,12 +28,14 @@ const helptextid = helptext ? randomid() : undefined;
19
28
  {/if}
20
29
  <div class="dialog-field-content">
21
30
  {#if helptext}
22
- <div id={helptextid} class="dialog-field-help">{helptext}</div>
31
+ <!-- svelte-ignore a11y-click-events-have-key-events -->
32
+ <div id={helptextid} class="dialog-field-help" class:expanded={showhelp} on:click={() => { showhelp = !showhelp }}>{helptext}</div>
23
33
  {/if}
24
- <slot {messagesid} {helptextid}/>
34
+ <slot {messagesid} helptextid={descids} />
25
35
  </div>
26
36
  <InlineMessages bind:id={messagesid} {messages} />
27
37
  </div>
38
+ {/if}
28
39
 
29
40
  <style>
30
41
  .dialog-field-container {
@@ -32,6 +43,13 @@ const helptextid = helptext ? randomid() : undefined;
32
43
  padding: var(--dialog-container-padding, 1em) 0;
33
44
  --dialog-container-tab-correct: calc(-1 * var(--tabs-panel-padding, 1em));
34
45
  }
46
+ .dialog-field-container[data-related~="1"] {
47
+ padding-top: 0;
48
+ padding-left: calc(var(--dialog-container-padding, 1em) + var(--dialog-related-padding, 1em));
49
+ }
50
+ .dialog-field-container[data-related~="2"] {
51
+ padding-left: calc(var(--dialog-container-padding, 1em) + (2 * var(--dialog-related-padding, 1em)));
52
+ }
35
53
  .dialog-field-container:last-child {
36
54
  border-bottom: 0;
37
55
  }
@@ -51,6 +69,13 @@ const helptextid = helptext ? randomid() : undefined;
51
69
  padding-left: var(--tabs-panel-padding, 1em);
52
70
  padding-right: var(--tabs-panel-padding, 1em);
53
71
  }
72
+ :global(.tabs-panel) .dialog-field-container[data-related~="1"] {
73
+ padding-left: calc(var(--tabs-panel-padding, 1em) + var(--dialog-container-padding, 1em));
74
+ }
75
+ :global(.tabs-panel) .dialog-field-container[data-related~="2"] {
76
+ padding-left: calc(var(--tabs-panel-padding, 1em) + (2 * var(--dialog-container-padding, 1em)));
77
+ }
78
+
54
79
  :global(.tabs-panel) .dialog-field-container:first-child {
55
80
  margin-top: var(--dialog-container-tab-correct);
56
81
  }
@@ -82,9 +107,19 @@ const helptextid = helptext ? randomid() : undefined;
82
107
  background-color: var(--dialog-field-bg2, transparent);
83
108
  color: var(--dialog-field-text2, inherit);
84
109
  }
85
- .dialog-field-container :global(.dialog-field-help) {
110
+ .dialog-field-help {
86
111
  font-size: 0.9em;
87
112
  color: #595959;
113
+ margin-bottom: 0.4em;
114
+ line-height: 1.25em;
115
+ overflow: hidden;
116
+ text-overflow: ellipsis;
117
+ white-space: nowrap;
118
+ cursor: help;
119
+ }
120
+ .dialog-field-help.expanded {
121
+ white-space: normal;
122
+ max-height: fit-content;
88
123
  }
89
124
 
90
125
  </style>
@@ -8,6 +8,8 @@ declare const __propDef: {
8
8
  helptext?: string | undefined;
9
9
  messages: Feedback[];
10
10
  required?: boolean | undefined;
11
+ related?: number | true | undefined;
12
+ conditional?: boolean | undefined;
11
13
  };
12
14
  events: {
13
15
  [evt: string]: CustomEvent<any>;
@@ -3,7 +3,7 @@
3
3
  <script>import arrowLeftLight from '@iconify-icons/ph/arrow-left-light';
4
4
  import arrowRightLight from '@iconify-icons/ph/arrow-right-light';
5
5
  import xLight from '@iconify-icons/ph/x-light';
6
- import { Modal, ScreenReaderOnly } from '@txstate-mws/svelte-components';
6
+ import { eq, Modal, ScreenReaderOnly } from '@txstate-mws/svelte-components';
7
7
  import { createEventDispatcher, setContext } from 'svelte';
8
8
  import { isNotBlank, randomid } from 'txstate-utils';
9
9
  import { Button, Icon } from './';
@@ -35,7 +35,7 @@ $: describedby = [title ? labelid : undefined, descid].filter(isNotBlank).join('
35
35
  </script>
36
36
 
37
37
  <Modal {escapable} {initialfocus} hidefocus={false} includeselector=".ck-body-wrapper" on:escape>
38
- <section class="{size}">
38
+ <section class="{size}" use:eq>
39
39
  {#if title || icon}
40
40
  <header id={labelid}>
41
41
  <Icon width="1.4em" {icon} inline />{title}
@@ -17,6 +17,8 @@ export let defaultValue = undefined;
17
17
  export let conditional = undefined;
18
18
  export let required = false;
19
19
  export let inputelement = undefined;
20
+ export let related = 0;
21
+ export let extradescid = undefined;
20
22
  export let helptext = undefined;
21
23
  let inputvalue = '';
22
24
  let popupvalue = undefined;
@@ -77,9 +79,9 @@ onMount(() => {
77
79
  });
78
80
  </script>
79
81
 
80
- <FieldStandard bind:id {label} {path} {required} {defaultValue} {conditional} {helptext} serialize={finalserialize} deserialize={finaldeserialize} let:value let:setVal let:valid let:invalid let:id let:onBlur let:messagesid let:helptextid>
82
+ <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>
81
83
  {@const _ = reactToValue(value, setVal)}
82
- <input bind:this={inputelement} bind:value={inputvalue} {id} {placeholder} class="dialog-input {className}" class:valid class:invalid aria-invalid={invalid} aria-expanded={false} aria-controls={menuid} on:blur={onBlur} on:keyup={onKeyUp(setVal)} autocapitalize="none" type="text" autocomplete="off" aria-autocomplete="list" role="combobox" {disabled} aria-describedby={getDescribedBy([messagesid, helptextid])}>
84
+ <input bind:this={inputelement} bind:value={inputvalue} {id} {placeholder} class="dialog-input {className}" class:valid class:invalid aria-invalid={invalid} aria-expanded={false} aria-controls={menuid} on:blur={onBlur} on:keyup={onKeyUp(setVal)} autocapitalize="none" type="text" autocomplete="off" aria-autocomplete="list" role="combobox" {disabled} aria-describedby={getDescribedBy([messagesid, helptextid, extradescid])}>
83
85
  <PopupMenu bind:menushown bind:menuid align="bottomleft" usePortal={portal} items={filteredChoices} buttonelement={inputelement} bind:value={popupvalue} on:change={onchangepopup(setVal)} emptyText="No options available"/>
84
86
  <ScreenReaderOnly arialive="polite" ariaatomic={true} id={liveTextId}>
85
87
  {filteredChoices.length} {filteredChoices.length === 1 ? 'option' : 'options'} available.
@@ -17,6 +17,8 @@ declare const __propDef: {
17
17
  conditional?: boolean | undefined;
18
18
  required?: boolean | undefined;
19
19
  inputelement?: HTMLInputElement | undefined;
20
+ related?: number | true | undefined;
21
+ extradescid?: string | undefined;
20
22
  helptext?: string | undefined;
21
23
  };
22
24
  events: {
@@ -1,6 +1,7 @@
1
1
  <script>import { randomid } from 'txstate-utils';
2
2
  import FieldStandard from './FieldStandard.svelte';
3
3
  import Checkbox from './Checkbox.svelte';
4
+ import { getDescribedBy } from './';
4
5
  let className = '';
5
6
  export { className as class };
6
7
  export let id = undefined;
@@ -11,6 +12,8 @@ export let defaultValue = undefined;
11
12
  export let conditional = undefined;
12
13
  export let required = false;
13
14
  export let inputelement = undefined;
15
+ export let related = 0;
16
+ export let extradescid = undefined;
14
17
  export let helptext = undefined;
15
18
  function onChange(setVal) {
16
19
  return function () {
@@ -20,10 +23,10 @@ function onChange(setVal) {
20
23
  const descid = randomid();
21
24
  </script>
22
25
 
23
- <FieldStandard bind:id {path} {descid} {label} {defaultValue} {conditional} {helptext} {required} let:value let:messagesid let:helptextid let:valid let:invalid let:id let:onBlur let:setVal>
26
+ <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>
24
27
  <div class={className}>
25
28
  <label for={id}>
26
- <Checkbox bind:inputelement {id} name={path} {value} {messagesid} {helptextid} {descid} {valid} {invalid} {onBlur} onChange={onChange(setVal)}></Checkbox>
29
+ <Checkbox bind:inputelement {id} name={path} {value} descid={getDescribedBy([descid, messagesid, helptextid, extradescid])} {valid} {invalid} {onBlur} onChange={onChange(setVal)}></Checkbox>
27
30
  <span>{boxLabel}</span>
28
31
  </label>
29
32
  </div>
@@ -10,6 +10,8 @@ declare const __propDef: {
10
10
  conditional?: boolean | undefined;
11
11
  required?: boolean | undefined;
12
12
  inputelement?: HTMLInputElement | undefined;
13
+ related?: number | true | undefined;
14
+ extradescid?: string | undefined;
13
15
  helptext?: string | undefined;
14
16
  };
15
17
  events: {
@@ -4,6 +4,7 @@ import { derivedStore } from '@txstate-mws/svelte-store';
4
4
  import { randomid } from 'txstate-utils';
5
5
  import Container from './Container.svelte';
6
6
  import Checkbox from './Checkbox.svelte';
7
+ import { getDescribedBy } from './helpers';
7
8
  let className = '';
8
9
  export { className as class };
9
10
  export let id = undefined;
@@ -14,6 +15,8 @@ export let defaultValue = [];
14
15
  export let conditional = undefined;
15
16
  export let maxwidth = 250;
16
17
  export let leftToRight = false;
18
+ export let related = 0;
19
+ export let extradescid = undefined;
17
20
  export let helptext = undefined;
18
21
  const store = getContext(FORM_CONTEXT);
19
22
  const currentWidth = derivedStore(store, 'width');
@@ -40,14 +43,14 @@ const descid = randomid();
40
43
  </script>
41
44
 
42
45
  <Field {path} {defaultValue} {conditional} let:path let:value let:onBlur let:setVal let:messages let:valid let:invalid>
43
- <Container {id} {label} {messages} {descid} {helptext} let:messagesid let:helptextid>
46
+ <Container {id} {label} {messages} {descid} {related} {helptext} let:messagesid let:helptextid>
44
47
  <div class="dialog-choices {className}" class:valid class:invalid>
45
48
  {#each choices as choice, idx}
46
49
  {@const checkid = `${path}.${idx}`}
47
50
  {@const included = value && value.includes(choice.value)}
48
51
  {@const label = choice.label || (typeof choice.value === 'string' ? choice.value : '')}
49
52
  <label for={checkid} style:width style:order={orders[idx]}>
50
- <Checkbox id={checkid} name={checkid} value={included} {messagesid} {helptextid} {descid} disabled={choice.disabled} onChange={() => onChangeCheckbox(setVal, choice, included)} {onBlur} />
53
+ <Checkbox id={checkid} name={checkid} value={included} descid={getDescribedBy([descid, messagesid, helptextid, extradescid])} disabled={choice.disabled} onChange={() => onChangeCheckbox(setVal, choice, included)} {onBlur} />
51
54
  <span>{label}</span>
52
55
  </label>
53
56
  {/each}
@@ -14,6 +14,8 @@ declare const __propDef: {
14
14
  conditional?: boolean | undefined;
15
15
  maxwidth?: number | undefined;
16
16
  leftToRight?: boolean | undefined;
17
+ related?: number | true | undefined;
18
+ extradescid?: string | undefined;
17
19
  helptext?: string | undefined;
18
20
  };
19
21
  events: {
@@ -19,6 +19,8 @@ export let folders = false;
19
19
  export let urlEntry = false;
20
20
  export let initialSource = undefined;
21
21
  export let initialPath = undefined;
22
+ export let related = 0;
23
+ export let extradescid = undefined;
22
24
  export let helptext = undefined;
23
25
  export let selectedAsset = undefined;
24
26
  // TODO: add a mime type acceptance prop, maybe a regex or function, to prevent users from
@@ -122,7 +124,7 @@ async function updateSelected(..._) {
122
124
  $: updateSelected($value);
123
125
  </script>
124
126
 
125
- <FieldStandard bind:id {path} {descid} {label} {defaultValue} {conditional} {required} {helptext} let:value let:messagesid let:helptextid let:valid let:invalid let:id let:onBlur let:setVal>
127
+ <FieldStandard bind:id {path} {descid} {label} {defaultValue} {conditional} {required} {related} {helptext} let:value let:messagesid let:helptextid let:valid let:invalid let:id let:onBlur let:setVal>
126
128
  {#if selectedAsset}
127
129
  <div class="dialog-chooser-container">
128
130
  <Thumbnail item={selectedAsset} />
@@ -133,7 +135,7 @@ $: updateSelected($value);
133
135
  {#if urlEntry}
134
136
  <input type="text" value={selectedAsset?.url ?? ''} on:change={userUrlEntry} on:keyup={userUrlEntry}>
135
137
  {/if}
136
- <button type="button" on:click={show} aria-describedby={getDescribedBy([descid, messagesid, helptextid])}>Select {#if value}New{/if} {#if assets && pages}Link Target{:else if images}Image{:else if assets}Asset{:else}Page{/if}</button>
138
+ <button type="button" on:click={show} aria-describedby={getDescribedBy([descid, messagesid, helptextid, extradescid])}>Select {#if value}New{/if} {#if assets && pages}Link Target{:else if images}Image{:else if assets}Asset{:else}Page{/if}</button>
137
139
  </div>
138
140
  {#if modalshown}
139
141
  <Chooser {store} {label} {pages} {assets} {images} {initialSource} {initialPath} {folders} {required} on:change={onChange(setVal)} on:escape={hide} />
@@ -16,6 +16,8 @@ declare const __propDef: {
16
16
  urlEntry?: boolean | undefined;
17
17
  initialSource?: string | undefined;
18
18
  initialPath?: string | undefined;
19
+ related?: number | true | undefined;
20
+ extradescid?: string | undefined;
19
21
  helptext?: string | undefined;
20
22
  selectedAsset?: AnyItem | RawURL | undefined;
21
23
  };
@@ -16,6 +16,8 @@ export let conditional = undefined;
16
16
  export let required = false;
17
17
  export let use = [];
18
18
  export let inputelement = undefined;
19
+ export let related = 0;
20
+ export let extradescid = undefined;
19
21
  export let helptext = undefined;
20
22
  export let language;
21
23
  const store = getContext(FORM_CONTEXT);
@@ -45,7 +47,7 @@ function updateValidState(invalidIn, messagesIdIn) {
45
47
  invalid = !!invalidIn;
46
48
  messagesid = messagesIdIn;
47
49
  inputelement?.setAttribute('aria-invalid', String(!!invalid));
48
- const descby = getDescribedBy([messagesid, helptextid]);
50
+ const descby = getDescribedBy([messagesid, helptextid, extradescid]);
49
51
  if (descby)
50
52
  inputelement?.setAttribute('aria-describedby', descby);
51
53
  else
@@ -53,7 +55,7 @@ function updateValidState(invalidIn, messagesIdIn) {
53
55
  }
54
56
  </script>
55
57
 
56
- <FieldStandard bind:id {label} {path} {required} {defaultValue} {conditional} {helptext} serialize={!notNull ? nullableSerialize : undefined} deserialize={!notNull ? nullableDeserialize : undefined} let:value let:valid let:invalid let:id let:onBlur let:onChange let:messagesid let:helptextid>
58
+ <FieldStandard bind:id {label} {path} {required} {defaultValue} {conditional} {related} {helptext} serialize={!notNull ? nullableSerialize : undefined} deserialize={!notNull ? nullableDeserialize : undefined} let:value let:valid let:invalid let:id let:onBlur let:onChange let:messagesid let:helptextid>
57
59
  {@const _ = setSlotProps(helptextid, onChange)}
58
60
  {@const __ = updateValidState(invalid, messagesid)}
59
61
  <div bind:this={editorelement} style:height="{rows * 1.333}em" class:valid class:invalid on:paste on:focusout={onBlur} use:passActions={use}></div>
@@ -13,6 +13,8 @@ declare const __propDef: {
13
13
  required?: boolean | undefined;
14
14
  use?: HTMLActionEntry<any>[] | undefined;
15
15
  inputelement?: HTMLTextAreaElement | undefined;
16
+ related?: number | true | undefined;
17
+ extradescid?: string | undefined;
16
18
  helptext?: string | undefined;
17
19
  language: 'js' | 'css' | 'html';
18
20
  };
@@ -13,9 +13,11 @@ export let step = undefined;
13
13
  export let conditional = undefined;
14
14
  export let required = false;
15
15
  export let inputelement = undefined;
16
+ export let related = 0;
17
+ export let extradescid = undefined;
16
18
  export let helptext = undefined;
17
19
  </script>
18
20
 
19
- <FieldStandard bind:id {label} {path} {required} {defaultValue} {conditional} {helptext} serialize={dateSerialize} deserialize={dateDeserialize} let:value let:valid let:invalid let:id let:onBlur let:onChange let:messagesid let:helptextid>
20
- <Input bind:inputelement type="date" name={path} {value} {id} class="dialog-input {className}" {onChange} {onBlur} {valid} {invalid} {min} {max} {step} {messagesid} {helptextid}/>
21
+ <FieldStandard bind:id {label} {path} {required} {defaultValue} {conditional} {related} {helptext} serialize={dateSerialize} deserialize={dateDeserialize} let:value let:valid let:invalid let:id let:onBlur let:onChange let:messagesid let:helptextid>
22
+ <Input bind:inputelement type="date" name={path} {value} {id} class="dialog-input {className}" {onChange} {onBlur} {valid} {invalid} {min} {max} {step} {extradescid} {messagesid} {helptextid}/>
21
23
  </FieldStandard>
@@ -16,6 +16,8 @@ declare const __propDef: {
16
16
  conditional?: boolean | undefined;
17
17
  required?: boolean | undefined;
18
18
  inputelement?: HTMLInputElement | undefined;
19
+ related?: number | true | undefined;
20
+ extradescid?: string | undefined;
19
21
  helptext?: string | undefined;
20
22
  };
21
23
  events: {
@@ -12,9 +12,11 @@ export let max = undefined;
12
12
  export let step = undefined;
13
13
  export let conditional = undefined;
14
14
  export let required = false;
15
+ export let related = 0;
16
+ export let extradescid = undefined;
15
17
  export let helptext = undefined;
16
18
  </script>
17
19
 
18
- <FieldStandard bind:id {label} {path} {required} {defaultValue} {conditional} {helptext} serialize={datetimeSerialize} deserialize={datetimeDeserialize} let:value let:valid let:invalid let:id let:onBlur let:onChange let:helptextid>
19
- <Input type="datetime-local" name={path} {value} {id} class="dialog-input {className}" {onChange} {onBlur} {valid} {invalid} {min} {max} {step} {helptextid}/>
20
+ <FieldStandard bind:id {label} {path} {required} {defaultValue} {conditional} {related} {helptext} serialize={datetimeSerialize} deserialize={datetimeDeserialize} let:value let:valid let:invalid let:id let:onBlur let:onChange let:helptextid let:messagesid>
21
+ <Input type="datetime-local" name={path} {value} {id} class="dialog-input {className}" {onChange} {onBlur} {valid} {invalid} {min} {max} {step} {extradescid} {messagesid} {helptextid}/>
20
22
  </FieldStandard>
@@ -15,6 +15,8 @@ declare const __propDef: {
15
15
  step?: number | undefined;
16
16
  conditional?: boolean | undefined;
17
17
  required?: boolean | undefined;
18
+ related?: number | true | undefined;
19
+ extradescid?: string | undefined;
18
20
  helptext?: string | undefined;
19
21
  };
20
22
  events: {
@@ -1,10 +1,11 @@
1
1
  <script>import menuRight from '@iconify-icons/mdi/menu-right.js';
2
2
  import menuLeft from '@iconify-icons/mdi/menu-left.js';
3
- import FieldStandard from './FieldStandard.svelte';
4
3
  import { ScreenReaderOnly, modifierKey } from '@txstate-mws/svelte-components';
4
+ import { randomid } from 'txstate-utils';
5
+ import FieldStandard from './FieldStandard.svelte';
5
6
  import Icon from './Icon.svelte';
6
7
  import Listbox from './Listbox.svelte';
7
- import { randomid } from 'txstate-utils';
8
+ import { getDescribedBy } from './';
8
9
  export let id = undefined;
9
10
  export let path;
10
11
  export let label = '';
@@ -15,6 +16,9 @@ export let choices;
15
16
  export let defaultValue = [];
16
17
  export let conditional = undefined;
17
18
  export let required = false;
19
+ export let related = 0;
20
+ export let extradescid = undefined;
21
+ export let helptext = undefined;
18
22
  let itemsToAdd = []; // the items selected in the left listbox
19
23
  let itemsToRemove = []; // the items selected in the right listbox
20
24
  let instructions = 'test';
@@ -79,12 +83,12 @@ function onkeydown(value, setVal) {
79
83
  }
80
84
  </script>
81
85
 
82
- <FieldStandard bind:id {label} {path} {required} {defaultValue} {conditional} {descid} let:value let:valid let:invalid let:id let:onBlur let:setVal>
86
+ <FieldStandard bind:id {label} {path} {required} {defaultValue} {conditional} {descid} {related} {helptext} let:value let:valid let:invalid let:id let:onBlur let:setVal let:helptextid let:messagesid>
83
87
  <div {id} role="group" class="dual-list-container" on:keydown={onkeydown(value, setVal)}>
84
88
  <ScreenReaderOnly>
85
89
  <span aria-live="polite">{instructions}</span>
86
90
  </ScreenReaderOnly>
87
- <Listbox label={sourceLabel} multiselect={multiselect} items={getAvailable(value)} {descid} {valid} {invalid} on:change={e => { itemsToAdd = e.detail }} selected={itemsToAdd} on:blur={onBlur}/>
91
+ <Listbox label={sourceLabel} multiselect={multiselect} items={getAvailable(value)} descid={getDescribedBy([descid, messagesid, helptextid, extradescid])} {valid} {invalid} on:change={e => { itemsToAdd = e.detail }} selected={itemsToAdd} on:blur={onBlur}/>
88
92
  <div class="toolbar">
89
93
  <button type="button" class="toolbar-button" title="Move selection to {selectedLabel}" disabled={itemsToAdd.length === 0} on:click={addToSelected(value, setVal)}>
90
94
  <Icon icon={menuRight} width='3em'/>
@@ -93,7 +97,7 @@ function onkeydown(value, setVal) {
93
97
  <Icon icon={menuLeft} width='3em'/>
94
98
  </button>
95
99
  </div>
96
- <Listbox label={selectedLabel} multiselect={multiselect} items={valueToSelectedChoices(value)} {descid} {valid} {invalid} on:change={e => { itemsToRemove = e.detail }} selected={itemsToRemove} on:blur={onBlur}/>
100
+ <Listbox label={selectedLabel} multiselect={multiselect} items={valueToSelectedChoices(value)} descid={getDescribedBy([descid, messagesid, helptextid, extradescid])} {valid} {invalid} on:change={e => { itemsToRemove = e.detail }} selected={itemsToRemove} on:blur={onBlur}/>
97
101
  </div>
98
102
  </FieldStandard>
99
103
 
@@ -12,6 +12,9 @@ declare const __propDef: {
12
12
  defaultValue?: string[] | undefined;
13
13
  conditional?: boolean | undefined;
14
14
  required?: boolean | undefined;
15
+ related?: number | true | undefined;
16
+ extradescid?: string | undefined;
17
+ helptext?: string | undefined;
15
18
  };
16
19
  events: {
17
20
  [evt: string]: CustomEvent<any>;
@@ -1,7 +1,10 @@
1
+ <script context="module">export const DG_DIALOG_FIELD_MULTIPLE = {};
2
+ function noOp(..._) { return ''; }
3
+ </script>
1
4
  <script>import plusCircleLight from '@iconify-icons/ph/plus-circle-light';
2
5
  import { AddMore, FORM_CONTEXT, FORM_INHERITED_PATH } from '@txstate-mws/svelte-forms';
3
6
  import { derivedStore } from '@txstate-mws/svelte-store';
4
- import { getContext } from 'svelte';
7
+ import { getContext, setContext } from 'svelte';
5
8
  import { isNotNull } from 'txstate-utils';
6
9
  import Button from './Button.svelte';
7
10
  import Container from './Container.svelte';
@@ -17,6 +20,10 @@ export let conditional = undefined;
17
20
  export let addMoreText = 'Add';
18
21
  export let maxedText = addMoreText;
19
22
  export let addMoreClass = undefined;
23
+ export let related = 0;
24
+ export let helptext = undefined;
25
+ const fieldMultipleContext = { helptextid: undefined };
26
+ setContext(DG_DIALOG_FIELD_MULTIPLE, fieldMultipleContext);
20
27
  const inheritedPath = getContext(FORM_INHERITED_PATH);
21
28
  const finalPath = [inheritedPath, path].filter(isNotNull).join('.');
22
29
  const store = getContext(FORM_CONTEXT);
@@ -31,13 +38,14 @@ function moveUpAndFocus(onMoveUp, idx) {
31
38
  $: messages = compact ? $messageStore : [];
32
39
  </script>
33
40
 
34
- <Container {label} {messages}>
41
+ <Container {label} {messages} {conditional} {related} {helptext} let:helptextid>
42
+ {noOp(fieldMultipleContext.helptextid = helptextid)}
35
43
  <AddMore {path} {initialState} {minLength} {maxLength} {conditional} let:path let:currentLength let:maxLength let:index let:minned let:maxed let:value let:onDelete let:onMoveUp>
36
44
  {@const showDelete = removable && !minned}
37
45
  {@const showMove = reorder && index > 0}
38
46
  <div class="dialog-multiple" class:has-delete-icon={showDelete}>
39
47
  <div class="dialog-multiple-content">
40
- <slot {path} {index} {value} {maxed} {maxLength} {currentLength} />
48
+ <slot {path} {index} {value} {maxed} {maxLength} {currentLength}/>
41
49
  </div>
42
50
  {#if showDelete || showMove}<div class="dialog-multiple-buttons">
43
51
  {#if reorder}<button bind:this={reorderelements[index]} class="dialog-multiple-move" type="button" aria-hidden={!showMove} disabled={!showMove} style:visibility={showMove ? 'visible' : 'hidden'} on:click|preventDefault|stopPropagation={moveUpAndFocus(onMoveUp, index)}>^</button>{/if}
@@ -1,4 +1,5 @@
1
1
  import { SvelteComponentTyped } from "svelte";
2
+ export declare const DG_DIALOG_FIELD_MULTIPLE: {};
2
3
  declare const __propDef: {
3
4
  props: {
4
5
  path: string;
@@ -13,6 +14,8 @@ declare const __propDef: {
13
14
  addMoreText?: string | undefined;
14
15
  maxedText?: string | undefined;
15
16
  addMoreClass?: string | undefined;
17
+ related?: number | true | undefined;
18
+ helptext?: string | undefined;
16
19
  };
17
20
  events: {
18
21
  [evt: string]: CustomEvent<any>;
@@ -1,8 +1,9 @@
1
1
  <script>import { MultiSelect } from '@txstate-mws/svelte-components';
2
2
  import { Store } from '@txstate-mws/svelte-store';
3
- import FieldStandard from './FieldStandard.svelte';
4
3
  import { onMount } from 'svelte';
5
4
  import { isNotBlank } from 'txstate-utils';
5
+ import FieldStandard from './FieldStandard.svelte';
6
+ import { getDescribedBy } from './helpers';
6
7
  export let id = undefined;
7
8
  export let path;
8
9
  export let label = '';
@@ -13,6 +14,9 @@ export let conditional = undefined;
13
14
  export let required = false;
14
15
  export let maxSelections = 0;
15
16
  export let getOptions;
17
+ export let related = 0;
18
+ export let extradescid = undefined;
19
+ export let helptext = undefined;
16
20
  // each time we run getOptions we will save the value -> label mappings
17
21
  // that it finds, so that we can display labels on pills
18
22
  const valueToLabel = {};
@@ -52,10 +56,10 @@ async function reactToValue(value) {
52
56
 
53
57
  <div bind:this={inputelement}></div>
54
58
  {#if hasInit}
55
- <FieldStandard bind:id {label} {path} {required} {defaultValue} {conditional} let:value let:valid let:invalid let:id let:onBlur let:setVal>
59
+ <FieldStandard bind:id {label} {path} {required} {defaultValue} {conditional} {related} {helptext} let:value let:valid let:invalid let:id let:onBlur let:setVal let:messagesid let:helptextid>
56
60
  {@const _ = reactToValue(value)}
57
61
  <div class:valid class:invalid>
58
- <MultiSelect {id} name={path} usePortal={portal} {disabled} {maxSelections} selected={$selectedStore} {placeholder} getOptions={wrapGetOptions} on:change={e => setVal(e.detail.map(itm => itm.value))} on:blur={onBlur}></MultiSelect>
62
+ <MultiSelect {id} name={path} usePortal={portal} descid={getDescribedBy([messagesid, helptextid, extradescid])} {disabled} {maxSelections} selected={$selectedStore} {placeholder} getOptions={wrapGetOptions} on:change={e => setVal(e.detail.map(itm => itm.value))} on:blur={onBlur} />
59
63
  </div>
60
64
  </FieldStandard>
61
65
  {/if}
@@ -12,6 +12,9 @@ declare const __propDef: {
12
12
  required?: boolean | undefined;
13
13
  maxSelections?: number | undefined;
14
14
  getOptions: (search: string) => Promise<PopupMenuItem[]>;
15
+ related?: number | true | undefined;
16
+ extradescid?: string | undefined;
17
+ helptext?: string | undefined;
15
18
  };
16
19
  events: {
17
20
  [evt: string]: CustomEvent<any>;
@@ -14,9 +14,11 @@ export let step = undefined;
14
14
  export let conditional = undefined;
15
15
  export let required = false;
16
16
  export let inputelement = undefined;
17
+ export let related = 0;
18
+ export let extradescid = undefined;
17
19
  export let helptext = undefined;
18
20
  </script>
19
21
 
20
- <FieldStandard bind:id {label} {path} {required} {defaultValue} {conditional} {helptext} serialize={numberSerialize} deserialize={nullable ? numberNullableDeserialize : numberDeserialize} let:value let:valid let:invalid let:id let:onBlur let:onChange let:helptextid>
21
- <Input bind:inputelement type="number" name={path} {value} {id} class="dialog-input {className}" {onChange} {onBlur} {valid} {invalid} {min} {max} {step} {helptextid}></Input>
22
+ <FieldStandard bind:id {label} {path} {required} {defaultValue} {conditional} {related} {helptext} serialize={numberSerialize} deserialize={nullable ? numberNullableDeserialize : numberDeserialize} let:value let:valid let:invalid let:id let:onBlur let:onChange let:helptextid>
23
+ <Input bind:inputelement type="number" name={path} {value} {id} class="dialog-input {className}" {onChange} {onBlur} {valid} {invalid} {min} {max} {step} {helptextid} {extradescid}></Input>
22
24
  </FieldStandard>
@@ -13,6 +13,8 @@ declare const __propDef: {
13
13
  conditional?: boolean | undefined;
14
14
  required?: boolean | undefined;
15
15
  inputelement?: HTMLInputElement | undefined;
16
+ related?: number | true | undefined;
17
+ extradescid?: string | undefined;
16
18
  helptext?: string | undefined;
17
19
  };
18
20
  events: {
@@ -11,6 +11,8 @@ export let defaultValue = notNull ? choices[0].value : undefined;
11
11
  export let conditional = undefined;
12
12
  export let required = false;
13
13
  export let horizontal = false;
14
+ export let related = 0;
15
+ export let extradescid = undefined;
14
16
  export let helptext = undefined;
15
17
  export let number = false;
16
18
  export let date = false;
@@ -21,5 +23,5 @@ export let deserialize = undefined;
21
23
  </script>
22
24
 
23
25
  <Field {path} {defaultValue} {conditional} {notNull} {number} {date} {datetime} {boolean} {serialize} {deserialize} let:value let:valid let:invalid let:onBlur let:onChange let:messages let:serialize>
24
- <Switcher bind:id class={className} name={path} {horizontal} {label} iptValue={value} {valid} {invalid} {required} {helptext} {messages} on:change={onChange} {onBlur} choices={choices.map(c => ({ ...c, value: serialize(c.value) }))} />
26
+ <Switcher bind:id class={className} name={path} {horizontal} {label} iptValue={value} {valid} {invalid} {required} {related} {extradescid} {helptext} {messages} on:change={onChange} {onBlur} choices={choices.map(c => ({ ...c, value: serialize(c.value) }))} />
25
27
  </Field>
@@ -15,6 +15,8 @@ declare const __propDef: {
15
15
  conditional?: boolean | undefined;
16
16
  required?: boolean | undefined;
17
17
  horizontal?: boolean | undefined;
18
+ related?: number | true | undefined;
19
+ extradescid?: string | undefined;
18
20
  helptext?: string | undefined;
19
21
  number?: boolean | undefined;
20
22
  date?: boolean | undefined;
@@ -13,6 +13,8 @@ export let defaultValue = notNull ? choices[0].value : undefined;
13
13
  export let conditional = undefined;
14
14
  export let required = false;
15
15
  export let inputelement = undefined;
16
+ export let related = 0;
17
+ export let extradescid = undefined;
16
18
  export let helptext = undefined;
17
19
  export let number = false;
18
20
  export let date = false;
@@ -22,8 +24,8 @@ export let serialize = undefined;
22
24
  export let deserialize = undefined;
23
25
  </script>
24
26
 
25
- <FieldStandard bind:id {label} {path} {required} {defaultValue} {conditional} {helptext} {notNull} {number} {date} {datetime} {boolean} {serialize} {deserialize} let:value let:valid let:invalid let:id let:onBlur let:onChange let:messagesid let:helptextid let:serialize>
26
- <select bind:this={inputelement} {id} name={path} {disabled} class="dialog-input dialog-select {className}" on:change={onChange} on:blur={onBlur} class:valid class:invalid aria-describedby={getDescribedBy([messagesid, helptextid])}>
27
+ <FieldStandard bind:id {label} {path} {required} {defaultValue} {conditional} {related} {helptext} {notNull} {number} {date} {datetime} {boolean} {serialize} {deserialize} let:value let:valid let:invalid let:id let:onBlur let:onChange let:messagesid let:helptextid let:serialize>
28
+ <select bind:this={inputelement} {id} name={path} {disabled} class="dialog-input dialog-select {className}" on:change={onChange} on:blur={onBlur} class:valid class:invalid aria-describedby={getDescribedBy([messagesid, helptextid, extradescid])}>
27
29
  {#if !notNull}<option value="" selected={!value}>{placeholder}</option>{/if}
28
30
  {#each choices as choice (choice.value)}
29
31
  {@const serializedValue = serialize(choice.value)}
@@ -17,6 +17,8 @@ declare const __propDef: {
17
17
  conditional?: boolean | undefined;
18
18
  required?: boolean | undefined;
19
19
  inputelement?: HTMLSelectElement | undefined;
20
+ related?: number | true | undefined;
21
+ extradescid?: string | undefined;
20
22
  helptext?: string | undefined;
21
23
  number?: boolean | undefined;
22
24
  date?: boolean | undefined;
@@ -16,11 +16,12 @@ export let deserialize = undefined;
16
16
  export let finalize = undefined;
17
17
  export let conditional = undefined;
18
18
  export let required = false;
19
+ export let related = 0;
19
20
  export let helptext = undefined;
20
21
  </script>
21
22
 
22
23
  <Field {path} {defaultValue} {conditional} {notNull} {number} {date} {datetime} {boolean} {serialize} {deserialize} {finalize} let:path let:value let:onBlur let:onChange let:setVal let:messages let:valid let:invalid let:serialize let:deserialize>
23
- <Container {id} {label} {messages} {descid} {required} {helptext} let:messagesid let:helptextid>
24
+ <Container {id} {label} {messages} {descid} {required} {related} {helptext} let:messagesid let:helptextid>
24
25
  <slot {id} {path} {value} {onBlur} {onChange} {setVal} {valid} {invalid} {messagesid} {helptextid} {serialize} {deserialize} />
25
26
  </Container>
26
27
  </Field>
@@ -16,6 +16,7 @@ declare const __propDef: {
16
16
  finalize?: ((value: any) => any) | undefined;
17
17
  conditional?: boolean | undefined;
18
18
  required?: boolean | undefined;
19
+ related?: number | true | undefined;
19
20
  helptext?: string | undefined;
20
21
  };
21
22
  events: {
@@ -15,9 +15,11 @@ export let conditional = undefined;
15
15
  export let required = false;
16
16
  export let use = [];
17
17
  export let inputelement = undefined;
18
+ export let related = 0;
19
+ export let extradescid = undefined;
18
20
  export let helptext = undefined;
19
21
  </script>
20
22
 
21
- <FieldStandard bind:id {label} {path} {required} {defaultValue} {conditional} {helptext} serialize={!notNull ? nullableSerialize : undefined} deserialize={!notNull ? nullableDeserialize : undefined} let:value let:valid let:invalid let:id let:onBlur let:onChange let:messagesid let:helptextid>
22
- <Input bind:inputelement {type} name={path} {value} {id} class="dialog-input {className}" {allowlastpass} {onChange} {onBlur} {valid} {invalid} {maxlength} {messagesid} {helptextid} {use}></Input>
23
+ <FieldStandard bind:id {label} {path} {required} {defaultValue} {conditional} {related} {helptext} serialize={!notNull ? nullableSerialize : undefined} deserialize={!notNull ? nullableDeserialize : undefined} let:value let:valid let:invalid let:id let:onBlur let:onChange let:messagesid let:helptextid>
24
+ <Input bind:inputelement {type} name={path} {value} {id} class="dialog-input {className}" {allowlastpass} {onChange} {onBlur} {valid} {invalid} {maxlength} {messagesid} {helptextid} {extradescid} {use}></Input>
23
25
  </FieldStandard>
@@ -15,6 +15,8 @@ declare const __propDef: {
15
15
  required?: boolean | undefined;
16
16
  use?: HTMLActionEntry<any>[] | undefined;
17
17
  inputelement?: HTMLInputElement | undefined;
18
+ related?: number | true | undefined;
19
+ extradescid?: string | undefined;
18
20
  helptext?: string | undefined;
19
21
  };
20
22
  events: {
@@ -15,11 +15,13 @@ export let conditional = undefined;
15
15
  export let required = false;
16
16
  export let use = [];
17
17
  export let inputelement = undefined;
18
+ export let related = 0;
19
+ export let extradescid = undefined;
18
20
  export let helptext = undefined;
19
21
  </script>
20
22
 
21
- <FieldStandard bind:id {label} {path} {required} {defaultValue} {conditional} {helptext} serialize={!notNull ? nullableSerialize : undefined} deserialize={!notNull ? nullableDeserialize : undefined} let:value let:valid let:invalid let:id let:onBlur let:onChange let:messagesid let:helptextid>
22
- <textarea bind:this={inputelement} name={path} {value} {id} {rows} class="dialog-input dialog-textarea {className}" class:valid class:invalid aria-invalid={invalid} aria-describedby={getDescribedBy([messagesid, helptextid])} on:change={onChange} on:blur={onBlur} on:keyup={onChange} on:paste {maxlength} use:passActions={use}></textarea>
23
+ <FieldStandard bind:id {label} {path} {required} {defaultValue} {conditional} {related} {helptext} serialize={!notNull ? nullableSerialize : undefined} deserialize={!notNull ? nullableDeserialize : undefined} let:value let:valid let:invalid let:id let:onBlur let:onChange let:messagesid let:helptextid>
24
+ <textarea bind:this={inputelement} name={path} {value} {id} {rows} class="dialog-input dialog-textarea {className}" class:valid class:invalid aria-invalid={invalid} aria-describedby={getDescribedBy([messagesid, helptextid, extradescid])} on:change={onChange} on:blur={onBlur} on:keyup={onChange} on:paste {maxlength} use:passActions={use}></textarea>
23
25
  </FieldStandard>
24
26
 
25
27
  <style>
@@ -14,6 +14,8 @@ declare const __propDef: {
14
14
  required?: boolean | undefined;
15
15
  use?: HTMLActionEntry<any>[] | undefined;
16
16
  inputelement?: HTMLTextAreaElement | undefined;
17
+ related?: number | true | undefined;
18
+ extradescid?: string | undefined;
17
19
  helptext?: string | undefined;
18
20
  };
19
21
  events: {
package/dist/Input.svelte CHANGED
@@ -13,6 +13,7 @@ export let max = undefined;
13
13
  export let step = undefined;
14
14
  export let id = undefined;
15
15
  export let disabled = false;
16
+ export let extradescid = undefined;
16
17
  export let messagesid = undefined;
17
18
  export let helptextid = undefined;
18
19
  export let valid = false;
@@ -22,7 +23,7 @@ export let onBlur;
22
23
  export let onSelect = undefined;
23
24
  export let use = [];
24
25
  export let inputelement = undefined;
25
- $: descby = [helptextid, messagesid].filter(isNotBlank).join(' ');
26
+ $: descby = [messagesid, helptextid, extradescid].filter(isNotBlank).join(' ');
26
27
  function resolveMinMax(dt) {
27
28
  if (typeof dt === 'undefined')
28
29
  return undefined;
@@ -17,6 +17,7 @@ declare const __propDef: {
17
17
  step?: number | undefined;
18
18
  id?: string | undefined;
19
19
  disabled?: boolean | undefined;
20
+ extradescid?: string | undefined;
20
21
  messagesid?: string | undefined;
21
22
  helptextid?: string | undefined;
22
23
  valid?: boolean | undefined;
@@ -120,6 +120,7 @@ function focusListbox() {
120
120
 
121
121
  <div class="listbox-container" class:valid class:invalid>
122
122
  <span id={labelId}>{label}</span>
123
+ <!-- svelte-ignore a11y-no-noninteractive-element-to-interactive-role -->
123
124
  <ul bind:this={listboxElement} role="listbox" id={listId} class="listbox-items" tabindex="0" aria-describedby={descid} aria-labelledby={labelId} aria-multiselectable={multiselect} on:keydown={onkeydown} on:focus={focusListbox}>
124
125
  {#each items as item, i (item.value)}
125
126
  <!-- svelte-ignore a11y-click-events-have-key-events -->
package/dist/Radio.svelte CHANGED
@@ -7,10 +7,11 @@ export let onChange = undefined;
7
7
  export let onBlur = undefined;
8
8
  export let messagesid = undefined;
9
9
  export let helptextid = undefined;
10
+ export let extradescid = undefined;
10
11
  export let disabled = false;
11
12
  export let valid = false;
12
13
  export let invalid = false;
13
- $: descby = [messagesid, helptextid].filter(isNotBlank).join(' ');
14
+ $: descby = [messagesid, helptextid, extradescid].filter(isNotBlank).join(' ');
14
15
  </script>
15
16
 
16
17
  <input {id} type="radio" {name} class:valid class:invalid checked={selected} {disabled} aria-describedby={descby} {value} on:change={onChange} on:blur={onBlur}>
@@ -9,6 +9,7 @@ declare const __propDef: {
9
9
  onBlur?: any;
10
10
  messagesid?: string | undefined;
11
11
  helptextid?: string | undefined;
12
+ extradescid?: string | undefined;
12
13
  disabled?: boolean | undefined;
13
14
  valid?: boolean | undefined;
14
15
  invalid?: boolean | undefined;
@@ -12,6 +12,8 @@ export let choices;
12
12
  export let horizontal = false;
13
13
  export let label;
14
14
  export let required = false;
15
+ export let related = 0;
16
+ export let extradescid = undefined;
15
17
  export let helptext = undefined;
16
18
  export let messages = [];
17
19
  export let iptValue = choices[0].value;
@@ -28,12 +30,12 @@ function onChange(e) {
28
30
  $: columns = Math.floor($store.width / 250);
29
31
  $: width = (horizontal ? 100 / Math.min(choices.length, choices.length === 4 && columns === 3 ? 2 : columns) : 100) + '%';
30
32
  </script>
31
- <Container {id} {label} {messages} descid={groupid} {required} {helptext} let:helptextid>
33
+ <Container {id} {label} {messages} descid={groupid} {required} {related} {helptext} let:helptextid>
32
34
  <div class="dialog-radio {className}" use:eq={{ store }} class:horizontal role="radiogroup" aria-labelledby={groupid} class:valid class:invalid>
33
35
  {#each choices as choice, idx}
34
36
  {@const radioid = `${groupid}.${idx}`}
35
37
  <label for={radioid} style:width>
36
- <Radio id={radioid} {name} value={choice.value} selected={iptValue === choice.value} disabled={choice.disabled} {onChange} {onBlur} {helptextid}/>
38
+ <Radio id={radioid} {name} value={choice.value} selected={iptValue === choice.value} disabled={choice.disabled} {onChange} {onBlur} {helptextid} {extradescid} />
37
39
  <span>{choice.label || choice.value}</span>
38
40
  </label>
39
41
  {/each}
@@ -13,6 +13,8 @@ declare const __propDef: {
13
13
  horizontal?: boolean | undefined;
14
14
  label: string;
15
15
  required?: boolean | undefined;
16
+ related?: number | true | undefined;
17
+ extradescid?: string | undefined;
16
18
  helptext?: string | undefined;
17
19
  messages?: Feedback[] | undefined;
18
20
  iptValue?: string | undefined;
package/dist/Tabs.svelte CHANGED
@@ -87,6 +87,7 @@ onMount(reactToCurrent);
87
87
 
88
88
  {#if $store.tabs.length > 1}
89
89
  {#if !$accordion}
90
+ <!-- svelte-ignore a11y-no-noninteractive-element-to-interactive-role -->
90
91
  <ul use:resize={{ store }} class="tabs-buttons" role="tablist">
91
92
  {#each $store.tabs as tab, idx (tab.name)}
92
93
  {@const active = isActive(idx, $store.current)}
@@ -91,23 +91,28 @@ onMount(async () => {
91
91
  <Tabs bind:store={tabStore} tabs={$sources.map(s => ({ name: s.name, title: s.label ?? s.name }))} />
92
92
  {/if}
93
93
  </header>
94
- <section class="dialog-chooser-chooser">
95
- {#if $store.initialized}
96
- <Tree headers={[
97
- { label: 'Path', id: 'name', grow: 4, icon: item => item.type === 'asset' ? iconForMime(item.mime) : (item.type === 'folder' ? (item.open ? folderNotchOpen : folderIcon) : applicationOutline), get: 'name' }
98
- ]} singleSelect store={treeStore} on:deselect={onDeselect} on:choose={onChoose} />
99
- {/if}
100
- </section>
101
- <section class="dialog-chooser-preview" tabindex="-1">
102
- {#if $preview}
103
- <Thumbnail item={$preview} larger />
104
- <Details item={$preview}>
105
- {#if $preview.type === 'folder'}
106
- <li>{$selected?.children?.length ?? 0} sub-items</li>
107
- {/if}
108
- </Details>
109
- {/if}
110
- </section>
94
+ <div class="dialog-chooser-body">
95
+ <section class="dialog-chooser-chooser">
96
+ {#if $store.initialized}
97
+ <Tree headers={[
98
+ { label: 'Path', id: 'name', grow: 4, icon: item => item.type === 'asset' ? iconForMime(item.mime) : (item.type === 'folder' ? (item.open ? folderNotchOpen : folderIcon) : applicationOutline), get: 'name' }
99
+ ]} singleSelect store={treeStore} on:deselect={onDeselect} on:choose={onChoose} />
100
+ {/if}
101
+ </section>
102
+ <section class="dialog-chooser-preview" tabindex="-1">
103
+ {#if $preview}
104
+ <Thumbnail item={$preview} larger />
105
+ <Details item={$preview}>
106
+ {#if $preview.type === 'folder'}
107
+ <div class="folder-info">
108
+ <dt>Contents:</dt>
109
+ <dd>{$selected?.children?.length ?? 0} sub-items</dd>
110
+ </div>
111
+ {/if}
112
+ </Details>
113
+ {/if}
114
+ </section>
115
+ </div>
111
116
  </section>
112
117
  </Dialog>
113
118
 
@@ -115,7 +120,6 @@ onMount(async () => {
115
120
  .dialog-chooser-window {
116
121
  position: relative;
117
122
  height: 80vh;
118
- display: flex;
119
123
  flex-wrap: wrap;
120
124
  align-items: stretch;
121
125
  justify-content: flex-end;
@@ -124,6 +128,10 @@ onMount(async () => {
124
128
  .dialog-chooser-window * {
125
129
  box-sizing: border-box;
126
130
  }
131
+
132
+ .dialog-chooser-body {
133
+ display: flex;
134
+ }
127
135
  .dialog-chooser-chooser {
128
136
  position: relative;
129
137
  width: 75%;
@@ -140,6 +148,12 @@ onMount(async () => {
140
148
  padding: 1em;
141
149
  overflow-y: auto;
142
150
  }
151
+ .folder-info dt {
152
+ font-weight: bold;
153
+ }
154
+ .folder-info dd {
155
+ margin: 0;
156
+ }
143
157
  header {
144
158
  position: relative;
145
159
  width: 100%;
@@ -2,25 +2,48 @@
2
2
  export let item;
3
3
  </script>
4
4
 
5
- <ul class="dialog-chooser-info" aria-live="polite">
5
+ <dl class="dialog-chooser-info" aria-live="polite">
6
6
  {#if item.type !== 'raw'}
7
- <li>{item.path}</li>
7
+ <div class="top-row">
8
+ <dt>Name:</dt>
9
+ <dd>{item.path}</dd>
10
+ </div>
8
11
  {:else if item.id}
9
- <li>External Link<br>{item.url}</li>
12
+ <div>
13
+ <dt>External Link:</dt>
14
+ <dd>{item.url}</dd>
15
+ </div>
10
16
  {/if}
11
- {#if item.type === 'asset' && item.image}
12
- <li>{item.image.width}x{item.image.height}</li>
17
+ {#if item.type === 'asset'}
18
+ <div class="asset-properties">
19
+ {#if item.image}
20
+ <div>
21
+ <dt>Dimensions:</dt>
22
+ <dd>{item.image.width}x{item.image.height}</dd>
23
+ </div>
24
+ {/if}
25
+ <div>
26
+ <dt>File Type:</dt>
27
+ <dd>{item.mime}</dd>
28
+ </div>
29
+ <div>
30
+ <dt>File Size:</dt>
31
+ <dd>{bytesToHuman(item.bytes)}</dd>
32
+ </div>
33
+ </div>
13
34
  {:else if item.type === 'page' && item.title}
14
- <li>{item.title}</li>
35
+ <div>
36
+ <dt>Title:</dt>
37
+ <dd>{item.title}</dd>
38
+ </div>
15
39
  {:else if item.type === 'folder'}
16
- <li>{item.path}</li>
17
- {/if}
18
- {#if item.type === 'asset'}
19
- <li>{item.mime}</li>
20
- <li>{bytesToHuman(item.bytes)}</li>
40
+ <div>
41
+ <dt>Path:</dt>
42
+ <dd>{item.path}</dd>
43
+ </div>
21
44
  {/if}
22
45
  <slot />
23
- </ul>
46
+ </dl>
24
47
 
25
48
  <style>
26
49
  .dialog-chooser-info {
@@ -28,5 +51,24 @@ export let item;
28
51
  margin: 0;
29
52
  list-style: none;
30
53
  }
54
+ .dialog-chooser-info dt {
55
+ font-weight: bold;
56
+ }
57
+ .dialog-chooser-info dd {
58
+ margin: 0;
59
+ }
60
+ .top-row {
61
+ margin-bottom: 1em;
62
+ }
63
+ .asset-properties {
64
+ display: flex;
65
+ justify-content: space-between;
66
+ }
67
+ :global([data-eq~="1400px"]) .asset-properties {
68
+ flex-direction: column;
69
+ }
70
+ :global([data-eq~="1400px"]) .asset-properties div:not(:last-child){
71
+ margin-bottom: 1em;
72
+ }
31
73
 
32
74
  </style>
package/dist/helpers.d.ts CHANGED
@@ -1 +1 @@
1
- export declare function getDescribedBy(ids: (string | undefined)[]): string | null;
1
+ export declare function getDescribedBy(ids: (string | undefined)[]): string | undefined;
package/dist/helpers.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { isNotBlank } from 'txstate-utils';
2
2
  export function getDescribedBy(ids) {
3
3
  const descby = ids.filter(isNotBlank).join(' ');
4
- return isNotBlank(descby) ? descby : null;
4
+ return isNotBlank(descby) ? descby : undefined;
5
5
  }
@@ -1,10 +1,9 @@
1
1
  <script>import { resize } from '@txstate-mws/svelte-components';
2
2
  import { derivedStore, Store } from '@txstate-mws/svelte-store';
3
- import { afterUpdate, beforeUpdate, onDestroy, onMount, setContext } from 'svelte';
4
- import { hashid } from 'txstate-utils';
3
+ import { afterUpdate, beforeUpdate, onDestroy, onMount, setContext, tick } from 'svelte';
5
4
  import LoadIcon from './LoadIcon.svelte';
6
5
  import TreeNode from './TreeNode.svelte';
7
- import { TreeStore, TREE_STORE_CONTEXT } from './treestore';
6
+ import { getHashId, TreeStore, TREE_STORE_CONTEXT } from './treestore';
8
7
  export let headers;
9
8
  export let nodeClass = undefined;
10
9
  export let singleSelect = undefined;
@@ -93,18 +92,24 @@ function headerDragEnd() {
93
92
  function headerDragReset() {
94
93
  store.resetHeaderOverride();
95
94
  }
95
+ let mounted = false;
96
96
  onMount(async () => {
97
97
  document.addEventListener('dragend', onDragEnd);
98
98
  const saveFocusId = $store.focused?.id;
99
+ headerSizes.set(calcHeaderSizes()); // seems to need a kick on first mount
100
+ await new Promise(resolve => requestAnimationFrame(resolve));
101
+ // need to wait long enough for headers to redraw before trying to mount the rows
102
+ await new Promise(resolve => requestAnimationFrame(resolve));
103
+ mounted = true;
99
104
  await store.refresh();
100
105
  if ($store.focused?.id && $store.focused.id === saveFocusId) {
101
- const el = document.getElementById(hashid($store.focused.id));
106
+ const el = document.getElementById(getHashId($store.focused.id));
102
107
  el?.scrollIntoView({ block: 'center' });
103
108
  }
104
- headerSizes.set(calcHeaderSizes()); // seems to need a kick on first mount
105
109
  });
106
110
  onDestroy(() => {
107
- document.removeEventListener('dragend', onDragEnd);
111
+ if (typeof document !== 'undefined')
112
+ document.removeEventListener('dragend', onDragEnd);
108
113
  });
109
114
  let hadFocus = false;
110
115
  beforeUpdate(() => {
@@ -112,7 +117,7 @@ beforeUpdate(() => {
112
117
  });
113
118
  afterUpdate(() => {
114
119
  if ($store.focused?.id) {
115
- const el = document.getElementById(hashid($store.focused.id));
120
+ const el = document.getElementById(getHashId($store.focused.id));
116
121
  if (el && hadFocus) {
117
122
  if (el !== document.activeElement)
118
123
  el.focus();
@@ -130,7 +135,8 @@ afterUpdate(() => {
130
135
  {#if enableResize && i !== headers.length - 1}<div class="tree-separator" on:mousedown={headerDragStart(header, i)} on:touchstart={headerDragStart(header, i)} on:dblclick={headerDragReset}>&nbsp;</div>{/if}
131
136
  {/each}
132
137
  </div>
133
- {#if $rootItems?.length}
138
+ {#if mounted && $rootItems?.length}
139
+ <!-- svelte-ignore a11y-no-noninteractive-element-to-interactive-role -->
134
140
  <ul bind:this={store.treeElement} role="tree" class:resizing={!!dragheaderid} on:mousemove={dragheaderid ? headerDrag : undefined} on:touchmove={dragheaderid ? headerDrag : undefined} on:mouseup={headerDragEnd} on:touchend={headerDragEnd}>
135
141
  {#each $rootItems as item, i (item.id)}
136
142
  <TreeNode
@@ -4,9 +4,9 @@ import menuDown from '@iconify-icons/mdi/menu-down';
4
4
  import menuRight from '@iconify-icons/mdi/menu-right';
5
5
  import { modifierKey, ScreenReaderOnly } from '@txstate-mws/svelte-components';
6
6
  import { createEventDispatcher, getContext } from 'svelte';
7
- import { hashid, isNotBlank, toArray } from 'txstate-utils';
7
+ import { isNotBlank, toArray } from 'txstate-utils';
8
8
  import { Icon } from '..';
9
- import { TREE_STORE_CONTEXT } from './treestore';
9
+ import { TREE_STORE_CONTEXT, getHashId } from './treestore';
10
10
  import LoadIcon from './LoadIcon.svelte';
11
11
  import TreeCell from './TreeCell.svelte';
12
12
  export let headers;
@@ -26,7 +26,7 @@ let nodeelement;
26
26
  let userWantsCopy = false;
27
27
  $: isSelected = $selected.has(item.id);
28
28
  $: showChildren = !!item.open && !!item.children?.length;
29
- $: hashedId = hashid(item.id);
29
+ $: hashedId = getHashId(item.id);
30
30
  $: isDraggable = $draggable && ((isSelected && !$selectedUndraggable) || store.dragEligible([item], true) || store.dragEligible([item], false));
31
31
  $: dropZone = $dragging && store.dropEffect(item, false, userWantsCopy) !== 'none';
32
32
  $: dropDisabled = $dragging && !dropZone;
@@ -48,7 +48,7 @@ export declare class TreeStore<T extends TreeItemFromDB> extends ActiveStore<ITr
48
48
  #private;
49
49
  fetchChildren: FetchChildrenFn<T>;
50
50
  treeElement?: HTMLElement;
51
- rootItems: import("@txstate-mws/svelte-store").DerivedStore<TypedTreeItem<T>[] | undefined, ITreeStore<T>>;
51
+ rootItems: import("svelte/store").Readable<any>;
52
52
  draggable: import("@txstate-mws/svelte-store").DerivedStore<boolean, ITreeStore<T>>;
53
53
  dragging: import("@txstate-mws/svelte-store").DerivedStore<boolean, ITreeStore<T>>;
54
54
  selectedUndraggable: import("@txstate-mws/svelte-store").DerivedStore<boolean | undefined, ITreeStore<T>>;
@@ -115,3 +115,5 @@ export declare class TreeStore<T extends TreeItemFromDB> extends ActiveStore<ITr
115
115
  setHeaderOverride(id: string, width: string): void;
116
116
  resetHeaderOverride(): void;
117
117
  }
118
+ export declare const hashedIds: Record<string, string>;
119
+ export declare function getHashId(str: string): string;
@@ -1,10 +1,12 @@
1
1
  import { ActiveStore, derivedStore } from '@txstate-mws/svelte-store';
2
- import { keyby } from 'txstate-utils';
2
+ import { derived } from 'svelte/store';
3
+ import { hashid, keyby } from 'txstate-utils';
3
4
  export const TREE_STORE_CONTEXT = {};
5
+ const rootItems = v => v.rootItems;
4
6
  export class TreeStore extends ActiveStore {
5
7
  fetchChildren;
6
8
  treeElement;
7
- rootItems = derivedStore(this, 'rootItems');
9
+ rootItems = derived(this, rootItems);
8
10
  draggable = derivedStore(this, v => v.draggable && !v.loading);
9
11
  dragging = derivedStore(this, 'dragging');
10
12
  selectedUndraggable = derivedStore(this, 'selectedUndraggable');
@@ -29,7 +31,7 @@ export class TreeStore extends ActiveStore {
29
31
  }
30
32
  async visit(item, cb) {
31
33
  await cb(item);
32
- await Promise.all((item.children ?? []).map(async (child) => await this.visit(child, cb)));
34
+ await Promise.all((item.children ?? []).map(async (child) => { await this.visit(child, cb); }));
33
35
  }
34
36
  visitSync(item, cb) {
35
37
  cb(item);
@@ -77,15 +79,17 @@ export class TreeStore extends ActiveStore {
77
79
  try {
78
80
  const children = await this.fetch(item);
79
81
  // re-open any open children
80
- await Promise.all(children.map(async (child) => await this.visit(child, async (child) => {
81
- child.open = this.value.itemsById[child.id]?.open;
82
- if (child.open) {
83
- child.children = await this.fetch(child);
84
- child.hasChildren = child.children.length > 0;
85
- if (!child.hasChildren)
86
- child.open = false;
87
- }
88
- })));
82
+ await Promise.all(children.map(async (child) => {
83
+ await this.visit(child, async (child) => {
84
+ child.open = this.value.itemsById[child.id]?.open;
85
+ if (child.open) {
86
+ child.children = await this.fetch(child);
87
+ child.hasChildren = child.children.length > 0;
88
+ if (!child.hasChildren)
89
+ child.open = false;
90
+ }
91
+ });
92
+ }));
89
93
  if (item) {
90
94
  this.visitSync(item, itm => { if (itm.id !== item.id)
91
95
  this.value.itemsById[itm.id] = undefined; });
@@ -336,3 +340,8 @@ export class TreeStore extends ActiveStore {
336
340
  this.trigger();
337
341
  }
338
342
  }
343
+ export const hashedIds = {};
344
+ export function getHashId(str) {
345
+ hashedIds[str] ??= hashid(str);
346
+ return hashedIds[str];
347
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dosgato/dialog",
3
3
  "description": "A component library for building forms that edit a JSON document.",
4
- "version": "0.0.46",
4
+ "version": "0.0.47",
5
5
  "scripts": {
6
6
  "prepublishOnly": "svelte-package",
7
7
  "dev": "vite dev --force",
@@ -20,7 +20,7 @@
20
20
  "./package.json": "./package.json"
21
21
  },
22
22
  "dependencies": {
23
- "@txstate-mws/svelte-components": "^1.3.9",
23
+ "@txstate-mws/svelte-components": "^1.4.5",
24
24
  "@txstate-mws/svelte-forms": "^1.3.4",
25
25
  "@iconify/svelte": "^3.0.0",
26
26
  "@iconify-icons/mdi": "^1.2.22",