@vit-foundation/ui 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/account/NewsletterSignup.svelte +11 -3
- package/dist/components/contact/ContactForm.svelte +6 -1
- package/dist/components/layout/Footer.svelte +10 -2
- package/dist/components/layout/Footer.svelte.d.ts +3 -0
- package/dist/components/layout/Nav.svelte +17 -4
- package/dist/components/layout/Nav.svelte.d.ts +8 -0
- package/dist/components/ui/Pagination.svelte +22 -10
- package/dist/components/weeklies/CommentSection.svelte +16 -4
- package/dist/edit/ActionLabel.svelte +45 -0
- package/dist/edit/ActionLabel.svelte.d.ts +22 -0
- package/dist/edit/index.d.ts +1 -0
- package/dist/edit/index.js +1 -0
- package/package.json +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { getUiConfig } from '../../config/context.js';
|
|
3
|
+
import ActionLabel from '../../edit/ActionLabel.svelte';
|
|
3
4
|
import Editable from '../../edit/Editable.svelte';
|
|
4
5
|
import { withNewsletterIntent } from '../../forms/transport.js';
|
|
5
6
|
import type { NewsletterToggleFormInstance } from './AccountPanel.svelte';
|
|
@@ -61,9 +62,16 @@
|
|
|
61
62
|
<form {...f}>
|
|
62
63
|
<input {...f.fields.action.as('hidden', 'subscribe')} />
|
|
63
64
|
<LocaleField field={f.fields.locale} />
|
|
64
|
-
<
|
|
65
|
-
{
|
|
66
|
-
|
|
65
|
+
<ActionLabel
|
|
66
|
+
edit={config.messageEdit?.('account_newsletterSubscribe')}
|
|
67
|
+
value={msg.account_newsletterSubscribe()}
|
|
68
|
+
>
|
|
69
|
+
{#snippet control()}
|
|
70
|
+
<Button type="submit" pending={f.pending}>
|
|
71
|
+
{msg.account_newsletterSubscribe()}
|
|
72
|
+
</Button>
|
|
73
|
+
{/snippet}
|
|
74
|
+
</ActionLabel>
|
|
67
75
|
</form>
|
|
68
76
|
{#if f.result}
|
|
69
77
|
<div class="feedback-slot">
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
<script lang="ts">
|
|
21
21
|
import { getUiConfig } from '../../config/context.js';
|
|
22
|
+
import ActionLabel from '../../edit/ActionLabel.svelte';
|
|
22
23
|
import { CONTACT_MESSAGE, CONTACT_NAME, EMAIL } from '../../forms/constraints.js';
|
|
23
24
|
import { CONTACT_CATEGORIES } from '../../content/types.js';
|
|
24
25
|
import { contactCategoryLabel } from '../../utils/contact.js';
|
|
@@ -120,7 +121,11 @@
|
|
|
120
121
|
<Honeypot form={f.fields} id="contact-website" />
|
|
121
122
|
|
|
122
123
|
<div class="actions">
|
|
123
|
-
<
|
|
124
|
+
<ActionLabel edit={config.messageEdit?.('contact_submit')} value={msg.contact_submit()}>
|
|
125
|
+
{#snippet control()}
|
|
126
|
+
<Button type="submit" pending={f.pending}>{msg.contact_submit()}</Button>
|
|
127
|
+
{/snippet}
|
|
128
|
+
</ActionLabel>
|
|
124
129
|
</div>
|
|
125
130
|
|
|
126
131
|
{#if f.result && !f.result.ok}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { getUiConfig } from '../../config/context.js';
|
|
3
3
|
import type { SiteLink } from '../../config/types.js';
|
|
4
|
+
import ActionLabel from '../../edit/ActionLabel.svelte';
|
|
4
5
|
import Editable from '../../edit/Editable.svelte';
|
|
6
|
+
import type { EditDescriptor } from '../../edit/types.js';
|
|
5
7
|
import Link from '../ui/Link.svelte';
|
|
6
8
|
|
|
7
9
|
/**
|
|
@@ -11,9 +13,11 @@
|
|
|
11
13
|
*/
|
|
12
14
|
interface Props {
|
|
13
15
|
links: SiteLink[];
|
|
16
|
+
/** Edit descriptors for the link labels — see Nav. */
|
|
17
|
+
editFor?: (link: SiteLink) => EditDescriptor | undefined;
|
|
14
18
|
}
|
|
15
19
|
|
|
16
|
-
let { links }: Props = $props();
|
|
20
|
+
let { links, editFor = undefined }: Props = $props();
|
|
17
21
|
|
|
18
22
|
const config = getUiConfig();
|
|
19
23
|
|
|
@@ -27,7 +31,11 @@
|
|
|
27
31
|
</span>
|
|
28
32
|
<ul>
|
|
29
33
|
{#each links as link (link.href)}
|
|
30
|
-
<li
|
|
34
|
+
<li>
|
|
35
|
+
<ActionLabel edit={editFor?.(link)} value={link.label}>
|
|
36
|
+
{#snippet control()}<Link href={link.href}>{link.label}</Link>{/snippet}
|
|
37
|
+
</ActionLabel>
|
|
38
|
+
</li>
|
|
31
39
|
{/each}
|
|
32
40
|
</ul>
|
|
33
41
|
<p class="rights">
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { SiteLink } from '../../config/types.js';
|
|
2
|
+
import type { EditDescriptor } from '../../edit/types.js';
|
|
2
3
|
/**
|
|
3
4
|
* The links are a prop rather than a package constant: the host app owns
|
|
4
5
|
* its routes, and Nav and Footer render the same list — the foundation
|
|
@@ -6,6 +7,8 @@ import type { SiteLink } from '../../config/types.js';
|
|
|
6
7
|
*/
|
|
7
8
|
interface Props {
|
|
8
9
|
links: SiteLink[];
|
|
10
|
+
/** Edit descriptors for the link labels — see Nav. */
|
|
11
|
+
editFor?: (link: SiteLink) => EditDescriptor | undefined;
|
|
9
12
|
}
|
|
10
13
|
declare const Footer: import("svelte").Component<Props, {}, "">;
|
|
11
14
|
type Footer = ReturnType<typeof Footer>;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { getUiConfig } from '../../config/context.js';
|
|
3
3
|
import type { SiteLink } from '../../config/types.js';
|
|
4
|
+
import ActionLabel from '../../edit/ActionLabel.svelte';
|
|
5
|
+
import type { EditDescriptor } from '../../edit/types.js';
|
|
4
6
|
import { isPathUnder } from '../../utils/paths.js';
|
|
5
7
|
import GhostButton from '../ui/GhostButton.svelte';
|
|
6
8
|
import Link from '../ui/Link.svelte';
|
|
@@ -16,9 +18,16 @@
|
|
|
16
18
|
account?: { displayName: string } | null;
|
|
17
19
|
/** The URL highlighting reads from. Only tests and stories pass one. */
|
|
18
20
|
url?: URL;
|
|
21
|
+
/**
|
|
22
|
+
* Edit descriptors for the link LABELS — a function because the host
|
|
23
|
+
* owns both the routes and the message keys behind them. While the
|
|
24
|
+
* adapter is editing, a link with a descriptor renders as editable
|
|
25
|
+
* text instead of an anchor (see ActionLabel).
|
|
26
|
+
*/
|
|
27
|
+
editFor?: (link: SiteLink) => EditDescriptor | undefined;
|
|
19
28
|
}
|
|
20
29
|
|
|
21
|
-
let { links, account = null, url = undefined }: Props = $props();
|
|
30
|
+
let { links, account = null, url = undefined, editFor = undefined }: Props = $props();
|
|
22
31
|
|
|
23
32
|
const config = getUiConfig();
|
|
24
33
|
const msg = $derived(config.messages);
|
|
@@ -77,9 +86,13 @@
|
|
|
77
86
|
<ul class="links">
|
|
78
87
|
{#each links as link (link.href)}
|
|
79
88
|
<li>
|
|
80
|
-
<
|
|
81
|
-
{
|
|
82
|
-
|
|
89
|
+
<ActionLabel edit={editFor?.(link)} value={link.label}>
|
|
90
|
+
{#snippet control()}
|
|
91
|
+
<Link href={link.href} aria-current={isCurrent(link.href) ? 'page' : undefined}>
|
|
92
|
+
{link.label}
|
|
93
|
+
</Link>
|
|
94
|
+
{/snippet}
|
|
95
|
+
</ActionLabel>
|
|
83
96
|
</li>
|
|
84
97
|
{/each}
|
|
85
98
|
</ul>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { SiteLink } from '../../config/types.js';
|
|
2
|
+
import type { EditDescriptor } from '../../edit/types.js';
|
|
2
3
|
interface Props {
|
|
3
4
|
/**
|
|
4
5
|
* Primary navigation entries. A prop rather than a package constant:
|
|
@@ -12,6 +13,13 @@ interface Props {
|
|
|
12
13
|
} | null;
|
|
13
14
|
/** The URL highlighting reads from. Only tests and stories pass one. */
|
|
14
15
|
url?: URL;
|
|
16
|
+
/**
|
|
17
|
+
* Edit descriptors for the link LABELS — a function because the host
|
|
18
|
+
* owns both the routes and the message keys behind them. While the
|
|
19
|
+
* adapter is editing, a link with a descriptor renders as editable
|
|
20
|
+
* text instead of an anchor (see ActionLabel).
|
|
21
|
+
*/
|
|
22
|
+
editFor?: (link: SiteLink) => EditDescriptor | undefined;
|
|
15
23
|
}
|
|
16
24
|
declare const Nav: import("svelte").Component<Props, {}, "">;
|
|
17
25
|
type Nav = ReturnType<typeof Nav>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { getUiConfig } from '../../config/context.js';
|
|
3
|
+
import ActionLabel from '../../edit/ActionLabel.svelte';
|
|
3
4
|
import Link from './Link.svelte';
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -37,21 +38,32 @@
|
|
|
37
38
|
|
|
38
39
|
{#if pages > 1 || isOutOfRange}
|
|
39
40
|
<nav class="pagination" aria-label={msg.pagination_label()}>
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
<ActionLabel
|
|
42
|
+
edit={config.messageEdit?.('pagination_previous')}
|
|
43
|
+
value={msg.pagination_previous()}
|
|
44
|
+
>
|
|
45
|
+
{#snippet control()}
|
|
46
|
+
{#if hasPrevious}
|
|
47
|
+
<Link href={href(previousPage)} rel="prev">{msg.pagination_previous()}</Link>
|
|
48
|
+
{:else}
|
|
49
|
+
<span class="disabled">{msg.pagination_previous()}</span>
|
|
50
|
+
{/if}
|
|
51
|
+
{/snippet}
|
|
52
|
+
</ActionLabel>
|
|
45
53
|
|
|
46
54
|
<p class="status" aria-live="polite">
|
|
47
55
|
{msg.pagination_status({ page, pages })}
|
|
48
56
|
</p>
|
|
49
57
|
|
|
50
|
-
{
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
58
|
+
<ActionLabel edit={config.messageEdit?.('pagination_next')} value={msg.pagination_next()}>
|
|
59
|
+
{#snippet control()}
|
|
60
|
+
{#if hasNext}
|
|
61
|
+
<Link href={href(page + 1)} rel="next">{msg.pagination_next()}</Link>
|
|
62
|
+
{:else}
|
|
63
|
+
<span class="disabled">{msg.pagination_next()}</span>
|
|
64
|
+
{/if}
|
|
65
|
+
{/snippet}
|
|
66
|
+
</ActionLabel>
|
|
55
67
|
</nav>
|
|
56
68
|
{/if}
|
|
57
69
|
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
<script lang="ts">
|
|
12
12
|
import { getUiConfig } from '../../config/context.js';
|
|
13
|
+
import ActionLabel from '../../edit/ActionLabel.svelte';
|
|
13
14
|
import Editable from '../../edit/Editable.svelte';
|
|
14
15
|
import { COMMENT_BODY } from '../../forms/constraints.js';
|
|
15
16
|
import type { CommentData, CommentThreadData } from '../../content/types.js';
|
|
@@ -118,9 +119,16 @@
|
|
|
118
119
|
<input {...reply.fields.weeklySlug.as('hidden', weeklySlug)} />
|
|
119
120
|
<input {...reply.fields.parentId.as('hidden', String(thread.id))} />
|
|
120
121
|
<div class="actions">
|
|
121
|
-
<
|
|
122
|
-
{
|
|
123
|
-
|
|
122
|
+
<ActionLabel
|
|
123
|
+
edit={config.messageEdit?.('comments_replySubmit')}
|
|
124
|
+
value={msg.comments_replySubmit()}
|
|
125
|
+
>
|
|
126
|
+
{#snippet control()}
|
|
127
|
+
<Button type="submit" pending={reply.pending}>
|
|
128
|
+
{msg.comments_replySubmit()}
|
|
129
|
+
</Button>
|
|
130
|
+
{/snippet}
|
|
131
|
+
</ActionLabel>
|
|
124
132
|
</div>
|
|
125
133
|
<FormErrorFeedback result={reply.result} messages={errorMessages} />
|
|
126
134
|
</form>
|
|
@@ -148,7 +156,11 @@
|
|
|
148
156
|
<input {...main.fields.weeklySlug.as('hidden', weeklySlug)} />
|
|
149
157
|
|
|
150
158
|
<div class="actions">
|
|
151
|
-
<
|
|
159
|
+
<ActionLabel edit={config.messageEdit?.('comments_submit')} value={msg.comments_submit()}>
|
|
160
|
+
{#snippet control()}
|
|
161
|
+
<Button type="submit" pending={main.pending}>{msg.comments_submit()}</Button>
|
|
162
|
+
{/snippet}
|
|
163
|
+
</ActionLabel>
|
|
152
164
|
</div>
|
|
153
165
|
|
|
154
166
|
<FormErrorFeedback result={main.result} messages={errorMessages} />
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import { getEditAdapter } from './context.js';
|
|
4
|
+
import Editable from './Editable.svelte';
|
|
5
|
+
import type { EditDescriptor } from './types.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The label of an INTERACTIVE control — a button, a nav link — made
|
|
9
|
+
* editable the way WeeklieCard's title is: while the adapter is editing
|
|
10
|
+
* and a descriptor is supplied, the control is REPLACED by its label as
|
|
11
|
+
* editable text, because a caret inside a live control would activate it
|
|
12
|
+
* (a link navigates mid-draft, a label focuses its input). The control
|
|
13
|
+
* comes back the moment editing turns off; with no descriptor or no
|
|
14
|
+
* adapter it renders untouched, byte-identical to a read-only build.
|
|
15
|
+
*/
|
|
16
|
+
interface Props {
|
|
17
|
+
/** Undefined leaves the control alone — the inert default. */
|
|
18
|
+
edit: EditDescriptor | undefined;
|
|
19
|
+
/** The label text the control renders. */
|
|
20
|
+
value: string;
|
|
21
|
+
/** The real control, rendered whenever the label is not being edited. */
|
|
22
|
+
control: Snippet;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let { edit, value, control }: Props = $props();
|
|
26
|
+
|
|
27
|
+
const adapter = getEditAdapter();
|
|
28
|
+
const editing = $derived(edit !== undefined && (adapter?.isEditing ?? false));
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
{#if editing}
|
|
32
|
+
<Editable {edit} {value}>
|
|
33
|
+
{#snippet children(text, attrs)}<span class="action-label" {...attrs}>{text}</span>{/snippet}
|
|
34
|
+
</Editable>
|
|
35
|
+
{:else}
|
|
36
|
+
{@render control()}
|
|
37
|
+
{/if}
|
|
38
|
+
|
|
39
|
+
<style>
|
|
40
|
+
/* Roughly the control's footprint, so the swap doesn't collapse the row. */
|
|
41
|
+
.action-label {
|
|
42
|
+
display: inline-block;
|
|
43
|
+
padding: 0.2em 0.4em;
|
|
44
|
+
}
|
|
45
|
+
</style>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { EditDescriptor } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* The label of an INTERACTIVE control — a button, a nav link — made
|
|
5
|
+
* editable the way WeeklieCard's title is: while the adapter is editing
|
|
6
|
+
* and a descriptor is supplied, the control is REPLACED by its label as
|
|
7
|
+
* editable text, because a caret inside a live control would activate it
|
|
8
|
+
* (a link navigates mid-draft, a label focuses its input). The control
|
|
9
|
+
* comes back the moment editing turns off; with no descriptor or no
|
|
10
|
+
* adapter it renders untouched, byte-identical to a read-only build.
|
|
11
|
+
*/
|
|
12
|
+
interface Props {
|
|
13
|
+
/** Undefined leaves the control alone — the inert default. */
|
|
14
|
+
edit: EditDescriptor | undefined;
|
|
15
|
+
/** The label text the control renders. */
|
|
16
|
+
value: string;
|
|
17
|
+
/** The real control, rendered whenever the label is not being edited. */
|
|
18
|
+
control: Snippet;
|
|
19
|
+
}
|
|
20
|
+
declare const ActionLabel: import("svelte").Component<Props, {}, "">;
|
|
21
|
+
type ActionLabel = ReturnType<typeof ActionLabel>;
|
|
22
|
+
export default ActionLabel;
|
package/dist/edit/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { getEditAdapter, setEditAdapter } from './context.js';
|
|
2
|
+
export { default as ActionLabel } from './ActionLabel.svelte';
|
|
2
3
|
export { default as Editable } from './Editable.svelte';
|
|
3
4
|
export { chromeEdit, entityEdit, pageCopyEdit } from './helpers.js';
|
|
4
5
|
export { localize } from './types.js';
|
package/dist/edit/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { getEditAdapter, setEditAdapter } from './context.js';
|
|
2
|
+
export { default as ActionLabel } from './ActionLabel.svelte';
|
|
2
3
|
export { default as Editable } from './Editable.svelte';
|
|
3
4
|
export { chromeEdit, entityEdit, pageCopyEdit } from './helpers.js';
|
|
4
5
|
export { localize } from './types.js';
|