@alikhalilll/ui 1.1.1 → 1.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.
Files changed (22) hide show
  1. package/README.md +1 -1
  2. package/dist/chunks/{ADrawerContent.vue_vue_type_script_setup_true_lang-BivIZvV1.mjs → ADrawerContent.vue_vue_type_script_setup_true_lang-W28CSzER.mjs} +15 -15
  3. package/dist/chunks/ADrawerContent.vue_vue_type_script_setup_true_lang-W28CSzER.mjs.map +1 -0
  4. package/dist/chunks/{APopoverContent.vue_vue_type_script_setup_true_lang-o1XhV9DM.mjs → APopoverContent.vue_vue_type_script_setup_true_lang-CjiJ12DR.mjs} +6 -6
  5. package/dist/chunks/APopoverContent.vue_vue_type_script_setup_true_lang-CjiJ12DR.mjs.map +1 -0
  6. package/dist/chunks/{AResponsivePopoverContent.vue_vue_type_script_setup_true_lang-BYEb5UBL.mjs → AResponsivePopoverContent.vue_vue_type_script_setup_true_lang-5YbO6FdM.mjs} +3 -3
  7. package/dist/chunks/{AResponsivePopoverContent.vue_vue_type_script_setup_true_lang-BYEb5UBL.mjs.map → AResponsivePopoverContent.vue_vue_type_script_setup_true_lang-5YbO6FdM.mjs.map} +1 -1
  8. package/dist/chunks/ATellInput.vue_vue_type_script_setup_true_lang-D7hPj1g1.mjs +1489 -0
  9. package/dist/chunks/ATellInput.vue_vue_type_script_setup_true_lang-D7hPj1g1.mjs.map +1 -0
  10. package/dist/drawer.mjs +1 -1
  11. package/dist/index.d.ts +105 -2
  12. package/dist/index.mjs +34 -29
  13. package/dist/popover.mjs +1 -1
  14. package/dist/responsive-popover.mjs +1 -1
  15. package/dist/tell-input.d.ts +105 -2
  16. package/dist/tell-input.mjs +11 -6
  17. package/entries/tell-input/README.md +18 -2
  18. package/package.json +1 -1
  19. package/dist/chunks/ADrawerContent.vue_vue_type_script_setup_true_lang-BivIZvV1.mjs.map +0 -1
  20. package/dist/chunks/APopoverContent.vue_vue_type_script_setup_true_lang-o1XhV9DM.mjs.map +0 -1
  21. package/dist/chunks/ATellInput.vue_vue_type_script_setup_true_lang-Clc-B8SW.mjs +0 -1353
  22. package/dist/chunks/ATellInput.vue_vue_type_script_setup_true_lang-Clc-B8SW.mjs.map +0 -1
@@ -24,6 +24,7 @@ size: ATellInputSize;
24
24
  placeholder: string;
25
25
  ipEndpoint: string;
26
26
  defaultCountry: string;
27
+ showValidationIcon: boolean;
27
28
  detectCountry: DetectionStrategy;
28
29
  detectFromInput: boolean;
29
30
  detectDebounceMs: number;
@@ -49,6 +50,8 @@ emptyText: string;
49
50
  loadingText: string;
50
51
  suggestedLabel: string;
51
52
  allCountriesLabel: string;
53
+ countryLabel: string;
54
+ selectCountryLabel: string;
52
55
  suggestedLimit: number;
53
56
  maxResults: number;
54
57
  kbdOpen: string | null;
@@ -96,6 +99,12 @@ declare type __VLS_Props_2 = {
96
99
  /** Override the right-side kbd hints. Pass `null` to hide. */
97
100
  kbdOpen?: string | null;
98
101
  kbdClose?: string | null;
102
+ /** BCP-47 locale — country names render localized via `Intl.DisplayNames`. */
103
+ locale?: string;
104
+ /** Prefix of the trigger's `aria-label` when a country is selected, e.g. `"Country"`. */
105
+ countryLabel?: string;
106
+ /** Trigger's `aria-label` when no country is selected. */
107
+ selectCountryLabel?: string;
99
108
  };
100
109
 
101
110
  declare type __VLS_Props_3 = {
@@ -391,19 +400,46 @@ export declare const ACountrySelect: __VLS_WithTemplateSlots_2<typeof __VLS_comp
391
400
 
392
401
  export declare const ATellInput: __VLS_WithTemplateSlots<typeof __VLS_component, __VLS_TemplateResult["slots"]>;
393
402
 
403
+ /** Text direction for the field. `'auto'` (or omitting the prop) inherits from the
404
+ * nearest `[dir]` ancestor / `<html dir>`; `'ltr'` / `'rtl'` force it. */
405
+ export declare type ATellInputDir = 'ltr' | 'rtl' | 'auto';
406
+
394
407
  export declare interface ATellInputProps {
395
408
  class?: HTMLAttributes['class'];
396
409
  placeholder?: string;
397
410
  disabled?: boolean;
398
411
  loading?: boolean;
399
412
  size?: ATellInputSize;
413
+ /**
414
+ * Text direction. Omit (or pass `'auto'`) to inherit from the page — RTL pages get an
415
+ * RTL field automatically. Pass `'ltr'` / `'rtl'` to force it.
416
+ */
417
+ dir?: ATellInputDir;
418
+ /**
419
+ * BCP-47 locale (e.g. `'ar'`, `'fr'`). When set, country names render localized via
420
+ * `Intl.DisplayNames` and the format hint uses the locale's numerals.
421
+ */
422
+ locale?: string;
423
+ /**
424
+ * Localized UI strings. A single bag covering the picker, validation errors, and a11y
425
+ * labels. Individual props (`searchPlaceholder`, `emptyText`, `loadingText`,
426
+ * `errorMessages`) take precedence over the matching `messages` key when both are set.
427
+ */
428
+ messages?: TellInputMessagesInput;
400
429
  /**
401
430
  * Whitelist of allowed dial-digit codes (no `+`), e.g. `['20', '966']`.
402
431
  * Countries outside this list are still shown in the picker but rendered as disabled.
403
432
  */
404
433
  allowedDialCodes?: string[];
405
- /** Show validation error text beneath the input when invalid. */
434
+ /** Light up the field's validation styling coloured border + ring on the input and the
435
+ * error message line below — when the number is valid / invalid. Default `false`, so the
436
+ * field stays neutral and validation surfacing is left to the consumer (via the
437
+ * `validation` ref exposure). */
406
438
  showValidation?: boolean;
439
+ /** Show the green check / red alert icon at the end of the field. Default `false`; opt
440
+ * in with `true`. Independent of `showValidation` — you can show the icon without the
441
+ * coloured field, or vice versa. The slots `#valid-icon` / `#error-icon` still apply. */
442
+ showValidationIcon?: boolean;
407
443
  /**
408
444
  * Country auto-detect strategy. Defaults to `'auto'` — try IP geolocation first, then
409
445
  * timezone, then `navigator.language`, finally `defaultCountry`.
@@ -467,6 +503,9 @@ export declare interface CountryOption<T = RestCountry> {
467
503
 
468
504
  export declare const DEFAULT_ERROR_MESSAGES: Record<PhoneValidationReason, string>;
469
505
 
506
+ /** English defaults for every {@link TellInputMessages} key. */
507
+ export declare const DEFAULT_MESSAGES: TellInputMessages;
508
+
470
509
  /**
471
510
  * Default flag URL builder — flagcdn.com hosts PNG flags at multiple widths and is
472
511
  * generous with caching + no API key required. Swap via the `flagUrl` prop on
@@ -528,6 +567,30 @@ declare interface ExtendedProps extends ATellInputProps {
528
567
 
529
568
  export declare type FlagUrlBuilder = (iso2: string, width: number) => string;
530
569
 
570
+ /**
571
+ * Base code points of contiguous decimal-digit blocks. Each block runs `base`‥`base+9`
572
+ * for digit `0`‥`9`, so the ASCII digit is `codePoint - base`. Add a script by appending
573
+ * one entry here.
574
+ */
575
+ export declare const LOCALE_DIGIT_RANGES: {
576
+ name: string;
577
+ base: number;
578
+ }[];
579
+
580
+ /**
581
+ * Return a copy of the country list with display names localized to `locale` via
582
+ * `Intl.DisplayNames`. `search_key` is rebuilt (keeping the English name too) so search
583
+ * still matches either spelling. Unknown locales / regions fall back to the English name.
584
+ */
585
+ export declare function localizeCountries(list: CountryOption[], locale?: string): CountryOption[];
586
+
587
+ /**
588
+ * Replace any supported non-ASCII decimal digit with its ASCII equivalent. Every other
589
+ * character (spaces, `+`, separators, letters) is left untouched — callers still run their
590
+ * own `\D` cleanup afterwards.
591
+ */
592
+ export declare function normalizeDigits(input: string): string;
593
+
531
594
  export declare interface PhoneRequiredInfo {
532
595
  iso2: string;
533
596
  dial_code: string;
@@ -560,6 +623,12 @@ export declare interface PhoneValidationResult {
560
623
  details?: Record<string, unknown>;
561
624
  }
562
625
 
626
+ /**
627
+ * Merge a partial `messages` override onto the English defaults. Used internally by
628
+ * `ATellInput` to resolve a complete {@link TellInputMessages} object.
629
+ */
630
+ export declare function resolveMessages(input?: TellInputMessagesInput): TellInputMessages;
631
+
563
632
  export declare interface RestCountry {
564
633
  name?: {
565
634
  common?: string;
@@ -587,6 +656,36 @@ declare function selectCountry(option: CountryOption): void;
587
656
  */
588
657
  declare type Size = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
589
658
 
659
+ /**
660
+ * Every user-facing string in the tell-input UI, bundled so a consumer can localize the
661
+ * component in one prop. Each key has an English default in {@link DEFAULT_MESSAGES}.
662
+ */
663
+ export declare interface TellInputMessages {
664
+ /** Placeholder of the country-picker search box. */
665
+ searchPlaceholder: string;
666
+ /** Shown when a search yields no countries. */
667
+ emptyText: string;
668
+ /** Shown while the country list is loading. */
669
+ loadingText: string;
670
+ /** Header of the "Suggested" group (current + recent picks). */
671
+ suggestedLabel: string;
672
+ /** Header of the full country list. */
673
+ allCountriesLabel: string;
674
+ /** Validation error text, keyed by reason. */
675
+ errorMessages: Record<PhoneValidationReason, string>;
676
+ /** Prefix of the country trigger's `aria-label`, e.g. `"Country: Egypt"`. */
677
+ countryLabel: string;
678
+ /** `aria-label` of the country trigger when no country is selected. */
679
+ selectCountryLabel: string;
680
+ /** `aria-label` of the phone input element. */
681
+ phoneInputLabel: string;
682
+ }
683
+
684
+ /** Partial override shape for the `messages` prop — every key (and every error reason) is optional. */
685
+ export declare type TellInputMessagesInput = Partial<Omit<TellInputMessages, 'errorMessages'>> & {
686
+ errorMessages?: Partial<Record<PhoneValidationReason, string>>;
687
+ };
688
+
590
689
  /**
591
690
  * Reactive wrapper. Kicks off detection in `onMounted` so SSR renders an empty value and the
592
691
  * client patches in the real country once resolved.
@@ -616,7 +715,7 @@ export declare interface UsePhoneValidationReturn {
616
715
  getRequiredInfo(country: {
617
716
  iso2: string;
618
717
  dial_code?: string;
619
- }): PhoneRequiredInfo | null;
718
+ }, locale?: string): PhoneRequiredInfo | null;
620
719
  validate(input: ValidateArgs): PhoneValidationResult;
621
720
  }
622
721
 
@@ -626,12 +725,16 @@ export declare type ValidateArgs = {
626
725
  dial_code?: string;
627
726
  } | null | undefined;
628
727
  phone?: undefined;
728
+ /** BCP-47 locale — localizes the numerals in the returned `required.format_hint`. */
729
+ locale?: string;
629
730
  } | {
630
731
  country: {
631
732
  iso2: string;
632
733
  dial_code?: string;
633
734
  } | null | undefined;
634
735
  phone: string | null;
736
+ /** BCP-47 locale — localizes the numerals in the returned `required.format_hint`. */
737
+ locale?: string;
635
738
  };
636
739
 
637
740
  export { }
@@ -1,13 +1,18 @@
1
- import { _ as e, a as s, b as l, D as n, c as u, d as o, e as r, u as A, f as c } from "./chunks/ATellInput.vue_vue_type_script_setup_true_lang-Clc-B8SW.mjs";
1
+ import { _ as e, a as t, b as l, D as n, c as o, L as r, d as u, e as i, f as A, l as E, n as S, r as C, u as D, g as _ } from "./chunks/ATellInput.vue_vue_type_script_setup_true_lang-D7hPj1g1.mjs";
2
2
  export {
3
3
  e as ACountryFlag,
4
- s as ACountrySelect,
4
+ t as ACountrySelect,
5
5
  l as ATellInput,
6
6
  n as DEFAULT_ERROR_MESSAGES,
7
+ o as DEFAULT_MESSAGES,
8
+ r as LOCALE_DIGIT_RANGES,
7
9
  u as aTellInputVariants,
8
- o as defaultFlagUrl,
9
- r as detectCountry,
10
- A as useCountryDetection,
11
- c as usePhoneValidation
10
+ i as defaultFlagUrl,
11
+ A as detectCountry,
12
+ E as localizeCountries,
13
+ S as normalizeDigits,
14
+ C as resolveMessages,
15
+ D as useCountryDetection,
16
+ _ as usePhoneValidation
12
17
  };
13
18
  //# sourceMappingURL=tell-input.mjs.map
@@ -1,6 +1,6 @@
1
1
  # `@alikhalilll/ui/tell-input`
2
2
 
3
- Vue 3 phone-number input with smart country detection (libphonenumber-js + IP/timezone/locale hint), a responsive popover/drawer country picker, and a structured `PhoneValidationResult` exposed via template ref.
3
+ Vue 3 phone-number input with smart country detection (libphonenumber-js + IP/timezone/locale hint), a responsive popover/drawer country picker, and a structured `PhoneValidationResult` exposed via template ref. RTL-aware, localisable, and accepts alternative numeral systems.
4
4
 
5
5
  ## Install
6
6
 
@@ -31,13 +31,29 @@ const country = ref<number | null>(null);
31
31
  </template>
32
32
  ```
33
33
 
34
- The default shape is a plain phone input with the country picker hidden. As the user types or pastes, detection runs (debounced) against known dial codes; on first match the picker slides in pre-filled and `phone` is normalised to the national significant number — `01066105963` becomes `1066105963`, `+447911123456` becomes `7911123456`.
34
+ The default shape is a plain phone input with the country picker hidden. As the user types or pastes, detection runs (debounced) against known dial codes; on first match a flag-only trigger reveals at the **end** of the field, the dial code shows as a static prefix inside the input, and `phone` is normalised to the national significant number — `01066105963` becomes `1066105963`, `+447911123456` becomes `7911123456`.
35
+
36
+ ## Internationalization
37
+
38
+ - **RTL** — direction inherits from the page (`<div dir="rtl">` / `<html dir="rtl">`), or force it with `dir="ltr"` / `dir="rtl"`. The phone field row stays LTR (dial prefix → digits → flag); only the helper/error text and the country popover follow the page direction.
39
+ - **`locale`** — localises country names (`Intl.DisplayNames`) and the format-hint numerals.
40
+ - **`messages`** — one bag for every UI string (picker labels, validation errors, a11y labels).
41
+ - **Alternative numerals** — digits typed as Arabic-Indic (`٠-٩`), Persian (`۰-۹`), Devanagari, or Bengali are normalised to ASCII. `normalizeDigits` is exported for standalone use.
42
+
43
+ ```vue
44
+ <template>
45
+ <div dir="rtl">
46
+ <ATellInput v-model:phone="phone" v-model:country="country" locale="ar" :messages="ar" />
47
+ </div>
48
+ </template>
49
+ ```
35
50
 
36
51
  ## Variants
37
52
 
38
53
  - **Picker pre-filled** — pass `default-country="…"` or seed `v-model:country` so the picker renders visible at mount.
39
54
  - **Restricted countries** — pass `allowed-dial-codes` (array of dial-digit strings, no `+`). Whitelisted countries surface in the Suggested group at the top; disallowed countries render below as disabled.
40
55
  - **Always-visible picker (legacy)** — `:detect-from-input="false"` reverts to the IP/timezone/locale chain auto-filling the picker on mount.
56
+ - **Validation visuals** — both off by default. `:show-validation="true"` lights up the field (coloured border + ring + error text); `:show-validation-icon="true"` adds the trailing green check / red alert icon. They're independent — combine as needed.
41
57
 
42
58
  ## Exposed via template ref
43
59
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alikhalilll/ui",
3
- "version": "1.1.1",
3
+ "version": "1.2.1",
4
4
  "description": "Headless, shadcn-vue style Vue 3 component library — every component is its own importable subpath (`@alikhalilll/ui/tell-input`, `@alikhalilll/ui/popover`, …) so users pay only for what they actually use.",
5
5
  "license": "MIT",
6
6
  "author": "alikhalilll",
@@ -1 +0,0 @@
1
- {"version":3,"file":"ADrawerContent.vue_vue_type_script_setup_true_lang-BivIZvV1.mjs","sources":["../../entries/drawer/components/ADrawer.vue","../../entries/drawer/components/ADrawerTrigger.vue","../../entries/drawer/components/ADrawerOverlay.vue","../../entries/drawer/components/ADrawerContent.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DrawerRoot, type DrawerRootEmits, type DrawerRootProps } from 'vaul-vue';\nimport { useForwardPropsEmits } from 'reka-ui';\n\nconst props = withDefaults(defineProps<DrawerRootProps>(), {\n shouldScaleBackground: true,\n});\nconst emits = defineEmits<DrawerRootEmits>();\nconst forwarded = useForwardPropsEmits(props, emits);\n</script>\n\n<template>\n <DrawerRoot data-slot=\"drawer\" v-bind=\"forwarded\">\n <slot />\n </DrawerRoot>\n</template>\n","<script setup lang=\"ts\">\nimport { DrawerTrigger, type DrawerTriggerProps } from 'vaul-vue';\nimport { useForwardProps } from 'reka-ui';\n\nconst props = defineProps<DrawerTriggerProps>();\nconst forwarded = useForwardProps(props);\n</script>\n\n<template>\n <DrawerTrigger data-slot=\"drawer-trigger\" v-bind=\"forwarded\">\n <slot />\n </DrawerTrigger>\n</template>\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue';\nimport { DrawerOverlay } from 'vaul-vue';\nimport type { DialogOverlayProps } from 'reka-ui';\nimport { reactiveOmit } from '@vueuse/core';\nimport { useForwardProps } from 'reka-ui';\nimport { cn } from '@/utils';\n\nconst props = defineProps<DialogOverlayProps & { class?: HTMLAttributes['class'] }>();\nconst delegated = reactiveOmit(props, 'class');\nconst forwarded = useForwardProps(delegated);\n</script>\n\n<template>\n <DrawerOverlay\n data-slot=\"drawer-overlay\"\n v-bind=\"forwarded\"\n :class=\"\n cn(\n 'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-40 bg-black/60 backdrop-blur-sm',\n props.class\n )\n \"\n />\n</template>\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue';\nimport { DrawerContent, DrawerPortal } from 'vaul-vue';\nimport type { DialogContentEmits, DialogContentProps } from 'reka-ui';\nimport { reactiveOmit } from '@vueuse/core';\nimport { useForwardPropsEmits } from 'reka-ui';\nimport { cn } from '@/utils';\nimport ADrawerOverlay from './ADrawerOverlay.vue';\n\ndefineOptions({ inheritAttrs: false });\n\nconst props = defineProps<DialogContentProps & { class?: HTMLAttributes['class'] }>();\nconst emits = defineEmits<DialogContentEmits>();\nconst delegated = reactiveOmit(props, 'class');\nconst forwarded = useForwardPropsEmits(delegated, emits);\n</script>\n\n<template>\n <DrawerPortal>\n <ADrawerOverlay />\n <DrawerContent\n data-slot=\"drawer-content\"\n v-bind=\"{ ...$attrs, ...forwarded }\"\n :class=\"\n cn(\n 'bg-background fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border outline-none',\n props.class\n )\n \"\n >\n <div class=\"bg-muted mx-auto mt-4 h-2 w-[100px] rounded-full\" />\n <slot />\n </DrawerContent>\n </DrawerPortal>\n</template>\n"],"names":["forwarded","useForwardPropsEmits","__props","__emit","_openBlock","_createBlock","_unref","_mergeProps","_renderSlot","_ctx","useForwardProps","props","delegated","reactiveOmit","cn","emits","DrawerPortal","_createVNode","ADrawerOverlay","DrawerContent","$attrs","_createElementVNode"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAQA,UAAMA,IAAYC,EAJJC,GAGAC,CACqC;sBAIjDC,EAAA,GAAAC,EAEaC,MAFbC,EAEa,EAFD,aAAU,SAAA,GAAiBD,EAAAN,CAAA,CAAS,GAAA;AAAA,iBAC9C,MAAQ;AAAA,QAARQ,EAAQC,EAAA,QAAA,SAAA;AAAA,MAAA;;;;;;;;;;;ACRZ,UAAMT,IAAYU,EADJR,CACyB;sBAIrCE,EAAA,GAAAC,EAEgBC,MAFhBC,EAEgB,EAFD,aAAU,iBAAA,GAAyBD,EAAAN,CAAA,CAAS,GAAA;AAAA,iBACzD,MAAQ;AAAA,QAARQ,EAAQC,EAAA,QAAA,SAAA;AAAA,MAAA;;;;;;;;;;;;;ACFZ,UAAME,IAAQT,GACRU,IAAYC,EAAaF,GAAO,OAAO,GACvCX,IAAYU,EAAgBE,CAAS;sBAIzCR,EAAA,GAAAC,EASEC,MATFC,EASE,EARA,aAAU,iBAAA,GACFD,EAAAN,CAAA,GAAS;AAAA,MAChB,OAAcM,EAAAQ,CAAA;AAAA;QAA+LH,EAAM;AAAA,MAAA;AAAA;;;;;;;;;;;;;;ACNxN,UAAMA,IAAQT,GACRa,IAAQZ,GACRS,IAAYC,EAAaF,GAAO,OAAO,GACvCX,IAAYC,EAAqBW,GAAWG,CAAK;2BAIrDV,EAeeC,EAAAU,CAAA,GAAA,MAAA;AAAA,iBAdb,MAAkB;AAAA,QAAlBC,EAAkBC,CAAA;AAAA,QAClBD,EAYgBX,EAAAa,CAAA,GAZhBZ,EAYgB,EAXd,aAAU,iBAAA,GAAgB,EAAA,GACba,EAAAA,QAAM,GAAKd,EAAAN,CAAA,KAAS;AAAA,UAChC,OAAgBM,EAAAQ,CAAA;AAAA;YAAuIH,EAAM;AAAA,UAAA;AAAA;qBAO9J,MAAgE;AAAA,4BAAhEU,EAAgE,OAAA,EAA3D,OAAM,mDAAA,GAAkD,MAAA,EAAA;AAAA,YAC7Db,EAAQC,EAAA,QAAA,SAAA;AAAA,UAAA;;;;;;;;"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"APopoverContent.vue_vue_type_script_setup_true_lang-o1XhV9DM.mjs","sources":["../../entries/popover/components/APopover.vue","../../entries/popover/components/APopoverTrigger.vue","../../entries/popover/components/APopoverOverlay.vue","../../entries/popover/components/APopoverContent.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { PopoverRootEmits, PopoverRootProps } from 'reka-ui';\nimport { PopoverRoot, useForwardPropsEmits } from 'reka-ui';\n\n/**\n * Defaults `modal` to `true` so the popover locks page scroll, traps focus, and an overlay\n * (rendered by APopoverContent when `overlay` is set) actually dims the page.\n * Pass `:modal=\"false\"` for tooltip-style non-modal popovers.\n */\nconst props = withDefaults(defineProps<PopoverRootProps>(), { modal: true });\nconst emits = defineEmits<PopoverRootEmits>();\nconst forwarded = useForwardPropsEmits(props, emits);\n</script>\n\n<template>\n <PopoverRoot v-slot=\"slotProps\" data-slot=\"popover\" v-bind=\"forwarded\">\n <slot v-bind=\"slotProps\" />\n </PopoverRoot>\n</template>\n","<script setup lang=\"ts\">\nimport type { PopoverTriggerProps } from 'reka-ui';\nimport { PopoverTrigger, useForwardProps } from 'reka-ui';\n\nconst props = defineProps<PopoverTriggerProps>();\nconst forwarded = useForwardProps(props);\n</script>\n\n<template>\n <PopoverTrigger data-slot=\"popover-trigger\" v-bind=\"forwarded\">\n <slot />\n </PopoverTrigger>\n</template>\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue';\nimport { onBeforeUnmount, onMounted } from 'vue';\nimport { cn } from '@/utils';\n\ndefineOptions({ inheritAttrs: false });\n\nconst props = defineProps<{ class?: HTMLAttributes['class'] }>();\n\n// Body-scroll-lock for the lifetime of the overlay. Mounted = lock; unmounted = restore.\n// Because this component is only rendered when `<APopoverContent :overlay=\"true\">` is\n// inside the open popover portal, mount/unmount tracks visibility 1:1.\nlet prevBodyOverflow = '';\nlet prevBodyTouchAction = '';\nlet prevPaddingRight = '';\n\nfunction getScrollbarWidth() {\n if (typeof window === 'undefined') return 0;\n return window.innerWidth - document.documentElement.clientWidth;\n}\n\nonMounted(() => {\n if (typeof document === 'undefined') return;\n const body = document.body;\n const sbw = getScrollbarWidth();\n prevBodyOverflow = body.style.overflow;\n prevBodyTouchAction = body.style.touchAction;\n prevPaddingRight = body.style.paddingRight;\n body.style.overflow = 'hidden';\n body.style.touchAction = 'none';\n // Compensate for the missing scrollbar so the layout doesn't jump.\n if (sbw > 0) body.style.paddingRight = `${sbw}px`;\n});\n\nonBeforeUnmount(() => {\n if (typeof document === 'undefined') return;\n const body = document.body;\n body.style.overflow = prevBodyOverflow;\n body.style.touchAction = prevBodyTouchAction;\n body.style.paddingRight = prevPaddingRight;\n});\n</script>\n\n<template>\n <div\n data-slot=\"popover-overlay\"\n aria-hidden=\"true\"\n :class=\"\n cn(\n // `fixed inset-0` covers the entire viewport; `pointer-events-auto` captures every\n // click so it can never reach the page underneath. `z-50` keeps us above any normal\n // page chrome; the popover content sits at `z-[60]`.\n 'fixed inset-0 z-50 bg-black/60 backdrop-blur-sm pointer-events-auto data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',\n props.class\n )\n \"\n />\n</template>\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue';\nimport { reactiveOmit } from '@vueuse/core';\nimport {\n PopoverContent,\n type PopoverContentEmits,\n type PopoverContentProps,\n PopoverPortal,\n useForwardPropsEmits,\n} from 'reka-ui';\nimport { cn } from '@/utils';\nimport APopoverOverlay from './APopoverOverlay.vue';\n\ndefineOptions({ inheritAttrs: false });\n\nconst props = withDefaults(\n defineProps<\n PopoverContentProps & {\n class?: HTMLAttributes['class'];\n /** Dim the entire viewport behind the popover and block all interaction with the\n * page (clicks are captured by the overlay; body scroll is locked while open).\n * Pair with `<APopover :modal=\"true\">` (the default) for the full modal behaviour. */\n overlay?: boolean;\n overlayClass?: HTMLAttributes['class'];\n }\n >(),\n { align: 'center', sideOffset: 4, overlay: false }\n);\nconst emits = defineEmits<PopoverContentEmits>();\nconst delegated = reactiveOmit(props, 'class', 'overlay', 'overlayClass');\nconst forwarded = useForwardPropsEmits(delegated, emits);\n</script>\n\n<template>\n <PopoverPortal>\n <!--\n Overlay is a sibling of PopoverContent inside the same portal. Reka-ui's\n DismissableLayer treats any pointer-down outside the content as a dismiss,\n so clicking the overlay closes the popover for free. The overlay component\n locks body scroll on mount and restores it on unmount.\n -->\n <APopoverOverlay v-if=\"props.overlay\" :class=\"props.overlayClass\" />\n <PopoverContent\n data-slot=\"popover-content\"\n v-bind=\"{ ...$attrs, ...forwarded }\"\n :class=\"\n cn(\n 'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-[60] w-72 rounded-md border p-4 shadow-md outline-none',\n props.class\n )\n \"\n >\n <slot />\n </PopoverContent>\n </PopoverPortal>\n</template>\n"],"names":["forwarded","useForwardPropsEmits","__props","__emit","_openBlock","_createBlock","_unref","_mergeProps","_withCtx","slotProps","_renderSlot","_ctx","useForwardProps","props","prevBodyOverflow","prevBodyTouchAction","prevPaddingRight","getScrollbarWidth","onMounted","body","sbw","onBeforeUnmount","_createElementBlock","_normalizeClass","cn","emits","delegated","reactiveOmit","PopoverPortal","APopoverOverlay","_createVNode","PopoverContent","$attrs"],"mappings":";;;;;;;;;;;;;AAWA,UAAMA,IAAYC,EAFJC,GACAC,CACqC;sBAIjDC,EAAA,GAAAC,EAEcC,MAFdC,EAEc,EAFkB,aAAU,UAAA,GAAkBD,EAAAN,CAAA,CAAS,GAAA;AAAA,MACnE,SAAAQ,EAAA,CADmBC,MAAS;AAAA,QAC5BC,EAA2BC,yBAAbF,CAAS,CAAA,CAAA;AAAA,MAAA;;;;;;;;;;;ACX3B,UAAMT,IAAYY,EADJV,CACyB;sBAIrCE,EAAA,GAAAC,EAEiBC,MAFjBC,EAEiB,EAFD,aAAU,kBAAA,GAA0BD,EAAAN,CAAA,CAAS,GAAA;AAAA,iBAC3D,MAAQ;AAAA,QAARU,EAAQC,EAAA,QAAA,SAAA;AAAA,MAAA;;;;;;;;;;;ACHZ,UAAME,IAAQX;AAKd,QAAIY,IAAmB,IACnBC,IAAsB,IACtBC,IAAmB;AAEvB,aAASC,IAAoB;AAC3B,aAAI,OAAO,SAAW,MAAoB,IACnC,OAAO,aAAa,SAAS,gBAAgB;AAAA,IACtD;AAEA,WAAAC,EAAU,MAAM;AACd,UAAI,OAAO,WAAa,IAAa;AACrC,YAAMC,IAAO,SAAS,MAChBC,IAAMH,EAAA;AACZ,MAAAH,IAAmBK,EAAK,MAAM,UAC9BJ,IAAsBI,EAAK,MAAM,aACjCH,IAAmBG,EAAK,MAAM,cAC9BA,EAAK,MAAM,WAAW,UACtBA,EAAK,MAAM,cAAc,QAErBC,IAAM,MAAGD,EAAK,MAAM,eAAe,GAAGC,CAAG;AAAA,IAC/C,CAAC,GAEDC,EAAgB,MAAM;AACpB,UAAI,OAAO,WAAa,IAAa;AACrC,YAAMF,IAAO,SAAS;AACtB,MAAAA,EAAK,MAAM,WAAWL,GACtBK,EAAK,MAAM,cAAcJ,GACzBI,EAAK,MAAM,eAAeH;AAAA,IAC5B,CAAC,mBAICM,EAYE,OAAA;AAAA,MAXA,aAAU;AAAA,MACV,eAAY;AAAA,MACX,OAAKC;AAAAA,QAASjB,EAAAkB,CAAA;AAAA;AAAA;AAAA;AAAA;UAA0cX,EAAM;AAAA,QAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChCne,UAAMA,IAAQX,GAaRuB,IAAQtB,GACRuB,IAAYC,EAAad,GAAO,SAAS,WAAW,cAAc,GAClEb,IAAYC,EAAqByB,GAAWD,CAAK;2BAIrDpB,EAoBgBC,EAAAsB,CAAA,GAAA,MAAA;AAAA,iBAbd,MAAoE;AAAA,QAA7Cf,EAAM,gBAA7BR,EAAoEwB,GAAA;AAAA;UAA7B,OAAKN,EAAEV,EAAM,YAAY;AAAA,QAAA;QAChEiB,EAWiBxB,EAAAyB,CAAA,GAXjBxB,EAWiB,EAVf,aAAU,kBAAA,GAAiB,EAAA,GACdyB,EAAAA,QAAM,GAAK1B,EAAAN,CAAA,KAAS;AAAA,UAChC,OAAgBM,EAAAkB,CAAA;AAAA;YAAwcX,EAAM;AAAA,UAAA;AAAA;qBAO/d,MAAQ;AAAA,YAARH,EAAQC,EAAA,QAAA,SAAA;AAAA,UAAA;;;;;;;;"}