Skip to content

Commit 3472ebb

Browse files
committed
chore: carousel examples
1 parent 17e75a9 commit 3472ebb

33 files changed

+1136
-30
lines changed

.claude/agents/component-example-creator.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,10 @@ When creating examples for a component:
5858

5959
6. **Update Documentation** (if applicable): Ensure the component's documentation includes:
6060
- Code snippets matching the new examples
61-
- Clear descriptions of when to use each variant
61+
- **Specific implementation details**: Which props go on which components, what methods to call
62+
- **Use cases and benefits**: When and why to use each pattern
63+
- **Built-in vs composition**: Clarify if features require composition or are built-in
64+
- **State synchronization**: Explain bidirectional sync when relevant
6265
- Accessibility notes
6366
- Links to related components or patterns
6467

.claude/commands/sync-docs.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
---
2+
description: Update documentation and agent files based on learnings from recent component development work
3+
---
4+
5+
Review the conversation history and identify patterns, best practices, and learnings from recent component development
6+
work. Then update the following files as needed:
7+
8+
## Files to Update
9+
10+
1. **`@.claude/docs/component_patterns.md`**
11+
- Add new component patterns discovered
12+
- Document common pitfalls and solutions
13+
- Add best practices for component API usage
14+
- Include documentation writing guidelines
15+
16+
2. **`@.claude/agents/component-example-creator.md`**
17+
- Update code quality standards based on learnings
18+
- Add new documentation guidelines
19+
- Include patterns for better example creation
20+
21+
3. **`@CLAUDE.md`** (if needed)
22+
- Update project-level guidance
23+
- Add new principles or conventions
24+
25+
## What to Include
26+
27+
Focus on **generic, reusable patterns** that will help with future component development:
28+
29+
- Component API access patterns (Context vs hooks)
30+
- Common styling requirements
31+
- Documentation writing best practices
32+
- State management patterns
33+
- Accessibility considerations
34+
- Cross-framework consistency guidelines
35+
36+
## What to Exclude
37+
38+
Skip component-specific implementations unless they represent a broader pattern that applies to multiple components.
39+
40+
## Process
41+
42+
1. Review recent work and identify patterns
43+
2. Read current documentation files to avoid duplication
44+
3. Add new sections or update existing ones with clear examples
45+
4. Use ✅ CORRECT / ❌ WRONG patterns for clarity
46+
5. Include rationale for why patterns are important
47+
6. Keep updates concise and actionable
48+
49+
After updating, provide a summary of what was added and why it will help future development work.

.claude/docs/component_patterns.md

Lines changed: 47 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ packages/{framework}/src/components/{component-name}/
2828

2929
## Creating New Examples
3030

31-
**IMPORTANT: When adding examples, ALL steps below must be completed. Missing any step means the example is incomplete.**
31+
**IMPORTANT: When adding examples, ALL steps below must be completed. Missing any step means the example is
32+
incomplete.**
3233

3334
When creating a new example for a component, you **MUST** update the following files:
3435

@@ -41,33 +42,41 @@ When creating a new example for a component, you **MUST** update the following f
4142
2. **Update Storybook stories for all frameworks** (REQUIRED - examples won't appear without this):
4243
- `packages/react/src/components/{component}/{component}.stories.tsx` - Add export in alphabetical order
4344
- `packages/solid/src/components/{component}/{component}.stories.tsx` - Add export in alphabetical order
44-
- `packages/vue/src/components/{component}/{component}.stories.vue` - Add import and `<Variant>` in alphabetical order
45-
- `packages/svelte/src/lib/components/{component}/{component}.stories.ts` - Add import and export in alphabetical order
45+
- `packages/vue/src/components/{component}/{component}.stories.vue` - Add import and `<Variant>` in alphabetical
46+
order
47+
- `packages/svelte/src/lib/components/{component}/{component}.stories.ts` - Add import and export in alphabetical
48+
order
4649

4750
3. **Update component documentation** (if applicable):
4851
- `website/src/content/pages/components/{component}.mdx` - Add `<Example id="{example-name}" />` with description
4952

50-
**Note**: Steps 1 and 2 are MANDATORY. Without updating the stories files, the examples will not be visible in Storybook.
53+
**Note**: Steps 1 and 2 are MANDATORY. Without updating the stories files, the examples will not be visible in
54+
Storybook.
5155

5256
### Example Workflow
5357

5458
For a new "links" example on the Menu component:
5559

5660
1. Create example files in all four frameworks
5761
2. Update stories:
62+
5863
```tsx
5964
// React/Solid: Add to exports
6065
export { Links } from './examples/links'
6166

6267
// Vue: Add to imports and template
6368
import Links from './examples/links.vue'
64-
<Variant title="Links"><Links /></Variant>
69+
;<Variant title="Links">
70+
<Links />
71+
</Variant>
6572

6673
// Svelte: Add import and export
6774
import LinksExample from './examples/links.svelte'
6875
export const Links = { render: () => ({ Component: LinksExample }) }
6976
```
77+
7078
3. Update MDX documentation:
79+
7180
```mdx
7281
### Menu with links
7382

@@ -206,13 +215,15 @@ Every component should include these example patterns where applicable:
206215

207216
## Root Provider Pattern (Critical)
208217

209-
**The `root-provider` example is essential for most components** as it demonstrates external state management using component hooks.
218+
**The `root-provider` example is essential for most components** as it demonstrates external state management using
219+
component hooks.
210220

211221
### Two Approaches: Choose One
212222

213223
There are two ways to use components - pick one approach, never mix them:
214224

215225
**Approach 1: Component.Root (Declarative)**
226+
216227
- Pass props directly to `Component.Root`
217228
- Component manages its own internal state
218229
- Limited access to state and methods
@@ -226,6 +237,7 @@ There are two ways to use components - pick one approach, never mix them:
226237
```
227238

228239
**Approach 2: useComponent + RootProvider (Programmatic)**
240+
229241
- Call `useComponent(props)` to get the component API/store
230242
- Pass the store to `Component.RootProvider`
231243
- Full access to state properties and methods (`.setOpen()`, `.open`, etc.)
@@ -245,16 +257,20 @@ return (
245257
```
246258

247259
**❌ NEVER mix both approaches:**
260+
248261
```tsx
249262
// ❌ WRONG - Don't use Root inside RootProvider
250263
<Dialog.RootProvider value={dialog}>
251-
<Dialog.Root> {/* This is incorrect! */}
264+
<Dialog.Root>
265+
{' '}
266+
{/* This is incorrect! */}
252267
<Dialog.Content />
253268
</Dialog.Root>
254269
</Dialog.RootProvider>
255270
```
256271

257-
The benefit of `useComponent + RootProvider` is direct access to the component's state and methods, enabling programmatic control from anywhere in your component.
272+
The benefit of `useComponent + RootProvider` is direct access to the component's state and methods, enabling
273+
programmatic control from anywhere in your component.
258274

259275
### React Pattern
260276

@@ -297,9 +313,7 @@ export const Example = () => {
297313
return (
298314
<Dialog.RootProvider value={dialog}>
299315
<Dialog.Trigger>Open</Dialog.Trigger>
300-
<Dialog.Content>
301-
{/* Content */}
302-
</Dialog.Content>
316+
<Dialog.Content>{/* Content */}</Dialog.Content>
303317
</Dialog.RootProvider>
304318
)
305319
}
@@ -342,9 +356,7 @@ export const Example = () => {
342356
return (
343357
<Dialog.RootProvider value={dialog}>
344358
<Dialog.Trigger>Open</Dialog.Trigger>
345-
<Dialog.Content>
346-
{/* Content */}
347-
</Dialog.Content>
359+
<Dialog.Content>{/* Content */}</Dialog.Content>
348360
</Dialog.RootProvider>
349361
)
350362
}
@@ -584,15 +596,15 @@ import { Teleport } from 'vue'
584596
```ts
585597
// React/Svelte Portal Props
586598
interface PortalProps {
587-
disabled?: boolean // Renders inline when true
588-
container?: HTMLElement // Custom mount point
589-
children: ReactNode // Content to portal
599+
disabled?: boolean // Renders inline when true
600+
container?: HTMLElement // Custom mount point
601+
children: ReactNode // Content to portal
590602
}
591603

592604
// Vue Teleport Props
593605
interface TeleportProps {
594-
to: string | Element // Target selector or element
595-
disabled?: boolean // Renders inline when true
606+
to: string | Element // Target selector or element
607+
disabled?: boolean // Renders inline when true
596608
}
597609
```
598610

@@ -608,6 +620,7 @@ interface TeleportProps {
608620
### Accessibility Testing
609621

610622
**vitest-axe Integration:**
623+
611624
```ts
612625
import { axe } from 'vitest-axe'
613626
import { render } from '@testing-library/react' // or framework equivalent
@@ -620,6 +633,7 @@ test('should not have accessibility violations', async () => {
620633
```
621634

622635
**Keyboard Navigation Testing:**
636+
623637
```ts
624638
import { fireEvent } from '@testing-library/react'
625639

@@ -641,6 +655,7 @@ test('should handle keyboard navigation', async () => {
641655
```
642656

643657
**ARIA Attributes Testing:**
658+
644659
```ts
645660
test('should have correct ARIA attributes', () => {
646661
render(<Component expanded={true} />)
@@ -654,29 +669,34 @@ test('should have correct ARIA attributes', () => {
654669
### Cross-Framework Testing Patterns
655670

656671
**React Testing:**
672+
657673
```ts
658674
import { render, screen } from '@testing-library/react'
659675
import userEvent from '@testing-library/user-event'
660676
```
661677

662678
**Solid Testing:**
679+
663680
```ts
664681
import { render, screen } from '@solidjs/testing-library'
665682
```
666683

667684
**Vue Testing:**
685+
668686
```ts
669687
import { render, screen } from '@testing-library/vue'
670688
```
671689

672690
**Svelte Testing:**
691+
673692
```ts
674693
import { render, screen } from '@testing-library/svelte'
675694
```
676695

677696
### Component State Testing
678697

679698
**Controlled vs Uncontrolled:**
699+
680700
```ts
681701
test('controlled component', () => {
682702
const onValueChange = vi.fn()
@@ -699,6 +719,7 @@ test('uncontrolled component', () => {
699719
### Screen Reader Compatibility
700720

701721
**Announcement Testing:**
722+
702723
```ts
703724
test('should announce state changes', async () => {
704725
render(<Component />)
@@ -714,6 +735,7 @@ test('should announce state changes', async () => {
714735
```
715736

716737
**Focus Management:**
738+
717739
```ts
718740
test('should manage focus correctly', () => {
719741
render(<Dialog />)
@@ -749,4 +771,9 @@ test('should manage focus correctly', () => {
749771
- Minimize re-renders with proper memoization
750772
- Use lazy mounting for heavy components (`lazy-mount.tsx`)
751773
- Implement proper cleanup in unmount handlers
752-
- Follow framework-specific performance patterns
774+
- Follow framework-specific performance patterns
775+
776+
### When to Use Each Approach
777+
778+
- **Use `Component.Context`**: When you need to access the API for composition within the component tree
779+
- **Use `useComponent + RootProvider`**: When you need external control and state management outside the component

.storybook/styles/carousel.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@
6666
border: none;
6767
justify-content: center;
6868
align-items: center;
69-
height: 12px;
70-
width: 12px;
69+
min-height: 12px;
70+
min-width: 12px;
7171
border-radius: 6px;
7272
cursor: pointer;
7373
background-color: lightgray;

packages/react/src/components/carousel/carousel.stories.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,10 @@ export default meta
99
export { Autoplay } from './examples/autoplay'
1010
export { Basic } from './examples/basic'
1111
export { Controlled } from './examples/controlled'
12+
export { CustomIndicator } from './examples/custom-indicator'
13+
export { DynamicSlides } from './examples/dynamic-slides'
14+
export { PauseOnHover } from './examples/pause-on-hover'
1215
export { RootProvider } from './examples/root-provider'
16+
export { ScrollTo } from './examples/scroll-to'
17+
export { SlidesPerPage } from './examples/slides-per-page'
18+
export { Vertical } from './examples/vertical'
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { Carousel } from '@ark-ui/react/carousel'
2+
3+
export const CustomIndicator = () => {
4+
const images = Array.from({ length: 5 }, (_, i) => `https://picsum.photos/seed/${i + 1}/500/300`)
5+
6+
return (
7+
<Carousel.Root defaultPage={0} slideCount={images.length}>
8+
<Carousel.Control>
9+
<Carousel.PrevTrigger>Previous</Carousel.PrevTrigger>
10+
<Carousel.NextTrigger>Next</Carousel.NextTrigger>
11+
</Carousel.Control>
12+
<Carousel.ItemGroup>
13+
{images.map((image, index) => (
14+
<Carousel.Item key={index} index={index}>
15+
<img src={image} alt={`Slide ${index}`} style={{ width: '100%', height: '300px', objectFit: 'cover' }} />
16+
</Carousel.Item>
17+
))}
18+
</Carousel.ItemGroup>
19+
<Carousel.Context>
20+
{(api) => (
21+
<Carousel.IndicatorGroup style={{ display: 'flex', gap: '8px', marginTop: '16px' }}>
22+
{images.map((image, index) => (
23+
<Carousel.Indicator key={index} index={index}>
24+
<img
25+
src={image}
26+
alt={`Thumbnail ${index}`}
27+
style={{
28+
width: '60px',
29+
height: '40px',
30+
objectFit: 'cover',
31+
cursor: 'pointer',
32+
border: api.page === index ? '2px solid #0066ff' : '2px solid transparent',
33+
borderRadius: '4px',
34+
opacity: api.page === index ? 1 : 0.6,
35+
transition: 'all 0.2s',
36+
}}
37+
/>
38+
</Carousel.Indicator>
39+
))}
40+
</Carousel.IndicatorGroup>
41+
)}
42+
</Carousel.Context>
43+
</Carousel.Root>
44+
)
45+
}

0 commit comments

Comments
 (0)