@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,48 @@
|
|
|
1
|
+
import { jsxs, Fragment, jsx } from "react/jsx-runtime";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { stripSystemProps, renderSystemProps, generateScopeId } from "../../utils/responsive-props.js";
|
|
4
|
+
const SIZE_PADDING = {
|
|
5
|
+
sm: { base: "var(--space-4)", lg: "var(--space-6)" },
|
|
6
|
+
md: { base: "var(--space-6)", lg: "var(--space-9)" },
|
|
7
|
+
lg: { base: "var(--space-9)", lg: "var(--space-16)" },
|
|
8
|
+
xl: { base: "var(--space-16)", lg: "var(--space-24)" }
|
|
9
|
+
};
|
|
10
|
+
function Section({ size, children, className = "", style, ref, ...allRest }) {
|
|
11
|
+
const rest = stripSystemProps(allRest);
|
|
12
|
+
const hasPyOverride = allRest.py !== void 0 || allRest.pt !== void 0 || allRest.pb !== void 0 || allRest.p !== void 0;
|
|
13
|
+
const sizeStyle = {};
|
|
14
|
+
let sizeMediaCSS = "";
|
|
15
|
+
if (size && !hasPyOverride) {
|
|
16
|
+
const preset = SIZE_PADDING[size];
|
|
17
|
+
sizeStyle.paddingTop = preset.base;
|
|
18
|
+
sizeStyle.paddingBottom = preset.base;
|
|
19
|
+
sizeMediaCSS = `@media(min-width:940px){__SEL__{padding-top:${preset.lg} !important;padding-bottom:${preset.lg} !important}}`;
|
|
20
|
+
}
|
|
21
|
+
const mergedStyle = { ...sizeStyle, ...style };
|
|
22
|
+
const { style: systemStyle, styleTag, dataId } = renderSystemProps(
|
|
23
|
+
allRest,
|
|
24
|
+
mergedStyle
|
|
25
|
+
);
|
|
26
|
+
const needsSizeMedia = !!sizeMediaCSS;
|
|
27
|
+
const finalDataId = dataId ?? (needsSizeMedia ? generateScopeId(sizeMediaCSS, "sec") : void 0);
|
|
28
|
+
const scopedSizeCSS = needsSizeMedia && finalDataId ? sizeMediaCSS.replace(/__SEL__/g, `[data-jds="${finalDataId}"]`) : "";
|
|
29
|
+
const elementProps = {
|
|
30
|
+
ref,
|
|
31
|
+
className: className || void 0,
|
|
32
|
+
style: systemStyle,
|
|
33
|
+
...rest
|
|
34
|
+
};
|
|
35
|
+
if (finalDataId) {
|
|
36
|
+
elementProps["data-jds"] = finalDataId;
|
|
37
|
+
}
|
|
38
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
39
|
+
styleTag,
|
|
40
|
+
scopedSizeCSS && /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: scopedSizeCSS } }),
|
|
41
|
+
React.createElement("section", elementProps, children)
|
|
42
|
+
] });
|
|
43
|
+
}
|
|
44
|
+
Section.displayName = "Section";
|
|
45
|
+
export {
|
|
46
|
+
Section
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=Section.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Section.js","sources":["../../../src/components/Section/Section.tsx"],"sourcesContent":["import React from 'react';\nimport {\n renderSystemProps,\n stripSystemProps,\n generateScopeId,\n type SystemProps,\n} from '../../utils/responsive-props';\n\n/**\n * Vertical padding preset for Section. Controls top/bottom padding at base and lg (940px) breakpoint.\n * Overridden when py or pt/pb are provided via system props.\n */\nexport type SectionSize = 'sm' | 'md' | 'lg' | 'xl';\n\n/**\n * Props for the Section component. Extends system props (responsive spacing, etc.).\n * size applies vertical padding presets unless py/pt/pb are set.\n */\nexport interface SectionProps extends Omit<React.HTMLAttributes<HTMLElement>, 'display'>, SystemProps {\n /**\n * Vertical padding preset. Ignored when py or pt/pb are provided.\n * - 'sm' — base: space-4, lg: space-6\n * - 'md' — base: space-6, lg: space-9\n * - 'lg' — base: space-9, lg: space-16\n * - 'xl' — base: space-16, lg: space-24\n * @default undefined\n */\n size?: SectionSize;\n /** Forwarded ref for the section element. @default undefined */\n ref?: React.Ref<HTMLElement>;\n /** Section content. @default undefined */\n children?: React.ReactNode;\n}\n\nconst SIZE_PADDING: Record<SectionSize, { base: string; lg: string }> = {\n sm: { base: 'var(--space-4)', lg: 'var(--space-6)' },\n md: { base: 'var(--space-6)', lg: 'var(--space-9)' },\n lg: { base: 'var(--space-9)', lg: 'var(--space-16)' },\n xl: { base: 'var(--space-16)', lg: 'var(--space-24)' },\n};\n\n/**\n * Semantic section element with optional vertical padding presets (size) and full\n * system props. Use as the wrapper for each major page block; combine with\n * Container for width and gutters. Do not nest Section for inner layout — use Box or Stack.\n *\n * @example\n * <Section size=\"lg\">\n * <Container>Page content</Container>\n * </Section>\n *\n * @example\n * <Section size=\"md\" py={{ base: 'space-8', xl: 'space-16' }}>Custom spacing</Section>\n */\nexport function Section({ size, children, className = '', style, ref, ...allRest }: SectionProps) {\n const rest = stripSystemProps(allRest);\n\n const hasPyOverride =\n allRest.py !== undefined ||\n allRest.pt !== undefined ||\n allRest.pb !== undefined ||\n allRest.p !== undefined;\n\n const sizeStyle: React.CSSProperties = {};\n let sizeMediaCSS = '';\n\n if (size && !hasPyOverride) {\n const preset = SIZE_PADDING[size];\n sizeStyle.paddingTop = preset.base;\n sizeStyle.paddingBottom = preset.base;\n sizeMediaCSS = `@media(min-width:940px){__SEL__{padding-top:${preset.lg} !important;padding-bottom:${preset.lg} !important}}`;\n }\n\n const mergedStyle = { ...sizeStyle, ...style };\n const { style: systemStyle, styleTag, dataId } = renderSystemProps(\n allRest as SystemProps,\n mergedStyle,\n );\n\n const needsSizeMedia = !!sizeMediaCSS;\n const finalDataId = dataId ?? (needsSizeMedia ? generateScopeId(sizeMediaCSS, 'sec') : undefined);\n const scopedSizeCSS = needsSizeMedia && finalDataId\n ? sizeMediaCSS.replace(/__SEL__/g, `[data-jds=\"${finalDataId}\"]`)\n : '';\n\n const elementProps: Record<string, unknown> = {\n ref,\n className: className || undefined,\n style: systemStyle,\n ...rest,\n };\n\n if (finalDataId) {\n elementProps['data-jds'] = finalDataId;\n }\n\n return (\n <>\n {styleTag}\n {scopedSizeCSS && <style dangerouslySetInnerHTML={{ __html: scopedSizeCSS }} />}\n {React.createElement('section', elementProps, children)}\n </>\n );\n}\n\nSection.displayName = 'Section';\n"],"names":[],"mappings":";;;AAkCA,MAAM,eAAkE;AAAA,EACtE,IAAI,EAAE,MAAM,kBAAkB,IAAI,iBAAA;AAAA,EAClC,IAAI,EAAE,MAAM,kBAAkB,IAAI,iBAAA;AAAA,EAClC,IAAI,EAAE,MAAM,kBAAkB,IAAI,kBAAA;AAAA,EAClC,IAAI,EAAE,MAAM,mBAAmB,IAAI,kBAAA;AACrC;AAeO,SAAS,QAAQ,EAAE,MAAM,UAAU,YAAY,IAAI,OAAO,KAAK,GAAG,WAAyB;AAChG,QAAM,OAAO,iBAAiB,OAAO;AAErC,QAAM,gBACJ,QAAQ,OAAO,UACf,QAAQ,OAAO,UACf,QAAQ,OAAO,UACf,QAAQ,MAAM;AAEhB,QAAM,YAAiC,CAAA;AACvC,MAAI,eAAe;AAEnB,MAAI,QAAQ,CAAC,eAAe;AAC1B,UAAM,SAAS,aAAa,IAAI;AAChC,cAAU,aAAa,OAAO;AAC9B,cAAU,gBAAgB,OAAO;AACjC,mBAAe,+CAA+C,OAAO,EAAE,8BAA8B,OAAO,EAAE;AAAA,EAChH;AAEA,QAAM,cAAc,EAAE,GAAG,WAAW,GAAG,MAAA;AACvC,QAAM,EAAE,OAAO,aAAa,UAAU,WAAW;AAAA,IAC/C;AAAA,IACA;AAAA,EAAA;AAGF,QAAM,iBAAiB,CAAC,CAAC;AACzB,QAAM,cAAc,WAAW,iBAAiB,gBAAgB,cAAc,KAAK,IAAI;AACvF,QAAM,gBAAgB,kBAAkB,cACpC,aAAa,QAAQ,YAAY,cAAc,WAAW,IAAI,IAC9D;AAEJ,QAAM,eAAwC;AAAA,IAC5C;AAAA,IACA,WAAW,aAAa;AAAA,IACxB,OAAO;AAAA,IACP,GAAG;AAAA,EAAA;AAGL,MAAI,aAAa;AACf,iBAAa,UAAU,IAAI;AAAA,EAC7B;AAEA,SACE,qBAAA,UAAA,EACG,UAAA;AAAA,IAAA;AAAA,IACA,iBAAiB,oBAAC,SAAA,EAAM,yBAAyB,EAAE,QAAQ,iBAAiB;AAAA,IAC5E,MAAM,cAAc,WAAW,cAAc,QAAQ;AAAA,EAAA,GACxD;AAEJ;AAEA,QAAQ,cAAc;"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Shape of a single select option. value is submitted; label is shown (falls back to value).
|
|
4
|
+
*/
|
|
5
|
+
export interface SelectOption {
|
|
6
|
+
/** Value submitted with the form. Must be unique. */
|
|
7
|
+
value: string;
|
|
8
|
+
/** Visible label. Falls back to value if omitted. @default undefined */
|
|
9
|
+
label?: string;
|
|
10
|
+
/** When true, this option cannot be selected. @default undefined */
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Props for the Select component. Native select with label, support text, placeholder,
|
|
15
|
+
* and error state. Supports controlled (value) or uncontrolled (defaultValue) usage.
|
|
16
|
+
*/
|
|
17
|
+
export interface SelectProps extends Omit<React.SelectHTMLAttributes<HTMLSelectElement>, 'size'> {
|
|
18
|
+
/** Label text displayed above the select. @default undefined */
|
|
19
|
+
label?: string;
|
|
20
|
+
/** Secondary label shown lighter beside the main label. @default undefined */
|
|
21
|
+
secondaryLabel?: string;
|
|
22
|
+
/** Supportive text rendered below the label. @default undefined */
|
|
23
|
+
supportText?: string;
|
|
24
|
+
/** Placeholder text shown when no value is selected. @default undefined */
|
|
25
|
+
placeholder?: string;
|
|
26
|
+
/** Options to render. Each: value, label?, disabled?. @default [] */
|
|
27
|
+
options?: SelectOption[];
|
|
28
|
+
/** Places the select in an error state. @default false */
|
|
29
|
+
error?: boolean;
|
|
30
|
+
/** Error message shown in the alert below the select when error is true. @default undefined */
|
|
31
|
+
errorMessage?: string;
|
|
32
|
+
/** Forwarded ref for the select element. @default undefined */
|
|
33
|
+
ref?: React.Ref<HTMLSelectElement>;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Native select dropdown with label, support text, placeholder, and error alert.
|
|
37
|
+
* Renders a single-choice list; for tab-style single choice (e.g. quantity 1–5) use
|
|
38
|
+
* SelectTab. Supports controlled (value) or uncontrolled (defaultValue) usage.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* <Select label="Country" placeholder="Choose" options={[{ value: 'ke', label: 'Kenya' }, { value: 'tz', label: 'Tanzania' }]} />
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* <Select label="Status" value={status} onChange={(e) => setStatus(e.target.value)} options={statusOptions} error={!!err} errorMessage={err} />
|
|
45
|
+
*/
|
|
46
|
+
export declare function Select({ label, secondaryLabel, supportText, placeholder, options, error, errorMessage, required, disabled, className, id: idProp, value, defaultValue, ref, ...rest }: SelectProps): import("react/jsx-runtime").JSX.Element;
|
|
47
|
+
//# sourceMappingURL=Select.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Select.d.ts","sourceRoot":"","sources":["../../../src/components/Select/Select.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAgB,MAAM,OAAO,CAAC;AAErC;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,qDAAqD;IACrD,KAAK,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,WACf,SAAQ,IAAI,CAAC,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACnE,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2EAA2E;IAC3E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qEAAqE;IACrE,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;IACzB,0DAA0D;IAC1D,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,+FAA+F;IAC/F,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,+DAA+D;IAC/D,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;CACpC;AA4CD;;;;;;;;;;GAUG;AACH,wBAAgB,MAAM,CAAC,EACrB,KAAK,EACL,cAAc,EACd,WAAW,EACX,WAAW,EACX,OAAY,EACZ,KAAa,EACb,YAAY,EACZ,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,EAAE,EAAE,MAAM,EACV,KAAK,EACL,YAAY,EACZ,GAAG,EACH,GAAG,IAAI,EACR,EAAE,WAAW,2CAiIb"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useId } from "react";
|
|
4
|
+
function ChevronDown({ className }) {
|
|
5
|
+
return /* @__PURE__ */ jsx(
|
|
6
|
+
"svg",
|
|
7
|
+
{
|
|
8
|
+
className,
|
|
9
|
+
viewBox: "0 0 20 20",
|
|
10
|
+
fill: "none",
|
|
11
|
+
stroke: "currentColor",
|
|
12
|
+
strokeWidth: "1.5",
|
|
13
|
+
strokeLinecap: "round",
|
|
14
|
+
strokeLinejoin: "round",
|
|
15
|
+
"aria-hidden": "true",
|
|
16
|
+
children: /* @__PURE__ */ jsx("path", { d: "M6 8l4 4 4-4" })
|
|
17
|
+
}
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
function ErrorIcon({ className }) {
|
|
21
|
+
return /* @__PURE__ */ jsx(
|
|
22
|
+
"svg",
|
|
23
|
+
{
|
|
24
|
+
className,
|
|
25
|
+
viewBox: "0 0 20 20",
|
|
26
|
+
fill: "currentColor",
|
|
27
|
+
"aria-hidden": "true",
|
|
28
|
+
children: /* @__PURE__ */ jsx(
|
|
29
|
+
"path",
|
|
30
|
+
{
|
|
31
|
+
fillRule: "evenodd",
|
|
32
|
+
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",
|
|
33
|
+
clipRule: "evenodd"
|
|
34
|
+
}
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
function Select({
|
|
40
|
+
label,
|
|
41
|
+
secondaryLabel,
|
|
42
|
+
supportText,
|
|
43
|
+
placeholder,
|
|
44
|
+
options = [],
|
|
45
|
+
error = false,
|
|
46
|
+
errorMessage,
|
|
47
|
+
required,
|
|
48
|
+
disabled,
|
|
49
|
+
className,
|
|
50
|
+
id: idProp,
|
|
51
|
+
value,
|
|
52
|
+
defaultValue,
|
|
53
|
+
ref,
|
|
54
|
+
...rest
|
|
55
|
+
}) {
|
|
56
|
+
const autoId = useId();
|
|
57
|
+
const id = idProp ?? autoId;
|
|
58
|
+
const hasValue = value !== void 0 ? value !== "" : defaultValue !== void 0 && defaultValue !== "";
|
|
59
|
+
const selectClasses = [
|
|
60
|
+
"w-full min-h-[48px] pl-space-4 pr-10 py-space-3 appearance-none",
|
|
61
|
+
"rounded-rad-md text-form-text outline-none",
|
|
62
|
+
"transition-all duration-150",
|
|
63
|
+
hasValue ? "text-text-primary" : "text-text-disabled",
|
|
64
|
+
// Default border & background
|
|
65
|
+
!disabled && !error && "border-border-sm border-border-form-primary bg-fill-form-primary",
|
|
66
|
+
!disabled && error && "border-border-sm border-border-err bg-fill-form-primary",
|
|
67
|
+
// Hover
|
|
68
|
+
!disabled && "hover:border-border-md hover:border-border-form-primary-hover",
|
|
69
|
+
// Focus (click → "Selected" state)
|
|
70
|
+
!disabled && "focus:border-border-md focus:border-border-form-primary-active focus:text-text-primary",
|
|
71
|
+
// Focus-visible (keyboard → "Focus" state + ring)
|
|
72
|
+
!disabled && [
|
|
73
|
+
"focus-visible:border-border-sm focus-visible:border-border-form-primary-focus",
|
|
74
|
+
"focus-visible:ring-[1.5px] focus-visible:ring-border-focus focus-visible:ring-offset-[3px]"
|
|
75
|
+
].join(" "),
|
|
76
|
+
// Disabled
|
|
77
|
+
disabled && "border-border-sm border-border-form-primary-disabled bg-fill-form-primary-disabled text-text-disabled cursor-not-allowed",
|
|
78
|
+
className
|
|
79
|
+
].filter(Boolean).join(" ");
|
|
80
|
+
const showErrorAlert = error && errorMessage;
|
|
81
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-space-2 w-full", children: [
|
|
82
|
+
(label || supportText) && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-space-1", children: [
|
|
83
|
+
label && /* @__PURE__ */ jsxs(
|
|
84
|
+
"label",
|
|
85
|
+
{
|
|
86
|
+
htmlFor: id,
|
|
87
|
+
className: `text-form-label ${disabled ? "text-text-disabled" : "text-text-primary"}`,
|
|
88
|
+
children: [
|
|
89
|
+
label,
|
|
90
|
+
secondaryLabel && /* @__PURE__ */ jsx("span", { className: "text-text-secondary font-normal ml-1", children: secondaryLabel }),
|
|
91
|
+
required && /* @__PURE__ */ jsx("span", { className: "text-text-err ml-0.5", children: "*" })
|
|
92
|
+
]
|
|
93
|
+
}
|
|
94
|
+
),
|
|
95
|
+
supportText && /* @__PURE__ */ jsx("p", { className: `text-text-xs ${disabled ? "text-text-disabled" : "text-text-secondary"}`, children: supportText })
|
|
96
|
+
] }),
|
|
97
|
+
/* @__PURE__ */ jsxs("div", { className: "relative w-full", children: [
|
|
98
|
+
/* @__PURE__ */ jsxs(
|
|
99
|
+
"select",
|
|
100
|
+
{
|
|
101
|
+
ref,
|
|
102
|
+
id,
|
|
103
|
+
disabled,
|
|
104
|
+
required,
|
|
105
|
+
"aria-invalid": error || void 0,
|
|
106
|
+
"aria-describedby": showErrorAlert ? `${id}-error` : void 0,
|
|
107
|
+
value,
|
|
108
|
+
defaultValue,
|
|
109
|
+
className: selectClasses,
|
|
110
|
+
...rest,
|
|
111
|
+
children: [
|
|
112
|
+
placeholder && /* @__PURE__ */ jsx("option", { value: "", disabled: true, hidden: true, children: placeholder }),
|
|
113
|
+
options.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value, disabled: opt.disabled, children: opt.label ?? opt.value }, opt.value))
|
|
114
|
+
]
|
|
115
|
+
}
|
|
116
|
+
),
|
|
117
|
+
/* @__PURE__ */ jsx(
|
|
118
|
+
"span",
|
|
119
|
+
{
|
|
120
|
+
className: `absolute right-3 top-1/2 -translate-y-1/2 pointer-events-none flex items-center ${disabled ? "text-icon-primary-disabled" : "text-icon-primary"}`,
|
|
121
|
+
children: /* @__PURE__ */ jsx(ChevronDown, { className: "w-5 h-5" })
|
|
122
|
+
}
|
|
123
|
+
)
|
|
124
|
+
] }),
|
|
125
|
+
showErrorAlert && /* @__PURE__ */ jsxs(
|
|
126
|
+
"div",
|
|
127
|
+
{
|
|
128
|
+
id: `${id}-error`,
|
|
129
|
+
role: "alert",
|
|
130
|
+
className: `flex items-start gap-space-4 p-space-4 rounded-rad-md ${disabled ? "bg-fill-bg-secondary" : "bg-fill-bg-err"}`,
|
|
131
|
+
children: [
|
|
132
|
+
/* @__PURE__ */ jsx(
|
|
133
|
+
ErrorIcon,
|
|
134
|
+
{
|
|
135
|
+
className: `w-5 h-5 shrink-0 ${disabled ? "text-icon-primary-disabled" : "text-icon-err"}`
|
|
136
|
+
}
|
|
137
|
+
),
|
|
138
|
+
/* @__PURE__ */ jsx(
|
|
139
|
+
"span",
|
|
140
|
+
{
|
|
141
|
+
className: `text-text-xs ${disabled ? "text-text-disabled" : "text-text-err"}`,
|
|
142
|
+
children: errorMessage
|
|
143
|
+
}
|
|
144
|
+
)
|
|
145
|
+
]
|
|
146
|
+
}
|
|
147
|
+
)
|
|
148
|
+
] });
|
|
149
|
+
}
|
|
150
|
+
export {
|
|
151
|
+
Select
|
|
152
|
+
};
|
|
153
|
+
//# sourceMappingURL=Select.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Select.js","sources":["../../../src/components/Select/Select.tsx"],"sourcesContent":["'use client';\n\nimport React, { useId } from 'react';\n\n/**\n * Shape of a single select option. value is submitted; label is shown (falls back to value).\n */\nexport interface SelectOption {\n /** Value submitted with the form. Must be unique. */\n value: string;\n /** Visible label. Falls back to value if omitted. @default undefined */\n label?: string;\n /** When true, this option cannot be selected. @default undefined */\n disabled?: boolean;\n}\n\n/**\n * Props for the Select component. Native select with label, support text, placeholder,\n * and error state. Supports controlled (value) or uncontrolled (defaultValue) usage.\n */\nexport interface SelectProps\n extends Omit<React.SelectHTMLAttributes<HTMLSelectElement>, 'size'> {\n /** Label text displayed above the select. @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 /** Placeholder text shown when no value is selected. @default undefined */\n placeholder?: string;\n /** Options to render. Each: value, label?, disabled?. @default [] */\n options?: SelectOption[];\n /** Places the select in an error state. @default false */\n error?: boolean;\n /** Error message shown in the alert below the select when error is true. @default undefined */\n errorMessage?: string;\n /** Forwarded ref for the select element. @default undefined */\n ref?: React.Ref<HTMLSelectElement>;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction ChevronDown({ className }: { className?: string }) {\n return (\n <svg\n className={className}\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M6 8l4 4 4-4\" />\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\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\n/**\n * Native select dropdown with label, support text, placeholder, and error alert.\n * Renders a single-choice list; for tab-style single choice (e.g. quantity 1–5) use\n * SelectTab. Supports controlled (value) or uncontrolled (defaultValue) usage.\n *\n * @example\n * <Select label=\"Country\" placeholder=\"Choose\" options={[{ value: 'ke', label: 'Kenya' }, { value: 'tz', label: 'Tanzania' }]} />\n *\n * @example\n * <Select label=\"Status\" value={status} onChange={(e) => setStatus(e.target.value)} options={statusOptions} error={!!err} errorMessage={err} />\n */\nexport function Select({\n label,\n secondaryLabel,\n supportText,\n placeholder,\n options = [],\n error = false,\n errorMessage,\n required,\n disabled,\n className,\n id: idProp,\n value,\n defaultValue,\n ref,\n ...rest\n}: SelectProps) {\n const autoId = useId();\n const id = idProp ?? autoId;\n\n const hasValue =\n value !== undefined ? value !== '' : defaultValue !== undefined && defaultValue !== '';\n\n const selectClasses = [\n 'w-full min-h-[48px] pl-space-4 pr-10 py-space-3 appearance-none',\n 'rounded-rad-md text-form-text outline-none',\n 'transition-all duration-150',\n hasValue ? 'text-text-primary' : 'text-text-disabled',\n\n // Default border & background\n !disabled && !error && 'border-border-sm border-border-form-primary bg-fill-form-primary',\n !disabled && error && 'border-border-sm border-border-err bg-fill-form-primary',\n\n // Hover\n !disabled && 'hover:border-border-md hover:border-border-form-primary-hover',\n\n // Focus (click → \"Selected\" state)\n !disabled && 'focus:border-border-md focus:border-border-form-primary-active focus:text-text-primary',\n\n // Focus-visible (keyboard → \"Focus\" state + ring)\n !disabled && [\n 'focus-visible:border-border-sm focus-visible:border-border-form-primary-focus',\n 'focus-visible:ring-[1.5px] focus-visible:ring-border-focus focus-visible:ring-offset-[3px]',\n ].join(' '),\n\n // Disabled\n disabled && 'border-border-sm border-border-form-primary-disabled bg-fill-form-primary-disabled text-text-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 className={`text-text-xs ${disabled ? 'text-text-disabled' : 'text-text-secondary'}`}>\n {supportText}\n </p>\n )}\n </div>\n )}\n\n {/* Select wrapper */}\n <div className=\"relative w-full\">\n <select\n ref={ref}\n id={id}\n disabled={disabled}\n required={required}\n aria-invalid={error || undefined}\n aria-describedby={showErrorAlert ? `${id}-error` : undefined}\n value={value}\n defaultValue={defaultValue}\n className={selectClasses}\n {...rest}\n >\n {placeholder && (\n <option value=\"\" disabled hidden>\n {placeholder}\n </option>\n )}\n {options.map((opt) => (\n <option key={opt.value} value={opt.value} disabled={opt.disabled}>\n {opt.label ?? opt.value}\n </option>\n ))}\n </select>\n\n {/* Chevron icon */}\n <span\n className={`absolute right-3 top-1/2 -translate-y-1/2 pointer-events-none flex items-center ${\n disabled ? 'text-icon-primary-disabled' : 'text-icon-primary'\n }`}\n >\n <ChevronDown className=\"w-5 h-5\" />\n </span>\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":";;;AA4CA;AACE;AACE;AAAC;AAAA;AACC;AACQ;AACH;AACE;AACK;AACE;AACC;AACH;AAEW;AAAA;AAG7B;AAEA;AACE;AACE;AAAC;AAAA;AACC;AACQ;AACH;AACO;AAEZ;AAAC;AAAA;AACU;AACP;AACO;AAAA;AAAA;AACX;AAGN;AAiBO;AAAgB;AACrB;AACA;AACA;AACA;AACU;AACF;AACR;AACA;AACA;AACA;AACI;AACJ;AACA;AACA;AAEF;AACE;AACA;AAEA;AAGA;AAAsB;AACpB;AACA;AACA;AACiC;AAAA;AAGV;AACD;AAAA;AAGT;AAAA;AAGA;AAAA;AAGA;AACX;AACA;AACQ;AAAA;AAGE;AAEZ;AAKF;AAEA;AAGM;AAEG;AACC;AAAC;AAAA;AACU;AAC0E;AAElF;AAAA;AAIC;AAGwC;AAAA;AAAA;AAAA;AAO5C;AAEJ;AAKA;AAAA;AAAC;AAAA;AACC;AACA;AACA;AACA;AACuB;AAC4B;AACnD;AACA;AACW;AACP;AAEH;AAGC;AAMD;AAAA;AAAA;AAAA;AAIH;AAAC;AAAA;AAGC;AAEiC;AAAA;AAAA;AAErC;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,62 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Shape of a single SelectTab option. Rendered as a 48×48 selectable cell.
|
|
4
|
+
*/
|
|
5
|
+
export interface SelectTabOption {
|
|
6
|
+
/** Value when this option is selected. Must be unique. */
|
|
7
|
+
value: string;
|
|
8
|
+
/** Visible label inside the cell. Falls back to value. @default undefined */
|
|
9
|
+
label?: string;
|
|
10
|
+
/** When true, this option cannot be selected. @default undefined */
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Props for the SelectTab component. Single selection from a row of 48×48 cells.
|
|
15
|
+
* Use for small choice sets (e.g. quantity 0–9, size XS–XL) where a dropdown is
|
|
16
|
+
* overkill. For a traditional dropdown use Select. value/onChange for controlled mode.
|
|
17
|
+
*/
|
|
18
|
+
export interface SelectTabProps {
|
|
19
|
+
/** Label text displayed above the tab row. @default undefined */
|
|
20
|
+
label?: string;
|
|
21
|
+
/** Secondary label shown lighter beside the main label. @default undefined */
|
|
22
|
+
secondaryLabel?: string;
|
|
23
|
+
/** Supportive text rendered below the label. @default undefined */
|
|
24
|
+
supportText?: string;
|
|
25
|
+
/** Options rendered as selectable 48×48 cells. Each: value, label?, disabled?. @see SelectTabOption */
|
|
26
|
+
options: SelectTabOption[];
|
|
27
|
+
/** Controlled selected value. Use with onChange. @default undefined */
|
|
28
|
+
value?: string;
|
|
29
|
+
/** Uncontrolled default selected value. @default undefined */
|
|
30
|
+
defaultValue?: string;
|
|
31
|
+
/** Called when the selected value changes. @default undefined */
|
|
32
|
+
onChange?: (value: string) => void;
|
|
33
|
+
/** Optional label at the end of the row (e.g. "Submit"). @default undefined */
|
|
34
|
+
submitLabel?: string;
|
|
35
|
+
/** Called when the submit label is clicked. @default undefined */
|
|
36
|
+
onSubmit?: () => void;
|
|
37
|
+
/** Disables all options. @default false */
|
|
38
|
+
disabled?: boolean;
|
|
39
|
+
/** Places the component in an error state. @default false */
|
|
40
|
+
error?: boolean;
|
|
41
|
+
/** Error message shown in the alert below the row when error is true. @default undefined */
|
|
42
|
+
errorMessage?: string;
|
|
43
|
+
/** When true, shows required asterisk next to the label. @default undefined */
|
|
44
|
+
required?: boolean;
|
|
45
|
+
/** Additional CSS class names on the outer wrapper. @default undefined */
|
|
46
|
+
className?: string;
|
|
47
|
+
/** Forwarded ref for the root div. @default undefined */
|
|
48
|
+
ref?: React.Ref<HTMLDivElement>;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Tab-style single-selection row where each option is a 48×48 cell. Use for quantity,
|
|
52
|
+
* size, or other small choice sets. Only one option can be selected (radio-like);
|
|
53
|
+
* supports keyboard navigation (arrows, Home, End). For dropdown single-select use Select.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* <SelectTab label="Quantity" options={[{ value: '0', label: '0' }, { value: '1', label: '1' }]} submitLabel="Submit" onSubmit={handleSubmit} />
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* <SelectTab label="Size" value={size} onChange={setSize} options={sizeOptions} error={!!err} errorMessage={err} />
|
|
60
|
+
*/
|
|
61
|
+
export declare function SelectTab({ label, secondaryLabel, supportText, options, value: valueProp, defaultValue, onChange, submitLabel, onSubmit, disabled, error, errorMessage, required, className, ref, ...rest }: SelectTabProps): import("react/jsx-runtime").JSX.Element;
|
|
62
|
+
//# sourceMappingURL=SelectTab.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SelectTab.d.ts","sourceRoot":"","sources":["../../../src/components/SelectTab/SelectTab.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAEnD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,0DAA0D;IAC1D,KAAK,EAAE,MAAM,CAAC;IACd,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,iEAAiE;IACjE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uGAAuG;IACvG,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8DAA8D;IAC9D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iEAAiE;IACjE,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,+EAA+E;IAC/E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,6DAA6D;IAC7D,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,4FAA4F;IAC5F,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;CACjC;AA2BD;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,cAAc,EACd,WAAW,EACX,OAAO,EACP,KAAK,EAAE,SAAS,EAChB,YAAY,EACZ,QAAQ,EACR,WAAW,EACX,QAAQ,EACR,QAAgB,EAChB,KAAa,EACb,YAAY,EACZ,QAAQ,EACR,SAAc,EACd,GAAG,EACH,GAAG,IAAI,EACR,EAAE,cAAc,2CAyLhB"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
3
|
+
import React, { useRef, useCallback } from "react";
|
|
4
|
+
function ErrorIcon({ className }) {
|
|
5
|
+
return /* @__PURE__ */ jsx(
|
|
6
|
+
"svg",
|
|
7
|
+
{
|
|
8
|
+
className,
|
|
9
|
+
viewBox: "0 0 20 20",
|
|
10
|
+
fill: "currentColor",
|
|
11
|
+
"aria-hidden": "true",
|
|
12
|
+
children: /* @__PURE__ */ jsx(
|
|
13
|
+
"path",
|
|
14
|
+
{
|
|
15
|
+
fillRule: "evenodd",
|
|
16
|
+
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",
|
|
17
|
+
clipRule: "evenodd"
|
|
18
|
+
}
|
|
19
|
+
)
|
|
20
|
+
}
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
function SelectTab({
|
|
24
|
+
label,
|
|
25
|
+
secondaryLabel,
|
|
26
|
+
supportText,
|
|
27
|
+
options,
|
|
28
|
+
value: valueProp,
|
|
29
|
+
defaultValue,
|
|
30
|
+
onChange,
|
|
31
|
+
submitLabel,
|
|
32
|
+
onSubmit,
|
|
33
|
+
disabled = false,
|
|
34
|
+
error = false,
|
|
35
|
+
errorMessage,
|
|
36
|
+
required,
|
|
37
|
+
className = "",
|
|
38
|
+
ref,
|
|
39
|
+
...rest
|
|
40
|
+
}) {
|
|
41
|
+
const isControlled = valueProp !== void 0;
|
|
42
|
+
const [internal, setInternal] = React.useState(defaultValue ?? "");
|
|
43
|
+
const selected = isControlled ? valueProp : internal;
|
|
44
|
+
const itemRefs = useRef([]);
|
|
45
|
+
const handleSelect = useCallback(
|
|
46
|
+
(val) => {
|
|
47
|
+
if (!isControlled) setInternal(val);
|
|
48
|
+
onChange == null ? void 0 : onChange(val);
|
|
49
|
+
},
|
|
50
|
+
[isControlled, onChange]
|
|
51
|
+
);
|
|
52
|
+
const focusItem = (idx) => {
|
|
53
|
+
var _a;
|
|
54
|
+
(_a = itemRefs.current[idx]) == null ? void 0 : _a.focus();
|
|
55
|
+
};
|
|
56
|
+
const handleKeyDown = (e, idx) => {
|
|
57
|
+
const enabled = options.map((o, i) => o.disabled || disabled ? -1 : i).filter((i) => i !== -1);
|
|
58
|
+
const pos = enabled.indexOf(idx);
|
|
59
|
+
switch (e.key) {
|
|
60
|
+
case "ArrowRight":
|
|
61
|
+
case "ArrowDown": {
|
|
62
|
+
e.preventDefault();
|
|
63
|
+
const next = enabled[(pos + 1) % enabled.length];
|
|
64
|
+
focusItem(next);
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
case "ArrowLeft":
|
|
68
|
+
case "ArrowUp": {
|
|
69
|
+
e.preventDefault();
|
|
70
|
+
const prev = enabled[(pos - 1 + enabled.length) % enabled.length];
|
|
71
|
+
focusItem(prev);
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
case "Home": {
|
|
75
|
+
e.preventDefault();
|
|
76
|
+
focusItem(enabled[0]);
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
case "End": {
|
|
80
|
+
e.preventDefault();
|
|
81
|
+
focusItem(enabled[enabled.length - 1]);
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
const showErrorAlert = error && errorMessage;
|
|
87
|
+
return /* @__PURE__ */ jsxs(
|
|
88
|
+
"div",
|
|
89
|
+
{
|
|
90
|
+
ref,
|
|
91
|
+
className: `flex flex-col gap-space-2 w-full ${className}`,
|
|
92
|
+
...rest,
|
|
93
|
+
children: [
|
|
94
|
+
(label || supportText) && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-space-1", children: [
|
|
95
|
+
label && /* @__PURE__ */ jsxs(
|
|
96
|
+
"span",
|
|
97
|
+
{
|
|
98
|
+
className: `text-form-label ${disabled ? "text-text-disabled" : "text-text-primary"}`,
|
|
99
|
+
children: [
|
|
100
|
+
label,
|
|
101
|
+
secondaryLabel && /* @__PURE__ */ jsx("span", { className: "text-text-secondary font-normal ml-1", children: secondaryLabel }),
|
|
102
|
+
required && /* @__PURE__ */ jsx("span", { className: "text-text-err ml-0.5", children: "*" })
|
|
103
|
+
]
|
|
104
|
+
}
|
|
105
|
+
),
|
|
106
|
+
supportText && /* @__PURE__ */ jsx("p", { className: `text-text-xs ${disabled ? "text-text-disabled" : "text-text-secondary"}`, children: supportText })
|
|
107
|
+
] }),
|
|
108
|
+
/* @__PURE__ */ jsxs(
|
|
109
|
+
"div",
|
|
110
|
+
{
|
|
111
|
+
role: "radiogroup",
|
|
112
|
+
"aria-label": label,
|
|
113
|
+
className: "flex items-center gap-space-2 flex-wrap",
|
|
114
|
+
children: [
|
|
115
|
+
options.map((opt, i) => {
|
|
116
|
+
const isSelected = selected === opt.value;
|
|
117
|
+
const isItemDisabled = disabled || !!opt.disabled;
|
|
118
|
+
const cellClasses = [
|
|
119
|
+
"flex w-[48px] h-[48px] justify-center items-center",
|
|
120
|
+
"rounded-rad-md font-mono text-[12px] leading-[1.4]",
|
|
121
|
+
"outline-none transition-all duration-150",
|
|
122
|
+
isSelected && !isItemDisabled && "bg-green-900 text-neutral-0 border-border-sm border-green-900",
|
|
123
|
+
!isSelected && !isItemDisabled && !error && "border-border-sm border-border-form-primary bg-fill-form-primary text-text-primary",
|
|
124
|
+
!isSelected && !isItemDisabled && error && "border-border-sm border-border-err bg-fill-form-primary text-text-primary",
|
|
125
|
+
!isItemDisabled && !isSelected && "hover:border-border-form-primary-hover active:border-border-form-primary-active",
|
|
126
|
+
!isItemDisabled && "focus-visible:ring-[1.5px] focus-visible:ring-border-focus focus-visible:ring-offset-[3px]",
|
|
127
|
+
isItemDisabled && !isSelected && "border-border-sm border-border-form-primary-disabled bg-fill-form-primary-disabled text-text-disabled cursor-not-allowed",
|
|
128
|
+
isItemDisabled && isSelected && "bg-green-900/50 text-neutral-0/50 border-border-sm border-green-900/50 cursor-not-allowed"
|
|
129
|
+
].filter(Boolean).join(" ");
|
|
130
|
+
return /* @__PURE__ */ jsx(
|
|
131
|
+
"button",
|
|
132
|
+
{
|
|
133
|
+
ref: (el) => {
|
|
134
|
+
itemRefs.current[i] = el;
|
|
135
|
+
},
|
|
136
|
+
type: "button",
|
|
137
|
+
role: "radio",
|
|
138
|
+
"aria-checked": isSelected,
|
|
139
|
+
"aria-disabled": isItemDisabled || void 0,
|
|
140
|
+
tabIndex: isSelected ? 0 : -1,
|
|
141
|
+
disabled: isItemDisabled,
|
|
142
|
+
className: cellClasses,
|
|
143
|
+
onClick: () => handleSelect(opt.value),
|
|
144
|
+
onKeyDown: (e) => handleKeyDown(e, i),
|
|
145
|
+
children: opt.label ?? opt.value
|
|
146
|
+
},
|
|
147
|
+
opt.value
|
|
148
|
+
);
|
|
149
|
+
}),
|
|
150
|
+
submitLabel && /* @__PURE__ */ jsx(
|
|
151
|
+
"button",
|
|
152
|
+
{
|
|
153
|
+
type: "button",
|
|
154
|
+
disabled,
|
|
155
|
+
onClick: onSubmit,
|
|
156
|
+
className: `text-text-xs font-medium ml-space-1 ${disabled ? "text-text-disabled cursor-not-allowed" : "text-text-primary hover:text-text-secondary"}`,
|
|
157
|
+
children: submitLabel
|
|
158
|
+
}
|
|
159
|
+
)
|
|
160
|
+
]
|
|
161
|
+
}
|
|
162
|
+
),
|
|
163
|
+
showErrorAlert && /* @__PURE__ */ jsxs(
|
|
164
|
+
"div",
|
|
165
|
+
{
|
|
166
|
+
role: "alert",
|
|
167
|
+
className: `flex items-start gap-space-4 p-space-4 rounded-rad-md ${disabled ? "bg-fill-bg-secondary" : "bg-fill-bg-err"}`,
|
|
168
|
+
children: [
|
|
169
|
+
/* @__PURE__ */ jsx(
|
|
170
|
+
ErrorIcon,
|
|
171
|
+
{
|
|
172
|
+
className: `w-5 h-5 shrink-0 ${disabled ? "text-icon-primary-disabled" : "text-icon-err"}`
|
|
173
|
+
}
|
|
174
|
+
),
|
|
175
|
+
/* @__PURE__ */ jsx(
|
|
176
|
+
"span",
|
|
177
|
+
{
|
|
178
|
+
className: `text-text-xs ${disabled ? "text-text-disabled" : "text-text-err"}`,
|
|
179
|
+
children: errorMessage
|
|
180
|
+
}
|
|
181
|
+
)
|
|
182
|
+
]
|
|
183
|
+
}
|
|
184
|
+
)
|
|
185
|
+
]
|
|
186
|
+
}
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
export {
|
|
190
|
+
SelectTab
|
|
191
|
+
};
|
|
192
|
+
//# sourceMappingURL=SelectTab.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SelectTab.js","sources":["../../../src/components/SelectTab/SelectTab.tsx"],"sourcesContent":["'use client';\n\nimport React, { useRef, useCallback } from 'react';\n\n/**\n * Shape of a single SelectTab option. Rendered as a 48×48 selectable cell.\n */\nexport interface SelectTabOption {\n /** Value when this option is selected. Must be unique. */\n value: string;\n /** Visible label inside the cell. Falls back to value. @default undefined */\n label?: string;\n /** When true, this option cannot be selected. @default undefined */\n disabled?: boolean;\n}\n\n/**\n * Props for the SelectTab component. Single selection from a row of 48×48 cells.\n * Use for small choice sets (e.g. quantity 0–9, size XS–XL) where a dropdown is\n * overkill. For a traditional dropdown use Select. value/onChange for controlled mode.\n */\nexport interface SelectTabProps {\n /** Label text displayed above the tab row. @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 /** Options rendered as selectable 48×48 cells. Each: value, label?, disabled?. @see SelectTabOption */\n options: SelectTabOption[];\n /** Controlled selected value. Use with onChange. @default undefined */\n value?: string;\n /** Uncontrolled default selected value. @default undefined */\n defaultValue?: string;\n /** Called when the selected value changes. @default undefined */\n onChange?: (value: string) => void;\n /** Optional label at the end of the row (e.g. \"Submit\"). @default undefined */\n submitLabel?: string;\n /** Called when the submit label is clicked. @default undefined */\n onSubmit?: () => void;\n /** Disables all options. @default false */\n disabled?: boolean;\n /** Places the component in an error state. @default false */\n error?: boolean;\n /** Error message shown in the alert below the row when error is true. @default undefined */\n errorMessage?: string;\n /** When true, shows required asterisk next to the label. @default undefined */\n required?: boolean;\n /** Additional CSS class names on the outer wrapper. @default undefined */\n className?: string;\n /** Forwarded ref for the root div. @default undefined */\n ref?: React.Ref<HTMLDivElement>;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\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\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\n/**\n * Tab-style single-selection row where each option is a 48×48 cell. Use for quantity,\n * size, or other small choice sets. Only one option can be selected (radio-like);\n * supports keyboard navigation (arrows, Home, End). For dropdown single-select use Select.\n *\n * @example\n * <SelectTab label=\"Quantity\" options={[{ value: '0', label: '0' }, { value: '1', label: '1' }]} submitLabel=\"Submit\" onSubmit={handleSubmit} />\n *\n * @example\n * <SelectTab label=\"Size\" value={size} onChange={setSize} options={sizeOptions} error={!!err} errorMessage={err} />\n */\nexport function SelectTab({\n label,\n secondaryLabel,\n supportText,\n options,\n value: valueProp,\n defaultValue,\n onChange,\n submitLabel,\n onSubmit,\n disabled = false,\n error = false,\n errorMessage,\n required,\n className = '',\n ref,\n ...rest\n}: SelectTabProps) {\n const isControlled = valueProp !== undefined;\n const [internal, setInternal] = React.useState(defaultValue ?? '');\n const selected = isControlled ? valueProp : internal;\n\n const itemRefs = useRef<(HTMLButtonElement | null)[]>([]);\n\n const handleSelect = useCallback(\n (val: string) => {\n if (!isControlled) setInternal(val);\n onChange?.(val);\n },\n [isControlled, onChange],\n );\n\n const focusItem = (idx: number) => {\n itemRefs.current[idx]?.focus();\n };\n\n const handleKeyDown = (e: React.KeyboardEvent, idx: number) => {\n const enabled = options\n .map((o, i) => (o.disabled || disabled ? -1 : i))\n .filter((i) => i !== -1);\n const pos = enabled.indexOf(idx);\n\n switch (e.key) {\n case 'ArrowRight':\n case 'ArrowDown': {\n e.preventDefault();\n const next = enabled[(pos + 1) % enabled.length];\n focusItem(next);\n break;\n }\n case 'ArrowLeft':\n case 'ArrowUp': {\n e.preventDefault();\n const prev = enabled[(pos - 1 + enabled.length) % enabled.length];\n focusItem(prev);\n break;\n }\n case 'Home': {\n e.preventDefault();\n focusItem(enabled[0]);\n break;\n }\n case 'End': {\n e.preventDefault();\n focusItem(enabled[enabled.length - 1]);\n break;\n }\n }\n };\n\n const showErrorAlert = error && errorMessage;\n\n return (\n <div\n ref={ref}\n className={`flex flex-col gap-space-2 w-full ${className}`}\n {...rest}\n >\n {/* Label + support text */}\n {(label || supportText) && (\n <div className=\"flex flex-col gap-space-1\">\n {label && (\n <span\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 </span>\n )}\n {supportText && (\n <p className={`text-text-xs ${disabled ? 'text-text-disabled' : 'text-text-secondary'}`}>\n {supportText}\n </p>\n )}\n </div>\n )}\n\n {/* Tab row */}\n <div\n role=\"radiogroup\"\n aria-label={label}\n className=\"flex items-center gap-space-2 flex-wrap\"\n >\n {options.map((opt, i) => {\n const isSelected = selected === opt.value;\n const isItemDisabled = disabled || !!opt.disabled;\n\n const cellClasses = [\n 'flex w-[48px] h-[48px] justify-center items-center',\n 'rounded-rad-md font-mono text-[12px] leading-[1.4]',\n 'outline-none transition-all duration-150',\n\n isSelected && !isItemDisabled &&\n 'bg-green-900 text-neutral-0 border-border-sm border-green-900',\n\n !isSelected && !isItemDisabled && !error &&\n 'border-border-sm border-border-form-primary bg-fill-form-primary text-text-primary',\n\n !isSelected && !isItemDisabled && error &&\n 'border-border-sm border-border-err bg-fill-form-primary text-text-primary',\n\n !isItemDisabled && !isSelected &&\n 'hover:border-border-form-primary-hover active:border-border-form-primary-active',\n\n !isItemDisabled &&\n 'focus-visible:ring-[1.5px] focus-visible:ring-border-focus focus-visible:ring-offset-[3px]',\n\n isItemDisabled && !isSelected &&\n 'border-border-sm border-border-form-primary-disabled bg-fill-form-primary-disabled text-text-disabled cursor-not-allowed',\n\n isItemDisabled && isSelected &&\n 'bg-green-900/50 text-neutral-0/50 border-border-sm border-green-900/50 cursor-not-allowed',\n ]\n .filter(Boolean)\n .join(' ');\n\n return (\n <button\n key={opt.value}\n ref={(el) => { itemRefs.current[i] = el; }}\n type=\"button\"\n role=\"radio\"\n aria-checked={isSelected}\n aria-disabled={isItemDisabled || undefined}\n tabIndex={isSelected ? 0 : -1}\n disabled={isItemDisabled}\n className={cellClasses}\n onClick={() => handleSelect(opt.value)}\n onKeyDown={(e) => handleKeyDown(e, i)}\n >\n {opt.label ?? opt.value}\n </button>\n );\n })}\n\n {submitLabel && (\n <button\n type=\"button\"\n disabled={disabled}\n onClick={onSubmit}\n className={`text-text-xs font-medium ml-space-1 ${\n disabled\n ? 'text-text-disabled cursor-not-allowed'\n : 'text-text-primary hover:text-text-secondary'\n }`}\n >\n {submitLabel}\n </button>\n )}\n </div>\n\n {/* Error alert */}\n {showErrorAlert && (\n <div\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":";;;AA0DA;AACE;AACE;AAAC;AAAA;AACC;AACQ;AACH;AACO;AAEZ;AAAC;AAAA;AACU;AACP;AACO;AAAA;AAAA;AACX;AAGN;AAiBO;AAAmB;AACxB;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACW;AACH;AACR;AACA;AACY;AACZ;AAEF;AACE;AACA;AACA;AAEA;AAEA;AAAqB;AAEjB;AACA;AAAW;AACb;AACuB;AAGzB;;AACE;AAAuB;AAGzB;AACE;AAGA;AAEA;AAAU;AACH;AAEH;AACA;AACA;AACA;AAAA;AACF;AACK;AAEH;AACA;AACA;AACA;AAAA;AACF;AAEE;AACA;AACA;AAAA;AACF;AAEE;AACA;AACA;AAAA;AACF;AAAA;AAIJ;AAEA;AACE;AAAC;AAAA;AACC;AACwD;AACpD;AAGF;AAEG;AACC;AAAC;AAAA;AACoF;AAElF;AAAA;AAIC;AAGwC;AAAA;AAAA;AAAA;AAO5C;AAEJ;AAIF;AAAC;AAAA;AACM;AACO;AACF;AAET;AACC;AACA;AAEA;AAAoB;AAClB;AACA;AACA;AAGE;AAGA;AAGA;AAGA;AAGA;AAGA;AAGA;AAKJ;AACE;AAAC;AAAA;AAEgB;AAAsB;AAAI;AACpC;AACA;AACS;AACmB;AACN;AACjB;AACC;AAC0B;AACD;AAElB;AAAA;AAZT;AAAA;AAed;AAGC;AAAC;AAAA;AACM;AACL;AACS;AAKT;AAEC;AAAA;AAAA;AACH;AAAA;AAAA;AAMF;AAAC;AAAA;AACM;AAGL;AAEA;AAAA;AAAC;AAAA;AAGC;AAAA;AAAA;AAEF;AAAC;AAAA;AAGC;AAEC;AAAA;AAAA;AACH;AAAA;AAAA;AACF;AAAA;AAIR;;;;"}
|