Skip to content

Commit

Permalink
feat: add angle-slider
Browse files Browse the repository at this point in the history
  • Loading branch information
segunadebayo committed Nov 21, 2024
1 parent e361fbd commit 58e48ba
Show file tree
Hide file tree
Showing 32 changed files with 1,821 additions and 276 deletions.
5 changes: 5 additions & 0 deletions .changeset/gentle-moons-pretend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@zag-js/angle-slider": minor
---

Add new angle slider machine to allow users to select an angle interactively.
84 changes: 84 additions & 0 deletions .xstate/angle-slider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
"use strict";

var _xstate = require("xstate");
const {
actions,
createMachine,
assign
} = _xstate;
const {
choose
} = actions;
const fetchMachine = createMachine({
id: "angle-slider",
initial: "idle",
context: {},
on: {
"VALUE.SET": {
actions: ["setValue"]
}
},
on: {
UPDATE_CONTEXT: {
actions: "updateContext"
}
},
states: {
idle: {
on: {
"CONTROL.POINTER_DOWN": {
target: "dragging",
actions: ["setPointerValue", "focusThumb"]
},
"THUMB.FOCUS": {
target: "focused"
}
}
},
focused: {
on: {
"CONTROL.POINTER_DOWN": {
target: "dragging",
actions: ["setPointerValue", "focusThumb"]
},
"THUMB.ARROW_DEC": {
actions: ["decrementValue", "invokeOnChangeEnd"]
},
"THUMB.ARROW_INC": {
actions: ["incrementValue", "invokeOnChangeEnd"]
},
"THUMB.HOME": {
actions: ["setValueToMin", "invokeOnChangeEnd"]
},
"THUMB.END": {
actions: ["setValueToMax", "invokeOnChangeEnd"]
},
"THUMB.BLUR": {
target: "idle"
}
}
},
dragging: {
entry: "focusThumb",
activities: "trackPointerMove",
on: {
"DOC.POINTER_UP": {
target: "focused",
actions: "invokeOnChangeEnd"
},
"DOC.POINTER_MOVE": {
actions: "setPointerValue"
}
}
}
}
}, {
actions: {
updateContext: assign((context, event) => {
return {
[event.contextKey]: true
};
})
},
guards: {}
});
1 change: 1 addition & 0 deletions examples/lit-ts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@zag-js/accordion": "workspace:*",
"@zag-js/anatomy": "workspace:*",
"@zag-js/anatomy-icons": "workspace:*",
"@zag-js/angle-slider": "workspace:*",
"@zag-js/aria-hidden": "workspace:*",
"@zag-js/auto-resize": "workspace:*",
"@zag-js/avatar": "workspace:*",
Expand Down
1 change: 1 addition & 0 deletions examples/next-ts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@zag-js/accordion": "workspace:*",
"@zag-js/anatomy": "workspace:*",
"@zag-js/anatomy-icons": "workspace:*",
"@zag-js/angle-slider": "workspace:*",
"@zag-js/aria-hidden": "workspace:*",
"@zag-js/auto-resize": "workspace:*",
"@zag-js/avatar": "workspace:*",
Expand Down
42 changes: 42 additions & 0 deletions examples/next-ts/pages/angle-slider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import * as angleSlider from "@zag-js/angle-slider"
import { useMachine, normalizeProps } from "@zag-js/react"
import { angleSliderControls } from "@zag-js/shared"
import { useId } from "react"
import { StateVisualizer } from "../components/state-visualizer"
import { Toolbar } from "../components/toolbar"
import { useControls } from "../hooks/use-controls"

export default function Page() {
const controls = useControls(angleSliderControls)

const [state, send] = useMachine(angleSlider.machine({ id: useId() }), {
context: controls.context,
})

const api = angleSlider.connect(state, send, normalizeProps)

return (
<>
<main className="angle-slider">
<div {...api.getRootProps()}>
<label {...api.getLabelProps()}>
Angle Slider: <div {...api.getValueTextProps()}>{api.valueAsDegree}</div>
</label>
<div {...api.getControlProps()}>
<div {...api.getThumbProps()}></div>
<div {...api.getMarkerGroupProps()}>
{[0, 45, 90, 135, 180, 225, 270, 315].map((value) => (
<div {...api.getMarkerProps({ value })}></div>
))}
</div>
</div>
<input {...api.getHiddenInputProps()} />
</div>
</main>

<Toolbar controls={controls.ui}>
<StateVisualizer state={state} />
</Toolbar>
</>
)
}
3 changes: 2 additions & 1 deletion examples/nuxt-ts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"@zag-js/accordion": "workspace:*",
"@zag-js/anatomy": "workspace:*",
"@zag-js/anatomy-icons": "workspace:*",
"@zag-js/angle-slider": "workspace:*",
"@zag-js/aria-hidden": "workspace:*",
"@zag-js/auto-resize": "workspace:*",
"@zag-js/avatar": "workspace:*",
Expand Down Expand Up @@ -94,6 +95,6 @@
"@nuxt/devtools": "latest",
"@types/form-serialize": "0.7.4",
"@types/node": "22.8.2",
"nuxt": "3.13.2"
"nuxt": "3.14.1592"
}
}
42 changes: 42 additions & 0 deletions examples/nuxt-ts/pages/angle-slider.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<script setup lang="ts">
import * as angleSlider from "@zag-js/angle-slider"
import { angleSliderControls } from "@zag-js/shared"
import { normalizeProps, useMachine } from "@zag-js/vue"
const controls = useControls(angleSliderControls)
const [state, send] = useMachine(angleSlider.machine({ id: "1" }), {
context: controls.context,
})
const api = computed(() => angleSlider.connect(state.value, send, normalizeProps))
</script>

<template>
<main class="angle-slider">
<div v-bind="api.getRootProps()">
<label v-bind="api.getLabelProps()">
Angle Slider:
<div v-bind="api.getValueTextProps()">{{ api.valueAsDegree }}</div>
</label>
<div v-bind="api.getControlProps()">
<div v-bind="api.getThumbProps()"></div>
<div v-bind="api.getMarkerGroupProps()">
<div
v-for="value in [0, 45, 90, 135, 180, 225, 270, 315]"
:key="value"
v-bind="api.getMarkerProps({ value })"
></div>
</div>
</div>
<input v-bind="api.getHiddenInputProps()" />
</div>
</main>

<Toolbar>
<StateVisualizer :state="state" />
<template #controls>
<Controls :control="controls" />
</template>
</Toolbar>
</template>
1 change: 1 addition & 0 deletions examples/preact-ts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"@zag-js/accordion": "workspace:*",
"@zag-js/anatomy": "workspace:*",
"@zag-js/anatomy-icons": "workspace:*",
"@zag-js/angle-slider": "workspace:*",
"@zag-js/aria-hidden": "workspace:*",
"@zag-js/auto-resize": "workspace:*",
"@zag-js/avatar": "workspace:*",
Expand Down
1 change: 1 addition & 0 deletions examples/react-19/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"@zag-js/accordion": "workspace:*",
"@zag-js/anatomy": "workspace:*",
"@zag-js/anatomy-icons": "workspace:*",
"@zag-js/angle-slider": "workspace:*",
"@zag-js/aria-hidden": "workspace:*",
"@zag-js/auto-resize": "workspace:*",
"@zag-js/avatar": "workspace:*",
Expand Down
1 change: 1 addition & 0 deletions examples/solid-ts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@zag-js/accordion": "workspace:*",
"@zag-js/anatomy": "workspace:*",
"@zag-js/anatomy-icons": "workspace:*",
"@zag-js/angle-slider": "workspace:*",
"@zag-js/aria-hidden": "workspace:*",
"@zag-js/auto-resize": "workspace:*",
"@zag-js/avatar": "workspace:*",
Expand Down
42 changes: 42 additions & 0 deletions examples/solid-ts/src/routes/angle-slider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import * as angleSlider from "@zag-js/angle-slider"
import { normalizeProps, useMachine } from "@zag-js/solid"
import { createMemo, createUniqueId, Index } from "solid-js"
import { angleSliderControls } from "@zag-js/shared"
import { StateVisualizer } from "../components/state-visualizer"
import { Toolbar } from "../components/toolbar"
import { useControls } from "../hooks/use-controls"

export default function Page() {
const controls = useControls(angleSliderControls)

const [state, send] = useMachine(angleSlider.machine({ id: createUniqueId() }), {
context: controls.context,
})

const api = createMemo(() => angleSlider.connect(state, send, normalizeProps))

return (
<>
<main class="angle-slider">
<div {...api().getRootProps()}>
<label {...api().getLabelProps()}>
Angle Slider: <div {...api().getValueTextProps()}>{api().valueAsDegree}</div>
</label>
<div {...api().getControlProps()}>
<div {...api().getThumbProps()}></div>
<div {...api().getMarkerGroupProps()}>
<Index each={[0, 45, 90, 135, 180, 225, 270, 315]}>
{(value) => <div {...api().getMarkerProps({ value: value() })}></div>}
</Index>
</div>
</div>
<input {...api().getHiddenInputProps()} />
</div>
</main>

<Toolbar controls={controls.ui}>
<StateVisualizer state={state} />
</Toolbar>
</>
)
}
3 changes: 2 additions & 1 deletion examples/svelte-ts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"@zag-js/accordion": "workspace:*",
"@zag-js/anatomy": "workspace:*",
"@zag-js/anatomy-icons": "workspace:*",
"@zag-js/angle-slider": "workspace:*",
"@zag-js/aria-hidden": "workspace:*",
"@zag-js/auto-resize": "workspace:*",
"@zag-js/avatar": "workspace:*",
Expand Down Expand Up @@ -100,4 +101,4 @@
"vite": "5.4.11",
"vite-tsconfig-paths": "5.0.1"
}
}
}
2 changes: 2 additions & 0 deletions examples/svelte-ts/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { routesData } from "@zag-js/shared"
import { Link, Route, Router } from "svelte-routing"
import Accordion from "./routes/accordion.svelte"
import AngleSlider from "./routes/angle-slider.svelte"
import Avatar from "./routes/avatar.svelte"
import Carousel from "./routes/carousel.svelte"
import Checkbox from "./routes/checkbox.svelte"
Expand Down Expand Up @@ -54,6 +55,7 @@
{ path: "/", component: Index },
{ path: "/accordion", component: Accordion },
{ path: "/avatar", component: Avatar },
{ path: "/angle-slider", component: AngleSlider },
{ path: "/carousel", component: Carousel },
{ path: "/checkbox", component: Checkbox },
{ path: "/clipboard", component: Clipboard },
Expand Down
38 changes: 38 additions & 0 deletions examples/svelte-ts/src/routes/angle-slider.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<script lang="ts">
import StateVisualizer from "$lib/components/state-visualizer.svelte"
import Toolbar from "$lib/components/toolbar.svelte"
import { useControls } from "$lib/use-controls.svelte"
import * as angleSlider from "@zag-js/angle-slider"
import { angleSliderControls } from "@zag-js/shared"
import { normalizeProps, useMachine } from "@zag-js/svelte"
const controls = useControls(angleSliderControls)
const [snapshot, send] = useMachine(angleSlider.machine({ id: "1" }), {
context: controls.context,
})
const api = $derived(angleSlider.connect(snapshot, send, normalizeProps))
</script>

<main class="angle-slider">
<div {...api.getRootProps()}>
<!-- svelte-ignore a11y_label_has_associated_control -->
<label {...api.getLabelProps()}>
Angle Slider: <div {...api.getValueTextProps()}>{api.valueAsDegree}</div>
</label>
<div {...api.getControlProps()}>
<div {...api.getThumbProps()}></div>
<div {...api.getMarkerGroupProps()}>
{#each [0, 45, 90, 135, 180, 225, 270, 315] as value}
<div {...api.getMarkerProps({ value })}></div>
{/each}
</div>
</div>
<input {...api.getHiddenInputProps()} />
</div>
</main>

<Toolbar {controls}>
<StateVisualizer state={snapshot} />
</Toolbar>
1 change: 1 addition & 0 deletions examples/vanilla-ts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"@zag-js/accordion": "workspace:*",
"@zag-js/anatomy": "workspace:*",
"@zag-js/anatomy-icons": "workspace:*",
"@zag-js/angle-slider": "workspace:*",
"@zag-js/aria-hidden": "workspace:*",
"@zag-js/auto-resize": "workspace:*",
"@zag-js/avatar": "workspace:*",
Expand Down
19 changes: 19 additions & 0 deletions packages/machines/angle-slider/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# @zag-js/angle-slider

Core logic for the angle-slider widget implemented as a state machine

## Installation

```sh
yarn add @zag-js/angle-slider
# or
npm i @zag-js/angle-slider
```

## Contribution

Yes please! See the [contributing guidelines](https://github.com/chakra-ui/zag/blob/main/CONTRIBUTING.md) for details.

## Licence

This project is licensed under the terms of the [MIT license](https://github.com/chakra-ui/zag/blob/main/LICENSE).
Loading

0 comments on commit 58e48ba

Please sign in to comment.