@talelk/newui-organisms 0.0.0-stage → 2.0.0

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.
Files changed (64) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +12 -2
  3. package/package.json +38 -3
  4. package/src/exports.test.ts +27 -0
  5. package/src/index.ts +1 -0
  6. package/src/organisms/AppSidebar/AppSidebar.test.tsx +136 -0
  7. package/src/organisms/AppSidebar/AppSidebar.tsx +259 -0
  8. package/src/organisms/AppSidebar/index.ts +1 -0
  9. package/src/organisms/AuthCard/AuthCard.a11y.test.tsx +36 -0
  10. package/src/organisms/AuthCard/AuthCard.test.tsx +56 -0
  11. package/src/organisms/AuthCard/AuthCard.tsx +89 -0
  12. package/src/organisms/AuthCard/index.ts +1 -0
  13. package/src/organisms/CommandPalette/CommandPalette.test.tsx +196 -0
  14. package/src/organisms/CommandPalette/CommandPalette.tsx +468 -0
  15. package/src/organisms/CommandPalette/index.ts +1 -0
  16. package/src/organisms/DataState/DataState.test.tsx +45 -0
  17. package/src/organisms/DataState/DataState.tsx +111 -0
  18. package/src/organisms/DataState/index.ts +6 -0
  19. package/src/organisms/DataTable/DataTable.test.tsx +161 -0
  20. package/src/organisms/DataTable/DataTable.tsx +612 -0
  21. package/src/organisms/DataTable/index.ts +1 -0
  22. package/src/organisms/DetailHeader/DetailHeader.test.tsx +55 -0
  23. package/src/organisms/DetailHeader/DetailHeader.tsx +95 -0
  24. package/src/organisms/DetailHeader/index.ts +1 -0
  25. package/src/organisms/FilterBar/FilterBar.test.tsx +152 -0
  26. package/src/organisms/FilterBar/FilterBar.tsx +251 -0
  27. package/src/organisms/FilterBar/index.ts +1 -0
  28. package/src/organisms/KanbanBoard/KanbanBoard.test.tsx +255 -0
  29. package/src/organisms/KanbanBoard/KanbanBoard.tsx +605 -0
  30. package/src/organisms/KanbanBoard/drag.test.ts +448 -0
  31. package/src/organisms/KanbanBoard/drag.ts +407 -0
  32. package/src/organisms/KanbanBoard/index.ts +17 -0
  33. package/src/organisms/MobileNav/MobileNav.browser.test.tsx +39 -0
  34. package/src/organisms/MobileNav/MobileNav.test.tsx +108 -0
  35. package/src/organisms/MobileNav/MobileNav.tsx +120 -0
  36. package/src/organisms/MobileNav/index.ts +6 -0
  37. package/src/organisms/PageToolbar/PageToolbar.a11y.test.tsx +35 -0
  38. package/src/organisms/PageToolbar/PageToolbar.test.tsx +42 -0
  39. package/src/organisms/PageToolbar/PageToolbar.tsx +126 -0
  40. package/src/organisms/PageToolbar/index.ts +1 -0
  41. package/src/organisms/Section/Section.test.tsx +41 -0
  42. package/src/organisms/Section/Section.tsx +108 -0
  43. package/src/organisms/Section/index.ts +1 -0
  44. package/src/organisms/SelectionBar/SelectionBar.test.tsx +35 -0
  45. package/src/organisms/SelectionBar/SelectionBar.tsx +84 -0
  46. package/src/organisms/SelectionBar/index.ts +5 -0
  47. package/src/organisms/SettingsDialog/SettingsDialog.a11y.test.tsx +58 -0
  48. package/src/organisms/SettingsDialog/SettingsDialog.browser.test.tsx +43 -0
  49. package/src/organisms/SettingsDialog/SettingsDialog.ssr.test.tsx +27 -0
  50. package/src/organisms/SettingsDialog/SettingsDialog.test.tsx +202 -0
  51. package/src/organisms/SettingsDialog/SettingsDialog.tsx +548 -0
  52. package/src/organisms/SettingsDialog/index.ts +20 -0
  53. package/src/organisms/Sidebar/Sidebar.browser.test.tsx +52 -0
  54. package/src/organisms/Sidebar/Sidebar.test.tsx +308 -0
  55. package/src/organisms/Sidebar/Sidebar.tsx +732 -0
  56. package/src/organisms/Sidebar/index.ts +22 -0
  57. package/src/organisms/StatGrid/StatGrid.a11y.test.tsx +40 -0
  58. package/src/organisms/StatGrid/StatGrid.test.tsx +95 -0
  59. package/src/organisms/StatGrid/StatGrid.tsx +151 -0
  60. package/src/organisms/StatGrid/index.ts +1 -0
  61. package/src/organisms/VirtualList/VirtualList.test.tsx +80 -0
  62. package/src/organisms/VirtualList/VirtualList.tsx +113 -0
  63. package/src/organisms/VirtualList/index.ts +1 -0
  64. package/src/organisms/index.ts +16 -0
@@ -0,0 +1,161 @@
1
+ import { render, screen, waitFor, within } from '@solidjs/testing-library'
2
+ import userEvent from '@testing-library/user-event'
3
+ import { describe, expect, it, vi } from 'vitest'
4
+ import { DataTable, type DataTableColumn } from './DataTable'
5
+
6
+ interface Row {
7
+ id: string
8
+ name: string
9
+ amount: number
10
+ }
11
+
12
+ const ROWS: Row[] = [
13
+ { id: '1', name: 'Alpha', amount: 10 },
14
+ { id: '2', name: 'Beta', amount: 20 },
15
+ { id: '3', name: 'Gamma', amount: 30 },
16
+ ]
17
+
18
+ const COLUMNS: DataTableColumn<Row>[] = [
19
+ { accessorKey: 'name', header: 'Name' },
20
+ {
21
+ accessorKey: 'amount',
22
+ header: 'Amount',
23
+ cell: (context) => `$${context.getValue()}`,
24
+ meta: { align: 'end' },
25
+ },
26
+ ]
27
+
28
+ const MOBILE_COLUMNS: DataTableColumn<Row>[] = [
29
+ { accessorKey: 'name', header: 'Name', meta: { mobile: 'title' } },
30
+ {
31
+ accessorKey: 'amount',
32
+ header: 'Amount',
33
+ cell: (context) => `$${context.getValue()}`,
34
+ meta: { align: 'end', mobile: 'amount' },
35
+ },
36
+ ]
37
+
38
+ function table(props: Partial<Parameters<typeof DataTable<Row>>[0]> = {}) {
39
+ return render(() => (
40
+ <DataTable
41
+ title="Rows"
42
+ rows={ROWS}
43
+ columns={COLUMNS}
44
+ pageSize={10}
45
+ {...props}
46
+ />
47
+ ))
48
+ }
49
+
50
+ describe('DataTable', () => {
51
+ it('renders headers, cells and a labelled region', () => {
52
+ table()
53
+ expect(screen.getByRole('region', { name: 'Rows' })).toBeTruthy()
54
+ expect(screen.getByRole('columnheader', { name: 'Name' })).toBeTruthy()
55
+ expect(screen.getByText('Alpha')).toBeTruthy()
56
+ expect(screen.getByText('$30')).toBeTruthy()
57
+ // Header row + three records.
58
+ expect(screen.getAllByRole('row')).toHaveLength(4)
59
+ })
60
+
61
+ it('filters as you type and reports the count', async () => {
62
+ table()
63
+ await userEvent.type(
64
+ screen.getByRole('searchbox', { name: 'Search rows' }),
65
+ 'beta',
66
+ )
67
+ await waitFor(() => expect(screen.queryByText('Alpha')).toBeNull())
68
+ expect(screen.getByText('Beta')).toBeTruthy()
69
+ expect(screen.getByRole('status').textContent).toContain('1')
70
+ })
71
+
72
+ it('selects rows and hands the ids to the bulk action', async () => {
73
+ const onRowsAction = vi.fn()
74
+ table({ onRowsAction, actionLabel: 'Archive selected' })
75
+ await userEvent.click(screen.getByRole('checkbox', { name: 'Select 1' }))
76
+ const bulk = await screen.findByRole('button', {
77
+ name: /Archive selected \(1\)/,
78
+ })
79
+ await userEvent.click(bulk)
80
+ expect(onRowsAction).toHaveBeenCalledWith(['1'])
81
+ })
82
+
83
+ it('sorts from the header and marks the column', async () => {
84
+ table()
85
+ const header = screen.getByRole('button', { name: 'Amount' })
86
+ await userEvent.click(header)
87
+ await waitFor(() => {
88
+ const cell = screen.getByRole('columnheader', { name: 'Amount' })
89
+ expect(['ascending', 'descending']).toContain(
90
+ cell.getAttribute('aria-sort'),
91
+ )
92
+ })
93
+ })
94
+
95
+ it('renders mobile cards from column meta', () => {
96
+ table({ columns: MOBILE_COLUMNS })
97
+ const cards = document.querySelector('[data-slot="data-table-cards"]')
98
+ expect(cards).toBeTruthy()
99
+ expect(within(cards as HTMLElement).getByText('Alpha')).toBeTruthy()
100
+ expect(within(cards as HTMLElement).getByText('$30')).toBeTruthy()
101
+ })
102
+
103
+ it('skips ineligible rows in selection and select-all', async () => {
104
+ const onRowsAction = vi.fn()
105
+ table({
106
+ columns: MOBILE_COLUMNS,
107
+ rowSelectable: (row) => row.id !== '2',
108
+ onRowsAction,
109
+ })
110
+ const tableRegion = screen.getByRole('region', { name: 'Rows table' })
111
+ expect(
112
+ within(tableRegion)
113
+ .getAllByRole('checkbox', { name: 'Select 2' })
114
+ .every((box) => box.hasAttribute('disabled')),
115
+ ).toBe(true)
116
+ await userEvent.click(
117
+ within(tableRegion).getByRole('checkbox', {
118
+ name: 'Select all rows on this page',
119
+ }),
120
+ )
121
+ const bulk = await screen.findByRole('button', {
122
+ name: /Update selected \(2\)/,
123
+ })
124
+ await userEvent.click(bulk)
125
+ expect(onRowsAction).toHaveBeenCalledWith(['1', '3'])
126
+ })
127
+
128
+ it('keeps a stable titled toolbar when an external filter bar owns search', () => {
129
+ render(() => (
130
+ <DataTable title="Rows" rows={ROWS} columns={COLUMNS} hideSearch />
131
+ ))
132
+ const toolbar = document.querySelector('[data-slot="data-table-toolbar"]')
133
+ expect(toolbar?.textContent).toContain('Rows')
134
+ expect(
135
+ document.querySelector('[data-slot="data-table-columns"]'),
136
+ ).toBeTruthy()
137
+ })
138
+
139
+ it('renders the shared loading and error states', () => {
140
+ const loading = render(() => (
141
+ <DataTable title="Rows" rows={[]} columns={COLUMNS} loading />
142
+ ))
143
+ expect(screen.getByRole('status', { name: 'Loading' })).toBeTruthy()
144
+ loading.unmount()
145
+ render(() => (
146
+ <DataTable title="Rows" rows={[]} columns={COLUMNS} error="Failed" />
147
+ ))
148
+ expect(screen.getByRole('alert')).toBeTruthy()
149
+ })
150
+
151
+ it('shows the mobile selection bar once a row is selected', async () => {
152
+ table({ onRowsAction: () => {} })
153
+ await userEvent.click(screen.getByRole('checkbox', { name: 'Select 1' }))
154
+ expect(document.querySelector('[data-slot="selection-bar"]')).toBeTruthy()
155
+ })
156
+
157
+ it('can be a read-only table with no selection column', () => {
158
+ table({ selectable: false })
159
+ expect(screen.queryByRole('checkbox', { name: /Select/ })).toBeNull()
160
+ })
161
+ })