@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,87 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { SkeletonProps, SkeletonRadius } from '../../types/skeleton';
|
|
3
|
+
/**
|
|
4
|
+
* Loading placeholder primitive. Renders an animated shimmer shape
|
|
5
|
+
* that communicates content is loading. Use in place of content
|
|
6
|
+
* while data is being fetched.
|
|
7
|
+
*
|
|
8
|
+
* Three preset sub-components are available for common use cases:
|
|
9
|
+
* - Skeleton.Text — single line text placeholder
|
|
10
|
+
* - Skeleton.Avatar — circular profile image placeholder
|
|
11
|
+
* - Skeleton.Card — rectangular card-shaped placeholder
|
|
12
|
+
*
|
|
13
|
+
* For custom shapes, use the Skeleton primitive directly with
|
|
14
|
+
* explicit width, height, and radius props.
|
|
15
|
+
*
|
|
16
|
+
* The shimmer animation uses design system colour tokens:
|
|
17
|
+
* background: var(--col-neutral-100), highlight: var(--col-neutral-50).
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* // Custom shape
|
|
21
|
+
* <Skeleton width="100%" height="2rem" radius="xs" />
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* // Paragraph placeholder
|
|
25
|
+
* <Stack spacing="space-2">
|
|
26
|
+
* <Skeleton.Text width="100%" />
|
|
27
|
+
* <Skeleton.Text width="90%" />
|
|
28
|
+
* <Skeleton.Text width="75%" />
|
|
29
|
+
* </Stack>
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* // Profile header placeholder
|
|
33
|
+
* <Stack direction="row" spacing="space-3" alignItems="center">
|
|
34
|
+
* <Skeleton.Avatar size="2.5rem" />
|
|
35
|
+
* <Stack spacing="space-1">
|
|
36
|
+
* <Skeleton.Text width="8rem" />
|
|
37
|
+
* <Skeleton.Text width="5rem" size="xs" />
|
|
38
|
+
* </Stack>
|
|
39
|
+
* </Stack>
|
|
40
|
+
*/
|
|
41
|
+
export declare function Skeleton({ width, height, radius, label, className, style, }: SkeletonProps): import("react/jsx-runtime").JSX.Element;
|
|
42
|
+
export declare namespace Skeleton {
|
|
43
|
+
var Text: ({ width, size, className, style, }: SkeletonTextProps) => import("react/jsx-runtime").JSX.Element;
|
|
44
|
+
var Avatar: ({ size, className, style, }: SkeletonAvatarProps) => import("react/jsx-runtime").JSX.Element;
|
|
45
|
+
var Card: ({ width, height, radius, className, style, }: SkeletonCardProps) => import("react/jsx-runtime").JSX.Element;
|
|
46
|
+
}
|
|
47
|
+
/** Props for Skeleton.Text. Single-line text placeholder. */
|
|
48
|
+
interface SkeletonTextProps {
|
|
49
|
+
/** Width of the text placeholder. Number = rem. @default '100%' */
|
|
50
|
+
width?: string | number;
|
|
51
|
+
/**
|
|
52
|
+
* Typography size to match. Controls height: xs=0.75rem, sm=1rem, md=1.125rem, lg=1.5rem.
|
|
53
|
+
* @default 'sm'
|
|
54
|
+
*/
|
|
55
|
+
size?: 'xs' | 'sm' | 'md' | 'lg';
|
|
56
|
+
/** Additional className. @default undefined */
|
|
57
|
+
className?: string;
|
|
58
|
+
/** Additional inline styles. @default undefined */
|
|
59
|
+
style?: React.CSSProperties;
|
|
60
|
+
}
|
|
61
|
+
/** Props for Skeleton.Avatar. Circular avatar placeholder. */
|
|
62
|
+
interface SkeletonAvatarProps {
|
|
63
|
+
/**
|
|
64
|
+
* Diameter of the avatar circle. Number = rem, string = used as-is.
|
|
65
|
+
* @default '2.5rem'
|
|
66
|
+
*/
|
|
67
|
+
size?: string | number;
|
|
68
|
+
/** Additional className. @default undefined */
|
|
69
|
+
className?: string;
|
|
70
|
+
/** Additional inline styles. @default undefined */
|
|
71
|
+
style?: React.CSSProperties;
|
|
72
|
+
}
|
|
73
|
+
/** Props for Skeleton.Card. Rectangular card-shaped placeholder. */
|
|
74
|
+
interface SkeletonCardProps {
|
|
75
|
+
/** Width of the card. Number = rem. @default '100%' */
|
|
76
|
+
width?: string | number;
|
|
77
|
+
/** Height of the card. Number = rem. @default '8rem' */
|
|
78
|
+
height?: string | number;
|
|
79
|
+
/** Border radius token. @default 'md' */
|
|
80
|
+
radius?: SkeletonRadius;
|
|
81
|
+
/** Additional className. @default undefined */
|
|
82
|
+
className?: string;
|
|
83
|
+
/** Additional inline styles. @default undefined */
|
|
84
|
+
style?: React.CSSProperties;
|
|
85
|
+
}
|
|
86
|
+
export {};
|
|
87
|
+
//# sourceMappingURL=Skeleton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Skeleton.d.ts","sourceRoot":"","sources":["../../../src/components/Skeleton/Skeleton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,cAAc,EACpB,MAAM,sBAAsB,CAAC;AAQ9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,MAAM,EACN,MAAa,EACb,KAAoB,EACpB,SAAc,EACd,KAAK,GACN,EAAE,aAAa,2CAiBf;yBAxBe,QAAQ;mDAwDrB,iBAAiB;8CAiCjB,mBAAmB;6DAqCnB,iBAAiB;;AAlGpB,6DAA6D;AAC7D,UAAU,iBAAiB;IACzB,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB;;;OAGG;IACH,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IACjC,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mDAAmD;IACnD,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B;AA8BD,8DAA8D;AAC9D,UAAU,mBAAmB;IAC3B;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mDAAmD;IACnD,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B;AAuBD,oEAAoE;AACpE,UAAU,iBAAiB;IACzB,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,wDAAwD;IACxD,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,yCAAyC;IACzC,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mDAAmD;IACnD,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { skeletonRadiusMap } from "../../types/skeleton.js";
|
|
3
|
+
function resolveSize(value, fallback) {
|
|
4
|
+
if (value === void 0) return fallback;
|
|
5
|
+
if (typeof value === "number") return `${value}rem`;
|
|
6
|
+
return value;
|
|
7
|
+
}
|
|
8
|
+
function Skeleton({
|
|
9
|
+
width,
|
|
10
|
+
height,
|
|
11
|
+
radius = "xs",
|
|
12
|
+
label = "Loading...",
|
|
13
|
+
className = "",
|
|
14
|
+
style
|
|
15
|
+
}) {
|
|
16
|
+
const internalStyle = {
|
|
17
|
+
width: resolveSize(width, "100%"),
|
|
18
|
+
height: resolveSize(height, "1rem"),
|
|
19
|
+
borderRadius: skeletonRadiusMap[radius],
|
|
20
|
+
display: "block",
|
|
21
|
+
...style
|
|
22
|
+
};
|
|
23
|
+
return /* @__PURE__ */ jsx(
|
|
24
|
+
"div",
|
|
25
|
+
{
|
|
26
|
+
role: "status",
|
|
27
|
+
"aria-label": label,
|
|
28
|
+
className: ["jiwambe-skeleton", className].filter(Boolean).join(" "),
|
|
29
|
+
style: internalStyle
|
|
30
|
+
}
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
const textHeightMap = {
|
|
34
|
+
xs: "0.75rem",
|
|
35
|
+
sm: "1rem",
|
|
36
|
+
md: "1.125rem",
|
|
37
|
+
lg: "1.5rem"
|
|
38
|
+
};
|
|
39
|
+
Skeleton.Text = function SkeletonText({
|
|
40
|
+
width,
|
|
41
|
+
size = "sm",
|
|
42
|
+
className,
|
|
43
|
+
style
|
|
44
|
+
}) {
|
|
45
|
+
return /* @__PURE__ */ jsx(
|
|
46
|
+
Skeleton,
|
|
47
|
+
{
|
|
48
|
+
width: width ?? "100%",
|
|
49
|
+
height: textHeightMap[size],
|
|
50
|
+
radius: "xs",
|
|
51
|
+
label: "Loading text...",
|
|
52
|
+
className,
|
|
53
|
+
style
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
};
|
|
57
|
+
Skeleton.Avatar = function SkeletonAvatar({
|
|
58
|
+
size = "2.5rem",
|
|
59
|
+
className,
|
|
60
|
+
style
|
|
61
|
+
}) {
|
|
62
|
+
const resolved = typeof size === "number" ? `${size}rem` : size;
|
|
63
|
+
return /* @__PURE__ */ jsx(
|
|
64
|
+
Skeleton,
|
|
65
|
+
{
|
|
66
|
+
width: resolved,
|
|
67
|
+
height: resolved,
|
|
68
|
+
radius: "rounded",
|
|
69
|
+
label: "Loading avatar...",
|
|
70
|
+
className,
|
|
71
|
+
style
|
|
72
|
+
}
|
|
73
|
+
);
|
|
74
|
+
};
|
|
75
|
+
Skeleton.Card = function SkeletonCard({
|
|
76
|
+
width,
|
|
77
|
+
height = "8rem",
|
|
78
|
+
radius = "md",
|
|
79
|
+
className,
|
|
80
|
+
style
|
|
81
|
+
}) {
|
|
82
|
+
return /* @__PURE__ */ jsx(
|
|
83
|
+
Skeleton,
|
|
84
|
+
{
|
|
85
|
+
width: width ?? "100%",
|
|
86
|
+
height,
|
|
87
|
+
radius,
|
|
88
|
+
label: "Loading card...",
|
|
89
|
+
className,
|
|
90
|
+
style
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
};
|
|
94
|
+
export {
|
|
95
|
+
Skeleton
|
|
96
|
+
};
|
|
97
|
+
//# sourceMappingURL=Skeleton.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Skeleton.js","sources":["../../../src/components/Skeleton/Skeleton.tsx"],"sourcesContent":["import React from 'react';\nimport {\n skeletonRadiusMap,\n type SkeletonProps,\n type SkeletonRadius,\n} from '../../types/skeleton';\n\nfunction resolveSize(value: string | number | undefined, fallback: string): string {\n if (value === undefined) return fallback;\n if (typeof value === 'number') return `${value}rem`;\n return value;\n}\n\n/**\n * Loading placeholder primitive. Renders an animated shimmer shape\n * that communicates content is loading. Use in place of content\n * while data is being fetched.\n *\n * Three preset sub-components are available for common use cases:\n * - Skeleton.Text — single line text placeholder\n * - Skeleton.Avatar — circular profile image placeholder\n * - Skeleton.Card — rectangular card-shaped placeholder\n *\n * For custom shapes, use the Skeleton primitive directly with\n * explicit width, height, and radius props.\n *\n * The shimmer animation uses design system colour tokens:\n * background: var(--col-neutral-100), highlight: var(--col-neutral-50).\n *\n * @example\n * // Custom shape\n * <Skeleton width=\"100%\" height=\"2rem\" radius=\"xs\" />\n *\n * @example\n * // Paragraph placeholder\n * <Stack spacing=\"space-2\">\n * <Skeleton.Text width=\"100%\" />\n * <Skeleton.Text width=\"90%\" />\n * <Skeleton.Text width=\"75%\" />\n * </Stack>\n *\n * @example\n * // Profile header placeholder\n * <Stack direction=\"row\" spacing=\"space-3\" alignItems=\"center\">\n * <Skeleton.Avatar size=\"2.5rem\" />\n * <Stack spacing=\"space-1\">\n * <Skeleton.Text width=\"8rem\" />\n * <Skeleton.Text width=\"5rem\" size=\"xs\" />\n * </Stack>\n * </Stack>\n */\nexport function Skeleton({\n width,\n height,\n radius = 'xs',\n label = 'Loading...',\n className = '',\n style,\n}: SkeletonProps) {\n const internalStyle: React.CSSProperties = {\n width: resolveSize(width, '100%'),\n height: resolveSize(height, '1rem'),\n borderRadius: skeletonRadiusMap[radius],\n display: 'block',\n ...style,\n };\n\n return (\n <div\n role=\"status\"\n aria-label={label}\n className={['jiwambe-skeleton', className].filter(Boolean).join(' ')}\n style={internalStyle}\n />\n );\n}\n\n// --- Skeleton.Text ---\n\n/** Props for Skeleton.Text. Single-line text placeholder. */\ninterface SkeletonTextProps {\n /** Width of the text placeholder. Number = rem. @default '100%' */\n width?: string | number;\n /**\n * Typography size to match. Controls height: xs=0.75rem, sm=1rem, md=1.125rem, lg=1.5rem.\n * @default 'sm'\n */\n size?: 'xs' | 'sm' | 'md' | 'lg';\n /** Additional className. @default undefined */\n className?: string;\n /** Additional inline styles. @default undefined */\n style?: React.CSSProperties;\n}\n\nconst textHeightMap = {\n xs: '0.75rem',\n sm: '1rem',\n md: '1.125rem',\n lg: '1.5rem',\n};\n\n/** Single-line text loading placeholder. Height matches typography size. */\nSkeleton.Text = function SkeletonText({\n width,\n size = 'sm',\n className,\n style,\n}: SkeletonTextProps) {\n return (\n <Skeleton\n width={width ?? '100%'}\n height={textHeightMap[size]}\n radius=\"xs\"\n label=\"Loading text...\"\n className={className}\n style={style}\n />\n );\n};\n\n// --- Skeleton.Avatar ---\n\n/** Props for Skeleton.Avatar. Circular avatar placeholder. */\ninterface SkeletonAvatarProps {\n /**\n * Diameter of the avatar circle. Number = rem, string = used as-is.\n * @default '2.5rem'\n */\n size?: string | number;\n /** Additional className. @default undefined */\n className?: string;\n /** Additional inline styles. @default undefined */\n style?: React.CSSProperties;\n}\n\n/** Circular profile image loading placeholder. Always uses radius=\"rounded\". */\nSkeleton.Avatar = function SkeletonAvatar({\n size = '2.5rem',\n className,\n style,\n}: SkeletonAvatarProps) {\n const resolved = typeof size === 'number' ? `${size}rem` : size;\n return (\n <Skeleton\n width={resolved}\n height={resolved}\n radius=\"rounded\"\n label=\"Loading avatar...\"\n className={className}\n style={style}\n />\n );\n};\n\n// --- Skeleton.Card ---\n\n/** Props for Skeleton.Card. Rectangular card-shaped placeholder. */\ninterface SkeletonCardProps {\n /** Width of the card. Number = rem. @default '100%' */\n width?: string | number;\n /** Height of the card. Number = rem. @default '8rem' */\n height?: string | number;\n /** Border radius token. @default 'md' */\n radius?: SkeletonRadius;\n /** Additional className. @default undefined */\n className?: string;\n /** Additional inline styles. @default undefined */\n style?: React.CSSProperties;\n}\n\n/** Card-shaped content block loading placeholder. */\nSkeleton.Card = function SkeletonCard({\n width,\n height = '8rem',\n radius = 'md',\n className,\n style,\n}: SkeletonCardProps) {\n return (\n <Skeleton\n width={width ?? '100%'}\n height={height}\n radius={radius}\n label=\"Loading card...\"\n className={className}\n style={style}\n />\n );\n};\n"],"names":[],"mappings":";;AAOA,SAAS,YAAY,OAAoC,UAA0B;AACjF,MAAI,UAAU,OAAW,QAAO;AAChC,MAAI,OAAO,UAAU,SAAU,QAAO,GAAG,KAAK;AAC9C,SAAO;AACT;AAwCO,SAAS,SAAS;AAAA,EACvB;AAAA,EACA;AAAA,EACA,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ;AACF,GAAkB;AAChB,QAAM,gBAAqC;AAAA,IACzC,OAAO,YAAY,OAAO,MAAM;AAAA,IAChC,QAAQ,YAAY,QAAQ,MAAM;AAAA,IAClC,cAAc,kBAAkB,MAAM;AAAA,IACtC,SAAS;AAAA,IACT,GAAG;AAAA,EAAA;AAGL,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAK;AAAA,MACL,cAAY;AAAA,MACZ,WAAW,CAAC,oBAAoB,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAAA,MACnE,OAAO;AAAA,IAAA;AAAA,EAAA;AAGb;AAmBA,MAAM,gBAAgB;AAAA,EACpB,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAGA,SAAS,OAAO,SAAS,aAAa;AAAA,EACpC;AAAA,EACA,OAAO;AAAA,EACP;AAAA,EACA;AACF,GAAsB;AACpB,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,OAAO,SAAS;AAAA,MAChB,QAAQ,cAAc,IAAI;AAAA,MAC1B,QAAO;AAAA,MACP,OAAM;AAAA,MACN;AAAA,MACA;AAAA,IAAA;AAAA,EAAA;AAGN;AAkBA,SAAS,SAAS,SAAS,eAAe;AAAA,EACxC,OAAO;AAAA,EACP;AAAA,EACA;AACF,GAAwB;AACtB,QAAM,WAAW,OAAO,SAAS,WAAW,GAAG,IAAI,QAAQ;AAC3D,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAO;AAAA,MACP,OAAM;AAAA,MACN;AAAA,MACA;AAAA,IAAA;AAAA,EAAA;AAGN;AAmBA,SAAS,OAAO,SAAS,aAAa;AAAA,EACpC;AAAA,EACA,SAAS;AAAA,EACT,SAAS;AAAA,EACT;AAAA,EACA;AACF,GAAsB;AACpB,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,OAAO,SAAS;AAAA,MAChB;AAAA,MACA;AAAA,MACA,OAAM;AAAA,MACN;AAAA,MACA;AAAA,IAAA;AAAA,EAAA;AAGN;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Skeleton/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Props for the Slider component. Range input with optional labels and min/max labels.
|
|
4
|
+
* Supports controlled (value/onChange) or uncontrolled (defaultValue) usage. Track and
|
|
5
|
+
* thumb use design tokens (e.g. green for fill when not disabled).
|
|
6
|
+
*/
|
|
7
|
+
export interface SliderProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'type' | 'value' | 'defaultValue' | 'onChange'> {
|
|
8
|
+
/** Optional label above the slider. @default undefined */
|
|
9
|
+
label?: string;
|
|
10
|
+
/** Supportive text below the label. @default undefined */
|
|
11
|
+
supportText?: string;
|
|
12
|
+
/** Label shown under the track at the min end (e.g. "5,000 KES"). Falls back to min. @default undefined */
|
|
13
|
+
minLabel?: string;
|
|
14
|
+
/** Label shown under the track at the max end (e.g. "255,000 KES"). Falls back to max. @default undefined */
|
|
15
|
+
maxLabel?: string;
|
|
16
|
+
/** Controlled value (number). Use with onChange. @default undefined */
|
|
17
|
+
value?: number;
|
|
18
|
+
/** Uncontrolled default value. @default min */
|
|
19
|
+
defaultValue?: number;
|
|
20
|
+
/** Called when the value changes (drag or keyboard). @default undefined */
|
|
21
|
+
onChange?: (value: number) => void;
|
|
22
|
+
/** Minimum value. @default 0 */
|
|
23
|
+
min?: number;
|
|
24
|
+
/** Maximum value. @default 100 */
|
|
25
|
+
max?: number;
|
|
26
|
+
/** Step increment. @default 1 */
|
|
27
|
+
step?: number;
|
|
28
|
+
/** Additional class name on the wrapper. @default undefined */
|
|
29
|
+
className?: string;
|
|
30
|
+
/** ID for the range input. @default undefined */
|
|
31
|
+
id?: string;
|
|
32
|
+
/** Forwarded ref for the native range input. @default undefined */
|
|
33
|
+
ref?: React.Ref<HTMLInputElement>;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Range slider with optional label, support text, and min/max value labels. Renders a
|
|
37
|
+
* custom track and thumb (design-token colours) with a hidden native range input for
|
|
38
|
+
* accessibility. Supports controlled (value/onChange) or uncontrolled (defaultValue) usage.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* <Slider label="Amount" min={0} max={100} defaultValue={50} minLabel="0" maxLabel="100" />
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* <Slider label="Price" value={price} onChange={setPrice} min={5000} max={255000} step={1000} minLabel="5,000 KES" maxLabel="255,000 KES" />
|
|
45
|
+
*/
|
|
46
|
+
export declare function Slider({ label, supportText, minLabel, maxLabel, value: valueProp, defaultValue, onChange, min, max, step, disabled, className, id: idProp, ref, ...rest }: SliderProps): import("react/jsx-runtime").JSX.Element;
|
|
47
|
+
//# sourceMappingURL=Slider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Slider.d.ts","sourceRoot":"","sources":["../../../src/components/Slider/Slider.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAqC,MAAM,OAAO,CAAC;AAM1D;;;;GAIG;AACH,MAAM,WAAW,WACf,SAAQ,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,cAAc,GAAG,UAAU,CAAC;IACzG,0DAA0D;IAC1D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0DAA0D;IAC1D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2GAA2G;IAC3G,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6GAA6G;IAC7G,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,gCAAgC;IAChC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,iCAAiC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+DAA+D;IAC/D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iDAAiD;IACjD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,mEAAmE;IACnE,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;CACnC;AASD;;;;;;;;;;GAUG;AACH,wBAAgB,MAAM,CAAC,EACrB,KAAK,EACL,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,KAAK,EAAE,SAAS,EAChB,YAAY,EACZ,QAAQ,EACR,GAAO,EACP,GAAS,EACT,IAAQ,EACR,QAAgB,EAChB,SAAS,EACT,EAAE,EAAE,MAAM,EACV,GAAG,EACH,GAAG,IAAI,EACR,EAAE,WAAW,2CA+Hb"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
3
|
+
import React, { useId, useRef, useCallback } from "react";
|
|
4
|
+
const THUMB = 24;
|
|
5
|
+
const TRACK = 1.25;
|
|
6
|
+
function Slider({
|
|
7
|
+
label,
|
|
8
|
+
supportText,
|
|
9
|
+
minLabel,
|
|
10
|
+
maxLabel,
|
|
11
|
+
value: valueProp,
|
|
12
|
+
defaultValue,
|
|
13
|
+
onChange,
|
|
14
|
+
min = 0,
|
|
15
|
+
max = 100,
|
|
16
|
+
step = 1,
|
|
17
|
+
disabled = false,
|
|
18
|
+
className,
|
|
19
|
+
id: idProp,
|
|
20
|
+
ref,
|
|
21
|
+
...rest
|
|
22
|
+
}) {
|
|
23
|
+
const autoId = useId();
|
|
24
|
+
const id = idProp ?? autoId;
|
|
25
|
+
const isControlled = valueProp !== void 0;
|
|
26
|
+
const [internal, setInternal] = React.useState(defaultValue ?? min);
|
|
27
|
+
const value = isControlled ? valueProp : internal;
|
|
28
|
+
const [focused, setFocused] = React.useState(false);
|
|
29
|
+
const trackRef = useRef(null);
|
|
30
|
+
const handleChange = useCallback(
|
|
31
|
+
(e) => {
|
|
32
|
+
const next = Number(e.target.value);
|
|
33
|
+
if (!isControlled) setInternal(next);
|
|
34
|
+
onChange == null ? void 0 : onChange(next);
|
|
35
|
+
},
|
|
36
|
+
[isControlled, onChange]
|
|
37
|
+
);
|
|
38
|
+
const percent = max > min ? (value - min) / (max - min) * 100 : 0;
|
|
39
|
+
const pct = Math.min(100, Math.max(0, percent));
|
|
40
|
+
const thumbBg = disabled ? "#ABB5B3" : "#005748";
|
|
41
|
+
const filledBg = disabled ? "#ABB5B3" : "#005748";
|
|
42
|
+
const unfilledBg = "#CED3D2";
|
|
43
|
+
return /* @__PURE__ */ jsxs(
|
|
44
|
+
"div",
|
|
45
|
+
{
|
|
46
|
+
className: `flex flex-col gap-space-2 w-full ${className ?? ""}`,
|
|
47
|
+
children: [
|
|
48
|
+
(label || supportText) && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-space-1", children: [
|
|
49
|
+
label && /* @__PURE__ */ jsx(
|
|
50
|
+
"label",
|
|
51
|
+
{
|
|
52
|
+
htmlFor: id,
|
|
53
|
+
className: `text-form-label ${disabled ? "text-text-disabled" : "text-text-primary"}`,
|
|
54
|
+
children: label
|
|
55
|
+
}
|
|
56
|
+
),
|
|
57
|
+
supportText && /* @__PURE__ */ jsx(
|
|
58
|
+
"p",
|
|
59
|
+
{
|
|
60
|
+
className: `text-text-xs ${disabled ? "text-text-disabled" : "text-text-secondary"}`,
|
|
61
|
+
children: supportText
|
|
62
|
+
}
|
|
63
|
+
)
|
|
64
|
+
] }),
|
|
65
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-space-2", children: [
|
|
66
|
+
/* @__PURE__ */ jsxs(
|
|
67
|
+
"div",
|
|
68
|
+
{
|
|
69
|
+
ref: trackRef,
|
|
70
|
+
className: "relative w-full",
|
|
71
|
+
style: { height: THUMB },
|
|
72
|
+
children: [
|
|
73
|
+
/* @__PURE__ */ jsx(
|
|
74
|
+
"div",
|
|
75
|
+
{
|
|
76
|
+
className: "absolute left-0 right-0 rounded-full",
|
|
77
|
+
style: {
|
|
78
|
+
height: TRACK,
|
|
79
|
+
top: (THUMB - TRACK) / 2,
|
|
80
|
+
background: `linear-gradient(to right, ${filledBg} ${pct}%, ${unfilledBg} ${pct}%)`
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
),
|
|
84
|
+
/* @__PURE__ */ jsx(
|
|
85
|
+
"div",
|
|
86
|
+
{
|
|
87
|
+
className: "absolute rounded-rad-xs transition-shadow duration-150",
|
|
88
|
+
style: {
|
|
89
|
+
width: THUMB,
|
|
90
|
+
height: THUMB,
|
|
91
|
+
top: 0,
|
|
92
|
+
background: thumbBg,
|
|
93
|
+
left: `calc(${pct}% - ${pct / 100 * THUMB}px)`,
|
|
94
|
+
boxShadow: focused && !disabled ? "0 0 0 2px #fff, 0 0 0 4px var(--color-border-focus, #005748)" : "none"
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
),
|
|
98
|
+
/* @__PURE__ */ jsx(
|
|
99
|
+
"input",
|
|
100
|
+
{
|
|
101
|
+
ref,
|
|
102
|
+
type: "range",
|
|
103
|
+
id,
|
|
104
|
+
min,
|
|
105
|
+
max,
|
|
106
|
+
step,
|
|
107
|
+
value,
|
|
108
|
+
disabled,
|
|
109
|
+
onChange: handleChange,
|
|
110
|
+
onFocus: () => setFocused(true),
|
|
111
|
+
onBlur: () => setFocused(false),
|
|
112
|
+
"aria-valuemin": min,
|
|
113
|
+
"aria-valuemax": max,
|
|
114
|
+
"aria-valuenow": value,
|
|
115
|
+
className: "absolute inset-0 w-full opacity-0 cursor-pointer disabled:cursor-not-allowed",
|
|
116
|
+
style: { height: THUMB, margin: 0 },
|
|
117
|
+
...rest
|
|
118
|
+
}
|
|
119
|
+
)
|
|
120
|
+
]
|
|
121
|
+
}
|
|
122
|
+
),
|
|
123
|
+
/* @__PURE__ */ jsxs("div", { className: "flex justify-between text-text-sm", children: [
|
|
124
|
+
/* @__PURE__ */ jsx(
|
|
125
|
+
"span",
|
|
126
|
+
{
|
|
127
|
+
className: disabled ? "text-text-disabled" : "text-text-primary",
|
|
128
|
+
children: minLabel ?? min
|
|
129
|
+
}
|
|
130
|
+
),
|
|
131
|
+
/* @__PURE__ */ jsx(
|
|
132
|
+
"span",
|
|
133
|
+
{
|
|
134
|
+
className: disabled ? "text-text-disabled" : "text-text-primary",
|
|
135
|
+
children: maxLabel ?? max
|
|
136
|
+
}
|
|
137
|
+
)
|
|
138
|
+
] })
|
|
139
|
+
] })
|
|
140
|
+
]
|
|
141
|
+
}
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
export {
|
|
145
|
+
Slider
|
|
146
|
+
};
|
|
147
|
+
//# sourceMappingURL=Slider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Slider.js","sources":["../../../src/components/Slider/Slider.tsx"],"sourcesContent":["'use client';\n\nimport React, { useId, useCallback, useRef } from 'react';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * Props for the Slider component. Range input with optional labels and min/max labels.\n * Supports controlled (value/onChange) or uncontrolled (defaultValue) usage. Track and\n * thumb use design tokens (e.g. green for fill when not disabled).\n */\nexport interface SliderProps\n extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'type' | 'value' | 'defaultValue' | 'onChange'> {\n /** Optional label above the slider. @default undefined */\n label?: string;\n /** Supportive text below the label. @default undefined */\n supportText?: string;\n /** Label shown under the track at the min end (e.g. \"5,000 KES\"). Falls back to min. @default undefined */\n minLabel?: string;\n /** Label shown under the track at the max end (e.g. \"255,000 KES\"). Falls back to max. @default undefined */\n maxLabel?: string;\n /** Controlled value (number). Use with onChange. @default undefined */\n value?: number;\n /** Uncontrolled default value. @default min */\n defaultValue?: number;\n /** Called when the value changes (drag or keyboard). @default undefined */\n onChange?: (value: number) => void;\n /** Minimum value. @default 0 */\n min?: number;\n /** Maximum value. @default 100 */\n max?: number;\n /** Step increment. @default 1 */\n step?: number;\n /** Additional class name on the wrapper. @default undefined */\n className?: string;\n /** ID for the range input. @default undefined */\n id?: string;\n /** Forwarded ref for the native range input. @default undefined */\n ref?: React.Ref<HTMLInputElement>;\n}\n\nconst THUMB = 24;\nconst TRACK = 1.25;\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\n/**\n * Range slider with optional label, support text, and min/max value labels. Renders a\n * custom track and thumb (design-token colours) with a hidden native range input for\n * accessibility. Supports controlled (value/onChange) or uncontrolled (defaultValue) usage.\n *\n * @example\n * <Slider label=\"Amount\" min={0} max={100} defaultValue={50} minLabel=\"0\" maxLabel=\"100\" />\n *\n * @example\n * <Slider label=\"Price\" value={price} onChange={setPrice} min={5000} max={255000} step={1000} minLabel=\"5,000 KES\" maxLabel=\"255,000 KES\" />\n */\nexport function Slider({\n label,\n supportText,\n minLabel,\n maxLabel,\n value: valueProp,\n defaultValue,\n onChange,\n min = 0,\n max = 100,\n step = 1,\n disabled = false,\n className,\n id: idProp,\n ref,\n ...rest\n}: SliderProps) {\n const autoId = useId();\n const id = idProp ?? autoId;\n\n const isControlled = valueProp !== undefined;\n const [internal, setInternal] = React.useState(defaultValue ?? min);\n const value = isControlled ? valueProp : internal;\n const [focused, setFocused] = React.useState(false);\n\n const trackRef = useRef<HTMLDivElement>(null);\n\n const handleChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const next = Number(e.target.value);\n if (!isControlled) setInternal(next);\n onChange?.(next);\n },\n [isControlled, onChange],\n );\n\n const percent = max > min ? ((value - min) / (max - min)) * 100 : 0;\n const pct = Math.min(100, Math.max(0, percent));\n\n const thumbBg = disabled ? '#ABB5B3' : '#005748';\n const filledBg = disabled ? '#ABB5B3' : '#005748';\n const unfilledBg = '#CED3D2';\n\n return (\n <div\n className={`flex flex-col gap-space-2 w-full ${className ?? ''}`}\n >\n {(label || supportText) && (\n <div className=\"flex flex-col gap-space-1\">\n {label && (\n <label\n htmlFor={id}\n className={`text-form-label ${\n disabled ? 'text-text-disabled' : 'text-text-primary'\n }`}\n >\n {label}\n </label>\n )}\n {supportText && (\n <p\n className={`text-text-xs ${\n disabled ? 'text-text-disabled' : 'text-text-secondary'\n }`}\n >\n {supportText}\n </p>\n )}\n </div>\n )}\n\n <div className=\"flex flex-col gap-space-2\">\n <div\n ref={trackRef}\n className=\"relative w-full\"\n style={{ height: THUMB }}\n >\n {/* Track — thin line centered at 50% of the 24px container */}\n <div\n className=\"absolute left-0 right-0 rounded-full\"\n style={{\n height: TRACK,\n top: (THUMB - TRACK) / 2,\n background: `linear-gradient(to right, ${filledBg} ${pct}%, ${unfilledBg} ${pct}%)`,\n }}\n />\n\n {/* Thumb — 24×24, rad-xs (6px), centered vertically */}\n <div\n className=\"absolute rounded-rad-xs transition-shadow duration-150\"\n style={{\n width: THUMB,\n height: THUMB,\n top: 0,\n background: thumbBg,\n left: `calc(${pct}% - ${(pct / 100) * THUMB}px)`,\n boxShadow: focused && !disabled\n ? '0 0 0 2px #fff, 0 0 0 4px var(--color-border-focus, #005748)'\n : 'none',\n }}\n />\n\n {/* Hidden native input for accessibility & interaction */}\n <input\n ref={ref}\n type=\"range\"\n id={id}\n min={min}\n max={max}\n step={step}\n value={value}\n disabled={disabled}\n onChange={handleChange}\n onFocus={() => setFocused(true)}\n onBlur={() => setFocused(false)}\n aria-valuemin={min}\n aria-valuemax={max}\n aria-valuenow={value}\n className=\"absolute inset-0 w-full opacity-0 cursor-pointer disabled:cursor-not-allowed\"\n style={{ height: THUMB, margin: 0 }}\n {...rest}\n />\n </div>\n\n <div className=\"flex justify-between text-text-sm\">\n <span\n className={\n disabled ? 'text-text-disabled' : 'text-text-primary'\n }\n >\n {minLabel ?? min}\n </span>\n <span\n className={\n disabled ? 'text-text-disabled' : 'text-text-primary'\n }\n >\n {maxLabel ?? max}\n </span>\n </div>\n </div>\n </div>\n );\n}\n"],"names":[],"mappings":";;;AA2CA;AACA;AAiBO;AAAgB;AACrB;AACA;AACA;AACA;AACO;AACP;AACA;AACM;AACA;AACC;AACI;AACX;AACI;AACJ;AAEF;AACE;AACA;AAEA;AACA;AACA;AACA;AAEA;AAEA;AAAqB;AAEjB;AACA;AACA;AAAW;AACb;AACuB;AAGzB;AACA;AAEA;AACA;AACA;AAEA;AACE;AAAC;AAAA;AAC+D;AAE5D;AAEG;AACC;AAAC;AAAA;AACU;AAGT;AAEC;AAAA;AAAA;AAIH;AAAC;AAAA;AAGC;AAEC;AAAA;AAAA;AAGP;AAIA;AAAA;AAAC;AAAA;AACM;AACK;AACO;AAGjB;AAAA;AAAC;AAAA;AACW;AACH;AACG;AACe;AACwD;AAAA;AACjF;AAAA;AAIF;AAAC;AAAA;AACW;AACH;AACE;AACC;AACH;AACO;AAC+B;AAGvC;AAAA;AACN;AAAA;AAIF;AAAC;AAAA;AACC;AACK;AACL;AACA;AACA;AACA;AACA;AACA;AACU;AACoB;AACA;AACf;AACA;AACA;AACL;AACsB;AAC5B;AAAA;AAAA;AACN;AAAA;AAAA;AAIA;AAAA;AAAC;AAAA;AAEqC;AAGvB;AAAA;AAAA;AAEf;AAAC;AAAA;AAEqC;AAGvB;AAAA;AAAA;AAEjB;AACF;AAAA;AAAA;AAGN;;;;"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { SpacingProps, SpacingToken, GapProps } from '../../types/spacing';
|
|
3
|
+
import { DimensionProps } from '../../utils/responsive-props';
|
|
4
|
+
import { StackLayoutProps, AlignItemsValue, JustifyContentValue } from '../../types/layout';
|
|
5
|
+
import { StackAlign, StackJustify } from '../../utils/spacing';
|
|
6
|
+
export type { StackAlign, StackJustify } from '../../utils/spacing';
|
|
7
|
+
/** Flex direction for Stack: column (vertical) or row (horizontal). */
|
|
8
|
+
export type StackDirection = 'column' | 'row';
|
|
9
|
+
/**
|
|
10
|
+
* Tailwind display utility class values accepted by Stack's `display` prop.
|
|
11
|
+
* When provided, this replaces the default hardcoded `flex` base class so
|
|
12
|
+
* that responsive visibility utilities (e.g. `className="hidden lg:flex"`)
|
|
13
|
+
* can work correctly without specificity conflicts.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* // Visible only at lg+ (940px)
|
|
17
|
+
* <Stack display="hidden" className="lg:flex" direction="row">…</Stack>
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* // Always flex (default, no prop needed)
|
|
21
|
+
* <Stack direction="row">…</Stack>
|
|
22
|
+
*/
|
|
23
|
+
export type StackDisplay = 'flex' | 'hidden' | 'block' | 'inline-flex' | 'inline-block' | 'inline' | 'grid' | 'inline-grid' | 'contents';
|
|
24
|
+
/**
|
|
25
|
+
* Props for the Stack component. Extends SpacingProps, StackLayoutProps
|
|
26
|
+
* (alignItems, justifyContent), and div attributes.
|
|
27
|
+
*/
|
|
28
|
+
export interface StackProps extends SpacingProps, GapProps, DimensionProps, StackLayoutProps, Omit<React.HTMLAttributes<HTMLDivElement>, 'display'> {
|
|
29
|
+
/**
|
|
30
|
+
* Flex direction. Controls whether children are stacked vertically
|
|
31
|
+
* or arranged horizontally.
|
|
32
|
+
* @default 'column'
|
|
33
|
+
*/
|
|
34
|
+
direction?: StackDirection;
|
|
35
|
+
/**
|
|
36
|
+
* Gap between direct children using CSS gap — not margin. Accepts any
|
|
37
|
+
* SpacingToken string. Spacing is consistent regardless of child
|
|
38
|
+
* visibility, since gap behaves differently from margin with hidden children.
|
|
39
|
+
* @default undefined
|
|
40
|
+
*/
|
|
41
|
+
spacing?: SpacingToken;
|
|
42
|
+
/**
|
|
43
|
+
* Shorthand for aligning children on the cross axis. Accepts Jiwambe
|
|
44
|
+
* shorthand values ('start', 'center', 'end', 'stretch'). When both
|
|
45
|
+
* align and alignItems are provided, alignItems takes precedence.
|
|
46
|
+
* @see alignItems
|
|
47
|
+
*/
|
|
48
|
+
align?: StackAlign;
|
|
49
|
+
/**
|
|
50
|
+
* CSS-value alias for the align prop. Cross-axis alignment. Takes
|
|
51
|
+
* precedence over align when both are provided. Prefer for clarity.
|
|
52
|
+
* @default undefined
|
|
53
|
+
* @see align
|
|
54
|
+
*/
|
|
55
|
+
alignItems?: AlignItemsValue;
|
|
56
|
+
/**
|
|
57
|
+
* Shorthand for distributing children along the main axis. Accepts
|
|
58
|
+
* Jiwambe shorthand ('start', 'center', 'end', 'between', 'around').
|
|
59
|
+
* When both justify and justifyContent are provided, justifyContent
|
|
60
|
+
* takes precedence.
|
|
61
|
+
* @see justifyContent
|
|
62
|
+
*/
|
|
63
|
+
justify?: StackJustify;
|
|
64
|
+
/**
|
|
65
|
+
* CSS-value alias for the justify prop. Main-axis distribution. Takes
|
|
66
|
+
* precedence over justify when both are provided.
|
|
67
|
+
* @default undefined
|
|
68
|
+
* @see justify
|
|
69
|
+
*/
|
|
70
|
+
justifyContent?: JustifyContentValue;
|
|
71
|
+
/**
|
|
72
|
+
* When true, children wrap to the next line when the Stack overflows
|
|
73
|
+
* its container. Sets flex-wrap: wrap. Only meaningful when
|
|
74
|
+
* direction="row".
|
|
75
|
+
* @default false
|
|
76
|
+
*/
|
|
77
|
+
wrap?: boolean;
|
|
78
|
+
/**
|
|
79
|
+
* The HTML element to render as the root. Use for semantic correctness
|
|
80
|
+
* (e.g. as="nav", as="section").
|
|
81
|
+
* @default 'div'
|
|
82
|
+
*/
|
|
83
|
+
as?: React.ElementType;
|
|
84
|
+
/** Forwarded ref for the root element. @default undefined */
|
|
85
|
+
ref?: React.Ref<HTMLDivElement>;
|
|
86
|
+
/** Child content. @default undefined */
|
|
87
|
+
children?: React.ReactNode;
|
|
88
|
+
/**
|
|
89
|
+
* Controls the CSS display value of the root element via a Tailwind utility
|
|
90
|
+
* class. When provided, replaces the default `flex` base class so that
|
|
91
|
+
* responsive overrides in `className` work without CSS specificity conflicts.
|
|
92
|
+
*
|
|
93
|
+
* Use this together with a responsive class in `className` to implement
|
|
94
|
+
* responsive show/hide:
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* // Hidden by default, shown as flex at lg (940px+)
|
|
98
|
+
* <Stack display="hidden" className="lg:flex" direction="row" align="center">…</Stack>
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* // Shown as flex from sm (600px), hidden again at lg (940px+)
|
|
102
|
+
* <Stack display="hidden" className="sm:flex lg:hidden" direction="row">…</Stack>
|
|
103
|
+
*
|
|
104
|
+
* @default undefined — falls back to the hardcoded 'flex' base class
|
|
105
|
+
*/
|
|
106
|
+
display?: StackDisplay;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* One-dimensional flex layout component. Stacks children vertically
|
|
110
|
+
* (default) or horizontally with consistent spacing between them.
|
|
111
|
+
*
|
|
112
|
+
* Stack is specifically for linear sequences of children. For
|
|
113
|
+
* two-dimensional or multi-column layouts, use Grid. For a
|
|
114
|
+
* general-purpose wrapper, use Box.
|
|
115
|
+
*
|
|
116
|
+
* Spacing between children is controlled by the spacing prop (CSS gap),
|
|
117
|
+
* not by margin on children. This means spacing is consistent regardless
|
|
118
|
+
* of which children are visible.
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* // Vertical stack — form fields, card content
|
|
122
|
+
* <Stack spacing="space-4">
|
|
123
|
+
* <Input label="Name" />
|
|
124
|
+
* <Input label="Email" />
|
|
125
|
+
* <Button>Submit</Button>
|
|
126
|
+
* </Stack>
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* // Horizontal stack — toolbar, inline actions
|
|
130
|
+
* <Stack direction="row" spacing="space-3" alignItems="center">
|
|
131
|
+
* <Icon />
|
|
132
|
+
* <Text>Label</Text>
|
|
133
|
+
* </Stack>
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* // Responsive visibility — hidden on mobile, flex at lg+
|
|
137
|
+
* <Stack display="hidden" className="lg:flex" direction="row" align="center">
|
|
138
|
+
* …desktop nav…
|
|
139
|
+
* </Stack>
|
|
140
|
+
*/
|
|
141
|
+
export declare function Stack({ direction, spacing, align, justify, alignItems, justifyContent, wrap, as: Tag, children, className, ref, display, ...rest }: StackProps): import("react/jsx-runtime").JSX.Element;
|
|
142
|
+
export declare namespace Stack {
|
|
143
|
+
var displayName: string;
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=Stack.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Stack.d.ts","sourceRoot":"","sources":["../../../src/components/Stack/Stack.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAChF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACpB,MAAM,oBAAoB,CAAC;AAQ5B,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEpE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEpE,uEAAuE;AACvE,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,KAAK,CAAC;AAE9C;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,YAAY,GACpB,MAAM,GACN,QAAQ,GACR,OAAO,GACP,aAAa,GACb,cAAc,GACd,QAAQ,GACR,MAAM,GACN,aAAa,GACb,UAAU,CAAC;AAEf;;;GAGG;AACH,MAAM,WAAW,UACf,SAAQ,YAAY,EACpB,QAAQ,EACR,cAAc,EACd,gBAAgB,EAChB,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,SAAS,CAAC;IACrD;;;;OAIG;IACH,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B;;;;;OAKG;IACH,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,mBAAmB,CAAC;IACrC;;;;;OAKG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;;;OAIG;IACH,EAAE,CAAC,EAAE,KAAK,CAAC,WAAW,CAAC;IACvB,6DAA6D;IAC7D,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC,wCAAwC;IACxC,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,EAAE,YAAY,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,KAAK,CAAC,EACpB,SAAoB,EACpB,OAAO,EACP,KAAK,EACL,OAAO,EACP,UAAU,EACV,cAAc,EACd,IAAY,EACZ,EAAE,EAAE,GAAW,EACf,QAAQ,EACR,SAAc,EACd,GAAG,EACH,OAAO,EACP,GAAG,IAAI,EACR,EAAE,UAAU,2CAqDZ;yBAnEe,KAAK"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { resolveSpacing, gapMap, alignMap, justifyMap } from "../../utils/spacing.js";
|
|
3
|
+
import { alignItemsMap, justifyContentMap } from "../../utils/layoutClasses.js";
|
|
4
|
+
function Stack({
|
|
5
|
+
direction = "column",
|
|
6
|
+
spacing,
|
|
7
|
+
align,
|
|
8
|
+
justify,
|
|
9
|
+
alignItems,
|
|
10
|
+
justifyContent,
|
|
11
|
+
wrap = false,
|
|
12
|
+
as: Tag = "div",
|
|
13
|
+
children,
|
|
14
|
+
className = "",
|
|
15
|
+
ref,
|
|
16
|
+
display,
|
|
17
|
+
...rest
|
|
18
|
+
}) {
|
|
19
|
+
const directionClass = direction === "row" ? "flex-row" : "flex-col";
|
|
20
|
+
const spacingClass = spacing !== void 0 ? gapMap[spacing] : "";
|
|
21
|
+
const alignClass = align ? alignMap[align] : "";
|
|
22
|
+
const justifyClass = justify ? justifyMap[justify] : "";
|
|
23
|
+
const alignItemsClass = alignItems !== void 0 ? alignItemsMap[alignItems] : "";
|
|
24
|
+
const justifyContentClass = justifyContent !== void 0 ? justifyContentMap[justifyContent] : "";
|
|
25
|
+
const wrapClass = wrap ? "flex-wrap" : "";
|
|
26
|
+
const spacingPropsClasses = resolveSpacing(rest);
|
|
27
|
+
const displayClass = display !== void 0 ? display : "flex";
|
|
28
|
+
const classes = [
|
|
29
|
+
displayClass,
|
|
30
|
+
directionClass,
|
|
31
|
+
spacingClass,
|
|
32
|
+
alignClass,
|
|
33
|
+
justifyClass,
|
|
34
|
+
alignItemsClass,
|
|
35
|
+
justifyContentClass,
|
|
36
|
+
wrapClass,
|
|
37
|
+
spacingPropsClasses,
|
|
38
|
+
className
|
|
39
|
+
].filter(Boolean).join(" ");
|
|
40
|
+
const {
|
|
41
|
+
p,
|
|
42
|
+
px,
|
|
43
|
+
py,
|
|
44
|
+
pt,
|
|
45
|
+
pb,
|
|
46
|
+
pl,
|
|
47
|
+
pr,
|
|
48
|
+
m,
|
|
49
|
+
mx,
|
|
50
|
+
my,
|
|
51
|
+
mt,
|
|
52
|
+
mb,
|
|
53
|
+
ml,
|
|
54
|
+
mr,
|
|
55
|
+
width,
|
|
56
|
+
height,
|
|
57
|
+
minWidth,
|
|
58
|
+
minHeight,
|
|
59
|
+
maxWidth,
|
|
60
|
+
maxHeight,
|
|
61
|
+
gap,
|
|
62
|
+
rowGap,
|
|
63
|
+
columnGap,
|
|
64
|
+
...domRest
|
|
65
|
+
} = rest;
|
|
66
|
+
const dimensionStyle = {};
|
|
67
|
+
if (width !== void 0) dimensionStyle.width = typeof width === "string" ? width : void 0;
|
|
68
|
+
if (height !== void 0) dimensionStyle.height = typeof height === "string" ? height : void 0;
|
|
69
|
+
if (minWidth !== void 0) dimensionStyle.minWidth = typeof minWidth === "string" ? minWidth : void 0;
|
|
70
|
+
if (minHeight !== void 0) dimensionStyle.minHeight = typeof minHeight === "string" ? minHeight : void 0;
|
|
71
|
+
if (maxWidth !== void 0) dimensionStyle.maxWidth = typeof maxWidth === "string" ? maxWidth : void 0;
|
|
72
|
+
if (maxHeight !== void 0) dimensionStyle.maxHeight = typeof maxHeight === "string" ? maxHeight : void 0;
|
|
73
|
+
const inlineStyle = Object.keys(dimensionStyle).length > 0 ? dimensionStyle : void 0;
|
|
74
|
+
return /* @__PURE__ */ jsx(Tag, { ref, className: classes, style: inlineStyle, ...domRest, children });
|
|
75
|
+
}
|
|
76
|
+
Stack.displayName = "Stack";
|
|
77
|
+
export {
|
|
78
|
+
Stack
|
|
79
|
+
};
|
|
80
|
+
//# sourceMappingURL=Stack.js.map
|