Skip to content

Commit

Permalink
feat: 0.3.0
Browse files Browse the repository at this point in the history
- added draggable prop to knob
- refactored knob
- refactored core
- updated docs
  • Loading branch information
eye-wave committed Nov 2, 2024
1 parent 5c1f3cf commit 08f1c7c
Show file tree
Hide file tree
Showing 16 changed files with 82 additions and 82 deletions.
26 changes: 13 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,29 +25,29 @@ npm install svelte-knobs

#### Basic Knob

```typescript
import { createFloatParam, createRange } from 'svelte-knobs';
```svelte
<script lang="ts">
import { createFloatParam, Knob } from '$lib';
const basicParam = createFloatParam(createRange('lin', 0, 100));
let basicValue = 0;
```
const basicParam = createFloatParam('lin', 0, 100);
let basicValue = 0;
</script>
```svelte
<Knob param={basicParam} bind:value={basicValue} label="Volume" unit="%" />
```

A basic knob control with linear scaling.

#### Logarithmic Knob

```typescript
import { createFloatParam, createRange } from 'svelte-knobs';
```svelte
<script lang="ts">
import { createFloatParam } from 'svelte-knobs';
const logParam = createFloatParam(createRange('log', 20, 20_000));
let logValue = 20;
```
const logParam = createFloatParam('log', 20, 20_000);
let logValue = 20;
</script>
```svelte
<Knob param={logParam} bind:value={logValue} label="Frequency" unit="Hz" />
```

Expand All @@ -69,7 +69,7 @@ Set specific snap points and adjust snapping sensitivity using `snapThreshold`.
```typescript
import { createFloatParam, createRange } from 'svelte-knobs';

const snapParam = createFloatParam(createRange('lin', 0, 2000));
const snapParam = createFloatParam('lin', 0, 2000);
const snapPoints = [0, 500, 1000, 1500, 2000];

let snapValue = 0;
Expand Down
Binary file modified bun.lockb
Binary file not shown.
12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "svelte-knobs",
"description": "Svelte component library for building customizable knob controls.",
"version": "0.2.2",
"version": "0.3.0",
"repository": {
"url": "https://github.com/eye-wave/svelte-knobs"
},
Expand Down Expand Up @@ -40,24 +40,24 @@
},
"devDependencies": {
"@sveltejs/adapter-static": "^3.0.6",
"@sveltejs/kit": "^2.7.3",
"@sveltejs/kit": "^2.7.4",
"@sveltejs/package": "^2.3.7",
"@sveltejs/vite-plugin-svelte": "^4.0.0",
"@types/eslint": "^9.6.1",
"eslint": "^9.13.0",
"eslint": "^9.14.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-svelte": "^2.46.0",
"globals": "^15.11.0",
"lint-staged": "^15.2.10",
"prettier": "^3.3.3",
"prettier-plugin-svelte": "^3.2.7",
"publint": "^0.2.12",
"shiki": "^1.22.1",
"shiki": "^1.22.2",
"simple-git-hooks": "^2.11.1",
"svelte": "^5.1.3",
"svelte": "^5.1.9",
"svelte-check": "^4.0.5",
"typescript": "^5.6.3",
"typescript-eslint": "^8.11.0",
"typescript-eslint": "^8.12.2",
"vite": "^5.4.10"
},
"svelte": "./dist/index.js",
Expand Down
2 changes: 1 addition & 1 deletion src-build/print-component.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const printComponent = () => {

return `{@html \`${html}\`}`;
} catch (err) {
console.error(err)
console.error(err);
return match;
}
});
Expand Down
73 changes: 33 additions & 40 deletions src/lib/Knob.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { normalize, format, unnormalizeToString, unnormalizeToNumber } from './params.js';
import { spring } from 'svelte/motion';
import type { EnumParam, FloatParam } from './params.js';
import { clamp } from './helpers/clamp.js';
interface Props {
style?: string;
Expand All @@ -18,6 +19,7 @@
snapValues?: Array<number>;
snapThreshold?: number;
disabled?: boolean;
draggable?: boolean;
colors?: {
arc?: string;
bg?: string;
Expand All @@ -40,6 +42,7 @@
snapValues = [],
snapThreshold = 0.1,
disabled = false,
draggable = true,
colors = {}
}: Props = $props();
Expand Down Expand Up @@ -76,32 +79,41 @@
}
const fixedSnapValues = $derived(completeFixedSnapValues(snapValues));
const rotationDegrees = spring(normalize(value, param) * 270 - 135, { stiffness });
const normalizedValue = $derived(normalize(value, param));
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const rotationDegrees = spring(normalize(value as any, param as any) * 270 - 135, { stiffness });
const formatted = $derived(isDragging ? format(value, param, decimalDigits) : '');
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const normalizedValue = $derived(normalize(value as any, param as any));
function toMobile(handler: ({ clientY }: MouseEvent) => boolean | void) {
return (event: TouchEvent) => {
const touch = event.touches?.[0];
if (touch === undefined) return;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const formatted = $derived(isDragging ? format(value as any, param as any, decimalDigits) : '');
const clientY = touch.clientY;
$effect(() => {
rotationDegrees.set(normalizedValue * 270 - 135);
});
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
handler({ clientY } as MouseEvent) && event.preventDefault();
};
}
function handleMouseDown(event: MouseEvent) {
function handleMouseDown({ clientY }: MouseEvent) {
if (!draggable) return;
isDragging = true;
startY = event.clientY;
startY = clientY;
startValue = normalizedValue;
return true;
}
function handleMouseMove(event: MouseEvent) {
function handleMouseMove({ clientY }: MouseEvent) {
if (!draggable) return;
if (disabled) return;
if (!isDragging) return;
const deltaY = startY - event.clientY;
const deltaY = startY - clientY;
const deltaValue = deltaY / 200;
setValue(Math.max(0, Math.min(1, startValue + deltaValue)));
setValue(clamp(startValue + deltaValue, 0, 1));
return true;
}
function handleMouseUp() {
Expand All @@ -115,38 +127,20 @@
(param as EnumParam<string[]>).variants?.[0];
if (val === undefined) return;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
setValue(Math.max(0, Math.min(1, normalize(val as any, param as any))));
setValue(clamp(normalize(val, param), 0, 1));
}
const handleTouchStart = toMobile(handleMouseDown);
const handleTouchMove = toMobile(handleMouseMove);
$effect(() => {
rotationDegrees.set(normalizedValue * 270 - 135);
// this was easier in svelte 4 :/
window.addEventListener('touchmove', handleTouchMove, { passive: false });
return () => window.removeEventListener('touchmove', handleTouchMove);
});
function handleTouchStart(event: TouchEvent) {
isDragging = true;
const touch = event.touches?.[0];
if (touch === undefined) return;
startY = touch.clientY;
startValue = normalizedValue;
}
function handleTouchMove(event: TouchEvent) {
if (!isDragging) return;
event.preventDefault();
if (disabled) return;
const touch = event.touches?.[0];
if (touch === undefined) return;
const deltaY = startY - touch.clientY;
const deltaValue = deltaY / 200;
setValue(Math.max(0, Math.min(1, startValue + deltaValue)));
}
function setValue(newNormalizedValue: number) {
if (param.type === 'enum-param') {
const newValue = unnormalizeToString(newNormalizedValue, param);
Expand Down Expand Up @@ -210,8 +204,7 @@
const values = param.type === 'enum-param' ? param.variants : snapValues;
for (let snapValue of values) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const normalizedSnapValue = normalize(snapValue as any, param as any);
const normalizedSnapValue = normalize(snapValue, param);
const angle = normalizedSnapValue * 270 - 135;
const [x1, y1] = polarToCartesian(center, center, arcRadius, angle);
const [x2, y2] = polarToCartesian(center, center, size * 0.46, angle);
Expand Down
3 changes: 3 additions & 0 deletions src/lib/helpers/clamp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function clamp(value: number, min: number, max: number) {
return Math.max(min, Math.min(max, value));
}
10 changes: 7 additions & 3 deletions src/lib/params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ export type Param = EnumParam<readonly string[]> | FloatParam;

export function normalize<V extends readonly string[]>(value: string, param: EnumParam<V>): number;
export function normalize(value: number, param: FloatParam): number;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function normalize(value: any, param: any): number {
export function normalize(value: string | number, param: Param): number;
export function normalize(value: string | number, param: Param): number {
switch (param.type) {
case 'enum-param': {
if (typeof value !== 'string')
Expand All @@ -27,6 +27,7 @@ export function normalize(value: any, param: any): number {
return FLOAT.normalize(value, param);
}
default:
//@ts-expect-error just in case
throw new TypeError(`Unsupported param type: ${param.type}`);
}
}
Expand All @@ -36,6 +37,7 @@ export function unnormalizeToNumber<V extends readonly string[]>(
param: EnumParam<V>
): number;
export function unnormalizeToNumber(value: number, param: FloatParam): number;
export function unnormalizeToNumber(value: number, param: Param): number;
export function unnormalizeToNumber(value: number, param: Param): number {
switch (param.type) {
case 'enum-param':
Expand All @@ -53,7 +55,8 @@ export function unnormalizeToString<V extends readonly string[]>(
param: EnumParam<V>
): V[number];
export function unnormalizeToString(value: number, param: FloatParam): string;
export function unnormalizeToString(value: number, param: Param): unknown {
export function unnormalizeToString(value: number, param: Param): string;
export function unnormalizeToString(value: number, param: Param): string {
switch (param.type) {
case 'enum-param':
return ENUM.unnormalizeToString(value, param);
Expand All @@ -70,6 +73,7 @@ export function format<V extends readonly string[]>(
param: EnumParam<V>
): V[number];
export function format(value: number, param: FloatParam, precision?: number): number;
export function format(value: unknown, param: Param, precision?: number): unknown;
export function format(value: unknown, param: Param, precision?: number): unknown {
switch (param.type) {
case 'enum-param':
Expand Down
6 changes: 3 additions & 3 deletions src/lib/params/float-param.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { type Range } from './range.js';
import { createRange, type Range } from './range.js';

export type FloatParam = {
type: 'float-param';
range: Range;
};

export function createFloatParam(range: Range): FloatParam {
export function createFloatParam(...args: Parameters<typeof createRange>): FloatParam {
return {
type: 'float-param',
range
range: createRange(...args)
};
}
export function normalize(value: number, param: FloatParam): number {
Expand Down
1 change: 1 addition & 0 deletions src/lib/params/range.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export type RangeType = Range['type'];

export function createRange(type: 'lin', min: number, max: number): LinearRange;
export function createRange(type: 'log', min: number, max: number, base?: number): LogRange;
export function createRange(type: RangeType, min: number, max: number, a?: number): Range;
export function createRange(type: RangeType, min: number, max: number, a?: number): Range {
switch (type) {
case 'lin':
Expand Down
3 changes: 1 addition & 2 deletions src/routes/CopyPaste.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,11 @@
:global(pre.shiki) {
box-sizing: border-box;
border-radius: 8px;
overflow: scroll;
overflow-x: scroll;
padding: 1rem;
}
:global(.shiki > code) {
text-wrap: wrap;
tab-size: 2;
}
Expand Down
4 changes: 2 additions & 2 deletions src/routes/examples/BasicKnob.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import { createFloatParam, createRange, Knob } from '$lib';
import { createFloatParam, Knob } from '$lib';
const basicParam = createFloatParam(createRange('lin', 0, 100));
const basicParam = createFloatParam('lin', 0, 100);
let basicValue = 0;
</script>

Expand Down
4 changes: 2 additions & 2 deletions src/routes/examples/ColoredKnobs.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import { createFloatParam, createRange, Knob } from '$lib';
import { createFloatParam, Knob } from '$lib';
const basicParam = createFloatParam(createRange('lin', 0, 100));
const basicParam = createFloatParam('lin', 0, 100);
</script>

<Knob param={basicParam} value={24} label="Svelte theme" colors={{ arc: '#ff3e00' }} />
Expand Down
4 changes: 2 additions & 2 deletions src/routes/examples/DisabledKnob.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import { createFloatParam, createRange, Knob } from '$lib';
import { createFloatParam, Knob } from '$lib';
const basicParam = createFloatParam(createRange('lin', 0, 100));
const basicParam = createFloatParam('lin', 0, 100);
</script>

<Knob param={basicParam} value={58} disabled />
8 changes: 4 additions & 4 deletions src/routes/examples/LogarithmicKnob.svelte
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<script lang="ts">
import { createFloatParam, createRange, Knob } from '$lib';
import { createFloatParam, Knob } from '$lib';
const freqParam = createFloatParam(createRange('log', 20, 20_000));
const gainParam = createFloatParam(createRange('log', -30, 30, Math.E));
const qParam = createFloatParam(createRange('log', 0.01, 30, 2));
const freqParam = createFloatParam('log', 20, 20_000);
const gainParam = createFloatParam('log', -30, 30, Math.E);
const qParam = createFloatParam('log', 0.01, 30, 2);
let freqValue = 20;
let gainValue = 0;
Expand Down
4 changes: 2 additions & 2 deletions src/routes/examples/SmoothKnob.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import { createFloatParam, createRange, Knob } from '$lib';
import { createFloatParam, Knob } from '$lib';
const smoothParam = createFloatParam(createRange('lin', 0, 100));
const smoothParam = createFloatParam('lin', 0, 100);
let smoothValue = 0;
</script>

Expand Down
4 changes: 2 additions & 2 deletions src/routes/examples/SnapPoints.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import { createFloatParam, createRange, Knob } from '$lib';
import { createFloatParam, Knob } from '$lib';
const snapParam = createFloatParam(createRange('lin', 0, 2000));
const snapParam = createFloatParam('lin', 0, 2000);
const snapPoints = Array.from({ length: 5 }, (_, i) => i * 500);
Expand Down

0 comments on commit 08f1c7c

Please sign in to comment.