@shohojdhara/atomix 0.2.7 → 0.2.8
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/CHANGELOG.md +2 -0
- package/dist/atomix.css +332 -54
- package/dist/atomix.min.css +2 -2
- package/dist/index.d.ts +286 -10
- package/dist/index.esm.js +451 -124
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +451 -124
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/themes/applemix.css +332 -54
- package/dist/themes/applemix.min.css +2 -2
- package/dist/themes/boomdevs.css +331 -53
- package/dist/themes/boomdevs.min.css +2 -2
- package/dist/themes/esrar.css +332 -54
- package/dist/themes/esrar.min.css +2 -2
- package/dist/themes/flashtrade.css +1636 -512
- package/dist/themes/flashtrade.min.css +113 -7
- package/dist/themes/mashroom.css +331 -53
- package/dist/themes/mashroom.min.css +2 -2
- package/dist/themes/shaj-default.css +331 -53
- package/dist/themes/shaj-default.min.css +2 -2
- package/package.json +1 -1
- package/src/components/Button/Button.stories.tsx +174 -0
- package/src/components/Button/Button.tsx +238 -78
- package/src/components/Card/Card.stories.tsx +202 -0
- package/src/components/Card/Card.tsx +248 -77
- package/src/components/Form/Input.stories.tsx +228 -2
- package/src/components/Tooltip/Tooltip.tsx +68 -66
- package/src/lib/composables/useButton.ts +37 -5
- package/src/lib/composables/useInput.ts +39 -1
- package/src/lib/constants/components.ts +53 -0
- package/src/lib/types/components.ts +278 -4
- package/src/styles/01-settings/_settings.tooltip.scss +2 -2
- package/src/styles/06-components/_components.button.scss +100 -0
- package/src/styles/06-components/_components.card.scss +219 -1
- package/src/styles/06-components/_components.tooltip.scss +89 -66
|
@@ -19,9 +19,29 @@ const meta: Meta<typeof Card> = {
|
|
|
19
19
|
image: { control: 'text' },
|
|
20
20
|
imageAlt: { control: 'text' },
|
|
21
21
|
footer: { control: 'text' },
|
|
22
|
+
size: {
|
|
23
|
+
control: 'select',
|
|
24
|
+
options: ['sm', 'md', 'lg'],
|
|
25
|
+
},
|
|
26
|
+
variant: {
|
|
27
|
+
control: 'select',
|
|
28
|
+
options: ['primary', 'secondary', 'success', 'error', 'warning', 'info', 'light', 'dark'],
|
|
29
|
+
},
|
|
30
|
+
appearance: {
|
|
31
|
+
control: 'select',
|
|
32
|
+
options: ['filled', 'outlined', 'ghost', 'elevated'],
|
|
33
|
+
},
|
|
34
|
+
elevation: {
|
|
35
|
+
control: 'select',
|
|
36
|
+
options: ['none', 'sm', 'md', 'lg', 'xl'],
|
|
37
|
+
},
|
|
22
38
|
row: { control: 'boolean' },
|
|
23
39
|
flat: { control: 'boolean' },
|
|
24
40
|
active: { control: 'boolean' },
|
|
41
|
+
disabled: { control: 'boolean' },
|
|
42
|
+
loading: { control: 'boolean' },
|
|
43
|
+
selected: { control: 'boolean' },
|
|
44
|
+
interactive: { control: 'boolean' },
|
|
25
45
|
className: { control: 'text' },
|
|
26
46
|
},
|
|
27
47
|
};
|
|
@@ -806,3 +826,185 @@ export const GlassCardLayouts: Story = {
|
|
|
806
826
|
</div>
|
|
807
827
|
),
|
|
808
828
|
};
|
|
829
|
+
|
|
830
|
+
// Size Variants
|
|
831
|
+
export const SizeVariants: Story = {
|
|
832
|
+
render: () => (
|
|
833
|
+
<div style={{ display: 'flex', gap: '1rem', flexWrap: 'wrap' }}>
|
|
834
|
+
<Card
|
|
835
|
+
size="sm"
|
|
836
|
+
title="Small Card"
|
|
837
|
+
text="This is a small card with compact spacing."
|
|
838
|
+
actions={<button className="c-btn c-btn--primary c-btn--sm">Action</button>}
|
|
839
|
+
/>
|
|
840
|
+
<Card
|
|
841
|
+
size="md"
|
|
842
|
+
title="Medium Card"
|
|
843
|
+
text="This is a medium card with default spacing."
|
|
844
|
+
actions={<button className="c-btn c-btn--primary c-btn--sm">Action</button>}
|
|
845
|
+
/>
|
|
846
|
+
<Card
|
|
847
|
+
size="lg"
|
|
848
|
+
title="Large Card"
|
|
849
|
+
text="This is a large card with spacious padding."
|
|
850
|
+
actions={<button className="c-btn c-btn--primary c-btn--sm">Action</button>}
|
|
851
|
+
/>
|
|
852
|
+
</div>
|
|
853
|
+
),
|
|
854
|
+
};
|
|
855
|
+
|
|
856
|
+
// Color Variants
|
|
857
|
+
export const ColorVariants: Story = {
|
|
858
|
+
render: () => (
|
|
859
|
+
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))', gap: '1rem' }}>
|
|
860
|
+
<Card variant="primary" title="Primary Card" text="Primary variant card." />
|
|
861
|
+
<Card variant="secondary" title="Secondary Card" text="Secondary variant card." />
|
|
862
|
+
<Card variant="success" title="Success Card" text="Success variant card." />
|
|
863
|
+
<Card variant="error" title="Error Card" text="Error variant card." />
|
|
864
|
+
<Card variant="warning" title="Warning Card" text="Warning variant card." />
|
|
865
|
+
<Card variant="info" title="Info Card" text="Info variant card." />
|
|
866
|
+
<Card variant="light" title="Light Card" text="Light variant card." />
|
|
867
|
+
<Card variant="dark" title="Dark Card" text="Dark variant card." />
|
|
868
|
+
</div>
|
|
869
|
+
),
|
|
870
|
+
};
|
|
871
|
+
|
|
872
|
+
// Appearance Variants
|
|
873
|
+
export const AppearanceVariants: Story = {
|
|
874
|
+
render: () => (
|
|
875
|
+
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))', gap: '1rem' }}>
|
|
876
|
+
<Card appearance="filled" variant="primary" title="Filled Card" text="Filled appearance with solid background." />
|
|
877
|
+
<Card appearance="outlined" variant="primary" title="Outlined Card" text="Outlined appearance with border only." />
|
|
878
|
+
<Card appearance="ghost" variant="primary" title="Ghost Card" text="Ghost appearance with minimal styling." />
|
|
879
|
+
<Card appearance="elevated" variant="primary" title="Elevated Card" text="Elevated appearance with shadow." />
|
|
880
|
+
</div>
|
|
881
|
+
),
|
|
882
|
+
};
|
|
883
|
+
|
|
884
|
+
// Elevation Levels
|
|
885
|
+
export const ElevationLevels: Story = {
|
|
886
|
+
render: () => (
|
|
887
|
+
<div style={{ display: 'flex', gap: '1rem', flexWrap: 'wrap' }}>
|
|
888
|
+
<Card elevation="none" title="No Elevation" text="Card with no shadow." />
|
|
889
|
+
<Card elevation="sm" title="Small Elevation" text="Card with small shadow." />
|
|
890
|
+
<Card elevation="md" title="Medium Elevation" text="Card with medium shadow." />
|
|
891
|
+
<Card elevation="lg" title="Large Elevation" text="Card with large shadow." />
|
|
892
|
+
<Card elevation="xl" title="Extra Large Elevation" text="Card with extra large shadow." />
|
|
893
|
+
</div>
|
|
894
|
+
),
|
|
895
|
+
};
|
|
896
|
+
|
|
897
|
+
// Disabled State
|
|
898
|
+
export const Disabled: Story = {
|
|
899
|
+
args: {
|
|
900
|
+
title: 'Disabled Card',
|
|
901
|
+
text: 'This card is disabled and cannot be interacted with.',
|
|
902
|
+
disabled: true,
|
|
903
|
+
actions: (
|
|
904
|
+
<React.Fragment>
|
|
905
|
+
<button className="c-btn c-btn--primary c-btn--sm">Action</button>
|
|
906
|
+
</React.Fragment>
|
|
907
|
+
),
|
|
908
|
+
},
|
|
909
|
+
};
|
|
910
|
+
|
|
911
|
+
// Loading State
|
|
912
|
+
export const Loading: Story = {
|
|
913
|
+
args: {
|
|
914
|
+
title: 'Loading Card',
|
|
915
|
+
text: 'This card is in a loading state.',
|
|
916
|
+
loading: true,
|
|
917
|
+
actions: (
|
|
918
|
+
<React.Fragment>
|
|
919
|
+
<button className="c-btn c-btn--primary c-btn--sm">Action</button>
|
|
920
|
+
</React.Fragment>
|
|
921
|
+
),
|
|
922
|
+
},
|
|
923
|
+
};
|
|
924
|
+
|
|
925
|
+
// Selected State
|
|
926
|
+
export const Selected: Story = {
|
|
927
|
+
args: {
|
|
928
|
+
title: 'Selected Card',
|
|
929
|
+
text: 'This card is in a selected state.',
|
|
930
|
+
selected: true,
|
|
931
|
+
variant: 'primary',
|
|
932
|
+
},
|
|
933
|
+
};
|
|
934
|
+
|
|
935
|
+
// Interactive Card
|
|
936
|
+
export const Interactive: Story = {
|
|
937
|
+
args: {
|
|
938
|
+
title: 'Interactive Card',
|
|
939
|
+
text: 'This card is interactive and responds to hover and click.',
|
|
940
|
+
interactive: true,
|
|
941
|
+
onClick: () => alert('Interactive card clicked!'),
|
|
942
|
+
variant: 'primary',
|
|
943
|
+
elevation: 'md',
|
|
944
|
+
},
|
|
945
|
+
};
|
|
946
|
+
|
|
947
|
+
// Link Card
|
|
948
|
+
export const LinkCard: Story = {
|
|
949
|
+
args: {
|
|
950
|
+
title: 'Link Card',
|
|
951
|
+
text: 'This card acts as a link. Click to navigate.',
|
|
952
|
+
href: 'https://example.com',
|
|
953
|
+
target: '_blank',
|
|
954
|
+
variant: 'primary',
|
|
955
|
+
interactive: true,
|
|
956
|
+
},
|
|
957
|
+
};
|
|
958
|
+
|
|
959
|
+
// Comprehensive Example
|
|
960
|
+
export const Comprehensive: Story = {
|
|
961
|
+
render: () => (
|
|
962
|
+
<Container>
|
|
963
|
+
<Grid>
|
|
964
|
+
<GridCol sm={6} lg={4}>
|
|
965
|
+
<Card
|
|
966
|
+
size="lg"
|
|
967
|
+
variant="primary"
|
|
968
|
+
appearance="elevated"
|
|
969
|
+
elevation="lg"
|
|
970
|
+
title="Premium Feature"
|
|
971
|
+
text="This is a comprehensive card example with all new features enabled."
|
|
972
|
+
image="https://placehold.co/400x200"
|
|
973
|
+
imageAlt="Feature image"
|
|
974
|
+
interactive
|
|
975
|
+
onClick={() => alert('Card clicked!')}
|
|
976
|
+
actions={
|
|
977
|
+
<React.Fragment>
|
|
978
|
+
<button className="c-btn c-btn--primary c-btn--sm">Get Started</button>
|
|
979
|
+
<button className="c-btn c-btn--outline-primary c-btn--sm">Learn More</button>
|
|
980
|
+
</React.Fragment>
|
|
981
|
+
}
|
|
982
|
+
/>
|
|
983
|
+
</GridCol>
|
|
984
|
+
<GridCol sm={6} lg={4}>
|
|
985
|
+
<Card
|
|
986
|
+
size="md"
|
|
987
|
+
variant="success"
|
|
988
|
+
appearance="outlined"
|
|
989
|
+
elevation="md"
|
|
990
|
+
title="Success Card"
|
|
991
|
+
text="This card uses the success variant with outlined appearance."
|
|
992
|
+
selected
|
|
993
|
+
actions={<button className="c-btn c-btn--success c-btn--sm">Action</button>}
|
|
994
|
+
/>
|
|
995
|
+
</GridCol>
|
|
996
|
+
<GridCol sm={6} lg={4}>
|
|
997
|
+
<Card
|
|
998
|
+
size="sm"
|
|
999
|
+
variant="error"
|
|
1000
|
+
appearance="ghost"
|
|
1001
|
+
title="Error Card"
|
|
1002
|
+
text="This is a small error card with ghost appearance."
|
|
1003
|
+
disabled
|
|
1004
|
+
actions={<button className="c-btn c-btn--error c-btn--sm">Action</button>}
|
|
1005
|
+
/>
|
|
1006
|
+
</GridCol>
|
|
1007
|
+
</Grid>
|
|
1008
|
+
</Container>
|
|
1009
|
+
),
|
|
1010
|
+
};
|
|
@@ -1,96 +1,267 @@
|
|
|
1
|
-
import React, { forwardRef,
|
|
1
|
+
import React, { forwardRef, useCallback, useMemo } from 'react';
|
|
2
2
|
import { CARD } from '../../lib/constants/components';
|
|
3
3
|
import { CardProps } from '../../lib/types/components';
|
|
4
4
|
import { AtomixGlass } from '../AtomixGlass/AtomixGlass';
|
|
5
5
|
|
|
6
|
-
export const Card =
|
|
7
|
-
(
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
6
|
+
export const Card = React.memo(
|
|
7
|
+
forwardRef<HTMLDivElement | HTMLAnchorElement, CardProps>(
|
|
8
|
+
(
|
|
9
|
+
{
|
|
10
|
+
// Variants
|
|
11
|
+
size = 'md',
|
|
12
|
+
variant = 'primary',
|
|
13
|
+
appearance = 'filled',
|
|
14
|
+
elevation = 'none',
|
|
15
|
+
// Layout
|
|
16
|
+
row = false,
|
|
17
|
+
flat = false,
|
|
18
|
+
// States
|
|
19
|
+
active = false,
|
|
20
|
+
disabled = false,
|
|
21
|
+
loading = false,
|
|
22
|
+
selected = false,
|
|
23
|
+
interactive = false,
|
|
24
|
+
// Content
|
|
25
|
+
header,
|
|
26
|
+
image,
|
|
27
|
+
imageAlt = '',
|
|
28
|
+
title,
|
|
29
|
+
text,
|
|
30
|
+
actions,
|
|
31
|
+
icon,
|
|
32
|
+
footer,
|
|
33
|
+
children,
|
|
34
|
+
// Interaction
|
|
35
|
+
onClick,
|
|
36
|
+
onHover,
|
|
37
|
+
onFocus,
|
|
38
|
+
href,
|
|
39
|
+
target,
|
|
40
|
+
// Glass
|
|
41
|
+
glass,
|
|
42
|
+
// Accessibility
|
|
43
|
+
role,
|
|
44
|
+
ariaLabel,
|
|
45
|
+
ariaDescribedBy,
|
|
46
|
+
tabIndex,
|
|
47
|
+
// Styling
|
|
48
|
+
className = '',
|
|
49
|
+
style,
|
|
50
|
+
...rest
|
|
51
|
+
},
|
|
52
|
+
ref
|
|
53
|
+
) => {
|
|
54
|
+
// Determine if card is clickable/interactive
|
|
55
|
+
const isClickable = Boolean(onClick || href || interactive);
|
|
56
|
+
const isDisabled = disabled || loading;
|
|
57
|
+
|
|
58
|
+
// Build CSS classes using BEM methodology
|
|
59
|
+
const cardClasses = useMemo(
|
|
60
|
+
() =>
|
|
61
|
+
[
|
|
62
|
+
CARD.CLASSES.BASE,
|
|
63
|
+
// Size modifiers
|
|
64
|
+
size === 'sm' ? CARD.CLASSES.SM : '',
|
|
65
|
+
size === 'md' ? CARD.CLASSES.MD : '',
|
|
66
|
+
size === 'lg' ? CARD.CLASSES.LG : '',
|
|
67
|
+
// Variant modifiers (will be handled in SCSS with @each)
|
|
68
|
+
variant ? `c-card--${variant}` : '',
|
|
69
|
+
// Appearance modifiers
|
|
70
|
+
appearance === 'filled' ? CARD.CLASSES.FILLED : '',
|
|
71
|
+
appearance === 'outlined' ? CARD.CLASSES.OUTLINED : '',
|
|
72
|
+
appearance === 'ghost' ? CARD.CLASSES.GHOST : '',
|
|
73
|
+
appearance === 'elevated' ? CARD.CLASSES.ELEVATED : '',
|
|
74
|
+
// Elevation modifiers
|
|
75
|
+
elevation === 'none' ? CARD.CLASSES.ELEVATION_NONE : '',
|
|
76
|
+
elevation === 'sm' ? CARD.CLASSES.ELEVATION_SM : '',
|
|
77
|
+
elevation === 'md' ? CARD.CLASSES.ELEVATION_MD : '',
|
|
78
|
+
elevation === 'lg' ? CARD.CLASSES.ELEVATION_LG : '',
|
|
79
|
+
elevation === 'xl' ? CARD.CLASSES.ELEVATION_XL : '',
|
|
80
|
+
// Layout modifiers
|
|
81
|
+
row ? CARD.CLASSES.ROW : '',
|
|
82
|
+
flat ? CARD.CLASSES.FLAT : '',
|
|
83
|
+
// State modifiers
|
|
84
|
+
active ? CARD.CLASSES.ACTIVE : '',
|
|
85
|
+
disabled ? CARD.CLASSES.DISABLED : '',
|
|
86
|
+
loading ? CARD.CLASSES.LOADING : '',
|
|
87
|
+
selected ? CARD.CLASSES.SELECTED : '',
|
|
88
|
+
interactive || isClickable ? CARD.CLASSES.INTERACTIVE : '',
|
|
89
|
+
glass ? CARD.CLASSES.GLASS : '',
|
|
90
|
+
className,
|
|
91
|
+
]
|
|
92
|
+
.filter(Boolean)
|
|
93
|
+
.join(' '),
|
|
94
|
+
[size, variant, appearance, elevation, row, flat, active, disabled, loading, selected, interactive, isClickable, glass, className]
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
// Determine ARIA role
|
|
98
|
+
const cardRole = useMemo(() => {
|
|
99
|
+
if (role) return role;
|
|
100
|
+
if (href) return 'link';
|
|
101
|
+
if (isClickable) return 'button';
|
|
102
|
+
return 'article';
|
|
103
|
+
}, [role, href, isClickable]);
|
|
104
|
+
|
|
105
|
+
// Handle click events
|
|
106
|
+
const handleClick = useCallback(
|
|
107
|
+
(event: React.MouseEvent<HTMLDivElement | HTMLAnchorElement>) => {
|
|
108
|
+
if (isDisabled) {
|
|
109
|
+
event.preventDefault();
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
onClick?.(event);
|
|
113
|
+
},
|
|
114
|
+
[isDisabled, onClick]
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
// Handle keyboard events for accessibility
|
|
118
|
+
const handleKeyDown = useCallback(
|
|
119
|
+
(event: React.KeyboardEvent<HTMLDivElement | HTMLAnchorElement>) => {
|
|
120
|
+
if (isDisabled) {
|
|
121
|
+
event.preventDefault();
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Enter or Space activates clickable cards
|
|
126
|
+
if (isClickable && (event.key === 'Enter' || event.key === ' ')) {
|
|
127
|
+
event.preventDefault();
|
|
128
|
+
if (onClick) {
|
|
129
|
+
onClick(event as unknown as React.MouseEvent<HTMLDivElement | HTMLAnchorElement>);
|
|
130
|
+
}
|
|
131
|
+
// If href is provided, the anchor will handle navigation
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
[isDisabled, isClickable, onClick]
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
// Handle hover events
|
|
138
|
+
const handleMouseEnter = useCallback(
|
|
139
|
+
(event: React.MouseEvent<HTMLDivElement | HTMLAnchorElement>) => {
|
|
140
|
+
if (!isDisabled) {
|
|
141
|
+
onHover?.(event);
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
[isDisabled, onHover]
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
// Handle focus events
|
|
148
|
+
const handleFocusEvent = useCallback(
|
|
149
|
+
(event: React.FocusEvent<HTMLDivElement | HTMLAnchorElement>) => {
|
|
150
|
+
if (!isDisabled) {
|
|
151
|
+
onFocus?.(event);
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
[isDisabled, onFocus]
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
// Determine tab index
|
|
158
|
+
const effectiveTabIndex = useMemo(() => {
|
|
159
|
+
if (tabIndex !== undefined) return tabIndex;
|
|
160
|
+
if (isDisabled) return -1;
|
|
161
|
+
if (isClickable) return 0;
|
|
162
|
+
return undefined;
|
|
163
|
+
}, [tabIndex, isDisabled, isClickable]);
|
|
47
164
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
)
|
|
165
|
+
// Card content structure
|
|
166
|
+
const cardContent = useMemo(
|
|
167
|
+
() => (
|
|
168
|
+
<>
|
|
169
|
+
{loading && (
|
|
170
|
+
<div className="c-card__loading" aria-label="Loading">
|
|
171
|
+
<div className="c-card__spinner" />
|
|
172
|
+
</div>
|
|
173
|
+
)}
|
|
51
174
|
|
|
52
|
-
|
|
53
|
-
|
|
175
|
+
{(image || icon || header) && (
|
|
176
|
+
<div className={CARD.SELECTORS.HEADER.substring(1)}>
|
|
177
|
+
{header}
|
|
178
|
+
{image && (
|
|
179
|
+
<img
|
|
180
|
+
src={image}
|
|
181
|
+
alt={imageAlt}
|
|
182
|
+
className={CARD.SELECTORS.IMAGE.substring(1)}
|
|
183
|
+
loading="lazy"
|
|
184
|
+
/>
|
|
185
|
+
)}
|
|
186
|
+
{icon && <div className={CARD.SELECTORS.ICON.substring(1)}>{icon}</div>}
|
|
187
|
+
</div>
|
|
188
|
+
)}
|
|
54
189
|
|
|
55
|
-
|
|
190
|
+
<div className={CARD.SELECTORS.BODY.substring(1)}>
|
|
191
|
+
{title && <h3 className={CARD.SELECTORS.TITLE.substring(1)}>{title}</h3>}
|
|
192
|
+
{text && <p className={CARD.SELECTORS.TEXT.substring(1)}>{text}</p>}
|
|
193
|
+
{children}
|
|
194
|
+
</div>
|
|
56
195
|
|
|
57
|
-
|
|
58
|
-
</div>
|
|
196
|
+
{actions && <div className={CARD.SELECTORS.ACTIONS.substring(1)}>{actions}</div>}
|
|
59
197
|
|
|
60
|
-
|
|
198
|
+
{footer && <div className={CARD.SELECTORS.FOOTER.substring(1)}>{footer}</div>}
|
|
199
|
+
</>
|
|
200
|
+
),
|
|
201
|
+
[loading, image, imageAlt, icon, header, title, text, children, actions, footer]
|
|
202
|
+
);
|
|
61
203
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
204
|
+
// Common props for both div and anchor
|
|
205
|
+
const commonProps = {
|
|
206
|
+
ref: ref as React.Ref<HTMLDivElement | HTMLAnchorElement>,
|
|
207
|
+
className: cardClasses,
|
|
208
|
+
style,
|
|
209
|
+
role: cardRole,
|
|
210
|
+
'aria-label': ariaLabel,
|
|
211
|
+
'aria-describedby': ariaDescribedBy,
|
|
212
|
+
'aria-disabled': isDisabled ? true : undefined,
|
|
213
|
+
tabIndex: effectiveTabIndex,
|
|
214
|
+
onClick: isClickable ? handleClick : undefined,
|
|
215
|
+
onKeyDown: isClickable ? handleKeyDown : undefined,
|
|
216
|
+
onMouseEnter: onHover ? handleMouseEnter : undefined,
|
|
217
|
+
onFocus: onFocus ? handleFocusEvent : undefined,
|
|
218
|
+
...rest,
|
|
219
|
+
};
|
|
65
220
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
onClick={onClick}
|
|
75
|
-
{...rest}
|
|
76
|
-
style={{ ...style }}
|
|
221
|
+
// Render as anchor if href is provided
|
|
222
|
+
if (href && !isDisabled) {
|
|
223
|
+
const anchorElement = (
|
|
224
|
+
<a
|
|
225
|
+
{...commonProps}
|
|
226
|
+
href={href}
|
|
227
|
+
target={target}
|
|
228
|
+
rel={target === '_blank' ? 'noopener noreferrer' : undefined}
|
|
77
229
|
>
|
|
78
230
|
{cardContent}
|
|
79
|
-
</
|
|
80
|
-
|
|
81
|
-
);
|
|
82
|
-
}
|
|
231
|
+
</a>
|
|
232
|
+
);
|
|
83
233
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
);
|
|
234
|
+
if (glass) {
|
|
235
|
+
const glassProps = glass === true ? {} : glass;
|
|
236
|
+
return (
|
|
237
|
+
<AtomixGlass {...{ ...glassProps, elasticity: 0 }}>
|
|
238
|
+
{anchorElement}
|
|
239
|
+
</AtomixGlass>
|
|
240
|
+
);
|
|
241
|
+
}
|
|
91
242
|
|
|
92
|
-
|
|
243
|
+
return anchorElement;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Render as div
|
|
247
|
+
const divElement = <div {...commonProps}>{cardContent}</div>;
|
|
248
|
+
|
|
249
|
+
if (glass) {
|
|
250
|
+
const glassProps = glass === true ? {} : glass;
|
|
251
|
+
return (
|
|
252
|
+
<AtomixGlass {...{ ...glassProps, elasticity: 0 }}>
|
|
253
|
+
{divElement}
|
|
254
|
+
</AtomixGlass>
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return divElement;
|
|
259
|
+
}
|
|
260
|
+
)
|
|
261
|
+
);
|
|
93
262
|
|
|
94
263
|
Card.displayName = 'Card';
|
|
95
264
|
|
|
265
|
+
export type { CardProps };
|
|
266
|
+
|
|
96
267
|
export default Card;
|