@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.
Files changed (58) 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 +81 -72
  17. package/dist/FieldNumber.svelte +20 -19
  18. package/dist/FieldRadio.svelte +42 -41
  19. package/dist/FieldSelect.svelte +45 -45
  20. package/dist/FieldStandard.svelte +28 -27
  21. package/dist/FieldText.svelte +27 -24
  22. package/dist/FieldTextArea.svelte +24 -24
  23. package/dist/FileIcon.svelte +10 -8
  24. package/dist/Form.svelte +40 -18
  25. package/dist/Form.svelte.d.ts +15 -13
  26. package/dist/FormDialog.svelte +40 -25
  27. package/dist/FormDialog.svelte.d.ts +23 -17
  28. package/dist/Icon.svelte +38 -33
  29. package/dist/InlineMessage.svelte +31 -29
  30. package/dist/InlineMessages.svelte +10 -7
  31. package/dist/Input.svelte +40 -39
  32. package/dist/Listbox.svelte +102 -109
  33. package/dist/MaxLength.svelte +19 -18
  34. package/dist/Radio.svelte +18 -15
  35. package/dist/Switcher.svelte +37 -33
  36. package/dist/Tab.svelte +23 -21
  37. package/dist/Tabs.svelte +111 -110
  38. package/dist/Tooltip.svelte +7 -7
  39. package/dist/chooser/Chooser.svelte +83 -76
  40. package/dist/chooser/ChooserPreview.svelte +16 -14
  41. package/dist/chooser/Details.svelte +6 -4
  42. package/dist/chooser/Thumbnail.svelte +20 -16
  43. package/dist/chooser/UploadUI.svelte +78 -69
  44. package/dist/code/CodeEditor.svelte +63 -66
  45. package/dist/code/FieldCodeEditor.svelte +21 -19
  46. package/dist/colorpicker/FieldColorPicker.svelte +36 -35
  47. package/dist/cropper/FieldCropper.svelte +142 -141
  48. package/dist/iconpicker/FieldIconPicker.svelte +102 -94
  49. package/dist/imageposition/FieldImagePosition.svelte +107 -98
  50. package/dist/tagpicker/FieldTagPicker.svelte +63 -54
  51. package/dist/tree/LoadIcon.svelte +0 -1
  52. package/dist/tree/Tree.svelte +198 -192
  53. package/dist/tree/Tree.svelte.d.ts +5 -5
  54. package/dist/tree/TreeCell.svelte +10 -6
  55. package/dist/tree/TreeCell.svelte.d.ts +5 -5
  56. package/dist/tree/TreeNode.svelte +213 -241
  57. package/dist/tree/TreeNode.svelte.d.ts +5 -5
  58. package/package.json +8 -9
@@ -1,82 +1,90 @@
1
- <script>import browserIcon from '@iconify-icons/ph/browser';
2
- import folderIcon from '@iconify-icons/ph/folder';
3
- import folderNotchOpen from '@iconify-icons/ph/folder-notch-open';
4
- import { createEventDispatcher, getContext, onMount, setContext, tick } from 'svelte';
5
- import { isNotBlank, randomid } from 'txstate-utils';
6
- import { Button, Dialog, iconForMime, Tabs, Tree, UploadUI, expandTreePath } from '..';
7
- import { CHOOSER_API_CONTEXT } from './ChooserAPI';
8
- import { CHOOSER_STORE_CONTEXT, ChooserStore } from './ChooserStore';
9
- import ChooserPreview from './ChooserPreview.svelte';
10
- const chooserClient = getContext(CHOOSER_API_CONTEXT);
11
- export let label = undefined;
12
- export let images = false;
13
- export let pages = false;
14
- export let assets = images;
15
- export let folders = false;
16
- export let required = false;
17
- export let initialSource = undefined;
18
- export let initialPath = undefined;
19
- export let activeSources = undefined;
20
- export let passthruFilters = undefined;
21
- export let filter = undefined;
22
- export let store = new ChooserStore(chooserClient);
23
- store.filter = filter;
24
- setContext(CHOOSER_STORE_CONTEXT, store);
25
- const dispatch = createEventDispatcher();
26
- let showuploader = false;
27
- let tabStore;
28
- const { sources, source, preview, treeStore, selected } = store;
29
- $: currentName = tabStore?.currentName();
30
- $: if ($currentName) {
31
- store.setSource($currentName);
32
- treeStore.refresh().catch(console.error);
33
- }
34
- $: store.setPreview($selected);
35
- function onChoose() {
36
- dispatch('change', $store.preview);
37
- }
38
- function onDeselect() {
39
- store.setPreview(undefined);
40
- thumbnailExpanded = false;
41
- }
42
- function onUploadComplete() {
43
- treeStore.openAndRefresh($selected).catch(console.error);
44
- showuploader = false;
45
- }
46
- async function selectPreview(preloadPath) {
47
- if (!$store.initialized)
48
- return;
1
+ <script lang="ts" generics="F">
2
+ import browserIcon from '@iconify-icons/ph/browser'
3
+ import folderIcon from '@iconify-icons/ph/folder'
4
+ import folderNotchOpen from '@iconify-icons/ph/folder-notch-open'
5
+ import { createEventDispatcher, getContext, onMount, setContext, tick } from 'svelte'
6
+ import { isNotBlank, randomid } from 'txstate-utils'
7
+ import { Button, Dialog, iconForMime, Tabs, Tree, type TypedTreeItem, type TabStore, UploadUI, expandTreePath } from '..'
8
+ import { CHOOSER_API_CONTEXT, type AnyItem, type Client } from './ChooserAPI'
9
+ import { CHOOSER_STORE_CONTEXT, ChooserStore } from './ChooserStore'
10
+ import ChooserPreview from './ChooserPreview.svelte'
11
+
12
+ const chooserClient = getContext<Client>(CHOOSER_API_CONTEXT)
13
+
14
+ export let label: string | undefined = undefined
15
+ export let images = false
16
+ export let pages = false
17
+ export let assets = images
18
+ export let folders = false
19
+ export let required = false
20
+ export let initialSource: string | undefined = undefined
21
+ export let initialPath: string | undefined = undefined
22
+ export let activeSources: string[] | undefined = undefined
23
+ export let passthruFilters: F | undefined = undefined
24
+ export let filter: undefined | ((item: AnyItem) => boolean | Promise<boolean>) = undefined
25
+ export let store = new ChooserStore<F>(chooserClient)
26
+ store.filter = filter
27
+
28
+ setContext(CHOOSER_STORE_CONTEXT, store)
29
+ const dispatch = createEventDispatcher()
30
+
31
+ let showuploader = false
32
+ let tabStore: TabStore
33
+ const { sources, source, preview, treeStore, selected } = store
34
+ $: currentName = tabStore?.currentName()
35
+
36
+ $: if ($currentName) {
37
+ store.setSource($currentName)
38
+ treeStore.refresh().catch(console.error)
39
+ }
40
+ $: store.setPreview($selected)
41
+
42
+ function onChoose () {
43
+ dispatch('change', $store.preview)
44
+ }
45
+
46
+ function onDeselect () {
47
+ store.setPreview(undefined)
48
+ thumbnailExpanded = false
49
+ }
50
+
51
+ function onUploadComplete () {
52
+ treeStore.openAndRefresh($selected!).catch(console.error)
53
+ showuploader = false
54
+ }
55
+
56
+ async function selectPreview (preloadPath) {
57
+ if (!$store.initialized) return
49
58
  if (preloadPath) {
50
- const currentSelection = await expandTreePath(treeStore, preloadPath.split('/').filter(isNotBlank));
51
- if (!currentSelection)
52
- return;
53
- store.setPreview(currentSelection);
54
- treeStore.select(currentSelection, { clear: true });
55
- await tick();
56
- const focusedElement = document.querySelector('.tree-node[tabindex="0"]');
57
- if (focusedElement?.classList.contains('tree-node'))
58
- focusedElement.scrollIntoView({ block: 'center' });
59
+ const currentSelection = await expandTreePath(treeStore, preloadPath.split('/').filter(isNotBlank))
60
+ if (!currentSelection) return
61
+ store.setPreview(currentSelection)
62
+ treeStore.select(currentSelection, { clear: true })
63
+ await tick()
64
+ const focusedElement = document.querySelector('.tree-node[tabindex="0"]')
65
+ if (focusedElement?.classList.contains('tree-node')) focusedElement.scrollIntoView({ block: 'center' })
59
66
  }
60
- }
61
- onMount(async () => {
62
- const preloadSource = $preview?.source ?? $selected?.source ?? $source?.name ?? initialSource;
63
- const preloadPath = $preview?.path ?? $selected?.path ?? initialPath;
64
- await store.init({ images, pages, assets, folders, activeSources, initialSource: preloadSource, initialPath: preloadPath, passthruFilters, filter });
65
- await treeStore.refresh();
66
- await selectPreview(preloadPath);
67
- });
68
- const previewId = randomid();
69
- let thumbnailExpanded = false;
70
- function iconForItem(item) {
67
+ }
68
+ onMount(async () => {
69
+ const preloadSource = $preview?.source ?? $selected?.source ?? $source?.name ?? initialSource
70
+ const preloadPath = $preview?.path ?? $selected?.path ?? initialPath
71
+ await store.init({ images, pages, assets, folders, activeSources, initialSource: preloadSource, initialPath: preloadPath, passthruFilters, filter })
72
+ await treeStore.refresh()
73
+ await selectPreview(preloadPath)
74
+ })
75
+
76
+ const previewId = randomid()
77
+ let thumbnailExpanded = false
78
+
79
+ function iconForItem (item: TypedTreeItem<AnyItem>) {
71
80
  if (item.icon) {
72
- return item.icon;
73
- }
74
- else {
75
- return {
76
- icon: item.type === 'asset' ? iconForMime(item.mime) : (item.type === 'folder' ? (item.open ? folderNotchOpen : folderIcon) : browserIcon)
77
- };
81
+ return item.icon
82
+ } else {
83
+ return {
84
+ icon: item.type === 'asset' ? iconForMime(item.mime) : (item.type === 'folder' ? (item.open ? folderNotchOpen : folderIcon) : browserIcon)
85
+ }
78
86
  }
79
- }
87
+ }
80
88
  </script>
81
89
 
82
90
  <Dialog size="xl" ignoreTabs title={label} on:escape continueText="Choose" disabled={!$preview && required} cancelText="Cancel">
@@ -150,5 +158,4 @@ function iconForItem(item) {
150
158
  height: 70%;
151
159
  }
152
160
  }
153
-
154
161
  </style>
@@ -1,16 +1,19 @@
1
- <script>import Thumbnail from './Thumbnail.svelte';
2
- import Details from './Details.svelte';
3
- import { createEventDispatcher } from 'svelte';
4
- export let previewId;
5
- export let store;
6
- const { preview } = store;
7
- export let thumbnailExpanded;
8
- const dispatch = createEventDispatcher();
9
- function reactToPreview(_preview) {
10
- if (thumbnailExpanded)
11
- dispatch('thumbnailsizechange');
12
- }
13
- $: reactToPreview($preview);
1
+ <script lang="ts">
2
+ import type { ChooserStore } from './ChooserStore'
3
+ import Thumbnail from './Thumbnail.svelte'
4
+ import Details from './Details.svelte'
5
+ import { createEventDispatcher } from 'svelte'
6
+
7
+ export let previewId: string
8
+ export let store: ChooserStore
9
+ const { preview } = store
10
+ export let thumbnailExpanded: boolean
11
+ const dispatch = createEventDispatcher()
12
+
13
+ function reactToPreview (_preview) {
14
+ if (thumbnailExpanded) dispatch('thumbnailsizechange')
15
+ }
16
+ $: reactToPreview($preview)
14
17
  </script>
15
18
 
16
19
  <section id={previewId} class="dialog-chooser-preview" class:image={$preview?.type === 'asset' && $preview.image} class:collapsed={!thumbnailExpanded} tabindex="-1">
@@ -141,5 +144,4 @@ $: reactToPreview($preview);
141
144
  display: none;
142
145
  }
143
146
  }
144
-
145
147
  </style>
@@ -1,6 +1,9 @@
1
- <script>import { bytesToHuman, cleanUrl, humanFileType } from './ChooserStore';
2
- export let item;
3
- export let singleLine = false;
1
+ <script lang="ts">
2
+ import type { AnyItem } from './ChooserAPI'
3
+ import { bytesToHuman, cleanUrl, type BrokenURL, type RawURL, humanFileType } from './ChooserStore'
4
+
5
+ export let item: AnyItem | RawURL | BrokenURL
6
+ export let singleLine = false
4
7
  </script>
5
8
 
6
9
  <dl class="dialog-chooser-info" aria-live="polite" class:multiLine={!singleLine} class:asset={item.type === 'asset'}>
@@ -88,5 +91,4 @@ export let singleLine = false;
88
91
  white-space: nowrap;
89
92
  text-overflow: ellipsis;
90
93
  }
91
-
92
94
  </style>
@@ -1,18 +1,23 @@
1
- <script>import folderOutline from '@iconify-icons/mdi/folder-outline.js';
2
- import fileLinkOutline from '@iconify-icons/mdi/file-link-outline.js';
3
- import FileIcon from '../FileIcon.svelte';
4
- import Icon from '../Icon.svelte';
5
- import { ScreenReaderOnly } from '@txstate-mws/svelte-components';
6
- import { collapseIconSVG, expandIconSVG } from './icons';
7
- import { createEventDispatcher } from 'svelte';
8
- export let item;
9
- export let larger = false;
10
- export let expandable = false;
11
- export let expanded = false;
12
- const dispatch = createEventDispatcher();
13
- function toggleThumbnailSize() {
14
- dispatch('thumbnailsizechange');
15
- }
1
+ <script lang="ts">
2
+ import folderOutline from '@iconify-icons/mdi/folder-outline.js'
3
+ import fileLinkOutline from '@iconify-icons/mdi/file-link-outline.js'
4
+ import FileIcon from '../FileIcon.svelte'
5
+ import Icon from '../Icon.svelte'
6
+ import type { AnyItem } from './ChooserAPI'
7
+ import type { BrokenURL, RawURL } from './ChooserStore'
8
+ import { ScreenReaderOnly } from '@txstate-mws/svelte-components'
9
+ import { collapseIconSVG, expandIconSVG } from './icons'
10
+ import { createEventDispatcher } from 'svelte'
11
+
12
+ export let item: AnyItem | RawURL | BrokenURL
13
+ export let larger = false
14
+ export let expandable = false
15
+ export let expanded = false
16
+ const dispatch = createEventDispatcher()
17
+
18
+ function toggleThumbnailSize () {
19
+ dispatch('thumbnailsizechange')
20
+ }
16
21
  </script>
17
22
  <div class="dialog-chooser-thumbnail" class:expanded>
18
23
  {#if item.type === 'asset'}
@@ -70,5 +75,4 @@ function toggleThumbnailSize() {
70
75
  width: 100%;
71
76
  height: 100%;
72
77
  }
73
-
74
78
  </style>
@@ -1,78 +1,88 @@
1
- <script>import trashLight from '@iconify-icons/ph/trash-light';
2
- import { roundTo, unique } from 'txstate-utils';
3
- import { createEventDispatcher } from 'svelte';
4
- import { Dialog, FileIcon, Icon } from '..';
5
- export let title;
6
- export let folder;
7
- export let maxFiles = 200;
8
- export let escapable = true;
9
- export let mimeWhitelist = [];
10
- export let mimeBlacklist = [];
11
- export let uploader;
12
- $: whitelist = new Set(mimeWhitelist);
13
- $: blacklist = new Set(mimeBlacklist);
14
- const dispatch = createEventDispatcher();
15
- let dragover = 0;
16
- let uploadList = [];
17
- let uploadLocked = false;
18
- let uploadProgress = 0;
19
- let uploadError;
20
- function onUploadEnter(e) {
21
- if (e.dataTransfer?.items.length)
22
- dragover++;
23
- }
24
- function onUploadLeave(e) {
25
- if (e.dataTransfer?.items.length)
26
- dragover--;
27
- }
28
- function onUploadDrop(e) {
29
- e.preventDefault();
30
- dragover = 0;
1
+ <script lang="ts">
2
+ import trashLight from '@iconify-icons/ph/trash-light'
3
+ import { roundTo, unique } from 'txstate-utils'
4
+ import { createEventDispatcher } from 'svelte'
5
+ import { Dialog, FileIcon, Icon, type Client, type Folder } from '..'
6
+
7
+ export let title: string
8
+ export let folder: Folder
9
+ export let maxFiles: number = 200
10
+ export let escapable = true
11
+ export let mimeWhitelist: string[] = []
12
+ export let mimeBlacklist: string[] = []
13
+ export let uploader: NonNullable<Client['upload']>
14
+ $: whitelist = new Set(mimeWhitelist)
15
+ $: blacklist = new Set(mimeBlacklist)
16
+
17
+ const dispatch = createEventDispatcher()
18
+
19
+ let dragover = 0
20
+ let uploadList: File[] = []
21
+ let uploadLocked = false
22
+ let uploadProgress = 0
23
+ let uploadError: string | undefined
24
+
25
+ function onUploadEnter (e: DragEvent) {
26
+ if (e.dataTransfer?.items.length) dragover++
27
+ }
28
+
29
+ function onUploadLeave (e: DragEvent) {
30
+ if (e.dataTransfer?.items.length) dragover--
31
+ }
32
+
33
+ function onUploadDrop (e: DragEvent) {
34
+ e.preventDefault()
35
+ dragover = 0
31
36
  if (!uploadLocked && e.dataTransfer?.items?.length) {
32
- uploadList = unique(uploadList.concat(Array.from(e.dataTransfer.files)), 'name').slice(-1 * maxFiles);
37
+ uploadList = unique(uploadList.concat(Array.from(e.dataTransfer.files)), 'name').slice(-1 * maxFiles)
33
38
  }
34
- }
35
- function onUploadChange(e) {
36
- const files = e.currentTarget.files;
37
- if (files?.length)
38
- uploadList = unique(uploadList.concat(Array.from(files)), 'name').slice(-1 * maxFiles);
39
- e.currentTarget.value = '';
40
- }
41
- async function onUploadSubmit() {
42
- if (uploadLocked)
43
- return;
44
- uploadLocked = true;
39
+ }
40
+
41
+ function onUploadChange (e: InputEvent & { currentTarget: HTMLInputElement }) {
42
+ const files = e.currentTarget.files
43
+ if (files?.length) uploadList = unique(uploadList.concat(Array.from(files)), 'name').slice(-1 * maxFiles)
44
+ e.currentTarget.value = ''
45
+ }
46
+
47
+ async function onUploadSubmit () {
48
+ if (uploadLocked) return
49
+ uploadLocked = true
45
50
  try {
46
- const data = new FormData();
47
- for (let i = 0; i < uploadList.length; i++) {
48
- data.append('file' + i, uploadList[i]);
49
- }
50
- // TODO: accept new list of children from uploader function and feed it
51
- // to the tree instead of refreshing the tree
52
- await uploader(folder, uploadList, ratio => { uploadProgress = ratio; });
53
- uploadList = [];
54
- uploadError = undefined;
55
- dispatch('saved');
56
- }
57
- catch (e) {
58
- uploadError = e.message;
59
- }
60
- finally {
61
- uploadLocked = false;
51
+ const data = new FormData()
52
+ for (let i = 0; i < uploadList.length; i++) {
53
+ data.append('file' + i, uploadList[i])
54
+ }
55
+
56
+ // TODO: accept new list of children from uploader function and feed it
57
+ // to the tree instead of refreshing the tree
58
+ await uploader(
59
+ folder,
60
+ uploadList,
61
+ ratio => { uploadProgress = ratio }
62
+ )
63
+ uploadList = []
64
+ uploadError = undefined
65
+ dispatch('saved')
66
+ } catch (e: any) {
67
+ uploadError = e.message
68
+ } finally {
69
+ uploadLocked = false
62
70
  }
63
- }
64
- function onUploadEscape() {
71
+ }
72
+
73
+ function onUploadEscape () {
65
74
  if (!uploadLocked && escapable) {
66
- uploadList = [];
67
- uploadError = undefined;
68
- dispatch('escape');
75
+ uploadList = []
76
+ uploadError = undefined
77
+ dispatch('escape')
69
78
  }
70
- }
71
- function onDeleteFile(file) {
79
+ }
80
+
81
+ function onDeleteFile (file: File) {
72
82
  return () => {
73
- uploadList = uploadList.filter(f => f !== file);
74
- };
75
- }
83
+ uploadList = uploadList.filter(f => f !== file)
84
+ }
85
+ }
76
86
  </script>
77
87
 
78
88
  <Dialog {title} disabled={!uploadList.length} cancelText="Cancel" continueText="Upload" on:escape={onUploadEscape} on:continue={onUploadSubmit}>
@@ -157,5 +167,4 @@ function onDeleteFile(file) {
157
167
  li div {
158
168
  width: 100%;
159
169
  }
160
-
161
170
  </style>
@@ -1,70 +1,68 @@
1
- <script>import { passActions } from '@txstate-mws/svelte-components';
2
- import { createEventDispatcher, onDestroy, onMount } from 'svelte';
3
- import { getDescribedBy } from '..';
4
- let className = '';
5
- export { className as class };
6
- export let id = undefined;
7
- export let rows = 8;
8
- export let language;
9
- export let use = [];
10
- export let inputelement = undefined;
11
- export let extradescid = undefined;
12
- export let helptextid = undefined;
13
- export let messagesid = undefined;
14
- export let valid = undefined;
15
- export let invalid = undefined;
16
- export let value;
17
- const dispatch = createEventDispatcher();
18
- let updateCode;
19
- let editorelement;
20
- let editor;
21
- onMount(async () => {
22
- const { EditorView, minimalSetup } = await import('codemirror');
23
- const { indentWithTab } = await import('@codemirror/commands');
24
- const { lineNumbers, highlightActiveLine, highlightActiveLineGutter, keymap } = await import('@codemirror/view');
25
- const { langmap } = await import('./langs.js');
1
+ <script lang="ts">
2
+ import { type HTMLActionEntry, passActions } from '@txstate-mws/svelte-components'
3
+ import type { EditorView, ViewUpdate } from '@codemirror/view'
4
+ import { createEventDispatcher, onDestroy, onMount } from 'svelte'
5
+ import { getDescribedBy } from '..'
6
+ let className = ''
7
+ export { className as class }
8
+ export let id: string | undefined = undefined
9
+ export let rows = 8
10
+ export let language: 'js' | 'css' | 'html'
11
+ export let use: HTMLActionEntry[] = []
12
+ export let inputelement: HTMLElement | undefined = undefined
13
+ export let extradescid: string | undefined = undefined
14
+ export let helptextid: string | undefined = undefined
15
+ export let messagesid: string | undefined = undefined
16
+ export let valid: boolean | undefined = undefined
17
+ export let invalid: boolean | undefined = undefined
18
+ export let value: any
19
+
20
+ const dispatch = createEventDispatcher()
21
+
22
+ let updateCode: (code: string) => void
23
+ let editorelement: HTMLElement | undefined
24
+ let editor: EditorView
25
+ onMount(async () => {
26
+ const { EditorView, minimalSetup } = await import('codemirror')
27
+ const { indentWithTab } = await import('@codemirror/commands')
28
+ const { lineNumbers, highlightActiveLine, highlightActiveLineGutter, keymap } = await import('@codemirror/view')
29
+ const { langmap } = await import('./langs.js')
26
30
  editor = new EditorView({
27
- extensions: [
28
- minimalSetup,
29
- lineNumbers(),
30
- highlightActiveLine(),
31
- highlightActiveLineGutter(),
32
- langmap[language],
33
- keymap.of([indentWithTab]),
34
- EditorView.updateListener.of((v) => {
35
- if (v.docChanged) {
36
- const newval = editor.state.doc.toString();
37
- if (value !== newval)
38
- dispatch('change', newval);
39
- }
40
- })
41
- ],
42
- parent: editorelement
43
- });
31
+ extensions: [
32
+ minimalSetup,
33
+ lineNumbers(),
34
+ highlightActiveLine(),
35
+ highlightActiveLineGutter(),
36
+ langmap[language],
37
+ keymap.of([indentWithTab]),
38
+ EditorView.updateListener.of((v: ViewUpdate) => {
39
+ if (v.docChanged) {
40
+ const newval = editor.state.doc.toString()
41
+ if (value !== newval) dispatch('change', newval)
42
+ }
43
+ })
44
+ ],
45
+ parent: editorelement
46
+ })
44
47
  updateCode = code => {
45
- if (editor.state.doc.toString() !== code)
46
- editor.update([editor.state.update({ changes: { from: 0, to: editor.state.doc.length, insert: code } })]);
47
- };
48
- inputelement = editorelement?.querySelector('.cm-content') ?? undefined;
49
- if (id)
50
- inputelement?.setAttribute('id', id);
51
- if (className)
52
- inputelement?.classList.add(...className.split(' '), ...[]);
53
- updateValidState();
54
- });
55
- onDestroy(() => {
56
- editor?.destroy();
57
- });
58
- $: updateCode?.(value ?? '');
59
- function updateValidState(..._) {
60
- inputelement?.setAttribute('aria-invalid', String(!!invalid));
61
- const descby = getDescribedBy([messagesid, helptextid, extradescid]);
62
- if (descby)
63
- inputelement?.setAttribute('aria-describedby', descby);
64
- else
65
- inputelement?.removeAttribute('aria-describedby');
66
- }
67
- $: updateValidState(invalid, messagesid);
48
+ if (editor.state.doc.toString() !== code) editor.update([editor.state.update({ changes: { from: 0, to: editor.state.doc.length, insert: code } })])
49
+ }
50
+ inputelement = editorelement?.querySelector('.cm-content') ?? undefined
51
+ if (id) inputelement?.setAttribute('id', id)
52
+ if (className) inputelement?.classList.add(...className.split(' '), ...[])
53
+ updateValidState()
54
+ })
55
+ onDestroy(() => {
56
+ editor?.destroy()
57
+ })
58
+ $: updateCode?.(value ?? '')
59
+ function updateValidState (..._: any[]) {
60
+ inputelement?.setAttribute('aria-invalid', String(!!invalid))
61
+ const descby = getDescribedBy([messagesid, helptextid, extradescid])
62
+ if (descby) inputelement?.setAttribute('aria-describedby', descby)
63
+ else inputelement?.removeAttribute('aria-describedby')
64
+ }
65
+ $: updateValidState(invalid, messagesid)
68
66
  </script>
69
67
 
70
68
  <div bind:this={editorelement} style:--cm-editor-minh="{rows * 1.5}em" class:valid class:invalid on:paste on:focusout use:passActions={use}></div>
@@ -81,5 +79,4 @@ $: updateValidState(invalid, messagesid);
81
79
  overflow: auto;
82
80
  resize: vertical;
83
81
  }
84
-
85
82
  </style>
@@ -1,22 +1,24 @@
1
- <script>import { nullableSerialize, nullableDeserialize } from '@txstate-mws/svelte-forms';
2
- import { FieldStandard } from '..';
3
- import CodeEditor from './CodeEditor.svelte';
4
- let className = '';
5
- export { className as class };
6
- export let id = undefined;
7
- export let path;
8
- export let label = '';
9
- export let notNull = false;
10
- export let defaultValue = notNull ? '' : undefined;
11
- export let rows = 8;
12
- export let conditional = undefined;
13
- export let required = false;
14
- export let use = [];
15
- export let inputelement = undefined;
16
- export let related = 0;
17
- export let extradescid = undefined;
18
- export let helptext = undefined;
19
- export let language;
1
+ <script lang="ts">
2
+ import type { HTMLActionEntry } from '@txstate-mws/svelte-components'
3
+ import { nullableSerialize, nullableDeserialize } from '@txstate-mws/svelte-forms'
4
+ import { FieldStandard } from '..'
5
+ import CodeEditor from './CodeEditor.svelte'
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 notNull = false
12
+ export let defaultValue: any = notNull ? '' : undefined
13
+ export let rows = 8
14
+ export let conditional: boolean | undefined = undefined
15
+ export let required = false
16
+ export let use: HTMLActionEntry[] = []
17
+ export let inputelement: HTMLElement = undefined as any
18
+ export let related: true | number = 0
19
+ export let extradescid: string | undefined = undefined
20
+ export let helptext: string | undefined = undefined
21
+ export let language: 'js' | 'css' | 'html'
20
22
  </script>
21
23
 
22
24
  <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:setVal let:messagesid let:helptextid>