@jiwambe/components 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.
- package/LICENSE +21 -0
- package/README.md +367 -0
- package/dist/client.d.ts +40 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +46 -0
- package/dist/client.js.map +1 -0
- package/dist/components/Accordion/Accordion.d.ts +74 -0
- package/dist/components/Accordion/Accordion.d.ts.map +1 -0
- package/dist/components/Accordion/Accordion.js +297 -0
- package/dist/components/Accordion/Accordion.js.map +1 -0
- package/dist/components/Box/Box.d.ts +56 -0
- package/dist/components/Box/Box.d.ts.map +1 -0
- package/dist/components/Box/Box.js +51 -0
- package/dist/components/Box/Box.js.map +1 -0
- package/dist/components/Breadcrumb/Breadcrumb.d.ts +66 -0
- package/dist/components/Breadcrumb/Breadcrumb.d.ts.map +1 -0
- package/dist/components/Button/Button.d.ts +54 -0
- package/dist/components/Button/Button.d.ts.map +1 -0
- package/dist/components/Button/Button.js +92 -0
- package/dist/components/Button/Button.js.map +1 -0
- package/dist/components/Card/Card.d.ts +54 -0
- package/dist/components/Card/Card.d.ts.map +1 -0
- package/dist/components/Card/Card.js +98 -0
- package/dist/components/Card/Card.js.map +1 -0
- package/dist/components/CheckboxGroup/CheckboxGroup.d.ts +61 -0
- package/dist/components/CheckboxGroup/CheckboxGroup.d.ts.map +1 -0
- package/dist/components/CheckboxGroup/CheckboxGroup.js +205 -0
- package/dist/components/CheckboxGroup/CheckboxGroup.js.map +1 -0
- package/dist/components/Container/Container.d.ts +72 -0
- package/dist/components/Container/Container.d.ts.map +1 -0
- package/dist/components/Container/Container.js +69 -0
- package/dist/components/Container/Container.js.map +1 -0
- package/dist/components/DateInput/DateInput.d.ts +61 -0
- package/dist/components/DateInput/DateInput.d.ts.map +1 -0
- package/dist/components/DateInput/DateInput.js +234 -0
- package/dist/components/DateInput/DateInput.js.map +1 -0
- package/dist/components/Divider/Divider.d.ts +44 -0
- package/dist/components/Divider/Divider.d.ts.map +1 -0
- package/dist/components/Divider/Divider.js +35 -0
- package/dist/components/Divider/Divider.js.map +1 -0
- package/dist/components/Drawer/Drawer.d.ts +35 -0
- package/dist/components/Drawer/Drawer.d.ts.map +1 -0
- package/dist/components/Drawer/Drawer.js +37 -0
- package/dist/components/Drawer/Drawer.js.map +1 -0
- package/dist/components/FAQ/FAQ.d.ts +40 -0
- package/dist/components/FAQ/FAQ.d.ts.map +1 -0
- package/dist/components/FAQ/FAQ.js +161 -0
- package/dist/components/FAQ/FAQ.js.map +1 -0
- package/dist/components/Grid/Grid.d.ts +61 -0
- package/dist/components/Grid/Grid.d.ts.map +1 -0
- package/dist/components/Grid/Grid.js +95 -0
- package/dist/components/Grid/Grid.js.map +1 -0
- package/dist/components/Icon/Icon.d.ts +21 -0
- package/dist/components/Icon/Icon.d.ts.map +1 -0
- package/dist/components/Icon/Icon.js +167 -0
- package/dist/components/Icon/Icon.js.map +1 -0
- package/dist/components/Link/Link.d.ts +49 -0
- package/dist/components/Link/Link.d.ts.map +1 -0
- package/dist/components/Link/Link.js +70 -0
- package/dist/components/Link/Link.js.map +1 -0
- package/dist/components/List/List.d.ts +36 -0
- package/dist/components/List/List.d.ts.map +1 -0
- package/dist/components/List/List.js +42 -0
- package/dist/components/List/List.js.map +1 -0
- package/dist/components/List/index.d.ts +3 -0
- package/dist/components/List/index.d.ts.map +1 -0
- package/dist/components/Overlay/Overlay.d.ts +35 -0
- package/dist/components/Overlay/Overlay.d.ts.map +1 -0
- package/dist/components/Overlay/Overlay.js +51 -0
- package/dist/components/Overlay/Overlay.js.map +1 -0
- package/dist/components/PhoneInput/PhoneInput.d.ts +55 -0
- package/dist/components/PhoneInput/PhoneInput.d.ts.map +1 -0
- package/dist/components/PhoneInput/PhoneInput.js +255 -0
- package/dist/components/PhoneInput/PhoneInput.js.map +1 -0
- package/dist/components/Popover/Popover.d.ts +46 -0
- package/dist/components/Popover/Popover.d.ts.map +1 -0
- package/dist/components/Popover/Popover.js +57 -0
- package/dist/components/Popover/Popover.js.map +1 -0
- package/dist/components/ProductImage/ProductImage.d.ts +78 -0
- package/dist/components/ProductImage/ProductImage.d.ts.map +1 -0
- package/dist/components/ProductImage/ProductImage.js +220 -0
- package/dist/components/ProductImage/ProductImage.js.map +1 -0
- package/dist/components/RadioGroup/RadioGroup.d.ts +63 -0
- package/dist/components/RadioGroup/RadioGroup.d.ts.map +1 -0
- package/dist/components/RadioGroup/RadioGroup.js +233 -0
- package/dist/components/RadioGroup/RadioGroup.js.map +1 -0
- package/dist/components/Section/Section.d.ts +44 -0
- package/dist/components/Section/Section.d.ts.map +1 -0
- package/dist/components/Section/Section.js +48 -0
- package/dist/components/Section/Section.js.map +1 -0
- package/dist/components/Select/Select.d.ts +47 -0
- package/dist/components/Select/Select.d.ts.map +1 -0
- package/dist/components/Select/Select.js +153 -0
- package/dist/components/Select/Select.js.map +1 -0
- package/dist/components/SelectTab/SelectTab.d.ts +62 -0
- package/dist/components/SelectTab/SelectTab.d.ts.map +1 -0
- package/dist/components/SelectTab/SelectTab.js +192 -0
- package/dist/components/SelectTab/SelectTab.js.map +1 -0
- package/dist/components/Skeleton/Skeleton.d.ts +87 -0
- package/dist/components/Skeleton/Skeleton.d.ts.map +1 -0
- package/dist/components/Skeleton/Skeleton.js +97 -0
- package/dist/components/Skeleton/Skeleton.js.map +1 -0
- package/dist/components/Skeleton/index.d.ts +3 -0
- package/dist/components/Skeleton/index.d.ts.map +1 -0
- package/dist/components/Slider/Slider.d.ts +47 -0
- package/dist/components/Slider/Slider.d.ts.map +1 -0
- package/dist/components/Slider/Slider.js +147 -0
- package/dist/components/Slider/Slider.js.map +1 -0
- package/dist/components/Stack/Stack.d.ts +145 -0
- package/dist/components/Stack/Stack.d.ts.map +1 -0
- package/dist/components/Stack/Stack.js +80 -0
- package/dist/components/Stack/Stack.js.map +1 -0
- package/dist/components/Tab/Tab.d.ts +38 -0
- package/dist/components/Tab/Tab.d.ts.map +1 -0
- package/dist/components/Tab/Tab.js +146 -0
- package/dist/components/Tab/Tab.js.map +1 -0
- package/dist/components/TextArea/TextArea.d.ts +32 -0
- package/dist/components/TextArea/TextArea.d.ts.map +1 -0
- package/dist/components/TextArea/TextArea.js +118 -0
- package/dist/components/TextArea/TextArea.js.map +1 -0
- package/dist/components/TextInput/TextInput.d.ts +35 -0
- package/dist/components/TextInput/TextInput.d.ts.map +1 -0
- package/dist/components/TextInput/TextInput.js +128 -0
- package/dist/components/TextInput/TextInput.js.map +1 -0
- package/dist/components/Toggle/Toggle.d.ts +83 -0
- package/dist/components/Toggle/Toggle.d.ts.map +1 -0
- package/dist/components/Toggle/Toggle.js +121 -0
- package/dist/components/Toggle/Toggle.js.map +1 -0
- package/dist/components/Typography/Typography.d.ts +321 -0
- package/dist/components/Typography/Typography.d.ts.map +1 -0
- package/dist/components/Typography/Typography.js +21 -0
- package/dist/components/Typography/Typography.js.map +1 -0
- package/dist/components/UploadInput/UploadInput.d.ts +39 -0
- package/dist/components/UploadInput/UploadInput.d.ts.map +1 -0
- package/dist/components/UploadInput/UploadInput.js +297 -0
- package/dist/components/UploadInput/UploadInput.js.map +1 -0
- package/dist/components/index.d.ts +65 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +69 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin/jiwambe-plugin.d.ts +37 -0
- package/dist/plugin/jiwambe-plugin.d.ts.map +1 -0
- package/dist/plugin/jiwambe-plugin.js +640 -0
- package/dist/plugin/jiwambe-plugin.js.map +1 -0
- package/dist/server.d.ts +22 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +23 -0
- package/dist/server.js.map +1 -0
- package/dist/types/index.d.ts +103 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/layout.d.ts +138 -0
- package/dist/types/layout.d.ts.map +1 -0
- package/dist/types/list.d.ts +69 -0
- package/dist/types/list.d.ts.map +1 -0
- package/dist/types/list.js +9 -0
- package/dist/types/list.js.map +1 -0
- package/dist/types/skeleton.d.ts +38 -0
- package/dist/types/skeleton.d.ts.map +1 -0
- package/dist/types/skeleton.js +13 -0
- package/dist/types/skeleton.js.map +1 -0
- package/dist/types/spacing.d.ts +105 -0
- package/dist/types/spacing.d.ts.map +1 -0
- package/dist/utils/layoutClasses.d.ts +44 -0
- package/dist/utils/layoutClasses.d.ts.map +1 -0
- package/dist/utils/layoutClasses.js +88 -0
- package/dist/utils/layoutClasses.js.map +1 -0
- package/dist/utils/responsive-props.d.ts +60 -0
- package/dist/utils/responsive-props.d.ts.map +1 -0
- package/dist/utils/responsive-props.js +184 -0
- package/dist/utils/responsive-props.js.map +1 -0
- package/dist/utils/spacing.d.ts +52 -0
- package/dist/utils/spacing.d.ts.map +1 -0
- package/dist/utils/spacing.js +625 -0
- package/dist/utils/spacing.js.map +1 -0
- package/package.json +96 -0
- package/tailwind.preset.d.ts +3 -0
- package/tailwind.preset.ts +21 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect } from "react";
|
|
4
|
+
function Overlay({
|
|
5
|
+
open,
|
|
6
|
+
onClose,
|
|
7
|
+
closeOnClick = true,
|
|
8
|
+
lockScroll = true,
|
|
9
|
+
children,
|
|
10
|
+
className = "",
|
|
11
|
+
style,
|
|
12
|
+
ref,
|
|
13
|
+
...rest
|
|
14
|
+
}) {
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
if (!lockScroll) return;
|
|
17
|
+
if (open) {
|
|
18
|
+
const prev = document.body.style.overflow;
|
|
19
|
+
document.body.style.overflow = "hidden";
|
|
20
|
+
return () => {
|
|
21
|
+
document.body.style.overflow = prev;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
}, [open, lockScroll]);
|
|
25
|
+
if (!open) return null;
|
|
26
|
+
const handleBackdropClick = (e) => {
|
|
27
|
+
if (closeOnClick && e.target === e.currentTarget) {
|
|
28
|
+
onClose == null ? void 0 : onClose();
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const classes = [
|
|
32
|
+
"fixed inset-0 z-40 bg-fill-bg-dimmer",
|
|
33
|
+
className
|
|
34
|
+
].filter(Boolean).join(" ");
|
|
35
|
+
return /* @__PURE__ */ jsx(
|
|
36
|
+
"div",
|
|
37
|
+
{
|
|
38
|
+
ref,
|
|
39
|
+
className: classes,
|
|
40
|
+
style,
|
|
41
|
+
onClick: handleBackdropClick,
|
|
42
|
+
"aria-hidden": "true",
|
|
43
|
+
...rest,
|
|
44
|
+
children
|
|
45
|
+
}
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
export {
|
|
49
|
+
Overlay
|
|
50
|
+
};
|
|
51
|
+
//# sourceMappingURL=Overlay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Overlay.js","sources":["../../../src/components/Overlay/Overlay.tsx"],"sourcesContent":["'use client';\n\nimport React, { useEffect } from 'react';\n\n/**\n * Props for the Overlay component. Control visibility with open; use onClose to respond to backdrop click.\n */\nexport interface OverlayProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Whether the overlay is visible. When false, nothing is rendered. */\n open: boolean;\n /** Called when the user dismisses (e.g. backdrop click). Use to set open to false. @default undefined */\n onClose?: () => void;\n /** When true, clicking the backdrop calls onClose. @default true */\n closeOnClick?: boolean;\n /** When true, body scroll is locked while open. @default true */\n lockScroll?: boolean;\n /** Content rendered above the backdrop (e.g. Drawer, modal dialog). @default undefined */\n children?: React.ReactNode;\n /** Forwarded ref for the root div. @default undefined */\n ref?: React.Ref<HTMLDivElement>;\n}\n\n/**\n * Full-screen dimmer backdrop for modals, drawers, and dialogs. Renders a fixed overlay\n * (z-index 40) and optional lock scroll. Renders nothing when open is false. Place\n * Drawer or dialog content as children; control open/onClose in parent state.\n *\n * @example\n * <Overlay open={isOpen} onClose={() => setIsOpen(false)}>\n * <Drawer anchor=\"right\">...</Drawer>\n * </Overlay>\n *\n * @example\n * <Overlay open={open} onClose={close} closeOnClick={false}>\n * <div role=\"dialog\">Must use button to close</div>\n * </Overlay>\n */\nexport function Overlay({\n open,\n onClose,\n closeOnClick = true,\n lockScroll = true,\n children,\n className = '',\n style,\n ref,\n ...rest\n}: OverlayProps) {\n useEffect(() => {\n if (!lockScroll) return;\n if (open) {\n const prev = document.body.style.overflow;\n document.body.style.overflow = 'hidden';\n return () => {\n document.body.style.overflow = prev;\n };\n }\n }, [open, lockScroll]);\n\n if (!open) return null;\n\n const handleBackdropClick = (e: React.MouseEvent<HTMLDivElement>) => {\n if (closeOnClick && e.target === e.currentTarget) {\n onClose?.();\n }\n };\n\n const classes = [\n 'fixed inset-0 z-40 bg-fill-bg-dimmer',\n className,\n ]\n .filter(Boolean)\n .join(' ');\n\n return (\n <div\n ref={ref}\n className={classes}\n style={style}\n onClick={handleBackdropClick}\n aria-hidden=\"true\"\n {...rest}\n >\n {children}\n </div>\n );\n}\n"],"names":[],"mappings":";;;AAqCO;AAAiB;AACtB;AACA;AACe;AACF;AACb;AACY;AACZ;AACA;AAEF;AACE;AACE;AACA;AACE;AACA;AACA;AACE;AAA+B;AACjC;AACF;AAGF;AAEA;AACE;AACE;AAAA;AACF;AAGF;AAAgB;AACd;AACA;AAKF;AACE;AAAC;AAAA;AACC;AACW;AACX;AACS;AACG;AACR;AAEH;AAAA;AAGP;;;;"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Shape of a country entry for the phone input country selector.
|
|
4
|
+
* iso3 is the key used for controlled/default country (e.g. "KEN").
|
|
5
|
+
*/
|
|
6
|
+
export interface PhoneCountry {
|
|
7
|
+
iso3: string;
|
|
8
|
+
iso2: string;
|
|
9
|
+
label: string;
|
|
10
|
+
dialCode: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Predefined list of East Africa countries (Burundi, DR Congo, Ethiopia, Kenya,
|
|
14
|
+
* Rwanda, Sudan, South Sudan, Somalia, Tanzania, Uganda). Use as the countries
|
|
15
|
+
* prop value when you only need East African numbers, or pass a custom array
|
|
16
|
+
* for other regions.
|
|
17
|
+
*/
|
|
18
|
+
export declare const EAST_AFRICA_COUNTRIES: PhoneCountry[];
|
|
19
|
+
/**
|
|
20
|
+
* Props for the PhoneInput component. Renders a country selector (ISO-3) plus a tel input.
|
|
21
|
+
* Country can be controlled (country/onCountryChange) or uncontrolled (defaultCountry).
|
|
22
|
+
*/
|
|
23
|
+
export interface PhoneInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size' | 'type'> {
|
|
24
|
+
/** Label text displayed above the input. @default undefined */
|
|
25
|
+
label?: string;
|
|
26
|
+
/** Secondary label shown lighter beside the main label. @default undefined */
|
|
27
|
+
secondaryLabel?: string;
|
|
28
|
+
/** Supportive text rendered below the label. @default undefined */
|
|
29
|
+
supportText?: string;
|
|
30
|
+
/** Controlled country ISO-3 code (e.g. "KEN"). Use with onCountryChange. @default undefined */
|
|
31
|
+
country?: string;
|
|
32
|
+
/** Default country ISO-3 code (uncontrolled). @default 'KEN' */
|
|
33
|
+
defaultCountry?: string;
|
|
34
|
+
/** Called when the selected country changes. @default undefined */
|
|
35
|
+
onCountryChange?: (country: PhoneCountry) => void;
|
|
36
|
+
/** Places the input in an error state. @default false */
|
|
37
|
+
error?: boolean;
|
|
38
|
+
/** Error message shown in the alert below the input when error is true. @default undefined */
|
|
39
|
+
errorMessage?: string;
|
|
40
|
+
/** Forwarded ref for the tel input element. @default undefined */
|
|
41
|
+
ref?: React.Ref<HTMLInputElement>;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Phone number input with a country selector dropdown. Renders country code (e.g. KE +254)
|
|
45
|
+
* plus a tel input. Use EAST_AFRICA_COUNTRIES as the default country list, or pass a custom
|
|
46
|
+
* list. Supports controlled or uncontrolled country selection.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* <PhoneInput label="Phone" defaultCountry="KEN" placeholder="712 345 678" />
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* <PhoneInput country={country} onCountryChange={setCountry} error={!!err} errorMessage={err} />
|
|
53
|
+
*/
|
|
54
|
+
export declare function PhoneInput({ label, secondaryLabel, supportText, country: countryProp, defaultCountry, onCountryChange, error, errorMessage, required, disabled, className, id: idProp, placeholder, ref, ...rest }: PhoneInputProps): import("react/jsx-runtime").JSX.Element;
|
|
55
|
+
//# sourceMappingURL=PhoneInput.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PhoneInput.d.ts","sourceRoot":"","sources":["../../../src/components/PhoneInput/PhoneInput.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA0D,MAAM,OAAO,CAAC;AAM/E;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,EAAE,YAAY,EAW/C,CAAC;AAMF;;;GAGG;AACH,MAAM,WAAW,eACf,SAAQ,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1E,+DAA+D;IAC/D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+FAA+F;IAC/F,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mEAAmE;IACnE,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,IAAI,CAAC;IAClD,yDAAyD;IACzD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,8FAA8F;IAC9F,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kEAAkE;IAClE,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;CACnC;AAmDD;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,cAAc,EACd,WAAW,EACX,OAAO,EAAE,WAAW,EACpB,cAAsB,EACtB,eAAe,EACf,KAAa,EACb,YAAY,EACZ,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,EAAE,EAAE,MAAM,EACV,WAA2B,EAC3B,GAAG,EACH,GAAG,IAAI,EACR,EAAE,eAAe,2CAkOjB"}
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useId, useState, useRef, useCallback, useEffect } from "react";
|
|
4
|
+
const EAST_AFRICA_COUNTRIES = [
|
|
5
|
+
{ iso3: "BDI", iso2: "BI", label: "Burundi", dialCode: "+257" },
|
|
6
|
+
{ iso3: "COD", iso2: "CD", label: "DR Congo", dialCode: "+243" },
|
|
7
|
+
{ iso3: "ETH", iso2: "ET", label: "Ethiopia", dialCode: "+251" },
|
|
8
|
+
{ iso3: "KEN", iso2: "KE", label: "Kenya", dialCode: "+254" },
|
|
9
|
+
{ iso3: "RWA", iso2: "RW", label: "Rwanda", dialCode: "+250" },
|
|
10
|
+
{ iso3: "SDN", iso2: "SD", label: "Sudan", dialCode: "+249" },
|
|
11
|
+
{ iso3: "SSD", iso2: "SS", label: "South Sudan", dialCode: "+211" },
|
|
12
|
+
{ iso3: "SOM", iso2: "SO", label: "Somalia", dialCode: "+252" },
|
|
13
|
+
{ iso3: "TZA", iso2: "TZ", label: "Tanzania", dialCode: "+255" },
|
|
14
|
+
{ iso3: "UGA", iso2: "UG", label: "Uganda", dialCode: "+256" }
|
|
15
|
+
];
|
|
16
|
+
function ChevronDown({ className }) {
|
|
17
|
+
return /* @__PURE__ */ jsx(
|
|
18
|
+
"svg",
|
|
19
|
+
{
|
|
20
|
+
className,
|
|
21
|
+
viewBox: "0 0 24 24",
|
|
22
|
+
fill: "none",
|
|
23
|
+
stroke: "currentColor",
|
|
24
|
+
strokeWidth: "1.25",
|
|
25
|
+
strokeLinecap: "round",
|
|
26
|
+
strokeLinejoin: "round",
|
|
27
|
+
"aria-hidden": "true",
|
|
28
|
+
children: /* @__PURE__ */ jsx("path", { d: "M6 9L12 15L18 9" })
|
|
29
|
+
}
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
function ErrorIcon({ className }) {
|
|
33
|
+
return /* @__PURE__ */ jsx(
|
|
34
|
+
"svg",
|
|
35
|
+
{
|
|
36
|
+
className,
|
|
37
|
+
viewBox: "0 0 20 20",
|
|
38
|
+
fill: "currentColor",
|
|
39
|
+
"aria-hidden": "true",
|
|
40
|
+
children: /* @__PURE__ */ jsx(
|
|
41
|
+
"path",
|
|
42
|
+
{
|
|
43
|
+
fillRule: "evenodd",
|
|
44
|
+
d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z",
|
|
45
|
+
clipRule: "evenodd"
|
|
46
|
+
}
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
function resolveCountry(iso3) {
|
|
52
|
+
return EAST_AFRICA_COUNTRIES.find((c) => c.iso3 === iso3) ?? EAST_AFRICA_COUNTRIES.find((c) => c.iso3 === "KEN");
|
|
53
|
+
}
|
|
54
|
+
function PhoneInput({
|
|
55
|
+
label,
|
|
56
|
+
secondaryLabel,
|
|
57
|
+
supportText,
|
|
58
|
+
country: countryProp,
|
|
59
|
+
defaultCountry = "KEN",
|
|
60
|
+
onCountryChange,
|
|
61
|
+
error = false,
|
|
62
|
+
errorMessage,
|
|
63
|
+
required,
|
|
64
|
+
disabled,
|
|
65
|
+
className,
|
|
66
|
+
id: idProp,
|
|
67
|
+
placeholder = "Placeholder",
|
|
68
|
+
ref,
|
|
69
|
+
...rest
|
|
70
|
+
}) {
|
|
71
|
+
const autoId = useId();
|
|
72
|
+
const id = idProp ?? autoId;
|
|
73
|
+
const isCountryControlled = countryProp !== void 0;
|
|
74
|
+
const [internalCountry, setInternalCountry] = useState(defaultCountry);
|
|
75
|
+
const activeIso = isCountryControlled ? countryProp : internalCountry;
|
|
76
|
+
const selected = resolveCountry(activeIso);
|
|
77
|
+
const [open, setOpen] = useState(false);
|
|
78
|
+
const dropdownRef = useRef(null);
|
|
79
|
+
const triggerRef = useRef(null);
|
|
80
|
+
const selectCountry = useCallback(
|
|
81
|
+
(c) => {
|
|
82
|
+
var _a;
|
|
83
|
+
if (!isCountryControlled) setInternalCountry(c.iso3);
|
|
84
|
+
onCountryChange == null ? void 0 : onCountryChange(c);
|
|
85
|
+
setOpen(false);
|
|
86
|
+
(_a = triggerRef.current) == null ? void 0 : _a.focus();
|
|
87
|
+
},
|
|
88
|
+
[isCountryControlled, onCountryChange]
|
|
89
|
+
);
|
|
90
|
+
useEffect(() => {
|
|
91
|
+
if (!open) return;
|
|
92
|
+
function handleClick(e) {
|
|
93
|
+
if (dropdownRef.current && !dropdownRef.current.contains(e.target) && triggerRef.current && !triggerRef.current.contains(e.target)) {
|
|
94
|
+
setOpen(false);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
document.addEventListener("mousedown", handleClick);
|
|
98
|
+
return () => document.removeEventListener("mousedown", handleClick);
|
|
99
|
+
}, [open]);
|
|
100
|
+
const handleDropdownKeyDown = (e) => {
|
|
101
|
+
var _a;
|
|
102
|
+
if (e.key === "Escape") {
|
|
103
|
+
setOpen(false);
|
|
104
|
+
(_a = triggerRef.current) == null ? void 0 : _a.focus();
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
const containerClasses = [
|
|
108
|
+
"phone-input-container",
|
|
109
|
+
"relative flex items-center gap-space-2 min-h-[48px]",
|
|
110
|
+
"pl-space-4 pr-space-3 py-space-3",
|
|
111
|
+
"rounded-rad-md outline-none",
|
|
112
|
+
"transition-all duration-150",
|
|
113
|
+
!disabled && !error && "border-border-sm border-border-form-primary bg-fill-form-primary",
|
|
114
|
+
!disabled && error && "border-border-sm border-border-err bg-fill-form-primary",
|
|
115
|
+
!disabled && "hover:border-border-md hover:border-border-form-primary-hover",
|
|
116
|
+
!disabled && "has-[:focus]:border-border-md has-[:focus]:border-border-form-primary-active",
|
|
117
|
+
!disabled && [
|
|
118
|
+
"has-[:focus-visible]:border-border-sm has-[:focus-visible]:border-border-form-primary-focus",
|
|
119
|
+
"has-[:focus-visible]:ring-[1.5px] has-[:focus-visible]:ring-border-focus has-[:focus-visible]:ring-offset-[3px]"
|
|
120
|
+
].join(" "),
|
|
121
|
+
disabled && "border-border-sm border-border-form-primary-disabled bg-fill-form-primary-disabled cursor-not-allowed",
|
|
122
|
+
className
|
|
123
|
+
].filter(Boolean).join(" ");
|
|
124
|
+
const showErrorAlert = error && errorMessage;
|
|
125
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-space-2 w-full", children: [
|
|
126
|
+
(label || supportText) && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-space-1", children: [
|
|
127
|
+
label && /* @__PURE__ */ jsxs(
|
|
128
|
+
"label",
|
|
129
|
+
{
|
|
130
|
+
htmlFor: id,
|
|
131
|
+
className: `text-form-label ${disabled ? "text-text-disabled" : "text-text-primary"}`,
|
|
132
|
+
children: [
|
|
133
|
+
label,
|
|
134
|
+
secondaryLabel && /* @__PURE__ */ jsx("span", { className: "text-text-secondary font-normal ml-1", children: secondaryLabel }),
|
|
135
|
+
required && /* @__PURE__ */ jsx("span", { className: "text-text-err ml-0.5", children: "*" })
|
|
136
|
+
]
|
|
137
|
+
}
|
|
138
|
+
),
|
|
139
|
+
supportText && /* @__PURE__ */ jsx(
|
|
140
|
+
"p",
|
|
141
|
+
{
|
|
142
|
+
className: `text-text-xs ${disabled ? "text-text-disabled" : "text-text-secondary"}`,
|
|
143
|
+
children: supportText
|
|
144
|
+
}
|
|
145
|
+
)
|
|
146
|
+
] }),
|
|
147
|
+
/* @__PURE__ */ jsxs("div", { className: containerClasses, children: [
|
|
148
|
+
/* @__PURE__ */ jsxs(
|
|
149
|
+
"button",
|
|
150
|
+
{
|
|
151
|
+
ref: triggerRef,
|
|
152
|
+
type: "button",
|
|
153
|
+
disabled,
|
|
154
|
+
"aria-haspopup": "listbox",
|
|
155
|
+
"aria-expanded": open,
|
|
156
|
+
onClick: () => setOpen((prev) => !prev),
|
|
157
|
+
className: `flex items-center gap-space-2 shrink-0 text-form-text outline-none bg-transparent ${disabled ? "text-text-disabled cursor-not-allowed" : "text-text-primary"}`,
|
|
158
|
+
children: [
|
|
159
|
+
/* @__PURE__ */ jsxs("span", { className: "whitespace-nowrap", children: [
|
|
160
|
+
selected.iso2,
|
|
161
|
+
" ",
|
|
162
|
+
selected.dialCode
|
|
163
|
+
] }),
|
|
164
|
+
/* @__PURE__ */ jsx(
|
|
165
|
+
ChevronDown,
|
|
166
|
+
{
|
|
167
|
+
className: `w-5 h-5 shrink-0 transition-transform duration-150 ${open ? "rotate-180" : ""} ${disabled ? "text-icon-primary-disabled" : "text-icon-primary"}`
|
|
168
|
+
}
|
|
169
|
+
)
|
|
170
|
+
]
|
|
171
|
+
}
|
|
172
|
+
),
|
|
173
|
+
open && !disabled && /* @__PURE__ */ jsx(
|
|
174
|
+
"div",
|
|
175
|
+
{
|
|
176
|
+
ref: dropdownRef,
|
|
177
|
+
role: "listbox",
|
|
178
|
+
"aria-label": "Select country",
|
|
179
|
+
onKeyDown: handleDropdownKeyDown,
|
|
180
|
+
className: "absolute left-0 top-full mt-space-1 z-50 w-full min-w-[200px] max-h-[240px] overflow-y-auto rounded-rad-md border-border-sm border-border-form-primary bg-fill-form-primary shadow-elev-sm",
|
|
181
|
+
children: EAST_AFRICA_COUNTRIES.map((c) => {
|
|
182
|
+
const isActive = c.iso3 === selected.iso3;
|
|
183
|
+
return /* @__PURE__ */ jsxs(
|
|
184
|
+
"button",
|
|
185
|
+
{
|
|
186
|
+
type: "button",
|
|
187
|
+
role: "option",
|
|
188
|
+
"aria-selected": isActive,
|
|
189
|
+
onClick: () => selectCountry(c),
|
|
190
|
+
className: `flex w-full items-center gap-space-3 px-space-4 py-space-3 text-form-text text-left outline-none transition-colors ${isActive ? "bg-green-50 text-green-900 font-medium" : "text-text-primary hover:bg-neutral-50"} focus-visible:bg-neutral-100`,
|
|
191
|
+
children: [
|
|
192
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 w-8 text-text-xs text-text-secondary", children: c.iso2 }),
|
|
193
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1 truncate", children: c.label }),
|
|
194
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 text-text-secondary", children: c.dialCode })
|
|
195
|
+
]
|
|
196
|
+
},
|
|
197
|
+
c.iso3
|
|
198
|
+
);
|
|
199
|
+
})
|
|
200
|
+
}
|
|
201
|
+
),
|
|
202
|
+
/* @__PURE__ */ jsx(
|
|
203
|
+
"span",
|
|
204
|
+
{
|
|
205
|
+
className: "text-form-text text-text-disabled shrink-0 select-none",
|
|
206
|
+
"aria-hidden": "true",
|
|
207
|
+
children: "|"
|
|
208
|
+
}
|
|
209
|
+
),
|
|
210
|
+
/* @__PURE__ */ jsx(
|
|
211
|
+
"input",
|
|
212
|
+
{
|
|
213
|
+
ref,
|
|
214
|
+
id,
|
|
215
|
+
type: "tel",
|
|
216
|
+
disabled,
|
|
217
|
+
required,
|
|
218
|
+
placeholder,
|
|
219
|
+
"aria-invalid": error || void 0,
|
|
220
|
+
"aria-describedby": showErrorAlert ? `${id}-error` : void 0,
|
|
221
|
+
className: `flex-1 min-w-0 bg-transparent text-form-text outline-none placeholder:text-text-disabled ${disabled ? "text-text-disabled cursor-not-allowed" : "text-text-primary"}`,
|
|
222
|
+
...rest
|
|
223
|
+
}
|
|
224
|
+
)
|
|
225
|
+
] }),
|
|
226
|
+
showErrorAlert && /* @__PURE__ */ jsxs(
|
|
227
|
+
"div",
|
|
228
|
+
{
|
|
229
|
+
id: `${id}-error`,
|
|
230
|
+
role: "alert",
|
|
231
|
+
className: `flex items-start gap-space-4 p-space-4 rounded-rad-md ${disabled ? "bg-fill-bg-secondary" : "bg-fill-bg-err"}`,
|
|
232
|
+
children: [
|
|
233
|
+
/* @__PURE__ */ jsx(
|
|
234
|
+
ErrorIcon,
|
|
235
|
+
{
|
|
236
|
+
className: `w-5 h-5 shrink-0 ${disabled ? "text-icon-primary-disabled" : "text-icon-err"}`
|
|
237
|
+
}
|
|
238
|
+
),
|
|
239
|
+
/* @__PURE__ */ jsx(
|
|
240
|
+
"span",
|
|
241
|
+
{
|
|
242
|
+
className: `text-text-xs ${disabled ? "text-text-disabled" : "text-text-err"}`,
|
|
243
|
+
children: errorMessage
|
|
244
|
+
}
|
|
245
|
+
)
|
|
246
|
+
]
|
|
247
|
+
}
|
|
248
|
+
)
|
|
249
|
+
] });
|
|
250
|
+
}
|
|
251
|
+
export {
|
|
252
|
+
EAST_AFRICA_COUNTRIES,
|
|
253
|
+
PhoneInput
|
|
254
|
+
};
|
|
255
|
+
//# sourceMappingURL=PhoneInput.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PhoneInput.js","sources":["../../../src/components/PhoneInput/PhoneInput.tsx"],"sourcesContent":["'use client';\n\nimport React, { useId, useState, useRef, useEffect, useCallback } from 'react';\n\n// ---------------------------------------------------------------------------\n// Country data (East Africa)\n// ---------------------------------------------------------------------------\n\n/**\n * Shape of a country entry for the phone input country selector.\n * iso3 is the key used for controlled/default country (e.g. \"KEN\").\n */\nexport interface PhoneCountry {\n iso3: string;\n iso2: string;\n label: string;\n dialCode: string;\n}\n\n/**\n * Predefined list of East Africa countries (Burundi, DR Congo, Ethiopia, Kenya,\n * Rwanda, Sudan, South Sudan, Somalia, Tanzania, Uganda). Use as the countries\n * prop value when you only need East African numbers, or pass a custom array\n * for other regions.\n */\nexport const EAST_AFRICA_COUNTRIES: PhoneCountry[] = [\n { iso3: 'BDI', iso2: 'BI', label: 'Burundi', dialCode: '+257' },\n { iso3: 'COD', iso2: 'CD', label: 'DR Congo', dialCode: '+243' },\n { iso3: 'ETH', iso2: 'ET', label: 'Ethiopia', dialCode: '+251' },\n { iso3: 'KEN', iso2: 'KE', label: 'Kenya', dialCode: '+254' },\n { iso3: 'RWA', iso2: 'RW', label: 'Rwanda', dialCode: '+250' },\n { iso3: 'SDN', iso2: 'SD', label: 'Sudan', dialCode: '+249' },\n { iso3: 'SSD', iso2: 'SS', label: 'South Sudan', dialCode: '+211' },\n { iso3: 'SOM', iso2: 'SO', label: 'Somalia', dialCode: '+252' },\n { iso3: 'TZA', iso2: 'TZ', label: 'Tanzania', dialCode: '+255' },\n { iso3: 'UGA', iso2: 'UG', label: 'Uganda', dialCode: '+256' },\n];\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * Props for the PhoneInput component. Renders a country selector (ISO-3) plus a tel input.\n * Country can be controlled (country/onCountryChange) or uncontrolled (defaultCountry).\n */\nexport interface PhoneInputProps\n extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size' | 'type'> {\n /** Label text displayed above the input. @default undefined */\n label?: string;\n /** Secondary label shown lighter beside the main label. @default undefined */\n secondaryLabel?: string;\n /** Supportive text rendered below the label. @default undefined */\n supportText?: string;\n /** Controlled country ISO-3 code (e.g. \"KEN\"). Use with onCountryChange. @default undefined */\n country?: string;\n /** Default country ISO-3 code (uncontrolled). @default 'KEN' */\n defaultCountry?: string;\n /** Called when the selected country changes. @default undefined */\n onCountryChange?: (country: PhoneCountry) => void;\n /** Places the input in an error state. @default false */\n error?: boolean;\n /** Error message shown in the alert below the input when error is true. @default undefined */\n errorMessage?: string;\n /** Forwarded ref for the tel input element. @default undefined */\n ref?: React.Ref<HTMLInputElement>;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction ChevronDown({ className }: { className?: string }) {\n return (\n <svg\n className={className}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.25\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M6 9L12 15L18 9\" />\n </svg>\n );\n}\n\nfunction ErrorIcon({ className }: { className?: string }) {\n return (\n <svg\n className={className}\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z\"\n clipRule=\"evenodd\"\n />\n </svg>\n );\n}\n\nfunction resolveCountry(iso3?: string): PhoneCountry {\n return (\n EAST_AFRICA_COUNTRIES.find((c) => c.iso3 === iso3) ??\n EAST_AFRICA_COUNTRIES.find((c) => c.iso3 === 'KEN')!\n );\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\n/**\n * Phone number input with a country selector dropdown. Renders country code (e.g. KE +254)\n * plus a tel input. Use EAST_AFRICA_COUNTRIES as the default country list, or pass a custom\n * list. Supports controlled or uncontrolled country selection.\n *\n * @example\n * <PhoneInput label=\"Phone\" defaultCountry=\"KEN\" placeholder=\"712 345 678\" />\n *\n * @example\n * <PhoneInput country={country} onCountryChange={setCountry} error={!!err} errorMessage={err} />\n */\nexport function PhoneInput({\n label,\n secondaryLabel,\n supportText,\n country: countryProp,\n defaultCountry = 'KEN',\n onCountryChange,\n error = false,\n errorMessage,\n required,\n disabled,\n className,\n id: idProp,\n placeholder = 'Placeholder',\n ref,\n ...rest\n}: PhoneInputProps) {\n const autoId = useId();\n const id = idProp ?? autoId;\n\n // Country selection\n const isCountryControlled = countryProp !== undefined;\n const [internalCountry, setInternalCountry] = useState(defaultCountry);\n const activeIso = isCountryControlled ? countryProp : internalCountry;\n const selected = resolveCountry(activeIso);\n\n // Dropdown state\n const [open, setOpen] = useState(false);\n const dropdownRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLButtonElement>(null);\n\n const selectCountry = useCallback(\n (c: PhoneCountry) => {\n if (!isCountryControlled) setInternalCountry(c.iso3);\n onCountryChange?.(c);\n setOpen(false);\n triggerRef.current?.focus();\n },\n [isCountryControlled, onCountryChange],\n );\n\n // Close dropdown on click outside\n useEffect(() => {\n if (!open) return;\n function handleClick(e: MouseEvent) {\n if (\n dropdownRef.current &&\n !dropdownRef.current.contains(e.target as Node) &&\n triggerRef.current &&\n !triggerRef.current.contains(e.target as Node)\n ) {\n setOpen(false);\n }\n }\n document.addEventListener('mousedown', handleClick);\n return () => document.removeEventListener('mousedown', handleClick);\n }, [open]);\n\n // Keyboard nav inside dropdown\n const handleDropdownKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Escape') {\n setOpen(false);\n triggerRef.current?.focus();\n }\n };\n\n // Container classes — border reacts to any child focus\n const containerClasses = [\n 'phone-input-container',\n 'relative flex items-center gap-space-2 min-h-[48px]',\n 'pl-space-4 pr-space-3 py-space-3',\n 'rounded-rad-md outline-none',\n 'transition-all duration-150',\n\n !disabled && !error &&\n 'border-border-sm border-border-form-primary bg-fill-form-primary',\n !disabled && error &&\n 'border-border-sm border-border-err bg-fill-form-primary',\n\n !disabled &&\n 'hover:border-border-md hover:border-border-form-primary-hover',\n\n !disabled &&\n 'has-[:focus]:border-border-md has-[:focus]:border-border-form-primary-active',\n\n !disabled && [\n 'has-[:focus-visible]:border-border-sm has-[:focus-visible]:border-border-form-primary-focus',\n 'has-[:focus-visible]:ring-[1.5px] has-[:focus-visible]:ring-border-focus has-[:focus-visible]:ring-offset-[3px]',\n ].join(' '),\n\n disabled &&\n 'border-border-sm border-border-form-primary-disabled bg-fill-form-primary-disabled cursor-not-allowed',\n\n className,\n ]\n .filter(Boolean)\n .join(' ');\n\n const showErrorAlert = error && errorMessage;\n\n return (\n <div className=\"flex flex-col gap-space-2 w-full\">\n {/* Label + support text */}\n {(label || supportText) && (\n <div className=\"flex flex-col gap-space-1\">\n {label && (\n <label\n htmlFor={id}\n className={`text-form-label ${disabled ? 'text-text-disabled' : 'text-text-primary'}`}\n >\n {label}\n {secondaryLabel && (\n <span className=\"text-text-secondary font-normal ml-1\">\n {secondaryLabel}\n </span>\n )}\n {required && (\n <span className=\"text-text-err ml-0.5\">*</span>\n )}\n </label>\n )}\n {supportText && (\n <p\n className={`text-text-xs ${disabled ? 'text-text-disabled' : 'text-text-secondary'}`}\n >\n {supportText}\n </p>\n )}\n </div>\n )}\n\n {/* Input container */}\n <div className={containerClasses}>\n {/* Country selector button */}\n <button\n ref={triggerRef}\n type=\"button\"\n disabled={disabled}\n aria-haspopup=\"listbox\"\n aria-expanded={open}\n onClick={() => setOpen((prev) => !prev)}\n className={`flex items-center gap-space-2 shrink-0 text-form-text outline-none bg-transparent ${\n disabled ? 'text-text-disabled cursor-not-allowed' : 'text-text-primary'\n }`}\n >\n <span className=\"whitespace-nowrap\">\n {selected.iso2} {selected.dialCode}\n </span>\n <ChevronDown\n className={`w-5 h-5 shrink-0 transition-transform duration-150 ${\n open ? 'rotate-180' : ''\n } ${disabled ? 'text-icon-primary-disabled' : 'text-icon-primary'}`}\n />\n </button>\n\n {/* Dropdown */}\n {open && !disabled && (\n <div\n ref={dropdownRef}\n role=\"listbox\"\n aria-label=\"Select country\"\n onKeyDown={handleDropdownKeyDown}\n className=\"absolute left-0 top-full mt-space-1 z-50 w-full min-w-[200px] max-h-[240px] overflow-y-auto rounded-rad-md border-border-sm border-border-form-primary bg-fill-form-primary shadow-elev-sm\"\n >\n {EAST_AFRICA_COUNTRIES.map((c) => {\n const isActive = c.iso3 === selected.iso3;\n return (\n <button\n key={c.iso3}\n type=\"button\"\n role=\"option\"\n aria-selected={isActive}\n onClick={() => selectCountry(c)}\n className={`flex w-full items-center gap-space-3 px-space-4 py-space-3 text-form-text text-left outline-none transition-colors ${\n isActive\n ? 'bg-green-50 text-green-900 font-medium'\n : 'text-text-primary hover:bg-neutral-50'\n } focus-visible:bg-neutral-100`}\n >\n <span className=\"shrink-0 w-8 text-text-xs text-text-secondary\">\n {c.iso2}\n </span>\n <span className=\"flex-1 truncate\">{c.label}</span>\n <span className=\"shrink-0 text-text-secondary\">\n {c.dialCode}\n </span>\n </button>\n );\n })}\n </div>\n )}\n\n {/* Separator */}\n <span\n className=\"text-form-text text-text-disabled shrink-0 select-none\"\n aria-hidden=\"true\"\n >\n |\n </span>\n\n {/* Phone number input */}\n <input\n ref={ref}\n id={id}\n type=\"tel\"\n disabled={disabled}\n required={required}\n placeholder={placeholder}\n aria-invalid={error || undefined}\n aria-describedby={showErrorAlert ? `${id}-error` : undefined}\n className={`flex-1 min-w-0 bg-transparent text-form-text outline-none placeholder:text-text-disabled ${\n disabled ? 'text-text-disabled cursor-not-allowed' : 'text-text-primary'\n }`}\n {...rest}\n />\n </div>\n\n {/* Error alert */}\n {showErrorAlert && (\n <div\n id={`${id}-error`}\n role=\"alert\"\n className={`flex items-start gap-space-4 p-space-4 rounded-rad-md ${\n disabled ? 'bg-fill-bg-secondary' : 'bg-fill-bg-err'\n }`}\n >\n <ErrorIcon\n className={`w-5 h-5 shrink-0 ${\n disabled ? 'text-icon-primary-disabled' : 'text-icon-err'\n }`}\n />\n <span\n className={`text-text-xs ${\n disabled ? 'text-text-disabled' : 'text-text-err'\n }`}\n >\n {errorMessage}\n </span>\n </div>\n )}\n </div>\n );\n}\n"],"names":[],"mappings":";;;AAyBO;AAA8C;AACI;AACC;AACA;AACH;AACC;AACD;AACM;AACJ;AACC;AAE1D;AAoCA;AACE;AACE;AAAC;AAAA;AACC;AACQ;AACH;AACE;AACK;AACE;AACC;AACH;AAEc;AAAA;AAGhC;AAEA;AACE;AACE;AAAC;AAAA;AACC;AACQ;AACH;AACO;AAEZ;AAAC;AAAA;AACU;AACP;AACO;AAAA;AAAA;AACX;AAGN;AAEA;AACE;AAIF;AAiBO;AAAoB;AACzB;AACA;AACA;AACS;AACQ;AACjB;AACQ;AACR;AACA;AACA;AACA;AACI;AACU;AACd;AAEF;AACE;AACA;AAGA;AACA;AACA;AACA;AAGA;AACA;AACA;AAEA;AAAsB;;AAElB;AACA;AACA;AACA;AAAoB;AACtB;AACqC;AAIvC;AACE;AACA;AACE;AAME;AAAa;AACf;AAEF;AACA;AAAkE;AAIpE;;AACE;AACE;AACA;AAAoB;AACtB;AAIF;AAAyB;AACvB;AACA;AACA;AACA;AACA;AAGE;AAEA;AAGA;AAGA;AAEW;AACX;AACA;AACQ;AAGR;AAEF;AAKF;AAEA;AAGM;AAEG;AACC;AAAC;AAAA;AACU;AAC0E;AAElF;AAAA;AAIC;AAGwC;AAAA;AAAA;AAAA;AAK5C;AAAC;AAAA;AACmF;AAEjF;AAAA;AAAA;AAGP;AAMA;AAAA;AAAC;AAAA;AACM;AACA;AACL;AACc;AACC;AACuB;AAGtC;AAEA;AACG;AAAS;AAAK;AAAW;AAC5B;AACA;AAAC;AAAA;AAGkE;AAAA;AAAA;AACnE;AAAA;AAAA;AAKA;AAAC;AAAA;AACM;AACA;AACM;AACA;AACD;AAGR;AACA;AACE;AAAC;AAAA;AAEM;AACA;AACU;AACe;AAK9B;AAEA;AAEA;AAC2C;AAG3C;AAAA;AAAA;AAjBO;AAAA;AAoBZ;AAAA;AAAA;AAKL;AAAC;AAAA;AACW;AACE;AACb;AAAA;AAAA;AAKD;AAAC;AAAA;AACC;AACA;AACK;AACL;AACA;AACA;AACuB;AAC4B;AAGnD;AACI;AAAA;AAAA;AAER;AAIE;AAAC;AAAA;AACU;AACJ;AAGL;AAEA;AAAA;AAAC;AAAA;AAGC;AAAA;AAAA;AAEF;AAAC;AAAA;AAGC;AAEC;AAAA;AAAA;AACH;AAAA;AAAA;AAKV;;;;;"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Horizontal alignment of the popover panel relative to its trigger container.
|
|
4
|
+
* 'left' — panel left edge aligns with container; 'right' — panel right edge aligns.
|
|
5
|
+
*/
|
|
6
|
+
export type PopoverAlign = 'left' | 'right';
|
|
7
|
+
/**
|
|
8
|
+
* Props for the Popover component. The trigger is not part of Popover — wrap trigger and
|
|
9
|
+
* Popover in a single relative container; Popover renders as a floating panel anchored
|
|
10
|
+
* below that container. open/onClose control visibility; click-outside calls onClose.
|
|
11
|
+
*/
|
|
12
|
+
export interface PopoverProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
13
|
+
/** Whether the popover panel is visible. */
|
|
14
|
+
open: boolean;
|
|
15
|
+
/** Called when the user clicks outside the popover (dismiss). Required for accessibility. */
|
|
16
|
+
onClose: () => void;
|
|
17
|
+
/** Horizontal alignment of the panel relative to the trigger container. @default 'left' */
|
|
18
|
+
align?: PopoverAlign;
|
|
19
|
+
/** Min width of the popover panel. @default '10rem' (160px) */
|
|
20
|
+
minWidth?: string;
|
|
21
|
+
/** Panel content (e.g. menu items, actions). @default undefined */
|
|
22
|
+
children?: React.ReactNode;
|
|
23
|
+
/** Forwarded ref for the panel div. @default undefined */
|
|
24
|
+
ref?: React.Ref<HTMLDivElement>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Floating content panel anchored below a trigger element. Handles click-outside
|
|
28
|
+
* dismissal. Wrap the trigger and Popover in a single relative container; the
|
|
29
|
+
* panel is positioned below it. Use for dropdown menus, tooltips, or action panels.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* <Box className="relative">
|
|
33
|
+
* <Button onClick={toggle}>Open</Button>
|
|
34
|
+
* <Popover open={isOpen} onClose={close} align="left">
|
|
35
|
+
* <Stack spacing="space-1">...</Stack>
|
|
36
|
+
* </Popover>
|
|
37
|
+
* </Box>
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* <div className="relative">
|
|
41
|
+
* <button onClick={() => setOpen(true)}>Menu</button>
|
|
42
|
+
* <Popover open={open} onClose={() => setOpen(false)} align="right" minWidth="12rem">...</Popover>
|
|
43
|
+
* </div>
|
|
44
|
+
*/
|
|
45
|
+
export declare function Popover({ open, onClose, align, minWidth, children, className, style, ref, ...rest }: PopoverProps): import("react/jsx-runtime").JSX.Element | null;
|
|
46
|
+
//# sourceMappingURL=Popover.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Popover.d.ts","sourceRoot":"","sources":["../../../src/components/Popover/Popover.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAyC,MAAM,OAAO,CAAC;AAE9D;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,OAAO,CAAC;AAE5C;;;;GAIG;AACH,MAAM,WAAW,YAAa,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IACxE,4CAA4C;IAC5C,IAAI,EAAE,OAAO,CAAC;IACd,6FAA6F;IAC7F,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,2FAA2F;IAC3F,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,0DAA0D;IAC1D,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;CACjC;AAOD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,OAAO,CAAC,EACtB,IAAI,EACJ,OAAO,EACP,KAAc,EACd,QAAkB,EAClB,QAAQ,EACR,SAAc,EACd,KAAK,EACL,GAAG,EACH,GAAG,IAAI,EACR,EAAE,YAAY,kDAyCd"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useRef, useCallback, useEffect } from "react";
|
|
4
|
+
const alignClasses = {
|
|
5
|
+
left: "left-0",
|
|
6
|
+
right: "right-0"
|
|
7
|
+
};
|
|
8
|
+
function Popover({
|
|
9
|
+
open,
|
|
10
|
+
onClose,
|
|
11
|
+
align = "left",
|
|
12
|
+
minWidth = "10rem",
|
|
13
|
+
children,
|
|
14
|
+
className = "",
|
|
15
|
+
style,
|
|
16
|
+
ref,
|
|
17
|
+
...rest
|
|
18
|
+
}) {
|
|
19
|
+
const innerRef = useRef(null);
|
|
20
|
+
const resolvedRef = ref || innerRef;
|
|
21
|
+
const handleClickOutside = useCallback(
|
|
22
|
+
(e) => {
|
|
23
|
+
var _a;
|
|
24
|
+
const el = resolvedRef && "current" in resolvedRef ? resolvedRef.current : innerRef.current;
|
|
25
|
+
if (el && !((_a = el.parentElement) == null ? void 0 : _a.contains(e.target))) {
|
|
26
|
+
onClose();
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
[onClose, resolvedRef]
|
|
30
|
+
);
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
if (!open) return;
|
|
33
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
34
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
35
|
+
}, [open, handleClickOutside]);
|
|
36
|
+
if (!open) return null;
|
|
37
|
+
const classes = [
|
|
38
|
+
"absolute top-full z-50 mt-space-1 rounded-rad-md bg-fill-bg-primary p-space-1 shadow-elevation-low",
|
|
39
|
+
alignClasses[align],
|
|
40
|
+
className
|
|
41
|
+
].filter(Boolean).join(" ");
|
|
42
|
+
return /* @__PURE__ */ jsx(
|
|
43
|
+
"div",
|
|
44
|
+
{
|
|
45
|
+
ref: innerRef,
|
|
46
|
+
className: classes,
|
|
47
|
+
style: { minWidth, ...style },
|
|
48
|
+
role: "menu",
|
|
49
|
+
...rest,
|
|
50
|
+
children
|
|
51
|
+
}
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
export {
|
|
55
|
+
Popover
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=Popover.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Popover.js","sources":["../../../src/components/Popover/Popover.tsx"],"sourcesContent":["'use client';\n\nimport React, { useRef, useEffect, useCallback } from 'react';\n\n/**\n * Horizontal alignment of the popover panel relative to its trigger container.\n * 'left' — panel left edge aligns with container; 'right' — panel right edge aligns.\n */\nexport type PopoverAlign = 'left' | 'right';\n\n/**\n * Props for the Popover component. The trigger is not part of Popover — wrap trigger and\n * Popover in a single relative container; Popover renders as a floating panel anchored\n * below that container. open/onClose control visibility; click-outside calls onClose.\n */\nexport interface PopoverProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Whether the popover panel is visible. */\n open: boolean;\n /** Called when the user clicks outside the popover (dismiss). Required for accessibility. */\n onClose: () => void;\n /** Horizontal alignment of the panel relative to the trigger container. @default 'left' */\n align?: PopoverAlign;\n /** Min width of the popover panel. @default '10rem' (160px) */\n minWidth?: string;\n /** Panel content (e.g. menu items, actions). @default undefined */\n children?: React.ReactNode;\n /** Forwarded ref for the panel div. @default undefined */\n ref?: React.Ref<HTMLDivElement>;\n}\n\nconst alignClasses: Record<PopoverAlign, string> = {\n left: 'left-0',\n right: 'right-0',\n};\n\n/**\n * Floating content panel anchored below a trigger element. Handles click-outside\n * dismissal. Wrap the trigger and Popover in a single relative container; the\n * panel is positioned below it. Use for dropdown menus, tooltips, or action panels.\n *\n * @example\n * <Box className=\"relative\">\n * <Button onClick={toggle}>Open</Button>\n * <Popover open={isOpen} onClose={close} align=\"left\">\n * <Stack spacing=\"space-1\">...</Stack>\n * </Popover>\n * </Box>\n *\n * @example\n * <div className=\"relative\">\n * <button onClick={() => setOpen(true)}>Menu</button>\n * <Popover open={open} onClose={() => setOpen(false)} align=\"right\" minWidth=\"12rem\">...</Popover>\n * </div>\n */\nexport function Popover({\n open,\n onClose,\n align = 'left',\n minWidth = '10rem',\n children,\n className = '',\n style,\n ref,\n ...rest\n}: PopoverProps) {\n const innerRef = useRef<HTMLDivElement>(null);\n const resolvedRef = (ref as React.RefObject<HTMLDivElement>) || innerRef;\n\n const handleClickOutside = useCallback(\n (e: MouseEvent) => {\n const el = resolvedRef && 'current' in resolvedRef ? resolvedRef.current : innerRef.current;\n if (el && !el.parentElement?.contains(e.target as Node)) {\n onClose();\n }\n },\n [onClose, resolvedRef],\n );\n\n useEffect(() => {\n if (!open) return;\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, [open, handleClickOutside]);\n\n if (!open) return null;\n\n const classes = [\n 'absolute top-full z-50 mt-space-1 rounded-rad-md bg-fill-bg-primary p-space-1 shadow-elevation-low',\n alignClasses[align],\n className,\n ]\n .filter(Boolean)\n .join(' ');\n\n return (\n <div\n ref={innerRef}\n className={classes}\n style={{ minWidth, ...style }}\n role=\"menu\"\n {...rest}\n >\n {children}\n </div>\n );\n}\n"],"names":[],"mappings":";;;AA8BA;AAAmD;AAC3C;AAER;AAqBO;AAAiB;AACtB;AACA;AACQ;AACG;AACX;AACY;AACZ;AACA;AAEF;AACE;AACA;AAEA;AAA2B;;AAEvB;AACA;AACE;AAAA;AACF;AACF;AACqB;AAGvB;AACE;AACA;AACA;AAAyE;AAG3E;AAEA;AAAgB;AACd;AACkB;AAClB;AAKF;AACE;AAAC;AAAA;AACM;AACM;AACW;AACjB;AACD;AAEH;AAAA;AAGP;;;;"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Props for the ProductImage component. Renders a single image in a bordered container
|
|
4
|
+
* with optional expand button. Uses next/image for optimization.
|
|
5
|
+
*/
|
|
6
|
+
export interface ProductImageProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
7
|
+
/** Image source URL. */
|
|
8
|
+
src: string;
|
|
9
|
+
/** Alt text for the image. @default '' */
|
|
10
|
+
alt?: string;
|
|
11
|
+
/** Width for next/image. @default 800 */
|
|
12
|
+
width?: number;
|
|
13
|
+
/** Height for next/image. @default 800 */
|
|
14
|
+
height?: number;
|
|
15
|
+
/** When true, shows an expand/fullscreen icon overlay. @default false */
|
|
16
|
+
showExpand?: boolean;
|
|
17
|
+
/** Called when the expand icon is clicked. @default undefined */
|
|
18
|
+
onExpand?: () => void;
|
|
19
|
+
/** Forwarded ref for the root div. @default undefined */
|
|
20
|
+
ref?: React.Ref<HTMLDivElement>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Single product image in a bordered, rounded container. Uses next/image. Optional
|
|
24
|
+
* expand button for opening in a lightbox or fullscreen (handle with onExpand).
|
|
25
|
+
* For multiple images with thumbnails use ProductImageGallery.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* <ProductImage src="/product.jpg" alt="Product" />
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* <ProductImage src={url} showExpand onExpand={() => openLightbox()} />
|
|
32
|
+
*/
|
|
33
|
+
export declare function ProductImage({ src, alt, width, height, showExpand, onExpand, className, ref, ...rest }: ProductImageProps): import("react/jsx-runtime").JSX.Element;
|
|
34
|
+
/**
|
|
35
|
+
* Shape of a single image in the gallery. Each item needs src; alt is optional.
|
|
36
|
+
*/
|
|
37
|
+
export interface GalleryImage {
|
|
38
|
+
src: string;
|
|
39
|
+
alt?: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Props for ProductImageGallery. Main image area shows one image at a time with
|
|
43
|
+
* optional prev/next arrows and expand; thumbnails strip below for multi-image selection.
|
|
44
|
+
* Supports controlled (activeIndex/onChange) or uncontrolled (defaultIndex) selection.
|
|
45
|
+
*/
|
|
46
|
+
export interface ProductImageGalleryProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> {
|
|
47
|
+
/** Array of images. Each: src (string), alt? (string). @see GalleryImage */
|
|
48
|
+
images: GalleryImage[];
|
|
49
|
+
/** Index of the initially selected image (uncontrolled). @default 0 */
|
|
50
|
+
defaultIndex?: number;
|
|
51
|
+
/** Controlled selected index. Use with onChange. @default undefined */
|
|
52
|
+
activeIndex?: number;
|
|
53
|
+
/** Called when the user selects another image (thumbnail or arrow). @default undefined */
|
|
54
|
+
onChange?: (index: number) => void;
|
|
55
|
+
/** When true, shows expand icon on the main image. @default true */
|
|
56
|
+
showExpand?: boolean;
|
|
57
|
+
/** Called when the expand icon is clicked; receives current image index. @default undefined */
|
|
58
|
+
onExpand?: (index: number) => void;
|
|
59
|
+
/** Width for next/image main image. @default 800 */
|
|
60
|
+
imageWidth?: number;
|
|
61
|
+
/** Height for next/image main image. Main area uses aspect ratio 4:3. @default 600 */
|
|
62
|
+
imageHeight?: number;
|
|
63
|
+
/** Forwarded ref for the root div. @default undefined */
|
|
64
|
+
ref?: React.Ref<HTMLDivElement>;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Product image gallery with main image and horizontal thumbnail strip. Main image
|
|
68
|
+
* has prev/next arrows and optional expand; thumbnails are selectable. Use for PDPs
|
|
69
|
+
* or any multi-image product view. Single image use ProductImage instead.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* <ProductImageGallery images={[{ src: '/a.jpg' }, { src: '/b.jpg', alt: 'Back' }]} />
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* <ProductImageGallery images={imgs} activeIndex={idx} onChange={setIdx} showExpand onExpand={openLightbox} />
|
|
76
|
+
*/
|
|
77
|
+
export declare function ProductImageGallery({ images, defaultIndex, activeIndex: activeProp, onChange, showExpand, onExpand, imageWidth, imageHeight, className, ref, ...rest }: ProductImageGalleryProps): import("react/jsx-runtime").JSX.Element;
|
|
78
|
+
//# sourceMappingURL=ProductImage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProductImage.d.ts","sourceRoot":"","sources":["../../../src/components/ProductImage/ProductImage.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAmD,MAAM,OAAO,CAAC;AAiDxE;;;GAGG;AACH,MAAM,WAAW,iBAAkB,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IAC7E,wBAAwB;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,0CAA0C;IAC1C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,yCAAyC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,iEAAiE;IACjE,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,yDAAyD;IACzD,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;CACjC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,EAAE,GAAG,EAAE,GAAQ,EAAE,KAAW,EAAE,MAAY,EAAE,UAAkB,EAAE,QAAQ,EAAE,SAAc,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,EAAE,iBAAiB,2CA4BvJ;AAMD;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;GAIG;AACH,MAAM,WAAW,wBAAyB,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC;IACtG,4EAA4E;IAC5E,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,uEAAuE;IACvE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uEAAuE;IACvE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0FAA0F;IAC1F,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,oEAAoE;IACpE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,+FAA+F;IAC/F,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,oDAAoD;IACpD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sFAAsF;IACtF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yDAAyD;IACzD,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;CACjC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,MAAM,EACN,YAAgB,EAChB,WAAW,EAAE,UAAU,EACvB,QAAQ,EACR,UAAiB,EACjB,QAAQ,EACR,UAAgB,EAChB,WAAiB,EACjB,SAAc,EACd,GAAG,EACH,GAAG,IAAI,EACR,EAAE,wBAAwB,2CAuJ1B"}
|