@dosgato/dialog 0.0.65 → 0.0.66
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/FieldAutocomplete.svelte +1 -5
- package/dist/FieldChooserLink.svelte +50 -32
- package/dist/FieldIdentifier.svelte +2 -1
- package/dist/FieldIdentifier.svelte.d.ts +1 -0
- package/dist/FieldMultiselect.svelte +1 -3
- package/dist/FieldSelect.svelte +5 -3
- package/dist/FieldText.svelte +6 -1
- package/dist/FieldTextArea.svelte +6 -1
- package/dist/FormDialog.svelte +1 -1
- package/dist/MaxLength.svelte +36 -0
- package/dist/MaxLength.svelte.d.ts +17 -0
- package/dist/Tooltip.svelte +0 -2
- package/dist/Tooltip.svelte.d.ts +0 -1
- package/dist/chooser/ChooserStore.d.ts +1 -0
- package/dist/chooser/ChooserStore.js +20 -0
- package/dist/chooser/Details.svelte +36 -43
- package/dist/chooser/Details.svelte.d.ts +1 -0
- package/dist/code/CodeEditor.svelte +85 -0
- package/dist/code/CodeEditor.svelte.d.ts +32 -0
- package/dist/code/FieldCodeEditor.svelte +24 -0
- package/dist/{FieldCodeEditor.svelte.d.ts → code/FieldCodeEditor.svelte.d.ts} +2 -2
- package/dist/code/index.d.ts +1 -0
- package/dist/code/index.js +1 -0
- package/dist/code/langs.d.ts +5 -0
- package/dist/code/langs.js +8 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/tree/TreeNode.svelte +5 -1
- package/package.json +7 -5
- package/dist/FieldCodeEditor.svelte +0 -71
|
@@ -73,16 +73,12 @@ function reactToValue(value, setVal) {
|
|
|
73
73
|
setVal(finaldeserialize(''));
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
|
-
let portal;
|
|
77
|
-
onMount(() => {
|
|
78
|
-
portal = inputelement.closest('.dialog-content');
|
|
79
|
-
});
|
|
80
76
|
</script>
|
|
81
77
|
|
|
82
78
|
<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>
|
|
83
79
|
{@const _ = reactToValue(value, setVal)}
|
|
84
80
|
<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])}>
|
|
85
|
-
<PopupMenu bind:menushown bind:menuid align="bottomleft"
|
|
81
|
+
<PopupMenu bind:menushown bind:menuid align="bottomleft" items={filteredChoices} buttonelement={inputelement} bind:value={popupvalue} on:change={onchangepopup(setVal)} emptyText="No options available"/>
|
|
86
82
|
<ScreenReaderOnly arialive="polite" ariaatomic={true} id={liveTextId}>
|
|
87
83
|
{filteredChoices.length} {filteredChoices.length === 1 ? 'option' : 'options'} available.
|
|
88
84
|
</ScreenReaderOnly>
|
|
@@ -1,17 +1,12 @@
|
|
|
1
|
-
<script
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
}
|
|
5
|
-
</script>
|
|
6
|
-
<script>import { FORM_CONTEXT, FORM_INHERITED_PATH } from '@txstate-mws/svelte-forms';
|
|
1
|
+
<script>import arrowClockwiseFill from '@iconify-icons/ph/arrow-clockwise-fill';
|
|
2
|
+
import deleteOutline from '@iconify-icons/mdi/delete-outline';
|
|
3
|
+
import { FORM_CONTEXT, FORM_INHERITED_PATH } from '@txstate-mws/svelte-forms';
|
|
7
4
|
import { getContext } from 'svelte';
|
|
8
5
|
import { isBlank, isNotBlank, randomid } from 'txstate-utils';
|
|
9
|
-
import { Chooser, ChooserStore, CHOOSER_API_CONTEXT } from './chooser';
|
|
6
|
+
import { Chooser, ChooserStore, CHOOSER_API_CONTEXT, cleanUrl } from './chooser';
|
|
10
7
|
import Details from './chooser/Details.svelte';
|
|
11
8
|
import Thumbnail from './chooser/Thumbnail.svelte';
|
|
12
|
-
import FieldStandard from './
|
|
13
|
-
import InlineMessage from './InlineMessage.svelte';
|
|
14
|
-
import { getDescribedBy } from './';
|
|
9
|
+
import { getDescribedBy, FieldStandard, InlineMessage, Icon } from './';
|
|
15
10
|
export let id = undefined;
|
|
16
11
|
export let path;
|
|
17
12
|
export let label = '';
|
|
@@ -61,6 +56,7 @@ function userUrlEntry() {
|
|
|
61
56
|
}
|
|
62
57
|
async function userUrlEntryDebounced() {
|
|
63
58
|
const url = this.value;
|
|
59
|
+
const cleanedUrl = cleanUrl(url);
|
|
64
60
|
store.clearPreview();
|
|
65
61
|
if (isBlank(url)) {
|
|
66
62
|
selectedAsset = undefined;
|
|
@@ -69,7 +65,9 @@ async function userUrlEntryDebounced() {
|
|
|
69
65
|
}
|
|
70
66
|
let found = false;
|
|
71
67
|
if (chooserClient.findByUrl) {
|
|
72
|
-
|
|
68
|
+
let item = await chooserClient.findByUrl(url);
|
|
69
|
+
if (!item && isNotBlank(cleanedUrl))
|
|
70
|
+
item = await chooserClient.findByUrl(cleanedUrl);
|
|
73
71
|
if (url !== this.value)
|
|
74
72
|
return;
|
|
75
73
|
if (item) {
|
|
@@ -98,20 +96,19 @@ async function userUrlEntryDebounced() {
|
|
|
98
96
|
selectedAsset = { type: 'raw', id: urlToValueCache[url], url };
|
|
99
97
|
}
|
|
100
98
|
else {
|
|
101
|
-
|
|
102
|
-
const reconstructed = reconstructUrl(url);
|
|
103
|
-
selectedAsset = {
|
|
104
|
-
type: 'raw',
|
|
105
|
-
id: chooserClient.urlToValue?.(reconstructed) ?? reconstructed,
|
|
106
|
-
url
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
catch {
|
|
99
|
+
if (isBlank(cleanedUrl) || cleanedUrl.startsWith('/')) {
|
|
110
100
|
// here we "select" a raw url so that we do not interrupt the users' typing, but
|
|
111
101
|
// we set its id to 'undefined' so that nothing makes it into the form until it's
|
|
112
102
|
// a valid URL
|
|
113
103
|
selectedAsset = { type: 'raw', id: undefined, url };
|
|
114
104
|
}
|
|
105
|
+
else {
|
|
106
|
+
selectedAsset = {
|
|
107
|
+
type: 'raw',
|
|
108
|
+
id: chooserClient.urlToValue?.(cleanedUrl) ?? cleanedUrl,
|
|
109
|
+
url
|
|
110
|
+
};
|
|
111
|
+
}
|
|
115
112
|
}
|
|
116
113
|
}
|
|
117
114
|
formStore.setField(finalPath, selectedAsset?.id);
|
|
@@ -128,14 +125,19 @@ async function updateSelected(..._) {
|
|
|
128
125
|
try {
|
|
129
126
|
if (!selectedAsset) {
|
|
130
127
|
const urlFromValue = chooserClient.valueToUrl?.($value) ?? $value;
|
|
131
|
-
|
|
132
|
-
|
|
128
|
+
const cleanedUrlFromValue = cleanUrl(urlFromValue);
|
|
129
|
+
if (isBlank(cleanedUrlFromValue)) {
|
|
130
|
+
selectedAsset = undefined;
|
|
131
|
+
}
|
|
132
|
+
else if (cleanedUrlFromValue.startsWith('/')) {
|
|
133
|
+
selectedAsset = { type: 'broken', id: $value, url: cleanedUrlFromValue };
|
|
133
134
|
}
|
|
134
|
-
|
|
135
|
-
selectedAsset = { type: '
|
|
135
|
+
else {
|
|
136
|
+
selectedAsset = { type: 'raw', id: $value, url: cleanedUrlFromValue };
|
|
136
137
|
}
|
|
137
138
|
}
|
|
138
|
-
|
|
139
|
+
if (selectedAsset)
|
|
140
|
+
urlToValueCache[selectedAsset.url] = $value;
|
|
139
141
|
}
|
|
140
142
|
catch (e) {
|
|
141
143
|
console.error(e);
|
|
@@ -149,15 +151,27 @@ $: updateSelected($value);
|
|
|
149
151
|
{#if selectedAsset?.id}
|
|
150
152
|
<div class="dialog-chooser-container">
|
|
151
153
|
<Thumbnail item={selectedAsset} />
|
|
152
|
-
<
|
|
154
|
+
<div class="dialog-chooser-right">
|
|
155
|
+
<Details item={selectedAsset} singleLine />
|
|
156
|
+
{#if !urlEntry}
|
|
157
|
+
<button type="button" on:click={show} aria-describedby={getDescribedBy([descid, messagesid, helptextid, extradescid])}>
|
|
158
|
+
<Icon icon={arrowClockwiseFill} /> Replace
|
|
159
|
+
</button>
|
|
160
|
+
{/if}
|
|
161
|
+
<button type="button" on:click={() => { selectedAsset = undefined; setVal(undefined) }} aria-describedby={getDescribedBy([descid, messagesid, helptextid, extradescid])}>
|
|
162
|
+
<Icon icon={deleteOutline} /> Remove
|
|
163
|
+
</button>
|
|
164
|
+
</div>
|
|
165
|
+
</div>
|
|
166
|
+
{/if}
|
|
167
|
+
{#if urlEntry || !selectedAsset?.id}
|
|
168
|
+
<div class="dialog-chooser-entry">
|
|
169
|
+
{#if urlEntry}
|
|
170
|
+
<input type="text" value={selectedAsset?.url ?? ''} on:change={userUrlEntry} on:keyup={userUrlEntry}>
|
|
171
|
+
{/if}
|
|
172
|
+
<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>
|
|
153
173
|
</div>
|
|
154
174
|
{/if}
|
|
155
|
-
<div class="dialog-chooser-entry">
|
|
156
|
-
{#if urlEntry}
|
|
157
|
-
<input type="text" value={selectedAsset?.url ?? ''} on:change={userUrlEntry} on:keyup={userUrlEntry}>
|
|
158
|
-
{/if}
|
|
159
|
-
<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>
|
|
160
|
-
</div>
|
|
161
175
|
{#if selectedAsset?.url.length && !selectedAsset.id}
|
|
162
176
|
<InlineMessage message={{ message: 'Entry does not match an internal resource and is not a valid URL. Nothing will be saved.', type: 'warning' }} />
|
|
163
177
|
{/if}
|
|
@@ -169,6 +183,7 @@ $: updateSelected($value);
|
|
|
169
183
|
<style>
|
|
170
184
|
.dialog-chooser-container {
|
|
171
185
|
display: flex;
|
|
186
|
+
flex-wrap: wrap;
|
|
172
187
|
margin-bottom: 0.25em;
|
|
173
188
|
font-size: 0.9em;
|
|
174
189
|
}
|
|
@@ -177,6 +192,9 @@ $: updateSelected($value);
|
|
|
177
192
|
padding-top: 0;
|
|
178
193
|
height: 5em;
|
|
179
194
|
}
|
|
195
|
+
.dialog-chooser-right button {
|
|
196
|
+
margin-top: 0.5em;
|
|
197
|
+
}
|
|
180
198
|
.dialog-chooser-entry {
|
|
181
199
|
display: flex;
|
|
182
200
|
}
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
import { randomid } from 'txstate-utils';
|
|
3
3
|
export let path;
|
|
4
4
|
export let conditional = undefined;
|
|
5
|
+
export let length = 10;
|
|
5
6
|
</script>
|
|
6
7
|
|
|
7
|
-
<Field {path} {conditional} defaultValue={randomid()} serialize={nullableSerialize} deserialize={nullableDeserialize} let:value>
|
|
8
|
+
<Field {path} {conditional} defaultValue={randomid(length)} serialize={nullableSerialize} deserialize={nullableDeserialize} let:value>
|
|
8
9
|
<input type="hidden" name={path} {value}>
|
|
9
10
|
</Field>
|
|
@@ -47,9 +47,7 @@ async function wrapGetOptions(search) {
|
|
|
47
47
|
const selectedStore = new Store([]);
|
|
48
48
|
let hasInit = !defaultValue.length;
|
|
49
49
|
let inputelement;
|
|
50
|
-
let portal;
|
|
51
50
|
onMount(async () => {
|
|
52
|
-
portal = inputelement.closest('.dialog-content');
|
|
53
51
|
await reactToValue(defaultValue);
|
|
54
52
|
hasInit = true;
|
|
55
53
|
});
|
|
@@ -73,7 +71,7 @@ async function reactToValue(value) {
|
|
|
73
71
|
<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>
|
|
74
72
|
{@const _ = reactToValue(value)}
|
|
75
73
|
<div class:valid class:invalid>
|
|
76
|
-
<MultiSelect {id} name={path}
|
|
74
|
+
<MultiSelect {id} name={path} descid={getDescribedBy([messagesid, helptextid, extradescid])}
|
|
77
75
|
{disabled} {maxSelections} selected={$selectedStore} {placeholder} getOptions={wrapGetOptions}
|
|
78
76
|
inputClass='multiselect-input'
|
|
79
77
|
on:change={e => setVal(e.detail.map(itm => itm.value))} on:blur={onBlur}
|
package/dist/FieldSelect.svelte
CHANGED
|
@@ -10,7 +10,7 @@ export let placeholder = 'Select' + (label ? ' ' + label : '');
|
|
|
10
10
|
export let notNull = false;
|
|
11
11
|
export let disabled = false;
|
|
12
12
|
export let choices;
|
|
13
|
-
export let defaultValue = notNull ? choices[0]
|
|
13
|
+
export let defaultValue = notNull ? choices[0]?.value : undefined;
|
|
14
14
|
export let conditional = undefined;
|
|
15
15
|
export let required = false;
|
|
16
16
|
export let inputelement = undefined;
|
|
@@ -32,10 +32,12 @@ function updateValue(valu, sVal, fDes) {
|
|
|
32
32
|
function reactToChoices(..._) {
|
|
33
33
|
if (!stVal)
|
|
34
34
|
return;
|
|
35
|
-
if (!choices.length)
|
|
35
|
+
if (!choices.length) {
|
|
36
36
|
stVal(finalDeserialize(''));
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
37
39
|
if (!choices.some(o => o.value === val))
|
|
38
|
-
stVal(notNull ?
|
|
40
|
+
stVal(notNull ? defaultValue : finalDeserialize(''));
|
|
39
41
|
}
|
|
40
42
|
$: reactToChoices(choices);
|
|
41
43
|
onMount(reactToChoices);
|
package/dist/FieldText.svelte
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
<script>import { nullableSerialize, nullableDeserialize } from '@txstate-mws/svelte-forms';
|
|
2
2
|
import FieldStandard from './FieldStandard.svelte';
|
|
3
3
|
import Input from './Input.svelte';
|
|
4
|
+
import MaxLength from './MaxLength.svelte';
|
|
5
|
+
import { isNotNull } from 'txstate-utils';
|
|
4
6
|
let className = '';
|
|
5
7
|
export { className as class };
|
|
6
8
|
export let id = undefined;
|
|
@@ -22,5 +24,8 @@ export let helptext = undefined;
|
|
|
22
24
|
</script>
|
|
23
25
|
|
|
24
26
|
<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>
|
|
25
|
-
<Input bind:inputelement {type} {autocomplete} name={path} {value} {id} class="dialog-input {className}" {allowlastpass} {onChange} {onBlur} {valid} {invalid} {
|
|
27
|
+
<Input bind:inputelement {type} {autocomplete} name={path} {value} {id} class="dialog-input {className}" {allowlastpass} {onChange} {onBlur} {valid} {invalid} {messagesid} {helptextid} {extradescid} {use}></Input>
|
|
28
|
+
{#if isNotNull(maxlength)}
|
|
29
|
+
<MaxLength {value} {maxlength}/>
|
|
30
|
+
{/if}
|
|
26
31
|
</FieldStandard>
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
import { passActions } from '@txstate-mws/svelte-components';
|
|
3
3
|
import { nullableSerialize, nullableDeserialize } from '@txstate-mws/svelte-forms';
|
|
4
4
|
import FieldStandard from './FieldStandard.svelte';
|
|
5
|
+
import MaxLength from './MaxLength.svelte';
|
|
6
|
+
import { isNotNull } from 'txstate-utils';
|
|
5
7
|
let className = '';
|
|
6
8
|
export { className as class };
|
|
7
9
|
export let id = undefined;
|
|
@@ -21,7 +23,10 @@ export let helptext = undefined;
|
|
|
21
23
|
</script>
|
|
22
24
|
|
|
23
25
|
<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
|
|
26
|
+
<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 use:passActions={use}></textarea>
|
|
27
|
+
{#if isNotNull(maxlength)}
|
|
28
|
+
<MaxLength {value} {maxlength}/>
|
|
29
|
+
{/if}
|
|
25
30
|
</FieldStandard>
|
|
26
31
|
|
|
27
32
|
<style>
|
package/dist/FormDialog.svelte
CHANGED
|
@@ -21,7 +21,7 @@ async function onSubmit() {
|
|
|
21
21
|
setContext(CHOOSER_API_CONTEXT, chooserClient);
|
|
22
22
|
</script>
|
|
23
23
|
|
|
24
|
-
<Dialog continueText="Save" continueIcon={contentSave} cancelText="Cancel" on:escape on:continue={onSubmit} {title} {icon} {size}>
|
|
24
|
+
<Dialog continueText="Save" continueIcon={contentSave} cancelText="Cancel" on:escape on:continue={onSubmit} {title} {icon} {size} escapable={false}>
|
|
25
25
|
<Form bind:store {submit} {validate} {chooserClient} {autocomplete} {name} {preload} on:saved let:messages let:allMessages let:showingInlineErrors let:saved let:valid let:invalid let:validating let:submitting let:data>
|
|
26
26
|
<slot {messages} {allMessages} {saved} {validating} {submitting} {valid} {invalid} {data} {showingInlineErrors} />
|
|
27
27
|
</Form>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<script>export let maxlength;
|
|
2
|
+
export let value;
|
|
3
|
+
let overLimit = false;
|
|
4
|
+
$: message = getMaxlengthMessage(value.length);
|
|
5
|
+
function getMaxlengthMessage(length) {
|
|
6
|
+
overLimit = false;
|
|
7
|
+
if (length === 0) {
|
|
8
|
+
return `${maxlength} characters allowed`;
|
|
9
|
+
}
|
|
10
|
+
else if (length <= maxlength) {
|
|
11
|
+
const diff = maxlength - length;
|
|
12
|
+
return `${diff} character${diff === 1 ? '' : 's'} remaining`;
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
overLimit = true;
|
|
16
|
+
const diff = length - maxlength;
|
|
17
|
+
return `${diff} character${diff === 1 ? '' : 's'} over limit`;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<div class:over={overLimit} aria-live="polite">{message}</div>
|
|
23
|
+
|
|
24
|
+
<style>
|
|
25
|
+
div {
|
|
26
|
+
font-size: 0.9em;
|
|
27
|
+
color: #595959;
|
|
28
|
+
line-height: 1.25em;
|
|
29
|
+
margin-top: 0.4em;
|
|
30
|
+
}
|
|
31
|
+
.over {
|
|
32
|
+
color: #9a3332;
|
|
33
|
+
font-weight: bold;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
</style>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
declare const __propDef: {
|
|
3
|
+
props: {
|
|
4
|
+
maxlength: number;
|
|
5
|
+
value: string;
|
|
6
|
+
};
|
|
7
|
+
events: {
|
|
8
|
+
[evt: string]: CustomEvent<any>;
|
|
9
|
+
};
|
|
10
|
+
slots: {};
|
|
11
|
+
};
|
|
12
|
+
export type MaxLengthProps = typeof __propDef.props;
|
|
13
|
+
export type MaxLengthEvents = typeof __propDef.events;
|
|
14
|
+
export type MaxLengthSlots = typeof __propDef.slots;
|
|
15
|
+
export default class MaxLength extends SvelteComponentTyped<MaxLengthProps, MaxLengthEvents, MaxLengthSlots> {
|
|
16
|
+
}
|
|
17
|
+
export {};
|
package/dist/Tooltip.svelte
CHANGED
package/dist/Tooltip.svelte.d.ts
CHANGED
|
@@ -95,3 +95,23 @@ export class ChooserStore extends Store {
|
|
|
95
95
|
});
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
|
+
export function cleanUrl(url) {
|
|
99
|
+
if (url.startsWith('//'))
|
|
100
|
+
url = 'https:' + url;
|
|
101
|
+
if (url.startsWith('/'))
|
|
102
|
+
return url;
|
|
103
|
+
try {
|
|
104
|
+
const _ = new URL(url);
|
|
105
|
+
return url;
|
|
106
|
+
}
|
|
107
|
+
catch (e) {
|
|
108
|
+
const fixed = 'https://' + url;
|
|
109
|
+
try {
|
|
110
|
+
const _ = new URL(fixed);
|
|
111
|
+
return fixed;
|
|
112
|
+
}
|
|
113
|
+
catch (e) {
|
|
114
|
+
return '';
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -1,54 +1,53 @@
|
|
|
1
|
-
<script>import { bytesToHuman } from './ChooserStore';
|
|
1
|
+
<script>import { bytesToHuman, cleanUrl } from './ChooserStore';
|
|
2
2
|
export let item;
|
|
3
|
+
export let singleLine = false;
|
|
3
4
|
</script>
|
|
4
5
|
|
|
5
|
-
<dl class="dialog-chooser-info" aria-live="polite">
|
|
6
|
+
<dl class="dialog-chooser-info" aria-live="polite" class:multiLine={!singleLine}>
|
|
6
7
|
{#if item.type === 'raw' && item.id}
|
|
7
|
-
<div>
|
|
8
|
+
<div class="top-row">
|
|
8
9
|
<dt>External Link:</dt>
|
|
9
|
-
<dd>{item.url}</dd>
|
|
10
|
+
<dd>{cleanUrl(item.url)}</dd>
|
|
10
11
|
</div>
|
|
11
12
|
{:else if item.type === 'broken'}
|
|
12
|
-
<div>
|
|
13
|
-
<dt>Unknown Link (
|
|
13
|
+
<div class="top-row">
|
|
14
|
+
<dt>Unknown Link (may have been deleted):</dt>
|
|
14
15
|
<dd>{item.url}</dd>
|
|
15
16
|
</div>
|
|
16
17
|
{:else if item.type !== 'raw'}
|
|
17
18
|
<div class="top-row">
|
|
18
19
|
<dt>Name:</dt>
|
|
19
|
-
<dd>{item.
|
|
20
|
+
<dd>{item.name}</dd>
|
|
20
21
|
</div>
|
|
21
22
|
{/if}
|
|
22
23
|
{#if item.type === 'asset'}
|
|
23
|
-
|
|
24
|
-
{#if item.image}
|
|
25
|
-
<div>
|
|
26
|
-
<dt>Dimensions:</dt>
|
|
27
|
-
<dd>{item.image.width}x{item.image.height}</dd>
|
|
28
|
-
</div>
|
|
29
|
-
{/if}
|
|
24
|
+
{#if item.image}
|
|
30
25
|
<div>
|
|
31
|
-
<dt>
|
|
32
|
-
<dd>{item.
|
|
33
|
-
</div>
|
|
34
|
-
<div>
|
|
35
|
-
<dt>File Size:</dt>
|
|
36
|
-
<dd>{bytesToHuman(item.bytes)}</dd>
|
|
26
|
+
<dt>Dimensions:</dt>
|
|
27
|
+
<dd>{item.image.width}x{item.image.height}</dd>
|
|
37
28
|
</div>
|
|
29
|
+
{/if}
|
|
30
|
+
<div>
|
|
31
|
+
<dt>File Type:</dt>
|
|
32
|
+
<dd>{item.mime}</dd>
|
|
33
|
+
</div>
|
|
34
|
+
<div>
|
|
35
|
+
<dt>File Size:</dt>
|
|
36
|
+
<dd>{bytesToHuman(item.bytes)}</dd>
|
|
38
37
|
</div>
|
|
39
38
|
{:else if item.type === 'page' && item.title}
|
|
40
|
-
<
|
|
41
|
-
|
|
39
|
+
<div>
|
|
40
|
+
<dt>Title:</dt>
|
|
41
|
+
<dd>{item.title}</dd>
|
|
42
|
+
</div>
|
|
42
43
|
{:else if item.type === 'folder'}
|
|
43
|
-
<div
|
|
44
|
-
<
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
<
|
|
49
|
-
|
|
50
|
-
<dd>{item.childCount} sub-items</dd>
|
|
51
|
-
</div>
|
|
44
|
+
<div>
|
|
45
|
+
<dt>Path:</dt>
|
|
46
|
+
<dd>{item.path}</dd>
|
|
47
|
+
</div>
|
|
48
|
+
<div>
|
|
49
|
+
<dt>Contents:</dt>
|
|
50
|
+
<dd>{item.childCount} sub-items</dd>
|
|
52
51
|
</div>
|
|
53
52
|
{/if}
|
|
54
53
|
<slot />
|
|
@@ -56,6 +55,10 @@ export let item;
|
|
|
56
55
|
|
|
57
56
|
<style>
|
|
58
57
|
.dialog-chooser-info {
|
|
58
|
+
display: flex;
|
|
59
|
+
flex-wrap: wrap;
|
|
60
|
+
justify-content: flex-start;
|
|
61
|
+
gap: 1em 1.5em;
|
|
59
62
|
padding: 0;
|
|
60
63
|
margin: 0;
|
|
61
64
|
list-style: none;
|
|
@@ -66,18 +69,8 @@ export let item;
|
|
|
66
69
|
.dialog-chooser-info dd {
|
|
67
70
|
margin: 0;
|
|
68
71
|
}
|
|
69
|
-
.top-row {
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
.horizontal-group {
|
|
73
|
-
display: flex;
|
|
74
|
-
justify-content: space-between;
|
|
75
|
-
}
|
|
76
|
-
:global([data-eq~="1400px"]) .horizontal-group {
|
|
77
|
-
flex-direction: column;
|
|
78
|
-
}
|
|
79
|
-
:global([data-eq~="1400px"]) .horizontal-group div:not(:last-child){
|
|
80
|
-
margin-bottom: 1em;
|
|
72
|
+
.multiLine .top-row {
|
|
73
|
+
width: 100%;
|
|
81
74
|
}
|
|
82
75
|
|
|
83
76
|
</style>
|
|
@@ -0,0 +1,85 @@
|
|
|
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');
|
|
26
|
+
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
|
+
});
|
|
44
|
+
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);
|
|
68
|
+
</script>
|
|
69
|
+
|
|
70
|
+
<div bind:this={editorelement} style:--cm-editor-minh="{rows * 1.5}em" class:valid class:invalid on:paste on:focusout use:passActions={use}></div>
|
|
71
|
+
|
|
72
|
+
<style>
|
|
73
|
+
div {
|
|
74
|
+
background-color: white;
|
|
75
|
+
}
|
|
76
|
+
div :global(.cm-content), div :global(.cm-gutter) {
|
|
77
|
+
min-height: var(--cm-editor-minh, 10em);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
div :global(.cm-scroller) {
|
|
81
|
+
overflow: auto;
|
|
82
|
+
resize: vertical;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
</style>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
import { type HTMLActionEntry } from '@txstate-mws/svelte-components';
|
|
3
|
+
declare const __propDef: {
|
|
4
|
+
props: {
|
|
5
|
+
class?: string | undefined;
|
|
6
|
+
id?: string | undefined;
|
|
7
|
+
rows?: number | undefined;
|
|
8
|
+
language: 'js' | 'css' | 'html';
|
|
9
|
+
use?: HTMLActionEntry[] | undefined;
|
|
10
|
+
inputelement?: HTMLElement | undefined;
|
|
11
|
+
extradescid?: string | undefined;
|
|
12
|
+
helptextid?: string | undefined;
|
|
13
|
+
messagesid?: string | undefined;
|
|
14
|
+
valid?: boolean | undefined;
|
|
15
|
+
invalid?: boolean | undefined;
|
|
16
|
+
value: any;
|
|
17
|
+
};
|
|
18
|
+
events: {
|
|
19
|
+
paste: ClipboardEvent;
|
|
20
|
+
focusout: FocusEvent;
|
|
21
|
+
change: CustomEvent<any>;
|
|
22
|
+
} & {
|
|
23
|
+
[evt: string]: CustomEvent<any>;
|
|
24
|
+
};
|
|
25
|
+
slots: {};
|
|
26
|
+
};
|
|
27
|
+
export type CodeEditorProps = typeof __propDef.props;
|
|
28
|
+
export type CodeEditorEvents = typeof __propDef.events;
|
|
29
|
+
export type CodeEditorSlots = typeof __propDef.slots;
|
|
30
|
+
export default class CodeEditor extends SvelteComponentTyped<CodeEditorProps, CodeEditorEvents, CodeEditorSlots> {
|
|
31
|
+
}
|
|
32
|
+
export {};
|
|
@@ -0,0 +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;
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<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>
|
|
23
|
+
<CodeEditor {id} bind:inputelement {language} {rows} class={className} {value} {valid} {invalid} {helptextid} {messagesid} {extradescid} on:paste on:focusout={onBlur} {use} on:change={e => setVal(e.detail)}/>
|
|
24
|
+
</FieldStandard>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SvelteComponentTyped } from "svelte";
|
|
2
|
-
import {
|
|
2
|
+
import type { HTMLActionEntry } from '@txstate-mws/svelte-components';
|
|
3
3
|
declare const __propDef: {
|
|
4
4
|
props: {
|
|
5
5
|
class?: string | undefined;
|
|
@@ -12,7 +12,7 @@ declare const __propDef: {
|
|
|
12
12
|
conditional?: boolean | undefined;
|
|
13
13
|
required?: boolean | undefined;
|
|
14
14
|
use?: HTMLActionEntry[] | undefined;
|
|
15
|
-
inputelement?:
|
|
15
|
+
inputelement?: HTMLElement | undefined;
|
|
16
16
|
related?: number | true | undefined;
|
|
17
17
|
extradescid?: string | undefined;
|
|
18
18
|
helptext?: string | undefined;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as FieldCodeEditor } from './FieldCodeEditor.svelte';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as FieldCodeEditor } from './FieldCodeEditor.svelte';
|
package/dist/index.d.ts
CHANGED
|
@@ -7,7 +7,6 @@ export { default as FieldAutocomplete } from './FieldAutocomplete.svelte';
|
|
|
7
7
|
export { default as FieldCheckbox } from './FieldCheckbox.svelte';
|
|
8
8
|
export { default as FieldChoices } from './FieldChoices.svelte';
|
|
9
9
|
export { default as FieldChooserLink } from './FieldChooserLink.svelte';
|
|
10
|
-
export { default as FieldCodeEditor } from './FieldCodeEditor.svelte';
|
|
11
10
|
export { default as FieldDate } from './FieldDate.svelte';
|
|
12
11
|
export { default as FieldDateTime } from './FieldDateTime.svelte';
|
|
13
12
|
export { default as FieldDualListbox } from './FieldDualListbox.svelte';
|
|
@@ -41,3 +40,4 @@ export * from './colorpicker/index.js';
|
|
|
41
40
|
export * from './helpers.js';
|
|
42
41
|
export * from './tree/index.js';
|
|
43
42
|
export * from './cropper/index.js';
|
|
43
|
+
export * from './code/index.js';
|
package/dist/index.js
CHANGED
|
@@ -7,7 +7,6 @@ export { default as FieldAutocomplete } from './FieldAutocomplete.svelte';
|
|
|
7
7
|
export { default as FieldCheckbox } from './FieldCheckbox.svelte';
|
|
8
8
|
export { default as FieldChoices } from './FieldChoices.svelte';
|
|
9
9
|
export { default as FieldChooserLink } from './FieldChooserLink.svelte';
|
|
10
|
-
export { default as FieldCodeEditor } from './FieldCodeEditor.svelte';
|
|
11
10
|
export { default as FieldDate } from './FieldDate.svelte';
|
|
12
11
|
export { default as FieldDateTime } from './FieldDateTime.svelte';
|
|
13
12
|
export { default as FieldDualListbox } from './FieldDualListbox.svelte';
|
|
@@ -41,3 +40,4 @@ export * from './colorpicker/index.js';
|
|
|
41
40
|
export * from './helpers.js';
|
|
42
41
|
export * from './tree/index.js';
|
|
43
42
|
export * from './cropper/index.js';
|
|
43
|
+
export * from './code/index.js';
|
|
@@ -303,7 +303,7 @@ $: if ($dragging) {
|
|
|
303
303
|
</div>
|
|
304
304
|
{#each headers as header, i (header.id)}
|
|
305
305
|
<div
|
|
306
|
-
class={(header.class ? toArray(header.class(item)) : []).concat([header.id]).join(' ')}
|
|
306
|
+
class={(header.class ? toArray(header.class(item)) : []).concat([header.id, 'tree-cell']).join(' ')}
|
|
307
307
|
style:width={$headerSizes?.[i] ?? '1px'}
|
|
308
308
|
style:padding-left={i === 0 ? `calc(min(${(level - 1) * 1.6}em, ${(level - 1) * 2.7}vw) + 1.4em)` : undefined}
|
|
309
309
|
class:left={i === 0}
|
|
@@ -418,6 +418,10 @@ $: if ($dragging) {
|
|
|
418
418
|
background-position: left top, right bottom, left bottom, right top;
|
|
419
419
|
animation: border-dance 1s infinite linear;
|
|
420
420
|
}
|
|
421
|
+
.tree-cell {
|
|
422
|
+
text-overflow: ellipsis;
|
|
423
|
+
overflow: hidden;
|
|
424
|
+
}
|
|
421
425
|
@keyframes border-dance {
|
|
422
426
|
0% {
|
|
423
427
|
background-position: left top, right bottom, left bottom, right top;
|
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.
|
|
4
|
+
"version": "0.0.66",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"prepublishOnly": "svelte-package",
|
|
7
7
|
"dev": "vite dev --force",
|
|
@@ -20,19 +20,21 @@
|
|
|
20
20
|
"./package.json": "./package.json"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@
|
|
24
|
-
"@
|
|
23
|
+
"@codemirror/lang-javascript": "^6.1.7",
|
|
24
|
+
"@codemirror/lang-css": "^6.2.0",
|
|
25
|
+
"@codemirror/lang-html": "^6.4.3",
|
|
25
26
|
"@iconify/svelte": "^3.0.0",
|
|
26
27
|
"@iconify-icons/mdi": "^1.2.22",
|
|
27
28
|
"@iconify-icons/ph": "^1.2.2",
|
|
28
|
-
"
|
|
29
|
+
"@txstate-mws/svelte-components": "^1.5.3",
|
|
30
|
+
"@txstate-mws/svelte-forms": "^1.3.4",
|
|
31
|
+
"codemirror": "^6.0.1",
|
|
29
32
|
"txstate-utils": "^1.8.0"
|
|
30
33
|
},
|
|
31
34
|
"devDependencies": {
|
|
32
35
|
"@sveltejs/adapter-auto": "^2.0.0",
|
|
33
36
|
"@sveltejs/kit": "^1.0.1",
|
|
34
37
|
"@sveltejs/package": "^2.0.1",
|
|
35
|
-
"@types/codeflask": "^1.4.3",
|
|
36
38
|
"eslint-config-standard-with-typescript": "^34.0.0",
|
|
37
39
|
"eslint-plugin-svelte3": "^4.0.0",
|
|
38
40
|
"svelte-check": "^3.0.1",
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
<script>import { passActions } from '@txstate-mws/svelte-components';
|
|
2
|
-
import { nullableSerialize, nullableDeserialize, FORM_CONTEXT, FormStore, FORM_INHERITED_PATH } from '@txstate-mws/svelte-forms';
|
|
3
|
-
import CodeFlask from 'codeflask';
|
|
4
|
-
import { getContext, onMount } from 'svelte';
|
|
5
|
-
import { isNotBlank } from 'txstate-utils';
|
|
6
|
-
import { getDescribedBy, FieldStandard } from './';
|
|
7
|
-
let className = '';
|
|
8
|
-
export { className as class };
|
|
9
|
-
export let id = undefined;
|
|
10
|
-
export let path;
|
|
11
|
-
export let label = '';
|
|
12
|
-
export let notNull = false;
|
|
13
|
-
export let defaultValue = notNull ? '' : undefined;
|
|
14
|
-
export let rows = 8;
|
|
15
|
-
export let conditional = undefined;
|
|
16
|
-
export let required = false;
|
|
17
|
-
export let use = [];
|
|
18
|
-
export let inputelement = undefined;
|
|
19
|
-
export let related = 0;
|
|
20
|
-
export let extradescid = undefined;
|
|
21
|
-
export let helptext = undefined;
|
|
22
|
-
export let language;
|
|
23
|
-
const store = getContext(FORM_CONTEXT);
|
|
24
|
-
const inheritedPath = getContext(FORM_INHERITED_PATH);
|
|
25
|
-
const finalPath = [inheritedPath, path].filter(isNotBlank).join('.');
|
|
26
|
-
const value = store.getField(finalPath);
|
|
27
|
-
let editorelement;
|
|
28
|
-
let flask;
|
|
29
|
-
onMount(() => {
|
|
30
|
-
flask = new CodeFlask(editorelement, { language, lineNumbers: true, areaId: id });
|
|
31
|
-
inputelement = editorelement.querySelector(`#${id}`);
|
|
32
|
-
if (className)
|
|
33
|
-
inputelement.classList.add(...className.split(' '));
|
|
34
|
-
inputelement.addEventListener('change', onChange);
|
|
35
|
-
updateValidState(invalid, messagesid);
|
|
36
|
-
});
|
|
37
|
-
$: flask?.updateCode($value ?? '');
|
|
38
|
-
let invalid;
|
|
39
|
-
let messagesid;
|
|
40
|
-
let helptextid;
|
|
41
|
-
let onChange;
|
|
42
|
-
function setSlotProps(helptextidIn, onChangeIn) {
|
|
43
|
-
helptextid = helptextidIn;
|
|
44
|
-
onChange = onChangeIn;
|
|
45
|
-
}
|
|
46
|
-
function updateValidState(invalidIn, messagesIdIn) {
|
|
47
|
-
invalid = !!invalidIn;
|
|
48
|
-
messagesid = messagesIdIn;
|
|
49
|
-
inputelement?.setAttribute('aria-invalid', String(!!invalid));
|
|
50
|
-
const descby = getDescribedBy([messagesid, helptextid, extradescid]);
|
|
51
|
-
if (descby)
|
|
52
|
-
inputelement?.setAttribute('aria-describedby', descby);
|
|
53
|
-
else
|
|
54
|
-
inputelement?.removeAttribute('aria-describedby');
|
|
55
|
-
}
|
|
56
|
-
</script>
|
|
57
|
-
|
|
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>
|
|
59
|
-
{@const _ = setSlotProps(helptextid, onChange)}
|
|
60
|
-
{@const __ = updateValidState(invalid, messagesid)}
|
|
61
|
-
<div bind:this={editorelement} style:height="{rows * 1.333}em" class:valid class:invalid on:paste on:focusout={onBlur} use:passActions={use}></div>
|
|
62
|
-
</FieldStandard>
|
|
63
|
-
|
|
64
|
-
<style>
|
|
65
|
-
div {
|
|
66
|
-
position: relative;
|
|
67
|
-
overflow: hidden;
|
|
68
|
-
resize: vertical;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
</style>
|