Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: slider component support vertical prop #356

Merged
merged 6 commits into from
Dec 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion components/Form/__test__/__snapshots__/form.spec.ts.snap

Large diffs are not rendered by default.

14 changes: 8 additions & 6 deletions components/Slider/__test__/__snapshots__/slider.spec.ts.snap
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`Test: KSlider > props: attrs 1`] = `"<div class=\\"k-slider k-slider--base k-slider--md\\" you=\\"world\\"><div class=\\"k-slider--runway k-slider--runway--md\\" aria-hidden=\\"true\\"><div class=\\"k-slider--button-wrapper\\" aria-hidden=\\"true\\" style=\\"left: 0%;\\"><div class=\\"k-slider--button k-slider--button--md\\"></div></div> <div class=\\"k-slider--bar\\" style=\\"width: 0%; left: 0%;\\"></div></div></div>"`;
exports[`Test: KSlider > props: attrs 1`] = `"<div class=\\"k-slider k-slider--base k-slider--md\\" you=\\"world\\"><div class=\\"k-slider--runway--md k-slider--runway\\" aria-hidden=\\"true\\"><div class=\\"k-slider--button-wrapper\\" aria-hidden=\\"true\\" style=\\"left: 0%\\"><div class=\\"k-slider--button k-slider--button--md\\"></div></div> <div class=\\"k-slider--bar\\" style=\\"width: 0%; left: 0%\\"></div></div></div>"`;

exports[`Test: KSlider > props: cls 1`] = `"<div class=\\"k-slider k-slider--base k-slider--md 窈窕淑女,君子好逑\\"><div class=\\"k-slider--runway k-slider--runway--md\\" aria-hidden=\\"true\\"><div class=\\"k-slider--button-wrapper\\" aria-hidden=\\"true\\" style=\\"left: 0%;\\"><div class=\\"k-slider--button k-slider--button--md\\"></div></div> <div class=\\"k-slider--bar\\" style=\\"width: 0%; left: 0%;\\"></div></div></div>"`;
exports[`Test: KSlider > props: cls 1`] = `"<div class=\\"k-slider k-slider--base k-slider--md 窈窕淑女,君子好逑\\"><div class=\\"k-slider--runway--md k-slider--runway\\" aria-hidden=\\"true\\"><div class=\\"k-slider--button-wrapper\\" aria-hidden=\\"true\\" style=\\"left: 0%\\"><div class=\\"k-slider--button k-slider--button--md\\"></div></div> <div class=\\"k-slider--bar\\" style=\\"width: 0%; left: 0%\\"></div></div></div>"`;

exports[`Test: KSlider > props: disabled 1`] = `"<div class=\\"k-slider k-slider--base k-slider--md\\"><div class=\\"k-slider--runway k-slider--runway--md\\" aria-hidden=\\"true\\"><div class=\\"k-slider--button-wrapper\\" aria-hidden=\\"true\\" style=\\"left: 0%;\\"><div class=\\"k-slider--button k-slider--button--md\\"></div></div> <div class=\\"k-slider--bar\\" style=\\"width: 0%; left: 0%;\\"></div></div></div>"`;
exports[`Test: KSlider > props: disabled 1`] = `"<div class=\\"k-slider k-slider--base k-slider--md\\"><div class=\\"k-slider--runway--md k-slider--runway\\" aria-hidden=\\"true\\"><div class=\\"k-slider--button-wrapper\\" aria-hidden=\\"true\\" style=\\"left: 0%\\"><div class=\\"k-slider--button k-slider--button--md\\"></div></div> <div class=\\"k-slider--bar\\" style=\\"width: 0%; left: 0%\\"></div></div></div>"`;

exports[`Test: KSlider > props: min and max 1`] = `"<div class=\\"k-slider k-slider--base k-slider--md\\"><div class=\\"k-slider--runway k-slider--runway--md\\" aria-hidden=\\"true\\"><div class=\\"k-slider--button-wrapper\\" aria-hidden=\\"true\\" style=\\"left: 100%;\\"><div class=\\"k-slider--button k-slider--button--md\\"></div></div> <div class=\\"k-slider--bar\\" style=\\"width: 100%; left: 0%;\\"></div></div></div>"`;
exports[`Test: KSlider > props: min and max 1`] = `"<div class=\\"k-slider k-slider--base k-slider--md\\"><div class=\\"k-slider--runway--md k-slider--runway\\" aria-hidden=\\"true\\"><div class=\\"k-slider--button-wrapper\\" aria-hidden=\\"true\\" style=\\"left: 100%\\"><div class=\\"k-slider--button k-slider--button--md\\"></div></div> <div class=\\"k-slider--bar\\" style=\\"width: 100%; left: 0%\\"></div></div></div>"`;

exports[`Test: KSlider > props: size 1`] = `"<div class=\\"k-slider k-slider--base k-slider--lg\\"><div class=\\"k-slider--runway k-slider--runway--lg\\" aria-hidden=\\"true\\"><div class=\\"k-slider--button-wrapper\\" aria-hidden=\\"true\\" style=\\"left: 0%;\\"><div class=\\"k-slider--button k-slider--button--lg\\"></div></div> <div class=\\"k-slider--bar\\" style=\\"width: 0%; left: 0%;\\"></div></div></div>"`;
exports[`Test: KSlider > props: size 1`] = `"<div class=\\"k-slider k-slider--base k-slider--lg\\"><div class=\\"k-slider--runway--lg k-slider--runway\\" aria-hidden=\\"true\\"><div class=\\"k-slider--button-wrapper\\" aria-hidden=\\"true\\" style=\\"left: 0%\\"><div class=\\"k-slider--button k-slider--button--lg\\"></div></div> <div class=\\"k-slider--bar\\" style=\\"width: 0%; left: 0%\\"></div></div></div>"`;

exports[`Test: KSlider > props: value 1`] = `"<div class=\\"k-slider k-slider--base k-slider--md\\"><div class=\\"k-slider--runway k-slider--runway--md\\" aria-hidden=\\"true\\"><div class=\\"k-slider--button-wrapper\\" aria-hidden=\\"true\\" style=\\"left: 10%;\\"><div class=\\"k-slider--button k-slider--button--md\\"></div></div> <div class=\\"k-slider--bar\\" style=\\"width: 10%; left: 0%;\\"></div></div></div>"`;
exports[`Test: KSlider > props: value 1`] = `"<div class=\\"k-slider k-slider--base k-slider--md\\"><div class=\\"k-slider--runway--md k-slider--runway\\" aria-hidden=\\"true\\"><div class=\\"k-slider--button-wrapper\\" aria-hidden=\\"true\\" style=\\"left: 10%\\"><div class=\\"k-slider--button k-slider--button--md\\"></div></div> <div class=\\"k-slider--bar\\" style=\\"width: 10%; left: 0%\\"></div></div></div>"`;

exports[`Test: KSlider > props: vertical 1`] = `"<div class=\\"k-slider k-slider--base__vertical k-slider--md__vertical\\"><div class=\\"k-slider--runway--md__vertical k-slider--runway__vertical\\" aria-hidden=\\"true\\"><div class=\\"k-slider--button-wrapper__vertical\\" aria-hidden=\\"true\\" style=\\"bottom: 0%\\"><div class=\\"k-slider--button k-slider--button--md\\"></div></div> <div class=\\"k-slider--bar__vertical\\" style=\\"height: 0%; bottom: 0%\\"></div></div></div>"`;
18 changes: 18 additions & 0 deletions components/Slider/__test__/slider.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,24 @@ describe('Test: KSlider', () => {
expect(host.innerHTML).matchSnapshot();
});

test('props: vertical', async () => {
const instance = new KSlider({
target: host,
props: {
vertical: true
}
});
expect(instance).toBeTruthy();
await tick();
expect((host as HTMLElement)!.innerHTML.includes('k-slider--base__vertical')).toBeTruthy();
expect((host as HTMLElement)!.innerHTML.includes('k-slider--runway__vertical')).toBeTruthy();
expect(
(host as HTMLElement)!.innerHTML.includes('k-slider--button-wrapper__vertical')
).toBeTruthy();
expect((host as HTMLElement)!.innerHTML.includes('k-slider--bar__vertical')).toBeTruthy();
expect(host.innerHTML).matchSnapshot();
});

test('props: min and max', async () => {
const value = 1;
const instance = new KSlider({
Expand Down
62 changes: 50 additions & 12 deletions components/Slider/src/index.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
export let value: KSliderProps['value'] = 0;
export let step: KSliderProps['step'] = 1;
export let disabled: KSliderProps['disabled'] = false;
export let vertical: KSliderProps['vertical'] = false;
export let attrs: KSliderProps['attrs'] = {};
export let cls: KSliderProps['cls'] = undefined;

Expand Down Expand Up @@ -52,6 +53,7 @@
// current value
let isDragging: boolean = false;
let startX: number = 0;
let startY: number = 0;
let startPosition: number;
let newPosition: number;

Expand All @@ -61,6 +63,8 @@
value = max;
}
$: percentage = `${((value - min) / (max - min)) * 100}%`;
$: barStyle = vertical ? `height: ${percentage}; bottom: 0%` : `width: ${percentage}; left: 0%`;
$: btnStyle = vertical ? `bottom: ${percentage}` : `left: ${percentage}`;

// element
let runwayRef: null | HTMLElement = null;
Expand All @@ -71,9 +75,16 @@
if (disabledInner) return;
let newPercent = 0;
const clientX = event.clientX;
const clientY = event.clientY;
const sliderOffsetLeft = runwayRef!.getBoundingClientRect().left;
const sliderSize = runwayRef!.getBoundingClientRect().width;
newPercent = ((clientX - sliderOffsetLeft) / sliderSize) * 100;
const sliderOffsetBottom = runwayRef!.getBoundingClientRect().bottom;
const sliderSize = vertical
? runwayRef!.getBoundingClientRect().height
: runwayRef!.getBoundingClientRect().width;
newPercent = vertical
? ((sliderOffsetBottom - clientY) / sliderSize) * 100
: ((clientX - sliderOffsetLeft) / sliderSize) * 100;
console.log(((sliderOffsetBottom - clientY) / sliderSize) * 100);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this log is unnecessary.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah,I forgot to delete

if (newPosition < 0 || newPosition > 100) return;
setPosition(newPercent);
};
Expand All @@ -94,12 +105,14 @@

const setPosition = (newPosition: number) => {
if (Number.isNaN(+newPosition)) return;

if (newPosition < 0) {
newPosition = 0;
}
if (newPosition > 100) {
newPosition = 100;
}

const lengthStep = 100 / ((max - min) / step);
const steps = Math.round(newPosition / lengthStep);
let newValue = steps * lengthStep * (max - min) * 0.01 + min;
Expand All @@ -111,18 +124,21 @@

const onDragStart = (event: MouseEvent) => {
isDragging = true;
const { clientX } = getClientXY(event);
const { clientX, clientY } = getClientXY(event);
startX = clientX;
startY = clientY;
startPosition = Number.parseFloat(percentage);
newPosition = startPosition;
};

const onDragging = (event: MouseEvent) => {
if (!isDragging || !runwayRef) return;
let diff: number;
const { clientX } = getClientXY(event);
const sliderWidth = runwayRef.getBoundingClientRect().width;
diff = ((clientX - startX) / sliderWidth) * 100;
const { clientX, clientY } = getClientXY(event);
const { width: sliderWidth, height: sliderHeight } = runwayRef.getBoundingClientRect();
diff = vertical
? ((startY - clientY) / sliderHeight) * 100
: ((clientX - startX) / sliderWidth) * 100;
newPosition = startPosition + diff;
setPosition(newPosition);
};
Expand All @@ -138,11 +154,33 @@

// class names
const prefixCls = getPrefixCls('slider');
$: baseCls = clsx(prefixCls, `${prefixCls}--base`, `${prefixCls}--${sizeInner}`, cls);
$: buttonWrapperCls = clsx(`${prefixCls}--button-wrapper`);
$: baseCls = clsx(
prefixCls,
{
[`${prefixCls}--base`]: !vertical,
[`${prefixCls}--base__vertical`]: vertical
},
{
[`${prefixCls}--${sizeInner}`]: !vertical,
[`${prefixCls}--${sizeInner}__vertical`]: vertical
},
cls
);
$: buttonWrapperCls = clsx({
[`${prefixCls}--button-wrapper`]: !vertical,
[`${prefixCls}--button-wrapper__vertical`]: vertical
});
$: buttonCls = clsx(`${prefixCls}--button`, `${prefixCls}--button--${sizeInner}`);
$: runwayCls = clsx(`${prefixCls}--runway`, `${prefixCls}--runway--${sizeInner}`, {
[`${prefixCls}--runway__disabled`]: disabledInner
$: runwayCls = clsx({
[`${prefixCls}--runway__disabled`]: disabledInner,
[`${prefixCls}--runway--${sizeInner}`]: !vertical,
[`${prefixCls}--runway`]: !vertical,
[`${prefixCls}--runway--${sizeInner}__vertical`]: vertical,
[`${prefixCls}--runway__vertical`]: vertical
});
$: barCls = clsx({
[`${prefixCls}--bar`]: !vertical,
[`${prefixCls}--bar__vertical`]: vertical
});
</script>

Expand All @@ -152,14 +190,14 @@
class={buttonWrapperCls}
aria-hidden="true"
on:mousedown={handleMouseDown}
style:left={percentage}
style={btnStyle}
>
{#if $$slots.buttonRender}
<slot name="buttonRender" />
{:else}
<div class={buttonCls}></div>
{/if}
</div>
<div class="k-slider--bar" style="width: {percentage}; left: 0%"></div>
<div class={barCls} style={barStyle}></div>
</div>
</div>
1 change: 1 addition & 0 deletions components/Slider/src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export type KSliderProps = {
value: number;
step: number;
disabled: boolean;
vertical: boolean;
cls: ClassValue;
attrs: Record<string, string>;
};
7 changes: 7 additions & 0 deletions docs/components/KSlider.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ npm install @ikun-ui/slider

<demo src="slider/basic.svelte" github="Slider"></demo>

## Vertical mode

Setting the `vertical` attribute to true enables vertical mode.

<demo src="slider/vertical.svelte" github="Slider"></demo>

## Disabled slider

Use `disabled` attribute to determine whether a slider is disabled.
Expand Down Expand Up @@ -58,6 +64,7 @@ Add `size` attribute to change the size of Slider. It supports `sm`, `md` and `l
| Name | Type | Default | Description |
| -------- | ------------------------ | ------- | -------------------------- |
| value | `number` | `0` | Binding value |
| vertical | `boolean` | `false` | Vertical mode |
| min | `number` | `0` | Minimum value |
| max | `number` | `100` | Maximum value |
| step | `number` | `1` | Step size |
Expand Down
13 changes: 13 additions & 0 deletions docs/example/slider/vertical.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<script>
import { KSlider } from '@ikun-ui/slider';

let value1 = 0;
const handleInput1 = (event) => {
value1 = event.detail;
};
</script>

<div class="flex items-end h-50">
baiwusanyu-c marked this conversation as resolved.
Show resolved Hide resolved
<KSlider vertical on:input={handleInput1} value={value1}></KSlider>
<p class="px-2">value: {value1}</p>
</div>
11 changes: 11 additions & 0 deletions preset/src/shortcuts/src/slider.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export const sliderShortcuts: Record<string, string> = {
// slider
'k-slider--base': 'w-full fi',
'k-slider--base__vertical': 'h-full fc',

// disabled
'k-slider--disabled': 'k-bg-disabled',
Expand All @@ -9,23 +10,33 @@ export const sliderShortcuts: Record<string, string> = {
'k-slider--sm': 'h-24px',
'k-slider--md': 'h-32px',
'k-slider--lg': 'h-40px',
'k-slider--sm__vertical': 'w-24px',
'k-slider--md__vertical': 'w-32px',
'k-slider--lg__vertical': 'w-40px',

// runway
'k-slider--runway': 'flex-1 rd-0.75 bg-ikun-light-900 cursor-pointer pr',
'k-slider--runway__vertical': 'rd-0.75 bg-ikun-light-900 cursor-pointer pr fe flex-col',

// runway size [2px border]
'k-slider--runway--sm': 'mx-8px h-3px',
'k-slider--runway--md': 'mx-10px h-4px',
'k-slider--runway--lg': 'mx-12px h-5px',
'k-slider--runway--sm__vertical': 'my-8px w-3px',
'k-slider--runway--md__vertical': 'my-10px w-4px',
'k-slider--runway--lg__vertical': 'my-12px w-5px',

'k-slider--bar': 'h-full border-rd-0.75 bg-ikun-main',
'k-slider--bar__vertical': 'w-full border-rd-0.75 bg-ikun-main',

// runway disabled
'k-slider--runway__disabled': 'k-cur-disabled',

// button
'k-slider--button-wrapper':
'fcc pa top-0 bottom-0 my-a translate-x--50% cursor-pointer select-none',
'k-slider--button-wrapper__vertical':
'fcc pa left-50% mx-a -translate-x-1/2 translate-y-1/2 cursor-pointer select-none',

// button wrapper size
'k-slider--button--sm': 'w-12px h-12px',
Expand Down