Skip to content

Commit 75aad46

Browse files
authored
feat: image cropper (#3677)
* feat: add image cropper for react * feat: add image cropper for solid * feat: add image cropper for svelte * feat: add image cropper for vue * chore: revert some changes in package.json * refactor: don't separate the split props to a new file * chore: update image cropper stories for vue * refactor: add the missing exports * fix: add the missing root provider for vue * refactor: use IntlTranslations type from image cropper directly * refactor: import package from preferred path * refactor: use the exported handles from image cropper * feat: add grid part * chore: add more examples * fix: export root provider in vue
1 parent e5a4ab3 commit 75aad46

File tree

92 files changed

+2189
-149
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+2189
-149
lines changed

.storybook/styles.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
@import url('./styles/file-upload.css');
1515
@import url('./styles/floating-panel.css');
1616
@import url('./styles/hover-card.css');
17+
@import url('./styles/image-cropper.css');
1718
@import url('./styles/json-tree-view.css');
1819
@import url('./styles/listbox.css');
1920
@import url('./styles/menu.css');
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
[data-scope='image-cropper'][data-part='root'] {
2+
max-width: fit-content;
3+
}
4+
5+
[data-scope='image-cropper'][data-part='selection'] {
6+
box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.5);
7+
border: 1px solid rgba(255, 255, 255, 0.5);
8+
cursor: move;
9+
&[data-shape='circle'] {
10+
border-radius: 50%;
11+
}
12+
}
13+
14+
[data-scope='image-cropper'][data-part='image'] {
15+
display: block;
16+
max-width: 100%;
17+
}
18+
19+
[data-scope='image-cropper'][data-part='handle'] {
20+
--handle-size: 12px;
21+
width: var(--handle-size);
22+
height: var(--handle-size);
23+
24+
&[data-position='n'],
25+
&[data-position='s'] {
26+
height: 6px;
27+
}
28+
29+
&[data-position='e'],
30+
&[data-position='w'] {
31+
width: 6px;
32+
}
33+
34+
& > div {
35+
width: calc(var(--handle-size) / 2);
36+
height: calc(var(--handle-size) / 2);
37+
background: #fff;
38+
position: absolute;
39+
top: 50%;
40+
left: 50%;
41+
transform: translate(-50%, -50%);
42+
}
43+
}
44+
45+
[data-scope='image-cropper'][data-part='grid'] {
46+
--grid-color: rgba(255, 255, 255, 0.7);
47+
--grid-line-width: 1px;
48+
49+
&[data-axis='vertical'] {
50+
border-inline: var(--grid-line-width) solid var(--grid-color);
51+
}
52+
53+
&[data-axis='horizontal'] {
54+
border-block: var(--grid-line-width) solid var(--grid-color);
55+
}
56+
}

bun.lock

Lines changed: 95 additions & 149 deletions
Large diffs are not rendered by default.

packages/react/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@
112112
"@zag-js/focus-trap": "1.27.1",
113113
"@zag-js/highlight-word": "1.27.1",
114114
"@zag-js/hover-card": "1.27.1",
115+
"@zag-js/image-cropper": "1.27.1",
115116
"@zag-js/i18n-utils": "1.27.1",
116117
"@zag-js/json-tree-utils": "1.27.1",
117118
"@zag-js/listbox": "1.27.1",

packages/react/src/components/anatomy.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export { fieldsetAnatomy } from './fieldset/fieldset.anatomy'
1717
export { fileUploadAnatomy } from './file-upload/file-upload.anatomy'
1818
export { floatingPanelAnatomy } from './floating-panel/floating-panel.anatomy'
1919
export { hoverCardAnatomy } from './hover-card/hover-card.anatomy'
20+
export { imageCropperAnatomy } from './image-cropper/image-cropper.anatomy'
2021
export { listboxAnatomy } from './listbox/listbox.anatomy'
2122
export { marqueeAnatomy } from './marquee/marquee.anatomy'
2223
export { menuAnatomy } from './menu/menu.anatomy'
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { ImageCropper } from '@ark-ui/react/image-cropper'
2+
3+
export const Basic = () => {
4+
return (
5+
<ImageCropper.Root>
6+
<ImageCropper.Viewport>
7+
<ImageCropper.Image src="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=800" alt="Sample" />
8+
<ImageCropper.Selection>
9+
{ImageCropper.handles.map((position) => (
10+
<ImageCropper.Handle key={position} position={position}>
11+
<div />
12+
</ImageCropper.Handle>
13+
))}
14+
<ImageCropper.Grid axis="horizontal" />
15+
<ImageCropper.Grid axis="vertical" />
16+
</ImageCropper.Selection>
17+
</ImageCropper.Viewport>
18+
</ImageCropper.Root>
19+
)
20+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { ImageCropper } from '@ark-ui/react/image-cropper'
2+
3+
export const Circle = () => {
4+
return (
5+
<ImageCropper.Root cropShape="circle">
6+
<ImageCropper.Viewport>
7+
<ImageCropper.Image src="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=800" alt="Sample" />
8+
<ImageCropper.Selection>
9+
{ImageCropper.handles.map((position) => (
10+
<ImageCropper.Handle key={position} position={position}>
11+
<div />
12+
</ImageCropper.Handle>
13+
))}
14+
</ImageCropper.Selection>
15+
</ImageCropper.Viewport>
16+
</ImageCropper.Root>
17+
)
18+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { ImageCropper } from '@ark-ui/react/image-cropper'
2+
import { useState } from 'react'
3+
4+
export const Controlled = () => {
5+
const [zoom, setZoom] = useState(1)
6+
7+
return (
8+
<>
9+
<button onClick={() => setZoom(zoom + 0.1)}>Zoom In</button>
10+
<button onClick={() => setZoom(zoom - 0.1)}>Zoom Out</button>
11+
12+
<ImageCropper.Root zoom={zoom} onZoomChange={(e) => setZoom(e.zoom)}>
13+
<ImageCropper.Viewport>
14+
<ImageCropper.Image src="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=800" alt="Sample" />
15+
<ImageCropper.Selection>
16+
{ImageCropper.handles.map((position) => (
17+
<ImageCropper.Handle key={position} position={position}>
18+
<div />
19+
</ImageCropper.Handle>
20+
))}
21+
<ImageCropper.Grid axis="horizontal" />
22+
<ImageCropper.Grid axis="vertical" />
23+
</ImageCropper.Selection>
24+
</ImageCropper.Viewport>
25+
</ImageCropper.Root>
26+
</>
27+
)
28+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { ImageCropper } from '@ark-ui/react/image-cropper'
2+
3+
export const Fixed = () => {
4+
return (
5+
<ImageCropper.Root fixedCropArea>
6+
<ImageCropper.Viewport>
7+
<ImageCropper.Image src="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=800" alt="Sample" />
8+
<ImageCropper.Selection>
9+
<ImageCropper.Grid axis="horizontal" />
10+
<ImageCropper.Grid axis="vertical" />
11+
</ImageCropper.Selection>
12+
</ImageCropper.Viewport>
13+
</ImageCropper.Root>
14+
)
15+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { ImageCropper, useImageCropper } from '@ark-ui/react/image-cropper'
2+
3+
export const RootProvider = () => {
4+
const imageCropper = useImageCropper()
5+
6+
return (
7+
<>
8+
<button onClick={() => imageCropper.setZoom(imageCropper.zoom + 0.1)}>Zoom In</button>
9+
<button onClick={() => imageCropper.setZoom(imageCropper.zoom - 0.1)}>Zoom Out</button>
10+
11+
<ImageCropper.RootProvider value={imageCropper}>
12+
<ImageCropper.Viewport>
13+
<ImageCropper.Image src="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=800" alt="Sample" />
14+
<ImageCropper.Selection>
15+
{ImageCropper.handles.map((position) => (
16+
<ImageCropper.Handle key={position} position={position}>
17+
<div />
18+
</ImageCropper.Handle>
19+
))}
20+
<ImageCropper.Grid axis="horizontal" />
21+
<ImageCropper.Grid axis="vertical" />
22+
</ImageCropper.Selection>
23+
</ImageCropper.Viewport>
24+
</ImageCropper.RootProvider>
25+
</>
26+
)
27+
}

0 commit comments

Comments
 (0)