@axium/contacts 0.1.1 → 0.2.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.
@@ -40,6 +40,7 @@
40
40
  border: 1px solid #8888;
41
41
  vertical-align: middle;
42
42
  margin-right: 0.5em;
43
+ object-fit: cover;
43
44
  /* see https://drafts.csswg.org/css-image-animation-1/ */
44
45
  image-animation: stopped;
45
46
  }
@@ -1,11 +1,11 @@
1
1
  <script lang="ts">
2
2
  import { text } from '@axium/client';
3
3
  import { dynamicRows } from '@axium/client/attachments';
4
- import { Icon, LocationSelect, ZodInput } from '@axium/client/components';
4
+ import { Icon, LocationSelect, ZodInput, Discovery, discovery } from '@axium/client/components';
5
5
  import { ContactURL, Custom, Email, Init, Phone, Relationship, SigDate, type Contact } from '@axium/contacts';
6
6
  import ContactPicture from './ContactPicture.svelte';
7
7
  import DateSelect from './DateSelect.svelte';
8
- import Discovery from './Discovery.svelte';
8
+ import { contactDiscovery } from './discovery.svelte';
9
9
  import { name as formatName } from '@axium/contacts/client/format';
10
10
 
11
11
  let showDetailed = $state(false);
@@ -140,8 +140,10 @@
140
140
  {#if i}<span />{/if}
141
141
  <div class="section">
142
142
  <Discovery
143
- exclude={[init.id, ...init.relationships.map(r => r.to)].filter((v): v is string => !!v)}
144
- onSelect={id => (rel.to = id)}
143
+ onSelect={result => (rel.to = result.contact.id)}
144
+ sources={[contactDiscovery]}
145
+ exclude={target =>
146
+ [init.id, ...init.relationships.map(r => r.to)].filter((v): v is string => !!v).includes(target.contact.id)}
145
147
  />
146
148
  <ZodInput
147
149
  bind:rootValue={init}
@@ -0,0 +1,21 @@
1
+ <script lang="ts" module>
2
+ import type { discovery } from '@axium/client/components';
3
+ import { fetchAPI } from '@axium/client/requests';
4
+ import type { NoExternal } from '@axium/contacts';
5
+ import { format } from '@axium/contacts/client';
6
+
7
+ export const contactDiscovery: discovery.Source<{ contact: NoExternal }> = {
8
+ name: 'contact',
9
+ async get(search) {
10
+ const contacts = await fetchAPI('POST', 'contact-discovery', search);
11
+ return contacts.map(contact => ({ contact }));
12
+ },
13
+ get render() {
14
+ return renderContact;
15
+ },
16
+ };
17
+ </script>
18
+
19
+ {#snippet renderContact(result: { contact: NoExternal })}
20
+ <span>{format.name(result.contact)}</span>
21
+ {/snippet}
package/lib/index.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export { default as ContactCard } from './ContactCard.svelte';
2
2
  export { default as ContactPicture } from './ContactPicture.svelte';
3
3
  export { default as DateSelect } from './DateSelect.svelte';
4
- export { default as Discovery } from './Discovery.svelte';
4
+ export { contactDiscovery } from './discovery.svelte';
5
5
  export { default as Field } from './Field.svelte';
6
6
  export { default as InitForm } from './InitForm.svelte';
7
7
  export { default as List } from './List.svelte';
package/locales/en.json CHANGED
@@ -39,10 +39,6 @@
39
39
  "toast_updated": "Updated contact picture",
40
40
  "toast_removed": "Removed contact picture"
41
41
  },
42
- "Discovery": {
43
- "placeholder": "Search for a contact",
44
- "no_results": "No contacts found"
45
- },
46
42
  "delete_confirm": "Are you sure you want to delete this contact?"
47
43
  },
48
44
  "contact": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axium/contacts",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "author": "James Prevett <axium@jamespre.dev>",
5
5
  "description": "Contacts for Axium",
6
6
  "funding": {
@@ -38,7 +38,7 @@
38
38
  "build": "tsc"
39
39
  },
40
40
  "peerDependencies": {
41
- "@axium/client": ">=0.22.0",
41
+ "@axium/client": ">=0.23.0",
42
42
  "@axium/core": ">=0.26.0",
43
43
  "@axium/server": ">=0.42.0",
44
44
  "@sveltejs/kit": "^2.27.3",
@@ -1,101 +0,0 @@
1
- <script lang="ts">
2
- import { text } from '@axium/client';
3
- import { fetchAPI } from '@axium/client/requests';
4
- import type { NoExternal } from '@axium/contacts';
5
- import { format } from '@axium/contacts/client';
6
- import { errorText } from 'ioium';
7
-
8
- const { onSelect, exclude = [] }: { onSelect(id: string): unknown; exclude?: string[] } = $props();
9
-
10
- let results = $state<NoExternal[]>([]),
11
- value = $state<string>(),
12
- gotError = $state<boolean>(false);
13
-
14
- async function oninput() {
15
- if (!value || !value.length) {
16
- results = [];
17
- return;
18
- }
19
-
20
- try {
21
- results = await fetchAPI('POST', 'contact-discovery', value);
22
- } catch (e) {
23
- gotError = true;
24
- console.warn('Can not use contact discovery:', errorText(e));
25
- results = [];
26
- }
27
- }
28
-
29
- function select(target: NoExternal) {
30
- return (e: Event) => {
31
- e.stopPropagation();
32
- onSelect(target.id);
33
- results = [];
34
- value = format.name(target);
35
- };
36
- }
37
- </script>
38
-
39
- <input bind:value type="text" placeholder={text('contacts.Discovery.placeholder')} {oninput} />
40
- {#if !gotError && value}
41
- <!-- Don't show results when we can't use the discovery API -->
42
- <div class="results">
43
- {#each results as result}
44
- {#if !exclude.includes(result.id)}
45
- <div class="result" onclick={select(result)}>
46
- <span>{format.name(result)}</span>
47
- </div>
48
- {/if}
49
- {:else}
50
- <i>{text('contacts.Discovery.no_results')}</i>
51
- {/each}
52
- </div>
53
- {/if}
54
-
55
- <style>
56
- :host {
57
- anchor-scope: --discovery-input;
58
- }
59
-
60
- input {
61
- anchor-name: --discovery-input;
62
- }
63
-
64
- input:focus + .results,
65
- .results:active {
66
- display: flex;
67
- animation: var(--A-zoom);
68
- }
69
-
70
- .results {
71
- position: fixed;
72
- position-anchor: --discovery-input;
73
- inset: anchor(bottom) anchor(right) auto anchor(left);
74
- display: none;
75
- flex-direction: column;
76
- gap: 0.25em;
77
- height: fit-content;
78
- max-height: 25em;
79
- background-color: var(--bg-accent);
80
- border-radius: 0.25em 0.25em 0.75em 0.75em;
81
- padding: 1em;
82
- border: var(--border-accent);
83
- align-items: stretch;
84
-
85
- i {
86
- text-align: center;
87
- }
88
- }
89
-
90
- .result {
91
- padding: 0.25em 0.75em;
92
- border-radius: 0.5em;
93
- display: inline-flex;
94
- align-items: center;
95
- }
96
-
97
- .result:hover {
98
- cursor: pointer;
99
- background-color: var(--bg-strong);
100
- }
101
- </style>