@wells-nelson/interactions 1.0.0 → 1.0.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.
- package/README.md +15 -2
- package/dist/AppVersion.svelte +79 -0
- package/dist/AppVersion.svelte.d.ts +11 -0
- package/dist/SearchBar.svelte +4 -3
- package/dist/UndoButton.svelte +2 -2
- package/dist/account/ContainerEditModal.svelte +9 -1
- package/dist/account/ContainerEditModal.svelte.d.ts +5 -0
- package/dist/account/ShareModal.svelte +9 -1
- package/dist/account/ShareModal.svelte.d.ts +5 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -13,7 +13,8 @@ npm install @wells-nelson/displays @wells-nelson/interactions
|
|
|
13
13
|
`TextField` (label, error, hint), `Checkbox` (optionally hidden label), `Toggle` (a switch for
|
|
14
14
|
settings that apply at once), `Combobox` (type to filter, offers "Create …"; plus `sameName`),
|
|
15
15
|
`AddRow` (inline "name + plus" that refocuses), `Segmented` (one of a few) and `SearchBar`
|
|
16
|
-
(fixed at the bottom, with a clear button
|
|
16
|
+
(fixed at the bottom, with a clear button; it sits above a `TabBar` via `--footer-offset`, as
|
|
17
|
+
does `UndoButton`).
|
|
17
18
|
|
|
18
19
|
```svelte
|
|
19
20
|
<ActiveList
|
|
@@ -55,6 +56,17 @@ undo.push({ undo: () => setDone(task, false) });
|
|
|
55
56
|
<UndoButton stack={undo} />
|
|
56
57
|
```
|
|
57
58
|
|
|
59
|
+
## App version
|
|
60
|
+
|
|
61
|
+
The running version, with an Update button once a newer deploy is out (in SvelteKit, feed it
|
|
62
|
+
`updated` from `$app/state`; set `kit.version.name` to the release version and a
|
|
63
|
+
`pollInterval`). Without an update, `oncheck` adds "Check for updates". `onupdate` defaults to
|
|
64
|
+
reloading the page.
|
|
65
|
+
|
|
66
|
+
```svelte
|
|
67
|
+
<AppVersion version={version} updateAvailable={updated.current} oncheck={() => updated.check()} />
|
|
68
|
+
```
|
|
69
|
+
|
|
58
70
|
## Dev wipe
|
|
59
71
|
|
|
60
72
|
```svelte
|
|
@@ -82,4 +94,5 @@ shape. Wording comes from `nouns` (`{ singular: 'project', plural: 'projects' }`
|
|
|
82
94
|
|
|
83
95
|
With `roles`, `ShareModal` shows a role picker and protects the last owner, and
|
|
84
96
|
`ContainerEditModal` offers "Leave" instead of "Delete" while other owners remain. Without roles
|
|
85
|
-
every member counts as an owner.
|
|
97
|
+
every member counts as an owner. `localOnlyReason` keeps a container local-only (e.g. built-in
|
|
98
|
+
sample data): both modals show that text instead of offering to make it cloud-enabled. The sandbox's Account page drives every state with a mock.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Button } from '@wells-nelson/displays';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The running version, with an Update button once a newer deploy is out. Feed it the app's
|
|
6
|
+
* update signal (in SvelteKit: `updated.current` from `$app/state`, with `updated.check` as
|
|
7
|
+
* `oncheck`). Without an update, `oncheck` adds a "Check for updates" button.
|
|
8
|
+
*/
|
|
9
|
+
let {
|
|
10
|
+
version,
|
|
11
|
+
updateAvailable = false,
|
|
12
|
+
onupdate = () => location.reload(),
|
|
13
|
+
oncheck
|
|
14
|
+
}: {
|
|
15
|
+
version: string;
|
|
16
|
+
updateAvailable?: boolean;
|
|
17
|
+
/** Load the new version. Defaults to reloading the page. */
|
|
18
|
+
onupdate?: () => void;
|
|
19
|
+
/** Look for a new version now; resolves true when there is one. */
|
|
20
|
+
oncheck?: () => Promise<boolean>;
|
|
21
|
+
} = $props();
|
|
22
|
+
|
|
23
|
+
let checking = $state(false);
|
|
24
|
+
let found = $state(false);
|
|
25
|
+
let status = $state<'latest' | 'failed' | null>(null);
|
|
26
|
+
const available = $derived(updateAvailable || found);
|
|
27
|
+
|
|
28
|
+
async function check() {
|
|
29
|
+
if (!oncheck) return;
|
|
30
|
+
checking = true;
|
|
31
|
+
status = null;
|
|
32
|
+
try {
|
|
33
|
+
found = await oncheck();
|
|
34
|
+
if (!found) status = 'latest';
|
|
35
|
+
} catch {
|
|
36
|
+
status = 'failed';
|
|
37
|
+
} finally {
|
|
38
|
+
checking = false;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
</script>
|
|
42
|
+
|
|
43
|
+
<section class="app-version" aria-label="Version">
|
|
44
|
+
<p class="line">
|
|
45
|
+
Version {version}{#if available}<span class="new"> · A new version is available.</span>{/if}
|
|
46
|
+
</p>
|
|
47
|
+
{#if available}
|
|
48
|
+
<Button variant="primary" icon="refresh" onclick={() => onupdate()}>Update</Button>
|
|
49
|
+
{:else if oncheck}
|
|
50
|
+
<Button variant="ghost" icon="refresh" onclick={check} disabled={checking}>
|
|
51
|
+
{checking ? 'Checking…' : 'Check for updates'}
|
|
52
|
+
</Button>
|
|
53
|
+
{#if status === 'latest'}
|
|
54
|
+
<p class="status" role="status">You have the latest version.</p>
|
|
55
|
+
{:else if status === 'failed'}
|
|
56
|
+
<p class="status" role="status">Couldn't check for updates. Try again when you're online.</p>
|
|
57
|
+
{/if}
|
|
58
|
+
{/if}
|
|
59
|
+
</section>
|
|
60
|
+
|
|
61
|
+
<style>
|
|
62
|
+
.app-version {
|
|
63
|
+
display: flex;
|
|
64
|
+
flex-direction: column;
|
|
65
|
+
align-items: center;
|
|
66
|
+
gap: 0.4rem;
|
|
67
|
+
text-align: center;
|
|
68
|
+
}
|
|
69
|
+
.line,
|
|
70
|
+
.status {
|
|
71
|
+
margin: 0;
|
|
72
|
+
color: var(--muted);
|
|
73
|
+
font-size: 0.85rem;
|
|
74
|
+
}
|
|
75
|
+
.new {
|
|
76
|
+
color: var(--text);
|
|
77
|
+
font-weight: 600;
|
|
78
|
+
}
|
|
79
|
+
</style>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
type $$ComponentProps = {
|
|
2
|
+
version: string;
|
|
3
|
+
updateAvailable?: boolean;
|
|
4
|
+
/** Load the new version. Defaults to reloading the page. */
|
|
5
|
+
onupdate?: () => void;
|
|
6
|
+
/** Look for a new version now; resolves true when there is one. */
|
|
7
|
+
oncheck?: () => Promise<boolean>;
|
|
8
|
+
};
|
|
9
|
+
declare const AppVersion: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
10
|
+
type AppVersion = ReturnType<typeof AppVersion>;
|
|
11
|
+
export default AppVersion;
|
package/dist/SearchBar.svelte
CHANGED
|
@@ -21,9 +21,10 @@
|
|
|
21
21
|
position: fixed;
|
|
22
22
|
left: 0;
|
|
23
23
|
right: 0;
|
|
24
|
-
bottom
|
|
24
|
+
/* Above a bottom tab bar when there is one (--footer-offset includes the safe area then). */
|
|
25
|
+
bottom: var(--footer-offset, 0px);
|
|
25
26
|
z-index: 40;
|
|
26
|
-
padding: 0.5rem 1rem calc(0.5rem + env(safe-area-inset-bottom, 0px));
|
|
27
|
+
padding: 0.5rem 1rem calc(0.5rem + max(0px, env(safe-area-inset-bottom, 0px) - var(--footer-offset, 0px)));
|
|
27
28
|
background: linear-gradient(to top, var(--bg) 70%, transparent);
|
|
28
29
|
}
|
|
29
30
|
.inner {
|
|
@@ -55,6 +56,6 @@
|
|
|
55
56
|
display: none;
|
|
56
57
|
}
|
|
57
58
|
.spacer {
|
|
58
|
-
height: calc(4.5rem + env(safe-area-inset-bottom, 0px));
|
|
59
|
+
height: calc(4.5rem + max(0px, env(safe-area-inset-bottom, 0px) - var(--footer-offset, 0px)));
|
|
59
60
|
}
|
|
60
61
|
</style>
|
package/dist/UndoButton.svelte
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { Icon } from '@wells-nelson/displays';
|
|
3
3
|
import type { UndoStack } from './undo.svelte.js';
|
|
4
4
|
|
|
5
|
-
/** Floating Undo button, bottom left (above a `SearchBar`), shown while `stack.visible`. */
|
|
5
|
+
/** Floating Undo button, bottom left (above a `SearchBar` and any `TabBar`), shown while `stack.visible`. */
|
|
6
6
|
let { stack, label = 'Undo' }: { stack: UndoStack; label?: string } = $props();
|
|
7
7
|
</script>
|
|
8
8
|
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
.undo {
|
|
18
18
|
position: fixed;
|
|
19
19
|
left: max(1rem, calc(50vw - var(--content-w) / 2 + 1rem));
|
|
20
|
-
bottom: calc(4.75rem + env(safe-area-inset-bottom, 0px));
|
|
20
|
+
bottom: calc(4.75rem + max(env(safe-area-inset-bottom, 0px), var(--footer-offset, 0px)));
|
|
21
21
|
z-index: 45;
|
|
22
22
|
display: inline-flex;
|
|
23
23
|
align-items: center;
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
nouns,
|
|
32
32
|
signInHref,
|
|
33
33
|
contentsLabel = 'everything in it',
|
|
34
|
+
localOnlyReason,
|
|
34
35
|
isDefault,
|
|
35
36
|
ondefaultchange,
|
|
36
37
|
onrename,
|
|
@@ -53,6 +54,11 @@
|
|
|
53
54
|
signInHref: string;
|
|
54
55
|
/** What gets deleted along with it, e.g. "all its tasks and notes". */
|
|
55
56
|
contentsLabel?: string;
|
|
57
|
+
/**
|
|
58
|
+
* Why this container has to stay local-only (e.g. built-in sample data). The cloud option
|
|
59
|
+
* is replaced by this text while it is local.
|
|
60
|
+
*/
|
|
61
|
+
localOnlyReason?: string;
|
|
56
62
|
isDefault: boolean;
|
|
57
63
|
ondefaultchange: (isDefault: boolean) => void;
|
|
58
64
|
onrename: (name: string) => void;
|
|
@@ -172,7 +178,9 @@
|
|
|
172
178
|
|
|
173
179
|
<section class="group">
|
|
174
180
|
<h3>Sync</h3>
|
|
175
|
-
{#if
|
|
181
|
+
{#if localOnlyReason && !isCloud}
|
|
182
|
+
<p class="muted small"><Icon name="wifi-off" size={16} /> {localOnlyReason}</p>
|
|
183
|
+
{:else if signedIn}
|
|
176
184
|
<Toggle
|
|
177
185
|
label="Cloud-enabled"
|
|
178
186
|
bind:checked={cloudToggle}
|
|
@@ -13,6 +13,11 @@ type $$ComponentProps = {
|
|
|
13
13
|
signInHref: string;
|
|
14
14
|
/** What gets deleted along with it, e.g. "all its tasks and notes". */
|
|
15
15
|
contentsLabel?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Why this container has to stay local-only (e.g. built-in sample data). The cloud option
|
|
18
|
+
* is replaced by this text while it is local.
|
|
19
|
+
*/
|
|
20
|
+
localOnlyReason?: string;
|
|
16
21
|
isDefault: boolean;
|
|
17
22
|
ondefaultchange: (isDefault: boolean) => void;
|
|
18
23
|
onrename: (name: string) => void;
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
signInHref,
|
|
34
34
|
signInPitch,
|
|
35
35
|
description,
|
|
36
|
+
localOnlyReason,
|
|
36
37
|
onmakecloud,
|
|
37
38
|
onclose
|
|
38
39
|
}: {
|
|
@@ -53,6 +54,11 @@
|
|
|
53
54
|
signInPitch?: string;
|
|
54
55
|
/** Who can do what, shown above the invite form. */
|
|
55
56
|
description?: string;
|
|
57
|
+
/**
|
|
58
|
+
* Why this container has to stay local-only (e.g. built-in sample data). The cloud option
|
|
59
|
+
* is replaced by this text while it is local.
|
|
60
|
+
*/
|
|
61
|
+
localOnlyReason?: string;
|
|
56
62
|
onmakecloud: () => Promise<unknown>;
|
|
57
63
|
onclose: () => void;
|
|
58
64
|
} = $props();
|
|
@@ -141,7 +147,9 @@
|
|
|
141
147
|
</script>
|
|
142
148
|
|
|
143
149
|
<Modal bind:open title={`Share “${name}”`} {onclose}>
|
|
144
|
-
{#if !
|
|
150
|
+
{#if localOnlyReason && !isCloud}
|
|
151
|
+
<p>{localOnlyReason}</p>
|
|
152
|
+
{:else if !cloud.configured}
|
|
145
153
|
<p class="muted">Sharing isn't available because cloud sync isn't set up for this copy of {appName}.</p>
|
|
146
154
|
{:else if !signedIn}
|
|
147
155
|
<p>{pitch}</p>
|
|
@@ -19,6 +19,11 @@ type $$ComponentProps = {
|
|
|
19
19
|
signInPitch?: string;
|
|
20
20
|
/** Who can do what, shown above the invite form. */
|
|
21
21
|
description?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Why this container has to stay local-only (e.g. built-in sample data). The cloud option
|
|
24
|
+
* is replaced by this text while it is local.
|
|
25
|
+
*/
|
|
26
|
+
localOnlyReason?: string;
|
|
22
27
|
onmakecloud: () => Promise<unknown>;
|
|
23
28
|
onclose: () => void;
|
|
24
29
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { default as ActiveList } from './ActiveList.svelte';
|
|
2
2
|
export { default as AddRow } from './AddRow.svelte';
|
|
3
|
+
export { default as AppVersion } from './AppVersion.svelte';
|
|
3
4
|
export { default as Checkbox } from './Checkbox.svelte';
|
|
4
5
|
export { default as CollapsibleSection } from './CollapsibleSection.svelte';
|
|
5
6
|
export { default as Combobox, sameName, type ComboChoice, type ComboOption } from './Combobox.svelte';
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { default as ActiveList } from './ActiveList.svelte';
|
|
2
2
|
export { default as AddRow } from './AddRow.svelte';
|
|
3
|
+
export { default as AppVersion } from './AppVersion.svelte';
|
|
3
4
|
export { default as Checkbox } from './Checkbox.svelte';
|
|
4
5
|
export { default as CollapsibleSection } from './CollapsibleSection.svelte';
|
|
5
6
|
export { default as Combobox, sameName } from './Combobox.svelte';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wells-nelson/interactions",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Svelte 5 inputs, actions (long-press, drag and drop), undo, and account/sharing UI shared by Wells Nelson apps.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"lint:package": "publint"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
|
-
"@wells-nelson/displays": ">=1.0.
|
|
41
|
+
"@wells-nelson/displays": ">=1.0.2 <2.0.0",
|
|
42
42
|
"svelte": "^5.40.0"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|