@axium/client 0.21.0 → 0.22.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/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './access.js';
2
+ export * from './cache.js';
2
3
  export * from './config.js';
3
4
  export * from './locales.js';
4
5
  export * from './requests.js';
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './access.js';
2
+ export * from './cache.js';
2
3
  export * from './config.js';
3
4
  export * from './locales.js';
4
5
  export * from './requests.js';
package/dist/locales.d.ts CHANGED
@@ -235,10 +235,19 @@ declare let currentLoaded: {
235
235
  readonly failed: "Login Failed";
236
236
  };
237
237
  };
238
+ readonly location: {
239
+ readonly country: "Country";
240
+ readonly subdivision: "State / province";
241
+ readonly locality: "City / town";
242
+ readonly postal_code: "Postal code";
243
+ readonly street1: "Street address";
244
+ readonly street2: "Street address line 2";
245
+ };
238
246
  readonly preference: {
239
247
  readonly debug: "Debug mode";
240
248
  };
241
249
  };
250
+ export declare let currentMonthNames: string[];
242
251
  /**
243
252
  * Current locale
244
253
  */
@@ -259,6 +268,8 @@ type _ArgsValue<V extends string[]> = UnionToIntersection<{
259
268
  type Replacements<K extends string> = ReplacementOptions & (GetByString<Locale, K> extends string ? _ArgsValue<Split<GetByString<Locale, K> & string, '{'>> : Record<string, any>);
260
269
  type ReplacementsArgs<K extends string> = {} extends Replacements<K> ? [replacements?: Replacements<K>] : [replacements: Replacements<K>];
261
270
  export declare function useLocale(newLocale: string): void;
271
+ export declare function countryName(code: string): string | undefined;
272
+ export declare function dateField(name: string): string | undefined;
262
273
  export declare function escape(text: string): string;
263
274
  /**
264
275
  * Get localized text for a given translation key
package/dist/locales.js CHANGED
@@ -15,7 +15,8 @@ export function extendLocale(locale, data) {
15
15
  debug('Extending locale: ' + locale);
16
16
  deepAssign(loadedLocales[locale], data);
17
17
  }
18
- let currentLoaded = en;
18
+ let currentLoaded = en, currentRegionNames, currentDateFields;
19
+ export let currentMonthNames;
19
20
  /**
20
21
  * Current locale
21
22
  */
@@ -25,6 +26,17 @@ export function useLocale(newLocale) {
25
26
  throw new Error('Locale is not available: ' + newLocale);
26
27
  currentLocale = newLocale;
27
28
  currentLoaded = loadedLocales[newLocale];
29
+ currentRegionNames = new Intl.DisplayNames(newLocale, { type: 'region' });
30
+ currentDateFields = new Intl.DisplayNames(newLocale, { type: 'dateTimeField' });
31
+ const formatter = new Intl.DateTimeFormat(newLocale, { month: 'long' });
32
+ currentMonthNames = Array.from({ length: 12 }, (_, monthIndex) => formatter.format(new Date(Date.UTC(2000, monthIndex + 1, 1))));
33
+ }
34
+ useLocale('en');
35
+ export function countryName(code) {
36
+ return currentRegionNames.of(code);
37
+ }
38
+ export function dateField(name) {
39
+ return currentDateFields.of(name);
28
40
  }
29
41
  const localeReplacement = /\{(\w+)\}/g;
30
42
  const escapePattern = /[&<>"']/g;
@@ -0,0 +1,20 @@
1
+ <script lang="ts">
2
+ import { countryName, text } from '@axium/client';
3
+ import { countries, type LocationInit } from '@axium/core';
4
+
5
+ let { value = $bindable<LocationInit>() }: { value: LocationInit } = $props();
6
+ </script>
7
+
8
+ <select bind:value={value.country} placeholder={text('location.country')}>
9
+ {#each countries as country}
10
+ <option value={country}>{countryName(country)}</option>
11
+ {/each}
12
+ </select>
13
+
14
+ <input type="text" placeholder={text('location.street1')} bind:value={value.street1} />
15
+ <input type="text" placeholder={text('location.street2')} bind:value={value.street2} />
16
+ <input type="text" placeholder={text('location.locality')} bind:value={value.locality} />
17
+ <div>
18
+ <input type="text" placeholder={text('location.subdivision')} bind:value={value.subdivision} />
19
+ <input type="text" placeholder={text('location.postal_code')} bind:value={value.postalCode} />
20
+ </div>
@@ -36,6 +36,7 @@
36
36
  border: 1px solid #8888;
37
37
  vertical-align: middle;
38
38
  margin-right: 0.5em;
39
+ object-fit: cover;
39
40
  /* see https://drafts.csswg.org/css-image-animation-1/ */
40
41
  image-animation: stopped;
41
42
  }
@@ -5,7 +5,7 @@
5
5
  interface Props {
6
6
  rootValue: any;
7
7
  schema: ZodObject;
8
- labels: Record<string, string>;
8
+ labels?: Record<string, string>;
9
9
  updateValue(value: any): void;
10
10
  idPrefix?: string;
11
11
  }
@@ -15,7 +15,7 @@
15
15
 
16
16
  <div class="ZodForm">
17
17
  {#each Object.keys(schema.shape).sort((a, b) => a.localeCompare(b)) as path}
18
- <ZodInput bind:rootValue {updateValue} {idPrefix} {path} schema={schema.shape[path]} label={labels[path] || path} />
18
+ <ZodInput bind:rootValue {updateValue} {idPrefix} {path} schema={schema.shape[path]} label={labels?.[path] || path} />
19
19
  {/each}
20
20
  </div>
21
21
 
@@ -14,15 +14,17 @@
14
14
  path: string;
15
15
  label?: string;
16
16
  schema: ZodPref;
17
+ _parseSchema?: ZodPref;
17
18
  defaultValue?: any;
18
19
  optional?: boolean;
19
- noLabel?: boolean;
20
+ readonly?: boolean;
21
+ noLabel?: boolean | 'placeholder';
20
22
  updateValue(value: any): void;
21
23
  }
22
24
 
23
25
  let { rootValue = $bindable(), ...props }: Props = $props();
24
26
 
25
- let { label, path, schema, optional, defaultValue, idPrefix, updateValue, noLabel } = props;
27
+ let { label, path, schema, _parseSchema = schema, optional, readonly, defaultValue, idPrefix, updateValue, noLabel } = props;
26
28
 
27
29
  const id = (idPrefix ? idPrefix + ':' : '') + path.replaceAll(' ', '_');
28
30
 
@@ -85,13 +87,28 @@
85
87
  const oninput = onchange;
86
88
 
87
89
  const labelText = $derived(zKeys.has(props.schema) ? text(zKeys.get(props.schema)!.key) : label || path);
90
+ const placeholder = noLabel == 'placeholder' ? labelText : undefined;
91
+
92
+ /** Array element types that indicate the array should put elements on their own lines */
93
+ const largeArrayTypes = ['object', 'array', 'record', 'tuple'];
88
94
  </script>
89
95
 
90
96
  {#snippet _in(rest: HTMLInputAttributes)}
91
97
  <div class="ZodInput">
92
98
  {#if !noLabel}<label for={id}>{labelText}</label>{/if}
93
99
  {#if error}<span class="ZodInput-error">{error}</span>{/if}
94
- <input {id} {...rest} bind:value {onchange} {oninput} required={!optional} {defaultValue} class={[error && 'error']} />
100
+ <input
101
+ {id}
102
+ {...rest}
103
+ bind:value
104
+ {onchange}
105
+ {oninput}
106
+ required={!optional}
107
+ {defaultValue}
108
+ {placeholder}
109
+ {readonly}
110
+ class={[error && 'error']}
111
+ />
95
112
  </div>
96
113
  {/snippet}
97
114
 
@@ -104,7 +121,7 @@
104
121
  {:else if schema.type == 'boolean'}
105
122
  <div class="ZodInput">
106
123
  {#if !noLabel}<label for="{id}:checkbox">{labelText}</label>{/if}
107
- <input bind:checked={value} id="{id}:checkbox" type="checkbox" {onchange} required={!optional} />
124
+ <input bind:checked={value} id="{id}:checkbox" type="checkbox" {onchange} required={!optional} {placeholder} />
108
125
  <label for="{id}:checkbox" {id} class="checkbox">
109
126
  {#if value}<Icon i="check" --size="1.3em" />{/if}
110
127
  </label>
@@ -128,19 +145,22 @@
128
145
  </div>
129
146
  {:else if schema.type == 'template_literal'}
130
147
  <!-- todo -->
148
+ {:else if schema.type == 'readonly'}
149
+ <ZodInput bind:rootValue {...props} label={labelText} schema={schema.def.innerType} readonly />
131
150
  {:else if schema.type == 'default'}
132
151
  <ZodInput bind:rootValue {...props} label={labelText} schema={schema.def.innerType} defaultValue={schema.def.defaultValue} />
133
152
  {:else if schema.type == 'nullable' || schema.type == 'optional'}
134
153
  <!-- defaults are handled differently -->
135
154
  <ZodInput bind:rootValue {...props} label={labelText} schema={schema.def.innerType} optional={true} />
155
+ {:else if schema.type == 'nonoptional'}
156
+ <ZodInput bind:rootValue {...props} label={labelText} schema={schema.def.innerType} optional={false} />
136
157
  {:else if schema.type == 'array'}
137
158
  <div class="ZodInput">
138
159
  {#if !noLabel}<label for={id}>{labelText}</label>{/if}
139
- {#if error}<span class="ZodInput-error">{error}</span>{/if}
140
- <div class="ZodInput-array">
160
+ <div class={['ZodInput-array', largeArrayTypes.includes(schema.element.type) && 'large']}>
141
161
  {#each value, i}
142
162
  <div class="ZodInput-element">
143
- <input id="{id}.{i}" bind:value={value[i]} {oninput} required={!optional} {defaultValue} class={[error && 'error']} />
163
+ <ZodInput bind:rootValue {updateValue} {idPrefix} path="{path}.{i}" schema={schema.element} noLabel={noLabel || true} />
144
164
  <button
145
165
  onclick={e => {
146
166
  value.splice(i, 1);
@@ -151,8 +171,11 @@
151
171
  </button>
152
172
  </div>
153
173
  {/each}
154
- <button onclick={() => value.push('')}>
174
+ <button class="icon-text" onclick={() => value.push('')}>
155
175
  <Icon i="plus" --size="16px" />
176
+ {#if noLabel == 'placeholder'}
177
+ <span>{labelText}</span>
178
+ {/if}
156
179
  </button>
157
180
  </div>
158
181
  </div>
@@ -161,14 +184,14 @@
161
184
  {#each Object.keys(value) as key}
162
185
  <div class="ZodInput-record-entry">
163
186
  {#if !noLabel}<label for={id}>{key}</label>{/if}
164
- <ZodInput bind:rootValue {updateValue} {idPrefix} path="{path}.{key}" schema={schema.valueType} />
187
+ <ZodInput bind:rootValue {updateValue} {idPrefix} {noLabel} path="{path}.{key}" schema={schema.valueType} />
165
188
  </div>
166
189
  {/each}
167
190
  </div>
168
191
  {:else if schema.type == 'object'}
169
192
  <!-- <div class="ZodInput-object"> -->
170
193
  {#each Object.entries(schema.shape) as [key, value]}
171
- <ZodInput bind:rootValue {updateValue} {idPrefix} path="{path}.{key}" schema={value} />
194
+ <ZodInput bind:rootValue {updateValue} {idPrefix} {noLabel} path="{path}.{key}" schema={value} />
172
195
  {/each}
173
196
  <!-- </div> -->
174
197
  {:else if schema.type == 'tuple'}
@@ -187,6 +210,14 @@
187
210
  {/each}
188
211
  </select>
189
212
  </div>
213
+ {:else if schema.type == 'success'}
214
+ <ZodInput bind:rootValue {...props} label={labelText} schema={schema.def.innerType} {_parseSchema} />
215
+ {:else if schema.type == 'pipe'}
216
+ <ZodInput bind:rootValue {...props} label={labelText} schema={schema.def.in} {_parseSchema} />
217
+ {:else if schema.type == 'union'}
218
+ <ZodInput bind:rootValue {...props} label={labelText} schema={schema.def.options[0]} {_parseSchema} />
219
+ {:else if schema.type == 'intersection'}
220
+ <ZodInput bind:rootValue {...props} label={labelText} schema={schema.def.left} {_parseSchema} />
190
221
  {:else}
191
222
  <!-- No idea how to render this -->
192
223
  <i class="error">{text('ZodInput.invalid_type', { type: JSON.stringify((schema as ZodPref)?.def?.type) })}</i>
@@ -217,9 +248,14 @@
217
248
  gap: 0.5em;
218
249
  align-items: center;
219
250
 
220
- button {
221
- position: relative;
222
- right: 1em;
251
+ & > button {
252
+ display: contents;
253
+ }
254
+
255
+ & > .ZodInput {
256
+ gap: 0.25em;
257
+ display: flex;
258
+ flex-direction: column;
223
259
  }
224
260
  }
225
261
 
@@ -227,6 +263,10 @@
227
263
  display: flex;
228
264
  gap: 0.5em;
229
265
  align-items: center;
266
+
267
+ &.large {
268
+ flex-direction: column;
269
+ }
230
270
  }
231
271
 
232
272
  .ZodInput-object,
package/lib/index.ts CHANGED
@@ -4,6 +4,7 @@ export { default as ColorPicker } from './ColorPicker.svelte';
4
4
  export { default as ClipboardCopy } from './ClipboardCopy.svelte';
5
5
  export { default as FormDialog } from './FormDialog.svelte';
6
6
  export { default as Icon } from './Icon.svelte';
7
+ export { default as LocationSelect } from './LocationSelect.svelte';
7
8
  export { default as Login } from './Login.svelte';
8
9
  export { default as Logout } from './Logout.svelte';
9
10
  export { default as NumberBar } from './NumberBar.svelte';
package/locales/en.json CHANGED
@@ -229,6 +229,14 @@
229
229
  "failed": "Login Failed"
230
230
  }
231
231
  },
232
+ "location": {
233
+ "country": "Country",
234
+ "subdivision": "State / province",
235
+ "locality": "City / town",
236
+ "postal_code": "Postal code",
237
+ "street1": "Street address",
238
+ "street2": "Street address line 2"
239
+ },
232
240
  "preference": {
233
241
  "debug": "Debug mode"
234
242
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axium/client",
3
- "version": "0.21.0",
3
+ "version": "0.22.1",
4
4
  "author": "James Prevett <jp@jamespre.dev>",
5
5
  "funding": {
6
6
  "type": "individual",
@@ -45,7 +45,7 @@
45
45
  "build": "tsc"
46
46
  },
47
47
  "peerDependencies": {
48
- "@axium/core": ">=0.24.0",
48
+ "@axium/core": ">=0.26.0",
49
49
  "svelte": "^5.36.0",
50
50
  "utilium": "^2.8.0",
51
51
  "zod": "^4.0.5"