cursedbelt 5.25.0 → 5.26.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.
- package/dist/react/components/Badge.d.ts +6 -6
- package/dist/react/components/Badge.d.ts.map +1 -1
- package/dist/react/components/Badge.js +13 -5
- package/dist/react/components/Badge.js.map +1 -1
- package/dist/react/components/DataTable/DataTable.d.ts +125 -5
- package/dist/react/components/DataTable/DataTable.d.ts.map +1 -1
- package/dist/react/components/DataTable/DataTable.js +335 -121
- package/dist/react/components/DataTable/DataTable.js.map +1 -1
- package/dist/react/components/DataTable/RowActions.d.ts +3 -1
- package/dist/react/components/DataTable/RowActions.d.ts.map +1 -1
- package/dist/react/components/DataTable/RowActions.js +9 -2
- package/dist/react/components/DataTable/RowActions.js.map +1 -1
- package/dist/react/components/DataTable/SortHeader.d.ts +4 -1
- package/dist/react/components/DataTable/SortHeader.d.ts.map +1 -1
- package/dist/react/components/DataTable/SortHeader.js +7 -1
- package/dist/react/components/DataTable/SortHeader.js.map +1 -1
- package/dist/react/components/DataTable/cells/CellRenderer.d.ts.map +1 -1
- package/dist/react/components/DataTable/cells/CellRenderer.js +4 -1
- package/dist/react/components/DataTable/cells/CellRenderer.js.map +1 -1
- package/dist/react/components/DataTable/index.d.ts +2 -2
- package/dist/react/components/DataTable/index.d.ts.map +1 -1
- package/dist/react/components/DataTable/index.js +1 -1
- package/dist/react/components/DataTable/index.js.map +1 -1
- package/dist/react/components/DataTable/lazyPart.d.ts +27 -0
- package/dist/react/components/DataTable/lazyPart.d.ts.map +1 -0
- package/dist/react/components/DataTable/lazyPart.js +46 -0
- package/dist/react/components/DataTable/lazyPart.js.map +1 -0
- package/dist/react/components/DataTable/types.d.ts +106 -0
- package/dist/react/components/DataTable/types.d.ts.map +1 -1
- package/dist/react/components/DataTable/types.js.map +1 -1
- package/dist/react/components/auth/SignInCard.d.ts +49 -0
- package/dist/react/components/auth/SignInCard.d.ts.map +1 -0
- package/dist/react/components/auth/SignInCard.js +21 -0
- package/dist/react/components/auth/SignInCard.js.map +1 -0
- package/dist/react/components/auth/index.d.ts +1 -0
- package/dist/react/components/auth/index.d.ts.map +1 -1
- package/dist/react/components/auth/index.js +1 -0
- package/dist/react/components/auth/index.js.map +1 -1
- package/dist/react/index.d.ts +1 -1
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +1 -1
- package/dist/react/index.js.map +1 -1
- package/dist/styles-areas/analytics.css +9 -6
- package/dist/styles-areas/core.css +8 -7
- package/dist/styles-areas/data-table.css +8 -5
- package/dist/styles-utilities.css +75 -0
- package/package.json +2 -2
- package/src/react/components/Badge.capsule.spec.ts +178 -0
- package/src/react/components/Badge.tsx +13 -5
- package/src/react/components/DataTable/DataTable.spec.tsx +6 -2
- package/src/react/components/DataTable/DataTable.tsx +518 -104
- package/src/react/components/DataTable/RowActions.tsx +18 -10
- package/src/react/components/DataTable/SortHeader.tsx +19 -0
- package/src/react/components/DataTable/cells/CellRenderer.tsx +2 -0
- package/src/react/components/DataTable/index.ts +10 -1
- package/src/react/components/DataTable/lazyPart.spec.tsx +99 -0
- package/src/react/components/DataTable/lazyPart.tsx +58 -0
- package/src/react/components/DataTable/rowHooks.spec.tsx +289 -0
- package/src/react/components/DataTable/selection.spec.tsx +6 -2
- package/src/react/components/DataTable/tableSystem.spec.tsx +6 -2
- package/src/react/components/DataTable/types.ts +110 -0
- package/src/react/components/DataTable/virtualize.spec.tsx +38 -2
- package/src/react/components/auth/SignInCard.spec.tsx +48 -0
- package/src/react/components/auth/SignInCard.tsx +90 -0
- package/src/react/components/auth/index.ts +1 -0
- package/src/react/index.ts +5 -0
- package/src/styles-areas/analytics.css +9 -6
- package/src/styles-areas/core.css +8 -7
- package/src/styles-areas/data-table.css +8 -5
- package/src/styles-utilities.css +75 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { HTMLAttributes, ReactNode } from 'react';
|
|
1
2
|
import type { FieldOption } from '../FieldInput.js';
|
|
2
3
|
|
|
3
4
|
// Re-exported so the DataTable subtree (cells, card view) is self-contained — a column's
|
|
@@ -58,6 +59,70 @@ export interface ColDef<TRow = Record<string, unknown>> {
|
|
|
58
59
|
/** Display-only formatter for table/card cells — may differ from the edit input.
|
|
59
60
|
* The base `text` renderer uses it; custom renderers may read it too. */
|
|
60
61
|
displayValue?: (value: unknown, row: TRow) => string;
|
|
62
|
+
/**
|
|
63
|
+
* Draw this column's cell yourself — `(row) => <StarRating … />`. Wins over `type` in every
|
|
64
|
+
* view the table has (grid, tablet list, phone card, card view), because it is read in the one
|
|
65
|
+
* seam they all pass through (`CellRenderer`).
|
|
66
|
+
*
|
|
67
|
+
* 🔴 Why (forge task 2302): the only other route to app JSX in a cell was
|
|
68
|
+
* `registerCellRenderer(type, …)`, a GLOBAL registry keyed by a string — one entry per
|
|
69
|
+
* column per app, a name to collide on, and a renderer that cannot close over the component
|
|
70
|
+
* state it needs (apps/music's star rating writes back through the list's `onRate`). A
|
|
71
|
+
* render function is the shape of that need. `type` still decides the edit field and, unless
|
|
72
|
+
* `align` or `meta.numeric` says otherwise, the alignment.
|
|
73
|
+
*/
|
|
74
|
+
render?: (row: TRow) => ReactNode;
|
|
75
|
+
/**
|
|
76
|
+
* Hide this column when the TABLE (its container, not the viewport) is narrower than:
|
|
77
|
+
* `'sm'` 42rem · `'md'` 56rem · `'lg'` 72rem. The header cell and the body cells go
|
|
78
|
+
* together, so a label never sits over another column's values. The column collapses to zero
|
|
79
|
+
* width rather than leaving the table, so rows that span it stay true (see `HIDE_BELOW_CLASS`).
|
|
80
|
+
*
|
|
81
|
+
* 🔴 Why (forge task 2302): the table's own narrow answer is `mobileCards`, which re-renders
|
|
82
|
+
* every loaded row as a card or a compact list — right for a record table, wrong for a
|
|
83
|
+
* five-thousand-row track list whose narrow form is the SAME rows with fewer columns. With
|
|
84
|
+
* `mobileCards={false}` this is how the grid sheds its least important columns instead.
|
|
85
|
+
* Container-sized, like the tiers, so a table in a narrow pane on a wide screen sheds them too.
|
|
86
|
+
* Applies to the grid; the card tiers already choose their own fields.
|
|
87
|
+
*/
|
|
88
|
+
hideBelow?: 'sm' | 'md' | 'lg';
|
|
89
|
+
/**
|
|
90
|
+
* A header click on this column starts DESCENDING — for columns where "most" is the
|
|
91
|
+
* interesting end (plays, rating, date added, length). Sorting a play count ascending first
|
|
92
|
+
* is right for nobody.
|
|
93
|
+
*/
|
|
94
|
+
sortDescFirst?: boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Draw this column BEFORE the row-selection checkbox — a drag handle, which leads the row in
|
|
97
|
+
* every product that has both (Notion's ⋮⋮, Linear's grip). Leading columns keep their order
|
|
98
|
+
* among themselves, and are never the frozen column under `stickyFirstColumn`. Grid only.
|
|
99
|
+
*
|
|
100
|
+
* 🔴 Why (forge task 2302): apps/music's grab handle is the row's first cell by the owner's
|
|
101
|
+
* own draft (2026-09-18) — the thing that says "pick this up" sits at the edge the hand comes
|
|
102
|
+
* from, with the checkbox beside it. The selection column was always first, so a list that had
|
|
103
|
+
* both could not keep that order.
|
|
104
|
+
*/
|
|
105
|
+
leading?: boolean;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Attributes and handlers for ONE body row — `DataTable`'s `getRowProps`. `data-*` included,
|
|
110
|
+
* which is what a browser test addresses a windowed row by.
|
|
111
|
+
*/
|
|
112
|
+
export type DataTableRowProps = Omit<HTMLAttributes<HTMLElement>, 'children' | 'dangerouslySetInnerHTML'> & {
|
|
113
|
+
[dataAttribute: `data-${string}`]: string | number | boolean | undefined;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* `DataTable`'s `selectAll` — the header box, owned by the caller. See the prop doc.
|
|
118
|
+
*/
|
|
119
|
+
export interface DataTableSelectAll {
|
|
120
|
+
checked: boolean | 'indeterminate';
|
|
121
|
+
/** The box's accessible name AND its tooltip — say what a press will do. */
|
|
122
|
+
label: string;
|
|
123
|
+
/** `true` from an unchecked or indeterminate box, `false` from a checked one. */
|
|
124
|
+
onChange: (next: boolean) => void;
|
|
125
|
+
disabled?: boolean;
|
|
61
126
|
}
|
|
62
127
|
|
|
63
128
|
/** The view modes a page can switch a dataset between (table rows vs. card grid). */
|
|
@@ -96,3 +161,48 @@ export function resolveColumnAlign<TRow>(col: ColDef<TRow>): 'left' | 'right' {
|
|
|
96
161
|
if (col.meta?.numeric === true) return 'right';
|
|
97
162
|
return NUMERIC_CELL_TYPES.has(col.type) ? 'right' : 'left';
|
|
98
163
|
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* `DataTable`'s `serverWindow` — the loaded rows are `[start, start + data.length)` of a
|
|
167
|
+
* result set of `total` rows the server holds. See the prop's doc for why each part is there.
|
|
168
|
+
*/
|
|
169
|
+
export interface DataTableServerWindow {
|
|
170
|
+
/** The row number of `data[0]` within the whole result set. */
|
|
171
|
+
start: number;
|
|
172
|
+
/** How many rows the query matches — what the spacer and the scrollbar describe. */
|
|
173
|
+
total: number;
|
|
174
|
+
/** The viewport is within `reachRows` of the END of the loaded window, and there is more. */
|
|
175
|
+
onReachEnd?: () => void;
|
|
176
|
+
/** The viewport is within `reachRowsUp` of the START of a window that does not begin at 0. */
|
|
177
|
+
onReachStart?: () => void;
|
|
178
|
+
/** The viewport came to REST wholly outside the window; the argument is its first row. */
|
|
179
|
+
onNeedWindow?: (firstVisibleRow: number) => void;
|
|
180
|
+
/** Default 20 — generous, because the page has to arrive before the reader does. */
|
|
181
|
+
reachRows?: number;
|
|
182
|
+
/** Default 8 — tighter, so a reveal landing near a window's top does not cascade upward. */
|
|
183
|
+
reachRowsUp?: number;
|
|
184
|
+
/** How long the scroll must be still before `onNeedWindow` fires. Default 120 ms. */
|
|
185
|
+
settleMs?: number;
|
|
186
|
+
/**
|
|
187
|
+
* Every row's height in px — FIXED, never measured (see the prop doc for why). Defaults to
|
|
188
|
+
* `virtualize.estimateRowHeight`, else the density's row (44, or 36 compact). Cells must fit
|
|
189
|
+
* it: truncate, do not wrap.
|
|
190
|
+
*/
|
|
191
|
+
rowHeight?: number;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/** `DataTable`'s imperative handle (`handleRef`). */
|
|
195
|
+
export interface DataTableHandle {
|
|
196
|
+
/** The box that scrolls — `null` until mounted, or when the table has no rows to show. */
|
|
197
|
+
readonly scrollElement: HTMLDivElement | null;
|
|
198
|
+
/**
|
|
199
|
+
* Scroll a row number over the WHOLE result set (a `serverWindow` row, loaded or not) into view.
|
|
200
|
+
* `align` defaults to `center`, `behavior` to `auto`. Returns the `scrollTop` it asked
|
|
201
|
+
* for — what a caller telling its own scrolls from the reader's compares against — or
|
|
202
|
+
* `null` when the table is not virtualized or not mounted.
|
|
203
|
+
*/
|
|
204
|
+
scrollToIndex(
|
|
205
|
+
index: number,
|
|
206
|
+
options?: { align?: 'start' | 'center' | 'end' | 'auto'; behavior?: 'auto' | 'smooth' },
|
|
207
|
+
): number | null;
|
|
208
|
+
}
|
|
@@ -10,11 +10,15 @@
|
|
|
10
10
|
* spacer rows that keep a `<table>`'s column grid intact, the absolute zebra index, the
|
|
11
11
|
* measurement hooks, and that leaving the prop off changes nothing at all.
|
|
12
12
|
*/
|
|
13
|
-
import { afterEach, describe, expect, test } from 'bun:test';
|
|
13
|
+
import { afterEach, beforeAll, describe, expect, test } from 'bun:test';
|
|
14
14
|
import { cleanup, render, screen } from '@testing-library/react';
|
|
15
|
-
import { DataTable } from './DataTable.js';
|
|
15
|
+
import { DataTable, preloadDataTableParts } from './DataTable.js';
|
|
16
16
|
import type { ColDef } from './types.js';
|
|
17
17
|
|
|
18
|
+
// The toolbar, pager and row menu are lazy (forge task 2309); loaded here, they draw on the
|
|
19
|
+
// first render, as these specs query them. `lazyPart.spec.tsx` covers the lazy path itself.
|
|
20
|
+
beforeAll(preloadDataTableParts);
|
|
21
|
+
|
|
18
22
|
afterEach(cleanup);
|
|
19
23
|
|
|
20
24
|
interface Row extends Record<string, unknown> {
|
|
@@ -108,3 +112,35 @@ describe('virtualize', () => {
|
|
|
108
112
|
expect(screen.getByText(/no results/i)).toBeTruthy();
|
|
109
113
|
});
|
|
110
114
|
});
|
|
115
|
+
|
|
116
|
+
describe('serverWindow (forge task 2300)', () => {
|
|
117
|
+
// The window arithmetic itself is `e2e/table-window.spec.ts`'s — happy-dom lays nothing out.
|
|
118
|
+
const windowed = (start: number, loaded: number, total: number) =>
|
|
119
|
+
render(
|
|
120
|
+
<DataTable<Row>
|
|
121
|
+
columns={COLUMNS}
|
|
122
|
+
data={Array.from({ length: loaded }, (_, i) => ({ id: `r${start + i}`, name: `Row ${start + i}` }))}
|
|
123
|
+
getRowId={(r) => r.id}
|
|
124
|
+
serverWindow={{ start, total, rowHeight: 50 }}
|
|
125
|
+
/>,
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
test('🔴 the spacer is sized from the SERVER total, not from the hundred rows loaded', () => {
|
|
129
|
+
windowed(0, 100, 5000);
|
|
130
|
+
const spacer = bodyRows().find((tr) => tr.getAttribute('aria-hidden') === 'true');
|
|
131
|
+
// 5,000 rows at 50px each = 250,000px; the loaded 100 would be 5,000.
|
|
132
|
+
expect(Number.parseFloat((spacer as HTMLElement).style.height)).toBeGreaterThan(240_000);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test('🔴 an empty window over a non-empty result set is NOT the empty state', () => {
|
|
136
|
+
// A scrollbar dragged past the loaded rows can briefly hold none of them; "No results"
|
|
137
|
+
// there would be a lie about a 5,000-row list.
|
|
138
|
+
windowed(4000, 0, 5000);
|
|
139
|
+
expect(screen.queryByText(/no results/i)).toBeNull();
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test('it turns pagination off, like virtualize', () => {
|
|
143
|
+
windowed(0, 100, 5000);
|
|
144
|
+
expect(screen.queryByRole('button', { name: /next page|previous page/i })).toBeNull();
|
|
145
|
+
});
|
|
146
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { afterEach, describe, expect, mock, test } from 'bun:test';
|
|
2
|
+
import { cleanup, fireEvent, render } from '@testing-library/react';
|
|
3
|
+
import { SignInCard } from './SignInCard.js';
|
|
4
|
+
|
|
5
|
+
afterEach(cleanup);
|
|
6
|
+
|
|
7
|
+
describe('SignInCard', () => {
|
|
8
|
+
test('names the app, says what it is, and the button signs in', () => {
|
|
9
|
+
const onSignIn = mock(() => {});
|
|
10
|
+
const { getByRole, getByText, queryByRole } = render(
|
|
11
|
+
<SignInCard title='Music' subtitle='Your library, wherever you are.' onSignIn={onSignIn} />,
|
|
12
|
+
);
|
|
13
|
+
expect(getByRole('heading', { name: 'Music' })).not.toBeNull();
|
|
14
|
+
expect(getByText('Your library, wherever you are.')).not.toBeNull();
|
|
15
|
+
// No refusal, no warning — the card is quiet until there is something to say.
|
|
16
|
+
expect(queryByRole('status')).toBeNull();
|
|
17
|
+
fireEvent.click(getByRole('button', { name: 'Sign in' }));
|
|
18
|
+
expect(onSignIn).toHaveBeenCalledTimes(1);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test('a refusal is a warning above the button, headed by default', () => {
|
|
22
|
+
const { getByRole, getByText } = render(
|
|
23
|
+
<SignInCard title='Family' onSignIn={() => {}} refusal='This account has no access here.' />,
|
|
24
|
+
);
|
|
25
|
+
const warning = getByRole('status');
|
|
26
|
+
expect(warning.textContent).toContain('That sign-in did not go through');
|
|
27
|
+
expect(getByText('This account has no access here.')).not.toBeNull();
|
|
28
|
+
// The warning comes BEFORE the button in reading order.
|
|
29
|
+
const button = getByRole('button', { name: 'Sign in' });
|
|
30
|
+
expect(warning.compareDocumentPosition(button) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('a disabled reason disables the button instead of hiding it', () => {
|
|
34
|
+
const onSignIn = mock(() => {});
|
|
35
|
+
const { getByRole } = render(
|
|
36
|
+
<SignInCard title='Music' onSignIn={onSignIn} disabledReason='Signing in needs a connection' />,
|
|
37
|
+
);
|
|
38
|
+
const button = getByRole('button', { name: 'Sign in' }) as HTMLButtonElement;
|
|
39
|
+
expect(button.disabled).toBe(true);
|
|
40
|
+
fireEvent.click(button);
|
|
41
|
+
expect(onSignIn).not.toHaveBeenCalled();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('renders on the aurora front door', () => {
|
|
45
|
+
const { container } = render(<SignInCard title='Vault' onSignIn={() => {}} />);
|
|
46
|
+
expect(container.querySelector('.cb-aurora')).not.toBeNull();
|
|
47
|
+
});
|
|
48
|
+
});
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import { Alert } from '../Alert.js';
|
|
3
|
+
import { Button } from '../Button.js';
|
|
4
|
+
import { AuthCard } from './AuthCard.js';
|
|
5
|
+
|
|
6
|
+
export interface SignInCardProps {
|
|
7
|
+
/** The app's name — the card's heading. */
|
|
8
|
+
title: ReactNode;
|
|
9
|
+
/** One line on what the app is, under the heading. */
|
|
10
|
+
subtitle?: ReactNode;
|
|
11
|
+
/** Brand mark above the heading. */
|
|
12
|
+
logo?: ReactNode;
|
|
13
|
+
/** What the button does — a single-sign-on app passes `() => startSsoSignIn()`. */
|
|
14
|
+
onSignIn: () => void;
|
|
15
|
+
/**
|
|
16
|
+
* Why the last attempt came back here (a refused grant, an app the account has no
|
|
17
|
+
* access to). Rendered as a warning above the button; nothing when absent. A
|
|
18
|
+
* cursedauth app passes `takeSsoError()` read once at mount.
|
|
19
|
+
*/
|
|
20
|
+
refusal?: ReactNode;
|
|
21
|
+
/** The warning's heading. Default "That sign-in did not go through". */
|
|
22
|
+
refusalTitle?: ReactNode;
|
|
23
|
+
/** The navigation has started — the button spins and cannot be pressed twice. */
|
|
24
|
+
busy?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Signing in cannot work right now — the button is disabled and this is its
|
|
27
|
+
* tooltip (a control that cannot work is visible with the reason, never hidden).
|
|
28
|
+
*/
|
|
29
|
+
disabledReason?: string;
|
|
30
|
+
/** Button label. Default "Sign in". */
|
|
31
|
+
label?: ReactNode;
|
|
32
|
+
/** Button tooltip. Default "Sign in with your account". */
|
|
33
|
+
tooltip?: string;
|
|
34
|
+
/** Anything the app must say between the warning and the button. */
|
|
35
|
+
children?: ReactNode;
|
|
36
|
+
/** A line under the card, outside it. */
|
|
37
|
+
footer?: ReactNode;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The fleet's signed-out front door: {@link AuthCard}'s aurora page chrome, an
|
|
42
|
+
* optional refusal {@link Alert}, and one full-width primary button.
|
|
43
|
+
*
|
|
44
|
+
* Seven apps drew this card by hand — the same aurora, the same glass box, the same
|
|
45
|
+
* button — each with its own radius, padding, blur and its own idea of how a refused
|
|
46
|
+
* sign-in looks (a bare red line in two, a warning box in one, nothing in the rest).
|
|
47
|
+
* The owner, 2026-09-28: *"General components like containers and cards should not
|
|
48
|
+
* be hand made and should all be using standardized versions in cb."*
|
|
49
|
+
*
|
|
50
|
+
* It knows nothing about HOW signing in works — `onSignIn` and `refusal` are the
|
|
51
|
+
* app's — so it has no dependency on cursedauth and a password app can use it too.
|
|
52
|
+
*/
|
|
53
|
+
export function SignInCard({
|
|
54
|
+
title,
|
|
55
|
+
subtitle,
|
|
56
|
+
logo,
|
|
57
|
+
onSignIn,
|
|
58
|
+
refusal,
|
|
59
|
+
refusalTitle = 'That sign-in did not go through',
|
|
60
|
+
busy = false,
|
|
61
|
+
disabledReason,
|
|
62
|
+
label = 'Sign in',
|
|
63
|
+
tooltip = 'Sign in with your account',
|
|
64
|
+
children,
|
|
65
|
+
footer,
|
|
66
|
+
}: SignInCardProps) {
|
|
67
|
+
return (
|
|
68
|
+
<AuthCard aurora title={title} subtitle={subtitle} logo={logo} footer={footer}>
|
|
69
|
+
<div className='flex flex-col gap-4'>
|
|
70
|
+
{refusal ? (
|
|
71
|
+
<Alert tone='warning' title={refusalTitle}>
|
|
72
|
+
{refusal}
|
|
73
|
+
</Alert>
|
|
74
|
+
) : null}
|
|
75
|
+
{children}
|
|
76
|
+
<Button
|
|
77
|
+
className='w-full'
|
|
78
|
+
variant='primary'
|
|
79
|
+
loading={busy}
|
|
80
|
+
disabled={disabledReason !== undefined}
|
|
81
|
+
tooltip={disabledReason ?? tooltip}
|
|
82
|
+
tooltipMobile={disabledReason ? 'icon' : 'off'}
|
|
83
|
+
onClick={onSignIn}
|
|
84
|
+
>
|
|
85
|
+
{label}
|
|
86
|
+
</Button>
|
|
87
|
+
</div>
|
|
88
|
+
</AuthCard>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
@@ -31,6 +31,7 @@ export {
|
|
|
31
31
|
type SetInitialPasswordProps,
|
|
32
32
|
type SetInitialPasswordValues,
|
|
33
33
|
} from './SetInitialPassword.js';
|
|
34
|
+
export { SignInCard, type SignInCardProps } from './SignInCard.js';
|
|
34
35
|
export { SignupForm, type SignupFormProps, type SignupValues } from './SignupForm.js';
|
|
35
36
|
export { TotpEntry, type TotpEntryProps, type TotpValues } from './TotpEntry.js';
|
|
36
37
|
export type { AuthError, AuthErrorMapper, AuthNavProps, AuthSubmitHandler } from './types.js';
|
package/src/react/index.ts
CHANGED
|
@@ -254,6 +254,7 @@ export {
|
|
|
254
254
|
isEmptyFilterQuery,
|
|
255
255
|
isRowDrag,
|
|
256
256
|
nextSortStack,
|
|
257
|
+
preloadDataTableParts,
|
|
257
258
|
readRowDrag,
|
|
258
259
|
type RowDragPayload,
|
|
259
260
|
rowDragTypes,
|
|
@@ -287,6 +288,10 @@ export {
|
|
|
287
288
|
type TableToolbarProps,
|
|
288
289
|
type TableViewMode,
|
|
289
290
|
TableViewToggle,
|
|
291
|
+
type DataTableHandle,
|
|
292
|
+
type DataTableRowProps,
|
|
293
|
+
type DataTableSelectAll,
|
|
294
|
+
type DataTableServerWindow,
|
|
290
295
|
type TableViewToggleProps,
|
|
291
296
|
ViewOptionsMenu,
|
|
292
297
|
type ViewOptionsMenuProps,
|
|
@@ -18,17 +18,20 @@
|
|
|
18
18
|
* after an app's responsive variant (task 2124). An app that imports every area gets exactly
|
|
19
19
|
* what `cursedbelt/styles-utilities.css` emits — proved rule by rule in
|
|
20
20
|
* src/stylesAreas.spec.ts, which is also what fails when this file is stale.
|
|
21
|
-
*
|
|
21
|
+
* 148 candidate(s).
|
|
22
22
|
*
|
|
23
23
|
* Written by scripts/generateAreaStyles.ts (`bun run styles:areas`), which
|
|
24
24
|
* `bun run build` runs. The map of what is in which area, and why the areas are
|
|
25
25
|
* import closures rather than a hand-written list, is scripts/styleAreas.ts.
|
|
26
26
|
*/
|
|
27
|
-
@source inline("-m-1 -mt-2 -mt-6 -mx-1 -my-2.5 -my-3 @3xl:block @3xl:hidden @
|
|
28
|
-
@source inline("
|
|
29
|
-
@source inline("
|
|
30
|
-
@source inline("border-0
|
|
31
|
-
@source inline("
|
|
27
|
+
@source inline("-m-1 -mt-2 -mt-6 -mx-1 -my-2.5 -my-3 @3xl:block @3xl:hidden @max-2xl:[&>*]:hidden");
|
|
28
|
+
@source inline("@max-2xl:border-0 @max-2xl:min-w-0! @max-2xl:p-0! @max-2xl:w-0! @max-4xl:[&>*]:hidden");
|
|
29
|
+
@source inline("@max-4xl:border-0 @max-4xl:min-w-0! @max-4xl:p-0! @max-4xl:w-0! @max-6xl:[&>*]:hidden");
|
|
30
|
+
@source inline("@max-6xl:border-0 @max-6xl:min-w-0! @max-6xl:p-0! @max-6xl:w-0! @xl:block @xl:hidden");
|
|
31
|
+
@source inline("[&>*]:hidden [&_svg]:size-3 [overflow-wrap:anywhere] active:cursor-grabbing appearance");
|
|
32
|
+
@source inline("appearance-none bg-[var(--cb-frozen-bg)] bg-card/95 bg-gradient-to-t bg-muted/30 bg-muted/40");
|
|
33
|
+
@source inline("bg-muted/50 border-0 border-accent-solid border-accent/60 border-field-error border-l border-r");
|
|
34
|
+
@source inline("cursor-grab cursor-not-allowed data-[ending-style]:opacity-0 data-[ending-style]:scale-95");
|
|
32
35
|
@source inline("data-[highlighted]:bg-accent/10 data-[highlighted]:text-accent-strong");
|
|
33
36
|
@source inline("data-[starting-style]:opacity-0 data-[starting-style]:scale-95");
|
|
34
37
|
@source inline("data-[state=closed]:slide-out-to-bottom data-[state=closed]:slide-out-to-left");
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* after an app's responsive variant (task 2124). An app that imports every area gets exactly
|
|
16
16
|
* what `cursedbelt/styles-utilities.css` emits — proved rule by rule in
|
|
17
17
|
* src/stylesAreas.spec.ts, which is also what fails when this file is stale.
|
|
18
|
-
*
|
|
18
|
+
* 715 candidate(s).
|
|
19
19
|
*
|
|
20
20
|
* Written by scripts/generateAreaStyles.ts (`bun run styles:areas`), which
|
|
21
21
|
* `bun run build` runs. The map of what is in which area, and why the areas are
|
|
@@ -51,12 +51,13 @@
|
|
|
51
51
|
@source inline("border-b-2 border-b-[7px] border-b-current border-border border-border-strong border-border/60");
|
|
52
52
|
@source inline("border-collapse border-current border-destructive/30 border-destructive/40 border-destructive/50");
|
|
53
53
|
@source inline("border-field-border border-success/30 border-success/40 border-success/50 border-t");
|
|
54
|
-
@source inline("border-
|
|
55
|
-
@source inline("border-x-transparent bot bottom bottom-0 break
|
|
56
|
-
@source inline("contain container content contents cursor
|
|
57
|
-
@source inline("cursor-pointer cursor-row-resize d dark
|
|
58
|
-
@source inline("dark:bg-gray-800 data data-[disabled]:hover:bg-border
|
|
59
|
-
@source inline("data-[disabled]:
|
|
54
|
+
@source inline("border-tone-sky-fg/30 border-tone-slate-fg/30 border-transparent border-warning/30");
|
|
55
|
+
@source inline("border-warning/40 border-warning/50 border-x-4 border-x-transparent bot bottom bottom-0 break");
|
|
56
|
+
@source inline("break-all break-words c ca cap capitalize co com contain container content contents cursor");
|
|
57
|
+
@source inline("cursor-col-resize cursor-default cursor-ew-resize cursor-pointer cursor-row-resize d dark");
|
|
58
|
+
@source inline("dark:bg-card-overlay dark:bg-card-raised dark:bg-gray-800 data data-[disabled]:hover:bg-border");
|
|
59
|
+
@source inline("data-[disabled]:opacity-50 data-[disabled]:pointer-events-none");
|
|
60
|
+
@source inline("data-[interactive=true]:duration-[var(--duration-base)]");
|
|
60
61
|
@source inline("data-[interactive=true]:ease-[var(--ease-out)] data-[interactive=true]:hover:-translate-y-0.5");
|
|
61
62
|
@source inline("data-[interactive=true]:hover:border-border-strong data-[interactive=true]:hover:shadow-overlay");
|
|
62
63
|
@source inline("data-[interactive=true]:transition-all data-[placeholder]:text-muted-foreground");
|
|
@@ -18,16 +18,19 @@
|
|
|
18
18
|
* after an app's responsive variant (task 2124). An app that imports every area gets exactly
|
|
19
19
|
* what `cursedbelt/styles-utilities.css` emits — proved rule by rule in
|
|
20
20
|
* src/stylesAreas.spec.ts, which is also what fails when this file is stale.
|
|
21
|
-
*
|
|
21
|
+
* 144 candidate(s).
|
|
22
22
|
*
|
|
23
23
|
* Written by scripts/generateAreaStyles.ts (`bun run styles:areas`), which
|
|
24
24
|
* `bun run build` runs. The map of what is in which area, and why the areas are
|
|
25
25
|
* import closures rather than a hand-written list, is scripts/styleAreas.ts.
|
|
26
26
|
*/
|
|
27
|
-
@source inline("-m-1 -mt-2 -mt-6 -mx-1 -my-2.5 -my-3 @3xl:block @3xl:hidden @
|
|
28
|
-
@source inline("
|
|
29
|
-
@source inline("
|
|
30
|
-
@source inline("
|
|
27
|
+
@source inline("-m-1 -mt-2 -mt-6 -mx-1 -my-2.5 -my-3 @3xl:block @3xl:hidden @max-2xl:[&>*]:hidden");
|
|
28
|
+
@source inline("@max-2xl:border-0 @max-2xl:min-w-0! @max-2xl:p-0! @max-2xl:w-0! @max-4xl:[&>*]:hidden");
|
|
29
|
+
@source inline("@max-4xl:border-0 @max-4xl:min-w-0! @max-4xl:p-0! @max-4xl:w-0! @max-6xl:[&>*]:hidden");
|
|
30
|
+
@source inline("@max-6xl:border-0 @max-6xl:min-w-0! @max-6xl:p-0! @max-6xl:w-0! @xl:block @xl:hidden");
|
|
31
|
+
@source inline("[&>*]:hidden [&_svg]:size-3 [overflow-wrap:anywhere] active:cursor-grabbing appearance");
|
|
32
|
+
@source inline("appearance-none bg-[var(--cb-frozen-bg)] bg-card/95 bg-gradient-to-t bg-muted/30 bg-muted/50");
|
|
33
|
+
@source inline("border-0 border-accent-solid border-accent/60 border-field-error border-l border-r cursor-grab");
|
|
31
34
|
@source inline("cursor-not-allowed data-[ending-style]:opacity-0 data-[ending-style]:scale-95");
|
|
32
35
|
@source inline("data-[highlighted]:bg-accent/10 data-[highlighted]:text-accent-strong");
|
|
33
36
|
@source inline("data-[starting-style]:opacity-0 data-[starting-style]:scale-95");
|
package/src/styles-utilities.css
CHANGED
|
@@ -1708,6 +1708,18 @@
|
|
|
1708
1708
|
border-color: color-mix(in oklab, var(--success) 50%, transparent);
|
|
1709
1709
|
}
|
|
1710
1710
|
}
|
|
1711
|
+
.border-tone-sky-fg\/30 {
|
|
1712
|
+
border-color: var(--tone-sky-fg);
|
|
1713
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
1714
|
+
border-color: color-mix(in oklab, var(--tone-sky-fg) 30%, transparent);
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1717
|
+
.border-tone-slate-fg\/30 {
|
|
1718
|
+
border-color: var(--tone-slate-fg);
|
|
1719
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
1720
|
+
border-color: color-mix(in oklab, var(--tone-slate-fg) 30%, transparent);
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1711
1723
|
.border-transparent {
|
|
1712
1724
|
border-color: transparent;
|
|
1713
1725
|
}
|
|
@@ -4158,6 +4170,51 @@
|
|
|
4158
4170
|
padding-inline: calc(var(--spacing) * 8);
|
|
4159
4171
|
}
|
|
4160
4172
|
}
|
|
4173
|
+
@container (width < 72rem) {
|
|
4174
|
+
.\@max-6xl\:w-0\! {
|
|
4175
|
+
width: 0px !important;
|
|
4176
|
+
}
|
|
4177
|
+
.\@max-6xl\:min-w-0\! {
|
|
4178
|
+
min-width: 0px !important;
|
|
4179
|
+
}
|
|
4180
|
+
.\@max-6xl\:border-0 {
|
|
4181
|
+
border-style: var(--tw-border-style);
|
|
4182
|
+
border-width: 0px;
|
|
4183
|
+
}
|
|
4184
|
+
.\@max-6xl\:p-0\! {
|
|
4185
|
+
padding: 0px !important;
|
|
4186
|
+
}
|
|
4187
|
+
}
|
|
4188
|
+
@container (width < 56rem) {
|
|
4189
|
+
.\@max-4xl\:w-0\! {
|
|
4190
|
+
width: 0px !important;
|
|
4191
|
+
}
|
|
4192
|
+
.\@max-4xl\:min-w-0\! {
|
|
4193
|
+
min-width: 0px !important;
|
|
4194
|
+
}
|
|
4195
|
+
.\@max-4xl\:border-0 {
|
|
4196
|
+
border-style: var(--tw-border-style);
|
|
4197
|
+
border-width: 0px;
|
|
4198
|
+
}
|
|
4199
|
+
.\@max-4xl\:p-0\! {
|
|
4200
|
+
padding: 0px !important;
|
|
4201
|
+
}
|
|
4202
|
+
}
|
|
4203
|
+
@container (width < 42rem) {
|
|
4204
|
+
.\@max-2xl\:w-0\! {
|
|
4205
|
+
width: 0px !important;
|
|
4206
|
+
}
|
|
4207
|
+
.\@max-2xl\:min-w-0\! {
|
|
4208
|
+
min-width: 0px !important;
|
|
4209
|
+
}
|
|
4210
|
+
.\@max-2xl\:border-0 {
|
|
4211
|
+
border-style: var(--tw-border-style);
|
|
4212
|
+
border-width: 0px;
|
|
4213
|
+
}
|
|
4214
|
+
.\@max-2xl\:p-0\! {
|
|
4215
|
+
padding: 0px !important;
|
|
4216
|
+
}
|
|
4217
|
+
}
|
|
4161
4218
|
@container (width >= 32rem) {
|
|
4162
4219
|
.\@lg\:col-span-6 {
|
|
4163
4220
|
grid-column: span 6 / span 6;
|
|
@@ -4486,9 +4543,27 @@
|
|
|
4486
4543
|
.\[\&\:\:-webkit-scrollbar\]\:hidden::-webkit-scrollbar {
|
|
4487
4544
|
display: none;
|
|
4488
4545
|
}
|
|
4546
|
+
.\[\&\>\*\]\:hidden > * {
|
|
4547
|
+
display: none;
|
|
4548
|
+
}
|
|
4489
4549
|
.\[\&\>\*\]\:min-w-0 > * {
|
|
4490
4550
|
min-width: 0px;
|
|
4491
4551
|
}
|
|
4552
|
+
@container (width < 72rem) {
|
|
4553
|
+
.\@max-6xl\:\[\&\>\*\]\:hidden > * {
|
|
4554
|
+
display: none;
|
|
4555
|
+
}
|
|
4556
|
+
}
|
|
4557
|
+
@container (width < 56rem) {
|
|
4558
|
+
.\@max-4xl\:\[\&\>\*\]\:hidden > * {
|
|
4559
|
+
display: none;
|
|
4560
|
+
}
|
|
4561
|
+
}
|
|
4562
|
+
@container (width < 42rem) {
|
|
4563
|
+
.\@max-2xl\:\[\&\>\*\]\:hidden > * {
|
|
4564
|
+
display: none;
|
|
4565
|
+
}
|
|
4566
|
+
}
|
|
4492
4567
|
.\[\&\>\:first-child\]\:w-\[var\(--cb-sidebar-side\)\] > :first-child {
|
|
4493
4568
|
width: var(--cb-sidebar-side);
|
|
4494
4569
|
}
|