ADDED: Card sub-components
TODO: Complete styles for card sub-components and section button
This commit is contained in:
parent
80702813f4
commit
d0a34e7a1f
40
app/page.tsx
40
app/page.tsx
|
@ -1,9 +1,12 @@
|
|||
import React from 'react';
|
||||
import testImage1 from './test-images/test-image-1.jpg';
|
||||
import { Card } from '../src/primitive-components/card/card';
|
||||
import { CardMedia } from '../src/primitive-components/card/card-media';
|
||||
import { CardActionArea } from '../src/primitive-components/card/card-action-area';
|
||||
import { Button } from '../src/primitive-components/button-components/button/button';
|
||||
|
||||
const cardStyles = { width: '256px', aspectRatio: 1 };
|
||||
import { CardHeader } from '../src/primitive-components/card/card-header';
|
||||
import { CardBody } from '../src/primitive-components/card/card-body';
|
||||
import { CardFooter } from '../src/primitive-components/card/card-footer';
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
|
@ -17,17 +20,36 @@ export default function Page() {
|
|||
padding: '8px',
|
||||
}}
|
||||
>
|
||||
<div style={{ display: 'flex', gap: '8px' }}>
|
||||
<Card style={cardStyles} variant={'filled'}>
|
||||
<CardActionArea>
|
||||
<div style={{ display: 'flex', gap: '8px', maxWidth: 512 }}>
|
||||
<Card variant={'outlined'}>
|
||||
<CardHeader>
|
||||
<h1>Header</h1>
|
||||
</CardHeader>
|
||||
<CardActionArea>
|
||||
<CardMedia src={testImage1.src} type={'img'} />
|
||||
<CardBody>
|
||||
<h4>
|
||||
<strong>Sub-header</strong>
|
||||
</h4>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consecrate
|
||||
adipiscing elit, sed do eiusmod tempor
|
||||
incididunt ut labore et dolore magna aliqua.
|
||||
Ut enim ad minim veniam, quis nostrud
|
||||
exercitation ullamco laboris nisi ut aliquip
|
||||
ex ea commodo consequat. Duis aute irure
|
||||
dolor in reprehenderit in voluptate velit
|
||||
esse cillum dolore eu fugiat nulla pariatur.
|
||||
Excepteur sint occaecat cupidatat non
|
||||
proident, sunt in culpa qui officia deserunt
|
||||
mollit anim id est laborum.
|
||||
</p>
|
||||
</CardBody>
|
||||
</CardActionArea>
|
||||
<div>
|
||||
<CardFooter>
|
||||
<Button>label</Button>
|
||||
</div>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
<Card style={cardStyles} variant={'outlined'} />
|
||||
<Card style={cardStyles} variant={'elevated'} />
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 132 KiB |
|
@ -0,0 +1,10 @@
|
|||
module.exports = {
|
||||
images: {
|
||||
remotePatterns: [
|
||||
{
|
||||
protocol: 'https',
|
||||
hostname: '**',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
|
@ -13,14 +13,14 @@ export const ButtonLayout = forwardRef<HTMLButtonElement, ButtonLayoutProps>(
|
|||
buttonId = useId(),
|
||||
events = useRippleEffect(ripplesRef, setIsActive);
|
||||
|
||||
const classes =
|
||||
const extraClassStyles =
|
||||
`m3${isActive ? ' is-active' : ''} ${props.className ?? ''}`.trimEnd();
|
||||
|
||||
return (
|
||||
<button
|
||||
{...props}
|
||||
{...events}
|
||||
className={classes}
|
||||
className={extraClassStyles}
|
||||
disabled={props.disabled}
|
||||
id={buttonId}
|
||||
ref={ref}
|
||||
|
|
|
@ -30,11 +30,11 @@ export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
|
|||
icon: toggled ? toggled.unselected ?? 'add_circle' : 'add_circle',
|
||||
});
|
||||
|
||||
const classes = `m3-icon-button ${toggleIcon.state} ${variant} ${toggled ? 'toggled' : ''} ${className}`;
|
||||
const extraClassStyles = `m3-icon-button ${toggleIcon.state} ${variant} ${toggled ? 'toggled' : ''} ${className}`;
|
||||
|
||||
const toggle = (classes: string, icon: string) => {
|
||||
const toggle = (extraClassStyles: string, icon: string) => {
|
||||
setToggleIcon({
|
||||
state: classes,
|
||||
state: extraClassStyles,
|
||||
icon: icon,
|
||||
});
|
||||
};
|
||||
|
@ -60,7 +60,7 @@ export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
|
|||
<ButtonLayout
|
||||
{...props}
|
||||
centralRipple={centralRipple}
|
||||
className={classes}
|
||||
className={extraClassStyles}
|
||||
disabled={disabled}
|
||||
onClick={callback}
|
||||
ref={buttonRef}
|
||||
|
|
|
@ -14,14 +14,14 @@ export const CardActionArea = forwardRef<HTMLDivElement, CardActionAreaProps>(
|
|||
setIsActive,
|
||||
ripples,
|
||||
);
|
||||
const classes =
|
||||
const extraClassStyles =
|
||||
`m3 m3-card-action-area${isActive ? ' is-active' : ''} ${props.className ?? ''}`.trimEnd();
|
||||
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
{...CardActionAreaEvents}
|
||||
className={classes}
|
||||
className={extraClassStyles}
|
||||
ref={ref}
|
||||
>
|
||||
<div className={'m3 m3-card-action-area-content'}>
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
import React from 'react';
|
||||
|
||||
export function CardActions(props) {
|
||||
return (
|
||||
<div></div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
import React, { forwardRef, HTMLAttributes } from 'react';
|
||||
|
||||
export const CardBody = forwardRef<HTMLElement, HTMLAttributes<HTMLElement>>(
|
||||
(props, ref) => {
|
||||
const extraClassStyles =
|
||||
`m3 m3-card-body ${props.className ?? ''}`.trimEnd();
|
||||
|
||||
return (
|
||||
<section {...props} className={extraClassStyles} ref={ref}>
|
||||
{props.children}
|
||||
</section>
|
||||
);
|
||||
},
|
||||
);
|
|
@ -1,7 +0,0 @@
|
|||
import React from 'react';
|
||||
|
||||
export function CardContent(props) {
|
||||
return (
|
||||
<div></div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
import React, { forwardRef, HTMLAttributes } from 'react';
|
||||
|
||||
export const CardFooter = forwardRef<
|
||||
HTMLDivElement,
|
||||
HTMLAttributes<HTMLDivElement>
|
||||
>((props, ref) => {
|
||||
const extraClassStyles =
|
||||
`m3 m3-card-footer ${props.className ?? ''}`.trimEnd();
|
||||
|
||||
return (
|
||||
<div {...props} className={extraClassStyles} ref={ref}>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
});
|
|
@ -1,7 +1,15 @@
|
|||
import React from 'react';
|
||||
import React, { forwardRef, HTMLAttributes } from 'react';
|
||||
|
||||
export const CardHeader = forwardRef<
|
||||
HTMLHeadElement,
|
||||
HTMLAttributes<HTMLHeadElement>
|
||||
>((props, ref) => {
|
||||
const extraClassStyles =
|
||||
`m3 m3-card-header ${props.className ?? ''}`.trimEnd();
|
||||
|
||||
export function CardHeader(props) {
|
||||
return (
|
||||
<div></div>
|
||||
<header {...props} className={extraClassStyles} ref={ref}>
|
||||
{props.children}
|
||||
</header>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,33 +1,19 @@
|
|||
import Image from 'next/image';
|
||||
import React, { forwardRef } from 'react';
|
||||
import { createElement, forwardRef } from 'react';
|
||||
import { CardMediaProps, CardMediaType } from './card.types';
|
||||
|
||||
export const CardMedia = forwardRef<CardMediaType, CardMediaProps>(
|
||||
(
|
||||
{
|
||||
alt,
|
||||
src,
|
||||
type,
|
||||
quality = 80,
|
||||
rounded = true,
|
||||
preview = true,
|
||||
className = '',
|
||||
...props
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
const classes =
|
||||
`m3 m3-card-media${rounded ? ' m3-rounded' : ''}${preview ? ' m3-preview' : ''} ${className}`.trimEnd();
|
||||
({ type, rounded = true, className = '', ...props }, ref) => {
|
||||
const extraClassStyles =
|
||||
`m3 m3-card-media${rounded ? ' m3-rounded' : ''} ${className}`.trimEnd();
|
||||
|
||||
switch (type) {
|
||||
case 'img':
|
||||
return <Image alt={alt} quality={quality} src={src} />;
|
||||
default:
|
||||
return React.createElement(type, {
|
||||
return createElement(
|
||||
type,
|
||||
{
|
||||
...props,
|
||||
className: classes,
|
||||
className: extraClassStyles,
|
||||
ref: ref,
|
||||
});
|
||||
}
|
||||
},
|
||||
props.children,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -4,12 +4,12 @@ import { Container } from '../container/container';
|
|||
|
||||
export const Card = forwardRef<HTMLDivElement, CardProps>(
|
||||
({ variant = 'filled', ...props }, ref) => {
|
||||
const classes = `m3-card m3-card-${variant} ${props.className ?? ''}`;
|
||||
const extraClassStyles = `m3-card m3-card-${variant} ${props.className ?? ''}`;
|
||||
|
||||
return (
|
||||
<Container
|
||||
{...props}
|
||||
className={classes}
|
||||
className={extraClassStyles}
|
||||
ref={ref}
|
||||
variant={variant}
|
||||
>
|
||||
|
|
|
@ -1,26 +1,22 @@
|
|||
import { HTMLAttributes } from 'react';
|
||||
import { HTMLProps } from 'react';
|
||||
import { ContainerProps } from '../container/container.types';
|
||||
import { RipplePropsForComponents } from '../ripple/ripple.types';
|
||||
|
||||
export interface CardProps extends ContainerProps {}
|
||||
|
||||
export interface CardActionAreaProps
|
||||
extends RipplePropsForComponents<HTMLDivElement> {
|
||||
ripples?: boolean;
|
||||
}
|
||||
|
||||
export interface CardProps extends ContainerProps {}
|
||||
|
||||
export interface CardMediaProps extends HTMLAttributes<CardMediaType> {
|
||||
alt: string;
|
||||
src: string;
|
||||
quality?: number;
|
||||
export interface CardMediaProps extends HTMLProps<CardMediaType> {
|
||||
rounded?: boolean;
|
||||
preview?: boolean;
|
||||
type: 'img' | 'video' | 'picture' | 'iframe' | 'audio';
|
||||
}
|
||||
|
||||
export type CardMediaType = HTMLImageElement &
|
||||
HTMLVideoElement &
|
||||
HTMLPictureElement &
|
||||
HTMLMediaElement &
|
||||
HTMLIFrameElement &
|
||||
HTMLAudioElement;
|
||||
export type CardMediaType =
|
||||
| HTMLImageElement
|
||||
| HTMLVideoElement
|
||||
| HTMLPictureElement
|
||||
| HTMLIFrameElement
|
||||
| HTMLAudioElement;
|
||||
|
|
|
@ -3,11 +3,11 @@ import { ContainerProps } from './container.types';
|
|||
|
||||
export const Container = forwardRef<HTMLDivElement, ContainerProps>(
|
||||
({ variant = 'filled', ...props }, ref) => {
|
||||
const classes =
|
||||
const extraClassStyles =
|
||||
`m3 m3-container m3-container-${variant} ${props.className ?? ''}`.trimEnd();
|
||||
|
||||
return (
|
||||
<div {...props} className={classes} ref={ref}>
|
||||
<div {...props} className={extraClassStyles} ref={ref}>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -21,7 +21,7 @@ export const CheckBoxLayout = forwardRef<HTMLInputElement, CheckboxLayoutProps>(
|
|||
|
||||
const classesType = typeInput || type;
|
||||
|
||||
const classes =
|
||||
const extraClassStyles =
|
||||
props.className !== undefined
|
||||
? `m3 m3-${type} ${props.className}`
|
||||
: `m3 m3-${classesType}`;
|
||||
|
@ -30,7 +30,7 @@ export const CheckBoxLayout = forwardRef<HTMLInputElement, CheckboxLayoutProps>(
|
|||
<input
|
||||
ref={checkboxRef}
|
||||
{...props}
|
||||
className={classes.trimEnd()}
|
||||
className={extraClassStyles.trimEnd()}
|
||||
type={type}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -26,7 +26,7 @@ export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
|
|||
checkboxRef = useRef(null),
|
||||
events = useRippleEffect(ripplesRef, setIsActive);
|
||||
|
||||
const classes =
|
||||
const extraClassStyles =
|
||||
`m3 m3-checkbox-label ${isActive === true ? 'visible' : ''}`.trimEnd();
|
||||
|
||||
useImperativeHandle(ref, () => checkboxRef.current);
|
||||
|
@ -36,7 +36,7 @@ export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
|
|||
}, [checkboxRef.current?.checked]);
|
||||
|
||||
return (
|
||||
<label {...events} className={classes}>
|
||||
<label {...events} className={extraClassStyles}>
|
||||
<CheckBoxLayout
|
||||
{...props}
|
||||
indeterminate={props.indeterminate}
|
||||
|
|
|
@ -18,11 +18,11 @@ export const Radio = forwardRef<HTMLInputElement, RadioProps>(
|
|||
ripplesRef = useRef(null),
|
||||
events = useRippleEffect(ripplesRef, setIsActive);
|
||||
|
||||
const classes =
|
||||
const extraClassStyles =
|
||||
`m3 m3-radio ${isActive === true ? 'visible' : ''}`.trimEnd();
|
||||
|
||||
return (
|
||||
<div {...events} className={classes}>
|
||||
<div {...events} className={extraClassStyles}>
|
||||
<CheckBoxLayout {...props} ref={ref} type={'radio'} />
|
||||
<span className={'m3 m3-radio-state-layer'} />
|
||||
<svg height={'20px'} viewBox={'0 0 20 20'} width={'20px'}>
|
||||
|
|
|
@ -24,7 +24,7 @@ const RippleArea = forwardRef(
|
|||
uniqueKey = useRef<number>(0),
|
||||
uniqueId = useId();
|
||||
|
||||
const classes = props.className
|
||||
const extraClassStyles = props.className
|
||||
? `m3 m3-ripple-domain ${props.className}`.trimEnd()
|
||||
: 'm3 m3-ripple-domain';
|
||||
|
||||
|
@ -121,7 +121,7 @@ const RippleArea = forwardRef(
|
|||
);
|
||||
|
||||
return (
|
||||
<span className={classes} id={uniqueId} ref={rippleDomain}>
|
||||
<span className={extraClassStyles} id={uniqueId} ref={rippleDomain}>
|
||||
<rippleAreaContext.Provider value={clicked.current}>
|
||||
<Ripples>{ripples}</Ripples>
|
||||
</rippleAreaContext.Provider>
|
||||
|
|
|
@ -1,8 +1,28 @@
|
|||
@import 'mixins/m3-mixins'
|
||||
|
||||
div.m3.m3-card-action-area
|
||||
$padding: 16px
|
||||
|
||||
.m3:not(:first-child):is(.m3-card)
|
||||
padding: $padding
|
||||
|
||||
:is(div.m3-card-footer, header.m3-card-header, section.m3-card-body).m3
|
||||
padding: $padding
|
||||
display: block
|
||||
box-sizing: border-box
|
||||
|
||||
.m3.m3-card-media
|
||||
&.m3-rounded
|
||||
border-radius: 12px
|
||||
|
||||
width: 100%
|
||||
height: 100%
|
||||
display: block
|
||||
contain: content
|
||||
position: relative
|
||||
box-sizing: border-box
|
||||
|
||||
div.m3.m3-card-action-area
|
||||
display: block
|
||||
cursor: pointer
|
||||
contain: content
|
||||
position: relative
|
||||
|
@ -10,9 +30,12 @@ div.m3.m3-card-action-area
|
|||
transition: box-shadow .2s cubic-bezier(0.2, 0, 0, 1)
|
||||
|
||||
& > div.m3.m3-card-action-area-content
|
||||
position: absolute
|
||||
top: 0
|
||||
width: 100%
|
||||
position: relative
|
||||
|
||||
& > span.m3.m3-card-state-layer
|
||||
& > span.m3:is(.m3-card-state-layer, .m3-ripple-domain)
|
||||
top: 0
|
||||
width: 100%
|
||||
height: 100%
|
||||
position: absolute
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue