parent
08c590c745
commit
d94e1b7360
18
app/page.tsx
18
app/page.tsx
|
@ -1,15 +1,16 @@
|
|||
import React from 'react';
|
||||
import testImage1 from './test-images/test-image-1.jpg';
|
||||
import { Card } from '../src/primitive-components/card/card';
|
||||
import { Checkbox } from '../src/primitive-components/components';
|
||||
import { CardBody } from '../src/primitive-components/card/card-body';
|
||||
import { CardMedia } from '../src/primitive-components/card/card-media';
|
||||
import { CardFooter } from '../src/primitive-components/card/card-footer';
|
||||
import { CardHeader } from '../src/primitive-components/card/card-header';
|
||||
import { SegmentedButtons } from '../src/primitive-components/components';
|
||||
import { Typography } from '../src/primitive-components/typography/typography';
|
||||
import { CardActionArea } from '../src/primitive-components/card/card-action-area';
|
||||
import { Button } from '../src/primitive-components/button-components/button/button';
|
||||
import { SegmentButton } from '../src/primitive-components/button-components/segmented-buttons/segmented-buttons';
|
||||
import { SegmentButton } from '../src/primitive-components/button-components/segmented-buttons/segment-button';
|
||||
import { SegmentedButtons } from '../src/primitive-components/button-components/segmented-buttons/segmented-buttons';
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
|
@ -23,7 +24,7 @@ export default function Page() {
|
|||
padding: '8px',
|
||||
}}
|
||||
>
|
||||
<div style={{ display: 'flex', gap: '8px', maxWidth: '512px' }}>
|
||||
<div style={{ display: 'flex', gap: '8px', maxWidth: '768px' }}>
|
||||
<Card variant={'outlined'}>
|
||||
<CardHeader>
|
||||
<Typography.h3> Header-3 </Typography.h3>
|
||||
|
@ -52,18 +53,23 @@ export default function Page() {
|
|||
<Button icon={'add'} iconPlace={'right'}>
|
||||
Label 2
|
||||
</Button>
|
||||
<SegmentedButtons>
|
||||
<SegmentButton icon={'add'}>
|
||||
<SegmentedButtons toggled>
|
||||
<SegmentButton
|
||||
fillIcon={1}
|
||||
icon={'change_history'}
|
||||
>
|
||||
Label 1
|
||||
</SegmentButton>
|
||||
<SegmentButton
|
||||
icon={'add'}
|
||||
fillIcon={1}
|
||||
icon={'change_history'}
|
||||
iconPlace={'right'}
|
||||
>
|
||||
Label 2
|
||||
</SegmentButton>
|
||||
<SegmentButton>Label 3</SegmentButton>
|
||||
</SegmentedButtons>
|
||||
<Checkbox />
|
||||
</div>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
'use client';
|
||||
|
||||
import { string } from 'prop-types';
|
||||
import React, { forwardRef, useState } from 'react';
|
||||
import { IconWrapper } from '../../icon/icon-wrapper';
|
||||
import { SegmentedButton } from './segmented-buttons.types';
|
||||
import { ButtonLayout } from '../button-layout/button-layout';
|
||||
import { ButtonLayoutProps } from '../button-layout/button-layout.types';
|
||||
|
||||
export const SegmentButton = forwardRef<
|
||||
HTMLButtonElement,
|
||||
ButtonLayoutProps & SegmentedButton
|
||||
>(
|
||||
(
|
||||
{
|
||||
icon,
|
||||
toggled = false,
|
||||
iconPlace = 'left',
|
||||
centralRipple = false,
|
||||
...props
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
const {
|
||||
fillIcon,
|
||||
grade,
|
||||
svgSize,
|
||||
iconSize,
|
||||
opticalSize,
|
||||
type,
|
||||
weight,
|
||||
} = props;
|
||||
|
||||
const [selectedState, setSelectedState] = useState<boolean>(false);
|
||||
const classes =
|
||||
`m3-button-segment${selectedState ? ' selected' : ''} ${props.className ?? ''}`.trimEnd();
|
||||
|
||||
const _icon = selectedState && icon;
|
||||
|
||||
return (
|
||||
<ButtonLayout
|
||||
{...props}
|
||||
centralRipple={centralRipple}
|
||||
className={classes}
|
||||
onClick={() => {
|
||||
if (toggled) {
|
||||
setSelectedState(state => !state);
|
||||
}
|
||||
props.onClick?.apply(this, props.onClick.arguments);
|
||||
}}
|
||||
ref={ref}
|
||||
>
|
||||
<IconWrapper
|
||||
fillIcon={fillIcon}
|
||||
grade={grade}
|
||||
icon={_icon}
|
||||
iconPlace={iconPlace}
|
||||
iconSize={iconSize}
|
||||
opticalSize={opticalSize}
|
||||
svgSize={svgSize}
|
||||
type={type}
|
||||
weight={weight}
|
||||
>
|
||||
<span className={'label-large'}>{props.children}</span>
|
||||
</IconWrapper>
|
||||
<span className={'m3 m3-button-segment-state-layer'} />
|
||||
</ButtonLayout>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
SegmentButton.propTypes = {
|
||||
children: string,
|
||||
};
|
|
@ -1,51 +1,33 @@
|
|||
import React, { forwardRef } from 'react';
|
||||
import {
|
||||
SegmentedButton,
|
||||
SegmentedButtonsProps,
|
||||
} from './segmented-buttons.types';
|
||||
import { string } from 'prop-types';
|
||||
import { ButtonLayout } from '../../components';
|
||||
import { ButtonLayoutProps } from '../button-layout/button-layout.types';
|
||||
import { IconWrapper } from '../../icon/icon-wrapper';
|
||||
'use client';
|
||||
|
||||
export const SegmentButton = forwardRef<
|
||||
HTMLButtonElement,
|
||||
ButtonLayoutProps & SegmentedButton
|
||||
>(({ centralRipple = false, iconPlace = 'left', icon, ...props }, ref) => {
|
||||
const classes = `m3-button-segment ${props.className ?? ''}`.trimEnd();
|
||||
return (
|
||||
<ButtonLayout
|
||||
{...props}
|
||||
centralRipple={centralRipple}
|
||||
className={classes}
|
||||
ref={ref}
|
||||
>
|
||||
<IconWrapper icon={icon} iconPlace={iconPlace}>
|
||||
<span className={'label-large'}>{props.children}</span>
|
||||
</IconWrapper>
|
||||
<span className={'m3 m3-button-segment-state-layer'} />
|
||||
</ButtonLayout>
|
||||
);
|
||||
});
|
||||
|
||||
SegmentButton.propTypes = {
|
||||
children: string,
|
||||
};
|
||||
import { SegmentButton } from './segment-button';
|
||||
import { SegmentedButtonsProps } from './segmented-buttons.types';
|
||||
import React, { cloneElement, forwardRef, ReactElement } from 'react';
|
||||
|
||||
export const SegmentedButtons = forwardRef<
|
||||
HTMLDivElement,
|
||||
SegmentedButtonsProps
|
||||
>(({ children, ...props }, ref) => {
|
||||
>(({ toggled = false, children, ...props }, ref) => {
|
||||
if (children.length <= 1) {
|
||||
throw 'You must build segmented button with 2 or more buttton';
|
||||
throw 'You must build segmented button with 2 or more button';
|
||||
}
|
||||
|
||||
const SegmentedButtons: Array<ReactElement> = children.map(
|
||||
(Button: ReactElement, index: number) => {
|
||||
return cloneElement(<SegmentButton />, {
|
||||
...Button.props,
|
||||
toggled: toggled,
|
||||
key: index,
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`m3 m3-segmented-buttons ${props.className ?? ''}`.trimEnd()}
|
||||
ref={ref}
|
||||
>
|
||||
{children}
|
||||
{SegmentedButtons}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
import { HTMLAttributes, ReactElement } from 'react';
|
||||
import { IconWrapperProps } from '../../icon/icon.types';
|
||||
import { IconProps, IconWrapperProps } from '../../icon/icon.types';
|
||||
|
||||
export type SegmentedButton = IconWrapperProps & {
|
||||
icon?: string;
|
||||
toggled?: boolean;
|
||||
centralRipple?: boolean;
|
||||
children?: string | ReactElement<IconProps>;
|
||||
};
|
||||
|
||||
export interface SegmentedButtons {
|
||||
toggled?: boolean;
|
||||
children?: ReactElement<HTMLButtonElement>[];
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ const Ripple = ({
|
|||
const rippleDomainContext = useContext(rippleAreaContext);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (endLifetime !== null && !rippleDomainContext) {
|
||||
if (endLifetime && !rippleDomainContext) {
|
||||
setClasses('m3 ripple');
|
||||
setTimeout(() => endLifetime(rippleKey), lifetime);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
input[type="button"].test-button
|
||||
color: white
|
||||
&:not(:checked)
|
||||
background-color: green
|
||||
&:checked
|
||||
background-color: blue
|
||||
|
||||
button:not(.m3-fab, .m3-icon-button)
|
||||
width: min-content
|
||||
height: min-content
|
||||
|
|
|
@ -1,31 +1,46 @@
|
|||
div.m3.m3-segmented-buttons
|
||||
padding: 0
|
||||
height: 40px
|
||||
display: flex
|
||||
flex-direction: row
|
||||
width: min-content
|
||||
border-radius: 20px
|
||||
box-sizing: border-box
|
||||
border-collapse: collapse
|
||||
|
||||
& > button.m3.m3-button-segment
|
||||
margin: 0 -0.5px 0 -0.5px
|
||||
|
||||
& > button.m3.m3-button-segment:first-child
|
||||
border-radius: 20px 0 0 20px
|
||||
& > button.m3.m3-button-segment:last-child
|
||||
border-radius: 0 20px 20px 0
|
||||
|
||||
& > button.m3.m3-button-segment
|
||||
height: 40px
|
||||
border-radius: 0
|
||||
display: flex
|
||||
min-width: 108px
|
||||
width: max-content
|
||||
box-sizing: border-box
|
||||
padding-inline: 10px
|
||||
border: 1px solid var(--md-sys-color-outline)
|
||||
|
||||
&
|
||||
border-radius: 0
|
||||
background-color: transparent
|
||||
|
||||
& > span
|
||||
color: var(--md-sys-color-on-surface)
|
||||
|
||||
& > svg > text
|
||||
fill: var(--md-sys-color-on-surface)
|
||||
|
||||
&:not(:first-child)
|
||||
margin-left: -1px
|
||||
&.selected
|
||||
background-color: var(--md-sys-color-secondary-container)
|
||||
|
||||
&:first-child
|
||||
border-radius: 20px 0 0 20px
|
||||
&.selected > span
|
||||
color: var(--md-sys-color-on-secondary-container)
|
||||
|
||||
&:last-child
|
||||
border-radius: 0 20px 20px 0
|
||||
&.selected > svg > text
|
||||
fill: var(--md-sys-color-on-secondary-container)
|
||||
|
||||
& > span.m3.m3-button-segment-state-layer
|
||||
position: absolute
|
||||
|
|
|
@ -443,6 +443,16 @@ button.m3.m3-fab:focus-visible.tertiary::before {
|
|||
background-color: color-mix(in srgb, var(--md-sys-color-on-tertiary-container) 12%, transparent);
|
||||
}
|
||||
|
||||
input[type=button].test-button {
|
||||
color: white;
|
||||
}
|
||||
input[type=button].test-button:not(:checked) {
|
||||
background-color: green;
|
||||
}
|
||||
input[type=button].test-button:checked {
|
||||
background-color: blue;
|
||||
}
|
||||
|
||||
button:not(.m3-fab, .m3-icon-button) {
|
||||
width: min-content;
|
||||
height: min-content;
|
||||
|
@ -712,33 +722,49 @@ button.m3.m3-icon-button:focus-visible:not(:disabled).tonal.toggled::before {
|
|||
}
|
||||
|
||||
div.m3.m3-segmented-buttons {
|
||||
padding: 0;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: min-content;
|
||||
border-radius: 20px;
|
||||
box-sizing: border-box;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
div.m3.m3-segmented-buttons > button.m3.m3-button-segment {
|
||||
margin: 0 -0.5px 0 -0.5px;
|
||||
}
|
||||
div.m3.m3-segmented-buttons > button.m3.m3-button-segment:first-child {
|
||||
border-radius: 20px 0 0 20px;
|
||||
}
|
||||
div.m3.m3-segmented-buttons > button.m3.m3-button-segment:last-child {
|
||||
border-radius: 0 20px 20px 0;
|
||||
}
|
||||
div.m3.m3-segmented-buttons > button.m3.m3-button-segment {
|
||||
height: 40px;
|
||||
border-radius: 0;
|
||||
display: flex;
|
||||
min-width: 108px;
|
||||
width: max-content;
|
||||
box-sizing: border-box;
|
||||
padding-inline: 10px;
|
||||
border: 1px solid var(--md-sys-color-outline);
|
||||
}
|
||||
div.m3.m3-segmented-buttons > button.m3.m3-button-segment {
|
||||
border-radius: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
div.m3.m3-segmented-buttons > button.m3.m3-button-segment > span {
|
||||
color: var(--md-sys-color-on-surface);
|
||||
}
|
||||
div.m3.m3-segmented-buttons > button.m3.m3-button-segment > svg > text {
|
||||
fill: var(--md-sys-color-on-surface);
|
||||
}
|
||||
div.m3.m3-segmented-buttons > button.m3.m3-button-segment:not(:first-child) {
|
||||
margin-left: -1px;
|
||||
div.m3.m3-segmented-buttons > button.m3.m3-button-segment.selected {
|
||||
background-color: var(--md-sys-color-secondary-container);
|
||||
}
|
||||
div.m3.m3-segmented-buttons > button.m3.m3-button-segment:first-child {
|
||||
border-radius: 20px 0 0 20px;
|
||||
div.m3.m3-segmented-buttons > button.m3.m3-button-segment.selected > span {
|
||||
color: var(--md-sys-color-on-secondary-container);
|
||||
}
|
||||
div.m3.m3-segmented-buttons > button.m3.m3-button-segment:last-child {
|
||||
border-radius: 0 20px 20px 0;
|
||||
div.m3.m3-segmented-buttons > button.m3.m3-button-segment.selected > svg > text {
|
||||
fill: var(--md-sys-color-on-secondary-container);
|
||||
}
|
||||
div.m3.m3-segmented-buttons > button.m3.m3-button-segment > span.m3.m3-button-segment-state-layer {
|
||||
position: absolute;
|
||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue