@octabits-io/nuxt-ui-kit 0.2.0 → 0.2.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
@@ -397,19 +397,6 @@ interface ApiErrorMessengerOptions {
397
397
  /** Default `console.error`. Pass `() => {}` to silence. */
398
398
  log?: (message: string, error: unknown) => void;
399
399
  }
400
- /**
401
- * Map API error bodies to user-facing i18n strings using a fixed key
402
- * convention the consumer's locale files fulfil:
403
- *
404
- * - `errors.<key>` — one entry per API error key (fallback: the raw
405
- * server `message`, and `errors.internal_server_error` for non-API errors)
406
- * - `validation.fields.<path>` — display names for validated fields
407
- * - `validation.messages.<snake_cased_message>` — validation message texts
408
- *
409
- * Framework-free: pass `t`/`te` from your i18n instance (the app-side
410
- * composable is typically `const { t, te } = useI18n()` + this factory).
411
- * Eden Treaty error envelopes (`{ value }`) are unwrapped automatically.
412
- */
413
400
  declare function createApiErrorMessenger(options: ApiErrorMessengerOptions): {
414
401
  getErrorMessage: (error: unknown) => string;
415
402
  isValidationError: (error: unknown) => error is ValidationApiErrorLike;
package/dist/index.js CHANGED
@@ -421,13 +421,25 @@ function useConfirmState() {
421
421
  *
422
422
  * - `errors.<key>` — one entry per API error key (fallback: the raw
423
423
  * server `message`, and `errors.internal_server_error` for non-API errors)
424
- * - `validation.fields.<path>` — display names for validated fields
425
- * - `validation.messages.<snake_cased_message>` — validation message texts
424
+ * - `validation.fields.<slug>` — display names for validated fields
425
+ * - `validation.messages.<slug>` — validation message texts
426
+ *
427
+ * `<slug>` is the path/message lowercased with every non-alphanumeric run
428
+ * collapsed to a single `_` (e.g. path `items.0.name` → `items_0_name`,
429
+ * message `Expected string to match 'email'` →
430
+ * `expected_string_to_match_email`) — so every derivable key is a flat,
431
+ * definable vue-i18n key. Raw paths/messages with dots or punctuation are
432
+ * not definable (dots nest in vue-i18n), which previously made this branch
433
+ * unimplementable for most real messages.
426
434
  *
427
435
  * Framework-free: pass `t`/`te` from your i18n instance (the app-side
428
436
  * composable is typically `const { t, te } = useI18n()` + this factory).
429
437
  * Eden Treaty error envelopes (`{ value }`) are unwrapped automatically.
430
438
  */
439
+ /** Lowercase + collapse every non-alphanumeric run to `_` (trimmed) — a flat, definable vue-i18n key segment. */
440
+ function i18nSlug(value) {
441
+ return value.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
442
+ }
431
443
  function createApiErrorMessenger(options) {
432
444
  const { t, te } = options;
433
445
  const log = options.log ?? ((message, error) => console.error(message, error));
@@ -442,9 +454,9 @@ function createApiErrorMessenger(options) {
442
454
  let actualError = error;
443
455
  if (typeof error === "object" && error !== null && "value" in error) actualError = error.value;
444
456
  if (isValidationError(actualError)) return actualError.fields.map((f) => {
445
- const fieldKey = `validation.fields.${f.path}`;
457
+ const fieldKey = `validation.fields.${i18nSlug(f.path)}`;
446
458
  const fieldName = te(fieldKey) ? t(fieldKey) : f.path;
447
- const messageKey = `validation.messages.${f.message.toLowerCase().replace(/\s+/g, "_")}`;
459
+ const messageKey = `validation.messages.${i18nSlug(f.message)}`;
448
460
  return `${fieldName}: ${te(messageKey) ? t(messageKey) : f.message}`;
449
461
  }).join(", ") || t("errors.validation_error");
450
462
  if (!isApiError(actualError)) return t("errors.internal_server_error");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@octabits-io/nuxt-ui-kit",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Frontend kit for Nuxt/Vue admin SPAs: OIDC session harness (oidc-client-ts), Eden Treaty client factory, auth/org store cores, and a route-guard builder — factory-style seams the app wires into its own plugins, stores, and middleware",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -28,6 +28,15 @@ const route = useRoute()
28
28
 
29
29
  const buttonLabel = computed(() => props.toggleLabel ?? props.title)
30
30
 
31
+ // A named handler rather than an inline `@click="open = true"`: Vue compiles an
32
+ // inline assignment to `$event => (open = true)`, whose return type is
33
+ // `boolean`. UButton types `onClick` as `(event) => void | Promise<void>` — a
34
+ // *union*, so TS's "a function returning a value is assignable to a void-returning
35
+ // signature" rule does not apply and the assignment errors (TS2322).
36
+ function openSidebar() {
37
+ open.value = true
38
+ }
39
+
31
40
  watch(
32
41
  () => [route.path, route.query[props.selectionQueryKey]],
33
42
  () => { open.value = false },
@@ -73,7 +82,7 @@ watch(
73
82
  color="neutral"
74
83
  variant="outline"
75
84
  size="sm"
76
- @click="open = true"
85
+ @click="openSidebar"
77
86
  />
78
87
  </div>
79
88
  <div class="min-w-0 flex-1 overflow-y-auto">