Skip to content

Commit 486a5e3

Browse files
authored
Merge pull request #1 from Eliav2/v0.1.2
V0.1.2
2 parents 4700166 + 713a908 commit 486a5e3

16 files changed

+450
-595
lines changed

README.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,6 @@ See the **Flush Immediately** example in the live demo.
119119
| `as` | `React.ElementType` | `"div"` | Polymorphic root element. |
120120
| `maxRows` | `number` | `1` | Visible rows before overflow. |
121121
| `maxVisibleItems` | `number` | `100` | Hard cap on visible items. |
122-
| `minVisibleItems` | `number` | `0` | Keep at least N visible. |
123122
| `renderOverflow` | `(hidden: T[]) => ReactNode` | default chip | Custom overflow UI. |
124123
| `renderOverflowItem` | `(item: T, i: number) => ReactNode` | `renderItem` | For expanded lists/menus. |
125124
| `renderOverflowProps` | `Partial<OverflowElementProps<T>>` || Props for default overflow. |
@@ -138,7 +137,7 @@ It’s **expected** you’ll wrap `OverflowList` for product needs (design syste
138137
- **Radix UI + Virtualization wrapper** (search, large datasets, a11y, perf):
139138

140139
- **Demo:** see [Radix UI + Virtualization](https://eliav2.github.io/react-responsive-overflow-list/#radix-ui-virtualization-example) in the live site
141-
- [**Source**](demo/src/examples/RadixVirtualizedOverflowList.tsx)
140+
- [**Source**](demo/src/components/RadixVirtualizedOverflowList.tsx)
142141
- Uses `@tanstack/react-virtual` and the helper `createLimitedRangeExtractor(...)`.
143142

144143
---
@@ -155,7 +154,7 @@ It’s **expected** you’ll wrap `OverflowList` for product needs (design syste
155154
### Edge cases handled
156155

157156
- Single wide item exceeding container width
158-
- `minVisibleItems` / `maxVisibleItems` respected
157+
- `maxRows` / `maxVisibleItems` respected
159158
- Varying item widths, responsive content
160159
- Multi-row overflow detection
161160

demo/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "demo",
33
"private": true,
4-
"version": "0.1.0",
4+
"version": "0.0.0",
55
"type": "module",
66
"scripts": {
77
"dev": "vite",

demo/src/App.tsx

Lines changed: 15 additions & 298 deletions
Original file line numberDiff line numberDiff line change
@@ -1,126 +1,16 @@
1-
import { useState } from "react";
2-
import { OverflowList } from "react-responsive-overflow-list";
3-
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
4-
import { tomorrow } from "react-syntax-highlighter/dist/esm/styles/prism";
5-
import { Theme, Switch } from "@radix-ui/themes";
1+
import { Theme } from "@radix-ui/themes";
62
import { CustomOverflowExample } from "./examples/CustomOverflowExample";
7-
import { RadixVirtualizedOverflowList } from "./examples/RadixVirtualizedOverflowList";
3+
import { BasicExample } from "./examples/BasicExample";
4+
import { ChildrenPatternExample } from "./examples/ChildrenPatternExample";
5+
import { MultiRowExample } from "./examples/MultiRowExample";
6+
import { CustomHostElementExample } from "./examples/CustomHostElementExample";
7+
import { RadixVirtualizationExample } from "./examples/RadixVirtualizationExample";
8+
import { FlushImmediatelyExample } from "./examples/FlushImmediatelyExample";
9+
import { OneItemWiderExample } from "./examples/OneItemWiderExample";
10+
import { MaxRowsOverflowExample } from "./examples/MaxRowsOverflowExample";
811
import { Github } from "lucide-react";
912
import "./App.css";
1013

11-
const fruits = ["Apple", "Banana", "Cherry", "Date", "Elderberry", "Fig", "Grape", "Honeydew", "Kiwi", "Lemon"];
12-
13-
const tags = ["React", "TypeScript", "CSS", "HTML", "JavaScript", "Node.js", "Express", "MongoDB", "Vite", "ESLint"];
14-
15-
const menuItems = ["Home", "About", "Services", "Portfolio", "Blog", "Contact", "Careers", "Support"];
16-
17-
function MultiRowExample() {
18-
const [maxRows, setMaxRows] = useState(2);
19-
20-
return (
21-
<section className="demo">
22-
<h2 id="multi-row-example">Multi-row Example</h2>
23-
<p>Allow up to {maxRows} rows before overflow</p>
24-
<div className="code-preview">
25-
<SyntaxHighlighter language="tsx" style={tomorrow}>
26-
{`<OverflowList
27-
items={fruits.concat(tags).concat(menuItems)}
28-
renderItem={(item) => <span className="multi-item">{item}</span>}
29-
maxRows={${maxRows}}
30-
style={{ gap: "4px" }}
31-
/>`}
32-
</SyntaxHighlighter>
33-
</div>
34-
<div className="controls">
35-
<label htmlFor="maxRows">Max Rows:</label>
36-
<input
37-
id="maxRows"
38-
type="number"
39-
min="1"
40-
max="10"
41-
value={maxRows}
42-
onChange={(e) => setMaxRows(parseInt(e.target.value) || 1)}
43-
className="max-rows-input"
44-
/>
45-
</div>
46-
47-
<div className="demo-container">
48-
<OverflowList
49-
items={fruits.concat(tags).concat(menuItems)}
50-
renderItem={(item) => <span className="multi-item">{item}</span>}
51-
maxRows={maxRows}
52-
style={{ gap: "4px" }}
53-
/>
54-
</div>
55-
</section>
56-
);
57-
}
58-
59-
function FlushImmediatelyExample() {
60-
const [flushImmediately, setFlushImmediately] = useState(false);
61-
62-
return (
63-
<section className="demo">
64-
<h2 id="flush-immediately-example">Flush Immediately Example</h2>
65-
<p>
66-
Control how updates are applied when the container resizes.
67-
<strong>flushImmediately={flushImmediately ? "true" : "false"}</strong>
68-
(default: true)
69-
</p>
70-
<div className="code-preview">
71-
<SyntaxHighlighter language="tsx" style={tomorrow}>
72-
{`<OverflowList
73-
items={fruits.concat(tags)}
74-
renderItem={(item) => <span className="multi-item">{item}</span>}
75-
flushImmediately={${flushImmediately}}
76-
style={{ gap: "4px" }}
77-
/>`}
78-
</SyntaxHighlighter>
79-
</div>
80-
<div className="controls">
81-
<div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
82-
<label htmlFor="flush-toggle">Flush Immediately:</label>
83-
<Switch id="flush-toggle" checked={flushImmediately} onCheckedChange={setFlushImmediately} />
84-
<span style={{ fontSize: "14px", color: "#666" }}>
85-
{flushImmediately ? "Enabled (No flickering)" : "Disabled (better performance)"}
86-
</span>
87-
</div>
88-
</div>
89-
90-
<div style={{ marginBottom: "16px", padding: "12px", backgroundColor: "#f5f5f5", borderRadius: "4px" }}>
91-
<h4 style={{ margin: "0 0 8px 0", fontSize: "14px" }}>Trade-offs:</h4>
92-
<ul style={{ margin: 0, paddingLeft: "20px", fontSize: "14px" }}>
93-
<li>
94-
<strong>flushImmediately=true:</strong> Updates are applied immediately using flushSync, avoiding flickering
95-
but may impact performance
96-
</li>
97-
<li>
98-
<strong>flushImmediately=false:</strong> Updates are applied in the requestAnimationFrame callback, avoiding
99-
forced reflow and improving performance but may cause slight flickering
100-
</li>
101-
<li>
102-
<strong>Default behavior:</strong> flushImmediately is true by default to prioritize smooth visual
103-
experience
104-
</li>
105-
</ul>
106-
107-
<div style={{ marginTop: "12px", fontStyle: "italic", color: "#888", fontSize: "14px" }}>
108-
Resize quickly below to observe the difference!
109-
</div>
110-
</div>
111-
112-
<div className="demo-container">
113-
<OverflowList
114-
items={fruits}
115-
renderItem={(item) => <span className="multi-item">{item}</span>}
116-
flushImmediately={flushImmediately}
117-
style={{ gap: "4px" }}
118-
/>
119-
</div>
120-
</section>
121-
);
122-
}
123-
12414
function App() {
12515
return (
12616
<Theme>
@@ -150,188 +40,15 @@ function App() {
15040
</header>
15141

15242
<main>
153-
<section className="demo">
154-
<h2 id="basic-example">Basic Example</h2>
155-
<p>Simple list with default overflow element</p>
156-
<div className="code-preview">
157-
<SyntaxHighlighter language="tsx" style={tomorrow}>
158-
{`<OverflowList
159-
items={fruits}
160-
renderItem={(item, index) => (
161-
<span key={index} className="fruit-item">
162-
{item}
163-
</span>
164-
)}
165-
style={{ gap: "8px" }}
166-
/>`}
167-
</SyntaxHighlighter>
168-
</div>
169-
<div className="demo-container">
170-
<OverflowList
171-
items={fruits}
172-
renderItem={(item, index) => (
173-
<span key={index} className="fruit-item">
174-
{item}
175-
</span>
176-
)}
177-
style={{ gap: "8px" }}
178-
/>
179-
</div>
180-
</section>
181-
182-
<section className="demo">
183-
<h2 id="children-pattern">Children Pattern</h2>
184-
<p>Using children instead of items array</p>
185-
<div className="code-preview">
186-
<SyntaxHighlighter language="tsx" style={tomorrow}>
187-
{`<OverflowList>
188-
<button>Action 1</button>
189-
<button>Action 2</button>
190-
...
191-
</OverflowList>`}
192-
</SyntaxHighlighter>
193-
</div>
194-
<div className="demo-container">
195-
<OverflowList style={{ gap: "8px" }}>
196-
<button className="action-button">Action 1</button>
197-
<button className="action-button">Action 2</button>
198-
<button className="action-button">Action 3</button>
199-
<button className="action-button">Action 4</button>
200-
<button className="action-button">Action 5</button>
201-
<button className="action-button">Action 6</button>
202-
</OverflowList>
203-
</div>
204-
</section>
205-
43+
<BasicExample />
44+
<ChildrenPatternExample />
20645
<MultiRowExample />
207-
20846
<CustomOverflowExample />
209-
210-
<section className="demo">
211-
<h2 id="custom-host-element">Custom Host Element</h2>
212-
<p>Using the 'as' prop to render as different HTML elements</p>
213-
<div className="code-preview">
214-
<SyntaxHighlighter language="tsx" style={tomorrow}>
215-
{`<OverflowList as="nav" style={{ gap: "8px" }}>
216-
<a href="#home">Home</a>
217-
<a href="#about">About</a>
218-
<a href="#contact">Contact</a>
219-
</OverflowList>`}
220-
</SyntaxHighlighter>
221-
</div>
222-
<div className="demo-container">
223-
<OverflowList as="nav" style={{ gap: "8px" }}>
224-
<a href="#home" className="demo-item demo-item--primary">
225-
Home
226-
</a>
227-
<a href="#about" className="demo-item demo-item--primary">
228-
About
229-
</a>
230-
<a href="#contact" className="demo-item demo-item--primary">
231-
Contact
232-
</a>
233-
<a href="#services" className="demo-item demo-item--primary">
234-
Services
235-
</a>
236-
<a href="#portfolio" className="demo-item demo-item--primary">
237-
Portfolio
238-
</a>
239-
</OverflowList>
240-
</div>
241-
</section>
242-
243-
<section className="demo">
244-
<h2 id="radix-ui-virtualization-example">Radix UI + Virtualization Example</h2>
245-
<p>
246-
This is an EXAMPLE implementation showing how to wrap OverflowList with Radix UI dropdown and
247-
virtualization. In real-world applications, it's expected that you'll wrap OverflowList with your own
248-
components tailored to your specific needs, design system, and UI framework.
249-
</p>
250-
<div className="code-preview">
251-
<SyntaxHighlighter language="tsx" style={tomorrow}>
252-
{`import { RadixVirtualizedOverflowList } from "./examples/RadixVirtualizedOverflowList";
253-
254-
// Small dataset - uses simple dropdown
255-
<RadixVirtualizedOverflowList
256-
items={tags}
257-
renderItem={(tag) => <span className="tag">#{tag}</span>}
258-
style={{ gap: "6px" }}
259-
/>
260-
261-
// Large dataset - automatically uses virtualization
262-
<RadixVirtualizedOverflowList
263-
items={Array.from({ length: 1000 }, (_, i) => \`Item \${i + 1}\`)}
264-
renderItem={(item) => <span className="tag">#{item}</span>}
265-
virtualizationThreshold={50}
266-
enableSearch={true}
267-
style={{ gap: "6px" }}
268-
/>`}
269-
</SyntaxHighlighter>
270-
</div>
271-
272-
<div className="demo-container">
273-
<h4 style={{ margin: "0 0 12px 0", fontSize: "16px" }}>Small Dataset (Simple Dropdown)</h4>
274-
<RadixVirtualizedOverflowList
275-
items={tags}
276-
renderItem={(tag) => <span className="tag">#{tag}</span>}
277-
style={{ gap: "6px" }}
278-
/>
279-
</div>
280-
281-
<div className="demo-container" style={{ marginTop: "24px" }}>
282-
<h4 style={{ margin: "0 0 12px 0", fontSize: "16px" }}>
283-
Large Dataset (Virtualized Dropdown with Search)
284-
</h4>
285-
<RadixVirtualizedOverflowList
286-
items={Array.from({ length: 1000 }, (_, i) => `Item ${i + 1}`)}
287-
renderItem={(item) => <span className="tag">#{item}</span>}
288-
virtualizationThreshold={50}
289-
enableSearch={true}
290-
searchPlaceholder="Search items..."
291-
style={{ gap: "6px" }}
292-
/>
293-
</div>
294-
295-
<div className="demo-note">
296-
<strong>This example demonstrates:</strong>
297-
<ul style={{ margin: "8px 0", paddingLeft: "20px" }}>
298-
<li>
299-
<strong>Automatic virtualization:</strong> Switches to virtualized dropdown when item count exceeds
300-
threshold
301-
</li>
302-
<li>
303-
<strong>Search functionality:</strong> Built-in search/filter for large datasets
304-
</li>
305-
<li>
306-
<strong>Radix UI integration:</strong> Full accessibility and keyboard navigation support
307-
</li>
308-
<li>
309-
<strong>Customizable:</strong> Configurable thresholds, styling, and behavior
310-
</li>
311-
<li>
312-
<strong>Performance optimized:</strong> Efficient rendering for thousands of items
313-
</li>
314-
</ul>
315-
<p style={{ margin: "12px 0 0 0", fontStyle: "italic", color: "#666" }}>
316-
<strong>Note:</strong> This is just an example implementation. In real-world applications, it's expected
317-
that you'll wrap OverflowList with your own components tailored to your specific needs and design
318-
system.
319-
<br />
320-
<strong>Source:</strong>{" "}
321-
<a
322-
href="https://github.com/eliav2/react-responsive-overflow-list/blob/main/demo/src/examples/RadixVirtualizedOverflowList.tsx"
323-
target="_blank"
324-
rel="noopener noreferrer"
325-
>
326-
View implementation on GitHub
327-
</a>
328-
</p>
329-
</div>
330-
</section>
331-
47+
<CustomHostElementExample />
48+
<RadixVirtualizationExample />
33249
<FlushImmediatelyExample />
333-
334-
{/* <div className="demo-container"></div> */}
50+
<OneItemWiderExample />
51+
<MaxRowsOverflowExample />
33552
</main>
33653

33754
<footer>

0 commit comments

Comments
 (0)