Skip to content

Commit c9b449a

Browse files
committed
docs: update documentation for react-selection v2.0.0
1 parent 7980903 commit c9b449a

19 files changed

Lines changed: 19986 additions & 497 deletions

.dumirc.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ export default defineConfig({
1313
codeBlockMode: 'passive',
1414
},
1515
themeConfig: {
16-
name: 'react-selection-docs',
17-
description: 'Docs for react-selection.',
16+
name: 'ReactSelection',
17+
description: 'A headless, type-safe selection component for React.',
1818
nav: [
1919
{
2020
title: 'Guide',

docs/components/index.md

Lines changed: 130 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,156 @@
11
---
2-
title: Components Overview
2+
title: ReactSelection
33
order: 0
44
---
55

6-
# Components
6+
# ReactSelection
77

8-
This section is for documenting your components.
8+
A headless, type-safe selection component for React with slot-based architecture.
99

10-
## Structure
10+
## When To Use
1111

12-
Organize your component documentation in this directory:
12+
- You need single or multiple selection without being tied to a specific UI framework
13+
- You want full control over the visual presentation of selection items
14+
- You need type-safe selection with TypeScript generics
15+
- You need configurable max selection limits with error handling
1316

14-
```
15-
docs/
16-
└── components/
17-
├── index.md # This file
18-
├── button.md # Button component docs
19-
├── input.md # Input component docs
20-
└── ...
21-
```
17+
## Main Exports
2218

23-
## Component Documentation Template
19+
| Export | Type | Description |
20+
| ------------------------ | --------- | ------------------------------------------ |
21+
| `ReactSelection` | Component | The main selection component |
22+
| `ReactSelectionProps` | Interface | Props type for the component |
23+
| `SelectionItemSlotProps` | Interface | Props passed to the item slot |
24+
| `Slot` | Type | Slot type (component, function, or object) |
25+
| `ErrorCode` | Enum | Error codes for selection errors |
2426

25-
```markdown
26-
---
27-
title: ComponentName
28-
order: 1
29-
---
27+
## API
3028

31-
# ComponentName
29+
### ReactSelection Props
3230

33-
Brief description of the component.
31+
Extends `Omit<ReactListProps<T>, 'slots'>` plus:
3432

35-
## When To Use
33+
| Property | Description | Type | Default |
34+
| --------------- | -------------------------------------------------- | ----------------------------------------------------------- | ------------------------------ |
35+
| `data` | Array of data items (each must have `value` field) | `T[]` | - |
36+
| `keyExtractor` | Custom key for list items | `keyof T \| ((item: T, index: number) => string \| number)` | `item.value` |
37+
| `allowDeselect` | Allow deselecting in single selection mode | `boolean` | `false` |
38+
| `max` | Maximum selections allowed (multiple mode) | `number` | `1000` |
39+
| `multiple` | Enable multiple selection | `boolean` | `false` |
40+
| `value` | Current selected value | `any` | `null` (or `[]` when multiple) |
41+
| `onChange` | Callback when selection changes | `(value: any) => void` | - |
42+
| `onError` | Callback when an error occurs | `(error: { code: ErrorCode }) => void` | - |
43+
| `slots` | Slot configuration (see below) | `SelectionSlots<T>` | - |
3644

37-
- Use case 1
38-
- Use case 2
45+
### SelectionItemSlotProps
3946

40-
## Examples
47+
Props received by the `slots.item` slot:
4148

42-
### Basic Usage
49+
| Property | Description | Type |
50+
| ---------- | ------------------------------------------- | ------------ |
51+
| `item` | The current data item | `T` |
52+
| `index` | Index in the data array | `number` |
53+
| `data` | The full data array | `T[]` |
54+
| `active` | Whether this item is currently selected | `boolean` |
55+
| `disabled` | Whether this item is disabled (max reached) | `boolean` |
56+
| `onClick` | Handler to select/deselect this item | `() => void` |
4357

44-
```tsx
45-
import { ComponentName } from 'your-package';
58+
### ErrorCode Enum
59+
60+
| Value | Description |
61+
| ------------------ | ------------------------------------------------------- |
62+
| `MAX_LIMIT_EXCEED` | Selection count has exceeded the configured `max` value |
63+
64+
### Slots Configuration
4665

47-
<ComponentName />
66+
```typescript
67+
interface SelectionSlots<T> {
68+
item: Slot<SelectionItemSlotProps<T>>; // Required
69+
empty?: Slot<{ data: T[] }>; // Optional
70+
}
4871
```
4972

50-
## API
73+
A `Slot` can be:
74+
75+
1. **Component**: `MyComponent`
76+
2. **Render function**: `({ item, active, onClick }) => <button>...</button>`
77+
3. **Object with props**: `{ component: MyComponent, props: { className: 'item' } }`
78+
79+
## Examples
80+
81+
### Single Selection
5182

52-
| Property | Description | Type | Default |
53-
|----------|-------------|------|---------|
54-
| prop1 | Description | `string` | - |
55-
| prop2 | Description | `number` | `0` |
83+
```tsx
84+
import { ReactSelection } from '@jswork/react-selection';
85+
86+
const items = [
87+
{ value: 'apple', label: 'Apple' },
88+
{ value: 'banana', label: 'Banana' },
89+
{ value: 'orange', label: 'Orange' },
90+
];
91+
92+
function App() {
93+
const [selected, setSelected] = useState('apple');
94+
95+
return (
96+
<ReactSelection
97+
data={items}
98+
value={selected}
99+
onChange={setSelected}
100+
slots={{
101+
item: ({ item, active, onClick }) => (
102+
<button
103+
className={active ? 'btn-primary' : 'btn-default'}
104+
onClick={onClick}
105+
>
106+
{item.label}
107+
</button>
108+
),
109+
}}
110+
/>
111+
);
112+
}
56113
```
57114

58-
## Writing Component Docs
115+
### Multiple Selection with Max Limit
59116

60-
1. Create a markdown file for each component
61-
2. Use frontmatter to set title and order
62-
3. Include code examples with syntax highlighting
63-
4. Document all props with a table
117+
```tsx
118+
<ReactSelection
119+
multiple
120+
max={3}
121+
data={items}
122+
value={selectedItems}
123+
onChange={setSelectedItems}
124+
onError={(err) => {
125+
if (err.code === ErrorCode.MAX_LIMIT_EXCEED) {
126+
console.warn('Maximum selections reached');
127+
}
128+
}}
129+
slots={{
130+
item: ({ item, active, disabled, onClick }) => (
131+
<button disabled={disabled} onClick={onClick}>
132+
{active ? '' : ''}
133+
{item.label}
134+
</button>
135+
),
136+
}}
137+
/>
138+
```
64139

65-
## Next Steps
140+
### With Empty State
66141

67-
- Explore specific component documentation
68-
- Check out the [API Reference](/api)
142+
```tsx
143+
<ReactSelection
144+
data={items}
145+
value={selected}
146+
onChange={setSelected}
147+
slots={{
148+
item: ({ item, active, onClick }) => (
149+
<div onClick={onClick} className={active ? 'active' : ''}>
150+
{item.label}
151+
</div>
152+
),
153+
empty: () => <div>No items available</div>,
154+
}}
155+
/>
156+
```

docs/guide/architecture.md

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
---
2+
title: Architecture
3+
order: 2
4+
---
5+
6+
# Architecture
7+
8+
## Design Principles
9+
10+
ReactSelection is built on a few core principles:
11+
12+
### Headless by Design
13+
14+
ReactSelection renders **no wrapper DOM element** — it directly returns a `ReactList`. There is no CSS, no className, no extra DOM nodes. You have full control over the rendered output through slots.
15+
16+
### Composition over Inheritance
17+
18+
ReactSelection wraps `@jswork/react-list`, adding selection behavior to the list's slot system. It does not extend or subclass — it composes:
19+
20+
```
21+
ReactSelection → ReactList → Your Slots
22+
```
23+
24+
### Slot Forwarding
25+
26+
The user's `slots.item` is wrapped internally. Selection state (`active`, `disabled`, `onClick`) is injected before rendering:
27+
28+
1. ReactSelection receives your `slots.item`
29+
2. For each data item, it computes selection state
30+
3. It wraps your slot with the computed props (`active`, `disabled`, `onClick`)
31+
4. The enhanced slot is passed to `ReactList`
32+
33+
## Internal Flow
34+
35+
### Single Selection
36+
37+
```
38+
User clicks item
39+
→ onClick handler fires
40+
→ If item is already selected and allowDeselect is true → deselect (value = null)
41+
→ If item is not selected → select (value = item.value)
42+
→ onChange callback fires with new value
43+
```
44+
45+
### Multiple Selection
46+
47+
```
48+
User clicks item
49+
→ onClick handler fires
50+
→ If item is already selected → remove from array
51+
→ If item is not selected:
52+
→ If current count >= max → fire onError (MAX_LIMIT_EXCEED)
53+
→ Otherwise → add to array
54+
→ onChange callback fires with new array
55+
```
56+
57+
## Performance
58+
59+
- **Memoized handlers** — Selection handlers are memoized with `useCallback`
60+
- **Deep equality** — State comparison uses `fast-deep-equal` for accurate change detection
61+
- **Key handling** — Keys default to `item.value`, falling back to `index` for React's reconciliation
62+
63+
## Type System
64+
65+
```typescript
66+
// The generic constraint ensures data items have a value field
67+
interface ReactSelectionProps<T extends { value: any }> {
68+
data: T[];
69+
// ... other props
70+
}
71+
72+
// Slot props are fully typed based on your data type
73+
interface SelectionItemSlotProps<T> {
74+
item: T;
75+
index: number;
76+
data: T[];
77+
active: boolean;
78+
disabled: boolean;
79+
onClick: () => void;
80+
}
81+
```
82+
83+
## Dependencies
84+
85+
| Package | Version | Purpose |
86+
| -------------------- | ------- | ------------------------------------ |
87+
| `react` | peer | UI framework |
88+
| `fast-deep-equal` | peer | Deep equality comparison for state |
89+
| `@jswork/react-list` | ^2.0.0 | Base list component with slot system |
90+
91+
## Project Structure
92+
93+
```
94+
react-selection/
95+
├── packages/
96+
│ ├── lib/
97+
│ │ └── src/
98+
│ │ └── index.tsx # Main component
99+
│ └── example/
100+
│ └── src/
101+
│ └── App.tsx # Usage examples
102+
├── llms.txt # LLM context file
103+
└── README.md
104+
```

0 commit comments

Comments
 (0)