intable 0.0.7 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/copilot-instructions.md +102 -0
- package/docs/index-BaMALNy6.css +1 -1
- package/docs/index-CDN48t9E.js +2 -2
- package/index.html +13 -14
- package/package.json +9 -4
- package/packages/intable/package.json +1 -1
- package/packages/intable/src/index.tsx +25 -17
- package/packages/intable/src/plugins/CopyPastePlugin.tsx +49 -13
- package/packages/intable/src/plugins/DiffPlugin.tsx +31 -18
- package/packages/intable/src/theme/dark.scss +46 -0
- package/packages/intable/src/theme/github.scss +80 -0
- package/packages/intable/src/theme/material.scss +73 -0
- package/packages/intable/src/theme/shadcn.scss +66 -0
- package/packages/intable/src/theme/stripe.scss +57 -0
- package/packages/react/package.json +13 -8
- package/packages/react/src/index.ts +1 -1
- package/packages/vue/package.json +1 -1
- package/scripts/publish.js +1 -1
- package/src/index.tsx +20 -0
- package/src/pages/demo/BasicDemo.tsx +19 -0
- package/src/pages/demo/CellMergeDemo.tsx +41 -0
- package/src/pages/demo/CellSelectionDemo.tsx +24 -0
- package/src/pages/demo/CompositeDemo.tsx +60 -0
- package/src/pages/demo/CopyPasteDemo.tsx +26 -0
- package/src/pages/demo/DiffDemo.tsx +33 -0
- package/src/pages/demo/DragDemo.tsx +25 -0
- package/src/pages/demo/EditableDemo.tsx +58 -0
- package/src/pages/demo/ExpandDemo.tsx +32 -0
- package/src/pages/demo/HeaderGroupDemo.tsx +36 -0
- package/src/pages/demo/HistoryDemo.tsx +28 -0
- package/src/pages/demo/ReactDemo.tsx +59 -0
- package/src/pages/demo/ResizeDemo.tsx +24 -0
- package/src/pages/demo/RowGroupDemo.tsx +43 -0
- package/src/pages/demo/RowSelectionDemo.tsx +27 -0
- package/src/pages/demo/TreeDemo.tsx +45 -0
- package/src/pages/demo/VirtualScrollDemo.tsx +21 -0
- package/src/pages/demo/helpers.tsx +39 -0
- package/src/pages/demo/index.tsx +180 -0
- package/src/pages/index.tsx +2 -0
- package/src/pages/website.scss +37 -0
- package/src/pages/website.tsx +651 -0
- package/vite.config.ts +70 -63
- package/src/demo.tsx +0 -107
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin test demo index — renders a list of demo sections,
|
|
3
|
+
* one per plugin, to visually verify each feature.
|
|
4
|
+
*/
|
|
5
|
+
import { createSignal, createEffect, onCleanup, For, Show, mergeProps } from 'solid-js'
|
|
6
|
+
import { useSearchParams } from '@solidjs/router'
|
|
7
|
+
|
|
8
|
+
import { BasicDemo } from './BasicDemo'
|
|
9
|
+
import { VirtualScrollDemo } from './VirtualScrollDemo'
|
|
10
|
+
import { HeaderGroupDemo } from './HeaderGroupDemo'
|
|
11
|
+
import { CellSelectionDemo } from './CellSelectionDemo'
|
|
12
|
+
import { EditableDemo } from './EditableDemo'
|
|
13
|
+
import { ExpandDemo } from './ExpandDemo'
|
|
14
|
+
import { RowSelectionDemo } from './RowSelectionDemo'
|
|
15
|
+
import { ResizeDemo } from './ResizeDemo'
|
|
16
|
+
import { DragDemo } from './DragDemo'
|
|
17
|
+
import { RowGroupDemo } from './RowGroupDemo'
|
|
18
|
+
import { CellMergeDemo } from './CellMergeDemo'
|
|
19
|
+
import { HistoryDemo } from './HistoryDemo'
|
|
20
|
+
import { DiffDemo } from './DiffDemo'
|
|
21
|
+
import { TreeDemo } from './TreeDemo'
|
|
22
|
+
import { CopyPasteDemo } from './CopyPasteDemo'
|
|
23
|
+
import { CompositeDemo } from './CompositeDemo'
|
|
24
|
+
import { ReactDemo } from './ReactDemo'
|
|
25
|
+
|
|
26
|
+
// ── Theme CSS (equivalent to: import 'intable/theme/*') ──────────────────────
|
|
27
|
+
import antdCss from '../../../packages/intable/src/theme/antd.scss?inline'
|
|
28
|
+
import elementPlusCss from '../../../packages/intable/src/theme/element-plus.scss?inline'
|
|
29
|
+
import darkCss from '../../../packages/intable/src/theme/dark.scss?inline'
|
|
30
|
+
import shadcnCss from '../../../packages/intable/src/theme/shadcn.scss?inline'
|
|
31
|
+
import stripeCss from '../../../packages/intable/src/theme/stripe.scss?inline'
|
|
32
|
+
import materialCss from '../../../packages/intable/src/theme/material.scss?inline'
|
|
33
|
+
import githubCss from '../../../packages/intable/src/theme/github.scss?inline'
|
|
34
|
+
|
|
35
|
+
const THEMES = [
|
|
36
|
+
{ name: 'Default', css: '', color: '#e5e7eb' },
|
|
37
|
+
{ name: 'Antd', css: antdCss, color: '#1677ff' },
|
|
38
|
+
{ name: 'Element Plus', css: elementPlusCss,color: '#409eff' },
|
|
39
|
+
{ name: 'Dark', css: darkCss, color: '#0d1117' },
|
|
40
|
+
{ name: 'GitHub', css: githubCss, color: '#1f2328' },
|
|
41
|
+
{ name: 'Shadcn', css: shadcnCss, color: '#18181b' },
|
|
42
|
+
{ name: 'Stripe', css: stripeCss, color: '#635bff' },
|
|
43
|
+
{ name: 'Material', css: materialCss, color: '#6750a4' },
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
const STYLE_ID = 'intable-theme-override'
|
|
47
|
+
|
|
48
|
+
function applyTheme(css: string) {
|
|
49
|
+
let el = document.getElementById(STYLE_ID) as HTMLStyleElement | null
|
|
50
|
+
if (!el) {
|
|
51
|
+
el = document.createElement('style')
|
|
52
|
+
el.id = STYLE_ID
|
|
53
|
+
document.head.appendChild(el)
|
|
54
|
+
}
|
|
55
|
+
el.textContent = css
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ── Custom theme dropdown ─────────────────────────────────────────────────────
|
|
59
|
+
function ThemeSelect(props: { themes: typeof THEMES; value: string; onChange: (v: string) => void }) {
|
|
60
|
+
const [open, setOpen] = createSignal(false)
|
|
61
|
+
let ref!: HTMLDivElement
|
|
62
|
+
|
|
63
|
+
const current = () => props.themes.find(t => t.name === props.value)!
|
|
64
|
+
|
|
65
|
+
const handleOutside = (e: MouseEvent) => {
|
|
66
|
+
if (!ref.contains(e.target as Node)) setOpen(false)
|
|
67
|
+
}
|
|
68
|
+
createEffect(() => {
|
|
69
|
+
if (open()) document.addEventListener('mousedown', handleOutside)
|
|
70
|
+
else document.removeEventListener('mousedown', handleOutside)
|
|
71
|
+
})
|
|
72
|
+
onCleanup(() => document.removeEventListener('mousedown', handleOutside))
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<div ref={ref} class='relative w-full'>
|
|
76
|
+
<button
|
|
77
|
+
type='button'
|
|
78
|
+
class='flex items-center gap-1.5 w-full text-xs px-2 py-1.5 rd-1 b-(1 solid #d1d5db) bg-white c-#374151 cursor-pointer text-left'
|
|
79
|
+
onClick={() => setOpen(o => !o)}
|
|
80
|
+
>
|
|
81
|
+
<span class='inline-block w-2.5 h-2.5 rd-full shrink-0 b-(1 solid #0002)' style={{ background: current().color }} />
|
|
82
|
+
<span class='flex-1'>{current().name}</span>
|
|
83
|
+
<svg class='w-3 h-3 c-gray shrink-0' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2.5'>
|
|
84
|
+
<path stroke-linecap='round' stroke-linejoin='round' d='M19.5 8.25l-7.5 7.5-7.5-7.5' />
|
|
85
|
+
</svg>
|
|
86
|
+
</button>
|
|
87
|
+
<Show when={open()}>
|
|
88
|
+
<div class='absolute top-full left-0 right-0 mt-0.5 bg-white b-(1 solid #d1d5db) rd-1 shadow-md z-50 py-0.5'>
|
|
89
|
+
<For each={props.themes}>{t => (
|
|
90
|
+
<button
|
|
91
|
+
type='button'
|
|
92
|
+
class={`flex items-center gap-1.5 w-full px-2 py-1.5 text-xs text-left cursor-pointer transition-colors ${
|
|
93
|
+
props.value === t.name ? 'bg-blue-50 c-blue-600 font-medium' : 'hover:bg-gray-50 c-#374151'
|
|
94
|
+
}`}
|
|
95
|
+
onClick={() => { props.onChange(t.name); setOpen(false) }}
|
|
96
|
+
>
|
|
97
|
+
<span class='inline-block w-2.5 h-2.5 rd-full shrink-0 b-(1 solid #0002)' style={{ background: t.color }} />
|
|
98
|
+
{t.name}
|
|
99
|
+
</button>
|
|
100
|
+
)}</For>
|
|
101
|
+
</div>
|
|
102
|
+
</Show>
|
|
103
|
+
</div>
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// ── Demo list ─────────────────────────────────────────────────────────────────
|
|
108
|
+
const demos = [
|
|
109
|
+
{ name: 'Basic', comp: BasicDemo, desc: 'Minimal table with index, border, sticky header' },
|
|
110
|
+
{ name: 'VirtualScroll', comp: VirtualScrollDemo, desc: 'Virtual scroll (X+Y) with 10k rows × 50 cols' },
|
|
111
|
+
{ name: 'HeaderGroup', comp: HeaderGroupDemo, desc: 'Nested column header groups with colspan/rowspan' },
|
|
112
|
+
{ name: 'CellSelection', comp: CellSelectionDemo, desc: 'Click and drag to select cell ranges' },
|
|
113
|
+
{ name: 'Editable', comp: EditableDemo, desc: 'Double-click cells to edit (text, number, select, date…)' },
|
|
114
|
+
{ name: 'Expand', comp: ExpandDemo, desc: 'Expandable rows with custom detail render' },
|
|
115
|
+
{ name: 'RowSelection', comp: RowSelectionDemo, desc: 'Checkbox row selection (single & multiple)' },
|
|
116
|
+
{ name: 'Resize', comp: ResizeDemo, desc: 'Drag column/row borders to resize' },
|
|
117
|
+
{ name: 'Drag', comp: DragDemo, desc: 'Drag-and-drop column & row reordering' },
|
|
118
|
+
{ name: 'RowGroup', comp: RowGroupDemo, desc: 'Group rows by field values with collapsible headers' },
|
|
119
|
+
{ name: 'CellMerge', comp: CellMergeDemo, desc: 'Merge cells (rowspan/colspan)' },
|
|
120
|
+
{ name: 'CopyPaste', comp: CopyPasteDemo, desc: 'Copy / paste cell ranges (Ctrl+C / Ctrl+V)' },
|
|
121
|
+
{ name: 'Tree', comp: TreeDemo, desc: 'Tree-structured data with expand/collapse' },
|
|
122
|
+
{ name: 'History', comp: HistoryDemo, desc: 'Undo / Redo (Ctrl+Z / Ctrl+Y)' },
|
|
123
|
+
{ name: 'Diff', comp: DiffDemo, desc: 'Track changes & commit (Ctrl+S)' },
|
|
124
|
+
{ name: 'Composite', comp: CompositeDemo, desc: 'All features combined' },
|
|
125
|
+
{ name: 'React', comp: ReactDemo, desc: 'React integration demo' }
|
|
126
|
+
]
|
|
127
|
+
|
|
128
|
+
export const DemoApp = () => {
|
|
129
|
+
const [_qs, setQs] = useSearchParams<any>()
|
|
130
|
+
const qs = mergeProps({ active: demos[0].name, theme: THEMES[0].name }, () => _qs)
|
|
131
|
+
|
|
132
|
+
createEffect(() => {
|
|
133
|
+
const t = THEMES.find(t => t.name === qs.theme)
|
|
134
|
+
applyTheme(t?.css ?? '')
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
onCleanup(() => document.getElementById(STYLE_ID)?.remove())
|
|
138
|
+
|
|
139
|
+
return (
|
|
140
|
+
<div class='flex h-100vh'>
|
|
141
|
+
{/* sidebar */}
|
|
142
|
+
<nav class='w-52 shrink-0 of-y-auto b-r-(1 solid #e5e7eb) p-2 bg-#fafafa flex flex-col gap-1'>
|
|
143
|
+
<h2 class='font-bold text-lg px-2 py-1'>Plugin Demos</h2>
|
|
144
|
+
|
|
145
|
+
{/* Theme switcher — custom dropdown for proper color rendering */}
|
|
146
|
+
<div class='px-2 pb-2 b-b-(1 solid #e5e7eb) mb-1 relative'>
|
|
147
|
+
<label class='text-xs c-gray font-medium tracking-wide uppercase block mb-1'>Theme</label>
|
|
148
|
+
<ThemeSelect themes={THEMES} value={qs.theme} onChange={t => setQs({ theme: t })} />
|
|
149
|
+
</div>
|
|
150
|
+
|
|
151
|
+
{/* Demo list */}
|
|
152
|
+
<For each={demos}>{d => (
|
|
153
|
+
<button
|
|
154
|
+
class={`block w-full text-left px-3 py-1.5 rd-1 text-sm truncate cursor-pointer ${qs.active === d.name ? 'bg-blue-500 c-white' : 'hover:bg-gray/10'}`}
|
|
155
|
+
onClick={() => setQs({ active: d.name })}
|
|
156
|
+
>
|
|
157
|
+
{d.name}
|
|
158
|
+
</button>
|
|
159
|
+
)}</For>
|
|
160
|
+
</nav>
|
|
161
|
+
|
|
162
|
+
{/* main */}
|
|
163
|
+
<main class='flex-1 w-0 p-4 of-auto'>
|
|
164
|
+
<For each={demos}>{d => (
|
|
165
|
+
<Show when={qs.active === d.name}>
|
|
166
|
+
<div class='flex items-baseline gap-3 mb-1'>
|
|
167
|
+
<h2 class='font-bold text-xl'>{d.name}</h2>
|
|
168
|
+
<span class='text-xs c-gray font-mono'>Theme: {qs.theme}</span>
|
|
169
|
+
</div>
|
|
170
|
+
<p class='c-gray text-sm mb-3'>{d.desc}</p>
|
|
171
|
+
<d.comp />
|
|
172
|
+
</Show>
|
|
173
|
+
)}</For>
|
|
174
|
+
</main>
|
|
175
|
+
</div>
|
|
176
|
+
)
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export default DemoApp
|
|
180
|
+
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/* intable official website — supplemental styles
|
|
2
|
+
* These override the component's default light-theme CSS variables
|
|
3
|
+
* so the live demo section matches the OLED dark aesthetic.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/* ── Live demo: dark-theme table overrides ─────────────────────────────────── */
|
|
7
|
+
.wt-live-demo {
|
|
8
|
+
/* Override the .data-table's own CSS variable declarations */
|
|
9
|
+
.data-table {
|
|
10
|
+
--bg: #0a0a12;
|
|
11
|
+
--c-primary: #6366f1;
|
|
12
|
+
--menu-bg: #1e1e2e;
|
|
13
|
+
--li-hover-bg: rgba(255, 255, 255, .06);
|
|
14
|
+
--table-b-c: rgba(255, 255, 255, .07);
|
|
15
|
+
--table-c: #cbd5e1;
|
|
16
|
+
--table-bg: #0a0a12;
|
|
17
|
+
--table-header-c: #64748b;
|
|
18
|
+
--table-header-bg: #0f0f1a;
|
|
19
|
+
--table-row-hover-bg: rgba(255, 255, 255, .04);
|
|
20
|
+
--select-area-bg: rgba(99, 102, 241, .15);
|
|
21
|
+
color-scheme: dark;
|
|
22
|
+
|
|
23
|
+
background: #0a0a12;
|
|
24
|
+
|
|
25
|
+
th, td {
|
|
26
|
+
border-color: rgba(255, 255, 255, .07);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
thead th {
|
|
30
|
+
background: #0f0f1a;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
tr:hover > td {
|
|
34
|
+
background: rgba(255, 255, 255, .04);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|