Skip to content

Commit

Permalink
feat: slider component support vertical prop (#356)
Browse files Browse the repository at this point in the history
* feat: slider component support vertical prop

* chore: fix chore

* feat: update slider snap & form snap
  • Loading branch information
pkc918 committed Dec 6, 2023
1 parent efd0fad commit 14292ed
Show file tree
Hide file tree
Showing 8 changed files with 109 additions and 19 deletions.
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);
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">
<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

0 comments on commit 14292ed

Please sign in to comment.