Skip to content

Commit 5e5c86c

Browse files
Bug fix and improvements
0 parents  commit 5e5c86c

File tree

14 files changed

+4981
-0
lines changed

14 files changed

+4981
-0
lines changed

.gitignore

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
.idea/
2+
*.iml
3+
.vscode/
4+
node_modules/
5+
npm-debug.log*
6+
yarn-debug.log*
7+
yarn-error.log*
8+
pnpm-debug.log*
9+
package-lock.json
10+
yarn.lock
11+
pnpm-lock.yaml
12+
coverage/
13+
.nyc_output/
14+
.env
15+
.DS_Store
16+
Thumbs.db

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 Codes Easy
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 351 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,351 @@
1+
# CollapseTable.JS
2+
3+
Make any HTML table **responsive**: low-priority columns automatically **collapse** into a per-row **details** panel with a **+/−** toggle.
4+
5+
[![npm](https://img.shields.io/npm/v/@codeseasy/collapsetable.svg)](https://www.npmjs.com/package/@codeseasy/collapsetable)
6+
[![license: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](#license)
7+
[![types: included](https://img.shields.io/badge/types-included-informational.svg)](./npm_usage.md)
8+
9+
* **Author:** Vishnu — [https://vishnu.wiki](https://vishnu.wiki)
10+
* **Company:** Codes Easy — [https://www.codeseasy.com](https://www.codeseasy.com)
11+
* **License:** MIT
12+
13+
---
14+
15+
## Why CollapseTable?
16+
17+
* 📱 Keeps important columns visible; folds the rest into an inline details view
18+
* ➕/➖ Per-row toggle (keyboard: **Enter** / **Space**)
19+
* ♿ Accessible by default (`aria-expanded`, `aria-controls`, `role="region"`, `aria-live="polite"`)
20+
* 🧩 Zero dependencies, tiny footprint
21+
* ⚙️ Production-ready: Resize/Mutation/Intersection observers, hidden-container deferral, stable row IDs, multi-`<tbody>` support
22+
* 🎛️ Flexible: `tableLayout`, `detailsRender` hook, custom icons/strings/classes
23+
* 📏 Sensible defaults: table is `width: 100%`, left-aligned cells, and a small control column auto-inserted at the start
24+
25+
---
26+
27+
## Quick Start (CDN)
28+
29+
**Pinned version (recommended):**
30+
31+
```html
32+
<script src="https://cdn.jsdelivr.net/npm/@codeseasy/collapsetable@1.1.1/dist/collapsetable.min.js"></script>
33+
```
34+
35+
**Always latest (auto-updates):**
36+
37+
```html
38+
<script src="https://cdn.jsdelivr.net/npm/@codeseasy/collapsetable@latest/dist/collapsetable.min.js"></script>
39+
```
40+
41+
**Initialize:**
42+
43+
```html
44+
<script>
45+
var ct = new CollapseTable();
46+
// target can be: "table1" (id, no #), "#table1", ".orders", "table.responsive", or a <table> element
47+
ct.set("table1");
48+
</script>
49+
```
50+
51+
**Minimal example:**
52+
53+
```html
54+
<script src="https://cdn.jsdelivr.net/npm/@codeseasy/collapsetable@1.1.1/dist/collapsetable.min.js"></script>
55+
56+
<table id="table1">
57+
<thead>
58+
<tr>
59+
<th data-priority="1" data-min="180">Project</th>
60+
<th data-priority="2" data-min="140">Client</th>
61+
<th data-priority="3" data-min="120">Status</th>
62+
<th data-priority="4" data-min="120">Budget</th>
63+
</tr>
64+
</thead>
65+
<tbody>
66+
<tr><td>Website Revamp</td><td>Acme</td><td>Active</td><td>₹2,50,000</td></tr>
67+
<tr><td>Android App</td><td>Globex</td><td>Planning</td><td>₹1,80,000</td></tr>
68+
</tbody>
69+
</table>
70+
71+
<script>
72+
var ct = new CollapseTable();
73+
ct.set("table1");
74+
</script>
75+
```
76+
77+
---
78+
79+
## Install via npm
80+
81+
```bash
82+
npm i @codeseasy/collapsetable
83+
```
84+
85+
**ESM:**
86+
87+
```ts
88+
import CollapseTable from '@codeseasy/collapsetable';
89+
90+
const ct = new CollapseTable();
91+
ct.set('#orders');
92+
```
93+
94+
**CommonJS:**
95+
96+
```js
97+
const CollapseTable = require('@codeseasy/collapsetable');
98+
99+
const ct = new CollapseTable();
100+
ct.set('#orders');
101+
```
102+
103+
> TypeScript types are bundled. See **[npm\_usage.md](./npm_usage.md)** for framework tips and advanced patterns.
104+
105+
---
106+
107+
## Markup requirements
108+
109+
* A `<thead>` with **one header row** (`<tr>`) is required.
110+
* At least one `<tbody>` is required (multi-`<tbody>` is supported).
111+
* **No `colspan`/`rowspan`** in header or body for responsive collapsing. If spans are detected, collapsing is **disabled** (base styles still apply and a console warning is emitted).
112+
* The control (+/−) column is automatically inserted as the **first** column if not present.
113+
114+
**Per-column attributes (on `<th>`):**
115+
116+
* `data-priority` — importance level.
117+
`1` = most important (**never hidden**). Higher numbers (`2`, `3`, `4`…) hide **earlier** as space shrinks.
118+
* `data-min` — width hint in **px** to improve fit decisions.
119+
* `data-label` *(optional)* — label shown in the details panel (defaults to header text).
120+
121+
Example:
122+
123+
```html
124+
<th data-priority="4" data-min="160" data-label="Placed On">Date</th>
125+
```
126+
127+
---
128+
129+
## API
130+
131+
### Constructor
132+
133+
```js
134+
const ct = new CollapseTable(globalOptions?);
135+
```
136+
137+
* **globalOptions** (optional) are applied to all tables unless overridden per table.
138+
139+
### Attach / Detach
140+
141+
```js
142+
ct.set(target, perTableOptions?); // one table
143+
ct.setAll(targets, perTableOptions?); // many tables
144+
ct.unset(target); // remove one
145+
ct.unsetAll(targets); // remove many
146+
```
147+
148+
* **target / targets** can be a table id (without `#`), a CSS selector, a `HTMLTableElement`, or a list (`NodeList`, `HTMLCollection`, `Element[]`). Non-table elements are ignored.
149+
* `set(...)` returns a **Controller** for that table.
150+
`setAll(...)` returns an **array** of Controllers.
151+
152+
### Refresh & controls
153+
154+
```js
155+
ct.refresh(target?); // re-measure & refit (omit to refresh all)
156+
ct.expandAll(target?); // expand details rows (only if some columns are hidden)
157+
ct.collapseAll(target?);
158+
159+
ct.expandRow(target, rowOrIndex); // by 0-based index across all TBODY rows or pass a <tr>
160+
ct.collapseRow(target, rowOrIndex);
161+
```
162+
163+
### Events
164+
165+
```js
166+
ct.on('expand', ({ table, row }) => {});
167+
ct.on('collapse', ({ table, row }) => {});
168+
ct.on('toggle', ({ table, row, expanded }) => {});
169+
ct.on('refit', ({ table, initial, anyHidden }) => {});
170+
ct.on('destroy', ({ table }) => {}); // fired when a table is unset or destroyed
171+
172+
// unsubscribe
173+
ct.off('expand', handler);
174+
```
175+
176+
**Payloads**
177+
178+
* `expand` / `collapse`: `{ table: HTMLTableElement, row: HTMLTableRowElement }`
179+
* `toggle`: `{ table, row, expanded: boolean }`
180+
* `refit`: `{ table, initial: boolean, anyHidden: boolean }`
181+
* `destroy`: `{ table: HTMLTableElement }`
182+
183+
---
184+
185+
## Options (with defaults)
186+
187+
```js
188+
{
189+
controlWidth: 46, // px reserved for the +/− column
190+
minWidthDefault: 140, // px when no data-min and cannot measure
191+
tableLayout: "auto", // "auto" | "fixed"
192+
deferWhenHidden: true, // if container is hidden, defer precise fit until visible
193+
194+
attrs: {
195+
priority: "data-priority", // lower = more important (1 never hidden)
196+
min: "data-min", // width hint (px)
197+
label: "data-label" // custom label used in details view
198+
},
199+
200+
classNames: {
201+
root: "ctbl",
202+
control: "ctbl-control",
203+
toggle: "ctbl-toggle",
204+
details: "ctbl-details",
205+
detailsInner: "ctbl-details-inner",
206+
detail: "ctbl-detail",
207+
name: "ctbl-name",
208+
value: "ctbl-value",
209+
hide: "ctbl-hide"
210+
},
211+
212+
icons: {
213+
expand: "+",
214+
collapse: ""
215+
},
216+
217+
strings: {
218+
toggleTitle: "Show more",
219+
show: "Show details",
220+
hide: "Hide details"
221+
},
222+
223+
// Optional custom details renderer
224+
// Return a Node (appended), an HTML string (innerHTML), or void for default "Label: Value" layout.
225+
detailsRender: undefined
226+
}
227+
```
228+
229+
**Per-table override:**
230+
231+
```js
232+
ct.set('#invoices', {
233+
tableLayout: 'fixed',
234+
icons: { expand: '', collapse: '' },
235+
strings: { toggleTitle: 'More', show: 'Show', hide: 'Hide' }
236+
});
237+
```
238+
239+
**Global helpers:**
240+
241+
```js
242+
ct.getOptions(); // clone of current global options
243+
ct.updateOptions({ tableLayout: 'fixed' }); // update globals + refresh attached tables
244+
CollapseTable.version; // "1.1.1"
245+
```
246+
247+
---
248+
249+
## Custom details rendering
250+
251+
You can completely control the details content:
252+
253+
```js
254+
ct.set('#orders', {
255+
detailsRender(row, hiddenColumns, cells) {
256+
const ul = document.createElement('ul');
257+
ul.style.margin = '0';
258+
ul.style.paddingLeft = '1rem';
259+
hiddenColumns.forEach(col => {
260+
const li = document.createElement('li');
261+
const label = col.th.getAttribute('data-label') || col.th.textContent || '';
262+
li.innerHTML = `<strong>${label}:</strong> ${cells[col.index]?.innerHTML ?? ''}`;
263+
ul.appendChild(li);
264+
});
265+
return ul; // or return HTML string
266+
}
267+
});
268+
```
269+
270+
---
271+
272+
## Accessibility
273+
274+
* Toggle buttons keep `aria-expanded` / `aria-controls` in sync
275+
* Keyboard support: **Enter** and **Space**
276+
* Details wrapper is a labeled live region (`role="region"`, `aria-live="polite"`)
277+
* Control column hides entirely if nothing is collapsed, avoiding “empty” first column
278+
279+
---
280+
281+
## Tips, limitations & troubleshooting
282+
283+
* **Nothing collapses on mobile?**
284+
Ensure some headers use `data-priority="2"` or higher. Priority `1` never hides.
285+
* **Toggle not visible?**
286+
The +/− control only shows when at least one non-priority-1 column is hidden.
287+
* **Hidden containers (`display:none`)?**
288+
With `deferWhenHidden: true`, precise fitting is deferred until visible (uses viewport width meanwhile).
289+
* **`colspan`/`rowspan` present?**
290+
Collapsing is **disabled** if spans are detected in `<thead>` or `<tbody>`; base styles still apply and a console warning is printed.
291+
* **Multiple `<tbody>` sections?**
292+
Supported. Row indices for `expandRow`/`collapseRow` are 0-based **across all** data rows in order.
293+
* **SSR / hydration?**
294+
Initialize on the client after the table is in the DOM.
295+
296+
---
297+
298+
## Browser support
299+
300+
Modern evergreen browsers. No dependencies. Uses `ResizeObserver`/`IntersectionObserver` when available, with sensible fallbacks.
301+
302+
---
303+
304+
## File structure
305+
306+
```
307+
src/
308+
CollapseTable.js
309+
types/
310+
collapsetable.d.ts
311+
dist/
312+
collapsetable.min.js
313+
collapsetable.js
314+
README.md
315+
npm_usage.md
316+
package.json
317+
```
318+
319+
* **Types:** Provided at `src/types/collapsetable.d.ts` and published with the package.
320+
321+
---
322+
323+
## npm usage & TypeScript
324+
325+
See **[npm\_usage.md](./npm_usage.md)** for:
326+
327+
* Framework integration notes
328+
* ESM/CJS patterns
329+
* Advanced TypeScript usage and examples
330+
* Bundler tips
331+
332+
---
333+
334+
## CDN links
335+
336+
* **Pinned version:**
337+
`https://cdn.jsdelivr.net/npm/@codeseasy/collapsetable@1.1.1/dist/collapsetable.min.js`
338+
* **Always latest:**
339+
`https://cdn.jsdelivr.net/npm/@codeseasy/collapsetable@latest/dist/collapsetable.min.js`
340+
341+
---
342+
343+
## Contributing
344+
345+
Issues and PRs are welcome! Please include a minimal repro (HTML + script) when reporting layout problems.
346+
347+
---
348+
349+
## License
350+
351+
MIT © 2025 Vishnu (Codes Easy). See [LICENSE](./LICENSE).

0 commit comments

Comments
 (0)