ADDED: slider label but it's not done

This commit is contained in:
doryan04 2024-02-25 19:52:36 +04:00
parent 1410861afb
commit 33bd4f57a6
5 changed files with 94 additions and 108 deletions

View File

@ -1,109 +1,14 @@
import React from 'react'; import React from 'react';
import { Card } from '../src/primitive-components/card/card'; import { Card } from '../src/primitive-components/card/card';
import {
Button,
FAB,
IconButton,
} from '../src/primitive-components/components';
import { CardFooter } from '../src/primitive-components/card/card-footer'; import { CardFooter } from '../src/primitive-components/card/card-footer';
import { SegmentButton } from '../src/primitive-components/button-components/segmented-buttons/segment-button'; import { Slider } from '../src/primitive-components/input-components/slider/slider';
import { SegmentedButtons } from '../src/primitive-components/button-components/segmented-buttons/segmented-buttons';
export default function Page() { export default function Page() {
return ( return (
<main> <main>
<Card variant={'outlined'}> <Card variant={'outlined'}>
<CardFooter> <CardFooter>
<Button> Default Button </Button> <Slider />
<Button ripple={false}> Default Button </Button>
<FAB icon={'edit'} variant={'secondary'} />
<FAB icon={'edit'} ripple={false} variant={'secondary'} />
<IconButton
icon={'settings'}
ripple={false}
variant={'filled'}
/>
<IconButton
icon={'settings'}
ripple={false}
variant={'default'}
/>
<IconButton
icon={'settings'}
ripple={false}
variant={'tonal'}
/>
<IconButton
icon={'settings'}
ripple={false}
variant={'outlined'}
/>
<IconButton
icon={'settings'}
ripple={false}
toggled={{
selected: 'settings',
unselected: 'settings',
}}
variant={'filled'}
/>
<IconButton
icon={'settings'}
ripple={false}
toggled={{
selected: 'settings',
unselected: 'settings',
}}
variant={'default'}
/>
<IconButton
icon={'settings'}
ripple={false}
toggled={{
selected: 'settings',
unselected: 'settings',
}}
variant={'tonal'}
/>
<IconButton
icon={'settings'}
ripple={false}
toggled={{
selected: 'settings',
unselected: 'settings',
}}
variant={'outlined'}
/>
<SegmentedButtons density={-2} selectable={true}>
<SegmentButton
fillIcon={1}
icon={'change_history'}
ripple={false}
>
Label 1
</SegmentButton>
<SegmentButton
fillIcon={1}
icon={'change_history'}
iconPlace={'right'}
ripple={false}
selectable={false}
>
Not selectable
</SegmentButton>
<SegmentButton
fillIcon={1}
icon={'change_history'}
iconPlace={'right'}
ripple={false}
>
Label 3
</SegmentButton>
<SegmentButton disabled>Label 4</SegmentButton>
</SegmentedButtons>
</CardFooter> </CardFooter>
</Card> </Card>
</main> </main>

View File

@ -1,5 +1,6 @@
'use client'; 'use client';
import { Typography } from '../../typography/typography';
import { InputLayout } from '../input-layout/input-layout'; import { InputLayout } from '../input-layout/input-layout';
import React, { import React, {
ChangeEvent, ChangeEvent,
@ -14,33 +15,71 @@ interface SliderProps extends InputHTMLAttributes<HTMLInputElement> {
options?: number[]; options?: number[];
} }
function fractionCalc(current: number | string, max: number | string): number {
const _current = isNaN(parseInt(current as string))
? 50
: parseInt(current as string);
const _max = isNaN(parseInt(max as string)) ? 100 : parseInt(max as string);
return (_current / _max) * 100;
}
function gradientStyle(value: number): string {
return `linear-gradient( to right, var(--md-sys-color-primary) ${value}%, var(--md-sys-color-surface-container-highest) ${value}%)`;
}
export const Slider = forwardRef<HTMLInputElement, SliderProps>( export const Slider = forwardRef<HTMLInputElement, SliderProps>(
({ options, ...props }, ref) => { ({ options, ...props }, ref) => {
const sliderId = useId(); const sliderId = useId();
const [isChrome, setIsChrome] = useState<boolean>(false); const [isChrome, setIsChrome] = useState<boolean>(false);
const [value, setValue] = useState(props.defaultValue ?? 50);
useLayoutEffect(() => { useLayoutEffect(() => {
setIsChrome(navigator.userAgent.indexOf('AppleWebKit') != -1); setIsChrome(navigator.userAgent.indexOf('AppleWebKit') != -1);
}, []); }, []);
if (isChrome) {
const initialFraction = fractionCalc(
(props.value as string) ?? (props.defaultValue as string),
props.max as string,
);
if (props.style === undefined) {
props.style = {};
}
props.style.background = gradientStyle(initialFraction);
}
const webkitProgress = (event: ChangeEvent<HTMLInputElement>) => {
if (isChrome) {
const fraction = fractionCalc(
(event.target.value as string) ??
(event.target.defaultValue as string),
event.target.max,
);
event.target.style.background = gradientStyle(fraction);
}
};
return ( return (
<div className={'m3 m3-slider-container'}> <div className={'m3 m3-slider-container'}>
<div className={'m3 m3-slider-label'}>
<Typography role={'label'} size={'small'}>
{value}
</Typography>
</div>
<InputLayout <InputLayout
{...props} {...props}
className={props.className} className={props.className}
list={sliderId} list={sliderId}
onChange={(event: ChangeEvent<HTMLInputElement>) => { onChange={(event: ChangeEvent<HTMLInputElement>) => {
props.onChange?.apply(this, props?.onChange?.prototype); props.onChange?.apply(this, props?.onChange?.prototype);
setValue(event.target.value);
if (isChrome) { if (isChrome) {
const fraction = webkitProgress(event);
(parseInt(event.target.value) /
parseInt(event.target.max)) *
100;
event.target.style.background = `linear-gradient(\
to right, var(--md-sys-color-primary) ${fraction}%, \
var(--md-sys-color-surface-container-highest) ${fraction}%\
)`;
} }
}} }}
ref={ref} ref={ref}

View File

@ -925,6 +925,29 @@ div.m3.m3-slider-container {
display: flex; display: flex;
align-items: center; align-items: center;
} }
div.m3.m3-slider-container div.m3.m3-slider-label {
display: inline-flex;
align-items: center;
justify-content: center;
position: absolute;
pointer-events: none;
}
div.m3.m3-slider-container div.m3.m3-slider-label::before {
content: "";
width: 28px;
rotate: 45deg;
aspect-ratio: 1;
position: absolute;
border-radius: 14px 14px 0 14px;
background-color: var(--md-sys-color-primary);
}
div.m3.m3-slider-container div.m3.m3-slider-label > label.m3.m3-typography {
display: inline;
font-weight: 500;
position: absolute;
font-size: 12px !important;
color: var(--md-sys-color-on-primary);
}
div.m3.m3-slider-container > datalist { div.m3.m3-slider-container > datalist {
display: none; display: none;
} }

File diff suppressed because one or more lines are too long

View File

@ -19,13 +19,32 @@
background: var(--md-sys-color-primary) background: var(--md-sys-color-primary)
transition: .2s cubic-bezier(0.2, 0, 0, 1) transition: .2s cubic-bezier(0.2, 0, 0, 1)
div.m3.m3-slider-container div.m3.m3-slider-container
height: 20px height: 20px
display: flex display: flex
align-items: center align-items: center
div.m3.m3-slider-label
@include center(inline-flex)
position: absolute
pointer-events: none
&::before
content: ""
width: 28px
rotate: 45deg
aspect-ratio: 1
position: absolute
border-radius: 14px 14px 0 14px
background-color: var(--md-sys-color-primary)
& > label.m3.m3-typography
display: inline
font-weight: 500
position: absolute
font-size: 12px !important
color: var(--md-sys-color-on-primary)
& > datalist & > datalist
display: none display: none