Tighten Soma public component surface

active-uix
dev 5 months ago
parent 1dd9d62eae
commit 96edd41545

@ -81,6 +81,16 @@ Actualizacion 2026-05-16:
`~sium`. `~sium`.
- Ninguna feature nueva entra si solo duplica Zod/Valibot sin consumidor - Ninguna feature nueva entra si solo duplica Zod/Valibot sin consumidor
propio de Active. propio de Active.
- Soma public surface:
- Cerrado: el wrapper publico de Select pasa de
`components/select-provider.svelte` a `components/select.svelte`. El
runtime interno sigue en `select-provider.svelte.ts`.
- Cerrado: `Command`, `Form` y `Table` ya no reexportan motores de `$libs`.
Los consumidores deben importar `computeFuzzyScore` desde `$libs/strings`,
`createForm` desde `$libs/forms` y `createTable`/tipos desde
`$libs/datagrid`.
- Guardia nueva en `src/uix/contracts.test.ts`: ningun barrel publico de Soma
puede exportar desde `*provider.svelte` ni desde `$libs/*`.
Actualizacion 2026-05-15: Actualizacion 2026-05-15:
@ -89,8 +99,8 @@ Actualizacion 2026-05-15:
- Las clases runtime internas `DialogProvider`, `DrawerProvider` y - Las clases runtime internas `DialogProvider`, `DrawerProvider` y
`PopoverProvider` dejan de exportarse desde los barrels publicos; los `PopoverProvider` dejan de exportarse desde los barrels publicos; los
wrappers siguen usandolas por import directo. wrappers siguen usandolas por import directo.
- `computeCommandScore` sigue reexportado desde Command por DX, pero el - `computeCommandScore` ya no se reexporta desde Command; el algoritmo vive
algoritmo vive como `computeFuzzyScore` en `src/libs/strings`. como `computeFuzzyScore` en `src/libs/strings`.
- `table-core` se mueve a `src/libs/datagrid` con su test. - `table-core` se mueve a `src/libs/datagrid` con su test.
- `form-core` se mueve a `src/libs/forms`, usa el Standard Schema comun de - `form-core` se mueve a `src/libs/forms`, usa el Standard Schema comun de
`src/libs/standard-schema.ts`, elimina la copia local de Soma y anade tests `src/libs/standard-schema.ts`, elimina la copia local de Soma y anade tests
@ -99,7 +109,7 @@ Actualizacion 2026-05-15:
existen en el arbol activo. existen en el arbol activo.
- `SelectType`/`ScrollAlignment` y el resto de tipos publicos de componentes - `SelectType`/`ScrollAlignment` y el resto de tipos publicos de componentes
salen de `types.ts`; los barrels ya no exportan contratos desde salen de `types.ts`; los barrels ya no exportan contratos desde
`*-provider.svelte.ts` (excepto el wrapper Svelte publico de Select). `*-provider.svelte.ts`.
- `Dismissal` y `SafePolygon` usan `uix.timers` cuando Soma lo tiene - `Dismissal` y `SafePolygon` usan `uix.timers` cuando Soma lo tiene
disponible, con fallback nativo solo para uso standalone fuera de UIX. disponible, con fallback nativo solo para uso standalone fuera de UIX.
- Cobertura nueva para Combobox: selección single/multiple, `inputValue` y - Cobertura nueva para Combobox: selección single/multiple, `inputValue` y
@ -291,8 +301,8 @@ Actualizacion 2026-05-15:
- `drag-drop-provider.svelte.test.ts` -> 2 tests OK. - `drag-drop-provider.svelte.test.ts` -> 2 tests OK.
- guardia `*-provider.svelte.ts` sin test directo -> `NO_MISSING_PROVIDER_TESTS`. - guardia `*-provider.svelte.ts` sin test directo -> `NO_MISSING_PROVIDER_TESTS`.
- guardia `rg "from './.*provider\\.svelte'" src/uix/soma/components -g 'exports.ts'` - guardia `rg "from './.*provider\\.svelte'" src/uix/soma/components -g 'exports.ts'`
-> solo queda `select/components/select-provider.svelte`, que es wrapper -> 0 resultados; Select ya no conserva el wrapper publico con nombre
publico, no runtime provider. `select-provider.svelte`.
- Commits nuevos empujados: - Commits nuevos empujados:
- `a3bcb66c` — `Refresh UIX audit follow-up docs` - `a3bcb66c` — `Refresh UIX audit follow-up docs`
- `25870b4e` — `Expand Soma component coverage` - `25870b4e` — `Expand Soma component coverage`

@ -315,6 +315,26 @@ describe('UIX layer contracts', () => {
expect(missingExports).toEqual([]); expect(missingExports).toEqual([]);
}); });
it('guards Soma public barrels from provider implementation filenames', () => {
const violations = collectPublicSomaComponentDirs()
.map((dir) => join(HERE, 'soma', 'components', dir, 'exports.ts'))
.filter((file) =>
/from ['"][^'"]*provider\.svelte(?:\.ts)?['"]/.test(readFileSync(file, 'utf8'))
)
.map((file) => file.replace(REPO_ROOT, ''));
expect(violations).toEqual([]);
});
it('guards Soma public barrels from shared lib facades', () => {
const violations = collectPublicSomaComponentDirs()
.map((dir) => join(HERE, 'soma', 'components', dir, 'exports.ts'))
.filter((file) => /from ['"]\$libs\//.test(readFileSync(file, 'utf8')))
.map((file) => file.replace(REPO_ROOT, ''));
expect(violations).toEqual([]);
});
it('guards Soma public component modules against Morfo soma scope', () => { it('guards Soma public component modules against Morfo soma scope', () => {
expect(collectPublicSomaComponentDirs()).toEqual(collectMorfoComponentNamesByScope('soma')); expect(collectPublicSomaComponentDirs()).toEqual(collectMorfoComponentNamesByScope('soma'));
}); });

@ -13,8 +13,6 @@ export { default as Empty } from './components/command-empty.svelte';
export { default as Loading } from './components/command-loading.svelte'; export { default as Loading } from './components/command-loading.svelte';
export { default as Separator } from './components/command-separator.svelte'; export { default as Separator } from './components/command-separator.svelte';
export { computeFuzzyScore as computeCommandScore } from '$libs/strings';
export type { export type {
CommandFilterFn, CommandFilterFn,
CommandApi, CommandApi,

@ -24,7 +24,7 @@ No single library covers all axes. `soma/Form` is the only one built on **Svelte
```svelte ```svelte
<script lang="ts"> <script lang="ts">
import { Form, Field } from '$soma/components'; import { Form, Field } from '$soma/components';
import { createForm } from '$soma/components/form'; import { createForm } from '$libs/forms';
import { z } from 'zod'; // Or valibot, arktype, anything Standard Schema import { z } from 'zod'; // Or valibot, arktype, anything Standard Schema
const schema = z.object({ const schema = z.object({
@ -269,6 +269,8 @@ By default `Form.Provider` renders a standard `<form>` and intercepts `onsubmit`
```svelte ```svelte
<script> <script>
import { enhance } from '$app/forms'; import { enhance } from '$app/forms';
import { createForm } from '$libs/forms';
const form = createForm({ defaults: {} }); const form = createForm({ defaults: {} });
</script> </script>
@ -330,7 +332,7 @@ The unique columns soma wins: **runes-native**, **UI primitives integrated**, **
```svelte ```svelte
<script lang="ts"> <script lang="ts">
import { Form, Field } from '$soma/components'; import { Form, Field } from '$soma/components';
import { createForm } from '$soma/components/form'; import { createForm } from '$libs/forms';
import { z } from 'zod'; import { z } from 'zod';
const schema = z.object({ const schema = z.object({

@ -1,8 +1,3 @@
// Core: runes-native form state + Standard Schema integration
export { createForm } from '$libs/forms';
export type { Form, FormErrors, FieldState, CreateFormOpts, SubmitFailureReason } from '$libs/forms';
export type { StandardSchemaV1 } from '$libs/standard-schema';
// UI primitives // UI primitives
export { default as Provider } from './components/form.svelte'; export { default as Provider } from './components/form.svelte';
export { default as Submit } from './components/form-submit.svelte'; export { default as Submit } from './components/form-submit.svelte';

@ -1,9 +1,6 @@
import type { Snippet } from 'svelte'; import type { Snippet } from 'svelte';
import type { WithChild, Without } from '../../types'; import type { WithChild, Without } from '../../types';
import type { import type { PrimitiveDivAttributes, PrimitiveButtonAttributes } from '../../types';
PrimitiveDivAttributes,
PrimitiveButtonAttributes
} from '../../types';
import type { Form, FormErrors, ValidationBehaviour } from '$libs/forms'; import type { Form, FormErrors, ValidationBehaviour } from '$libs/forms';
import type { StandardSchemaV1 } from '$libs/standard-schema'; import type { StandardSchemaV1 } from '$libs/standard-schema';
@ -33,51 +30,50 @@ export type FormErrorSummarySnippetProps = {
// ── Root ──────────────────────────────────────────────────────────────────── // ── Root ────────────────────────────────────────────────────────────────────
/** Props for the root `Form.Provider`. */ /** Props for the root `Form.Provider`. */
export type FormProviderProps<TForm extends Form = Form, TDefaults = Record<string, unknown>> = export type FormProviderProps<
WithChild< TForm extends Form = Form,
{ TDefaults = Record<string, unknown>
/** DOM id. Auto-generated when omitted. */ > = WithChild<
id?: string; {
/** /** DOM id. Auto-generated when omitted. */
* Optional bindable handle to the form instance. id?: string;
* When omitted, `Form.Provider` creates one internally. /**
*/ * Optional bindable handle to the form instance.
form?: TForm; * When omitted, `Form.Provider` creates one internally.
/** Optional Standard Schema override. Falls back to `SiumProvider` when present. */ */
schema?: StandardSchemaV1; form?: TForm;
/** /** Optional Standard Schema override. Falls back to `SiumProvider` when present. */
* Initial values used when `Form.Provider` creates the form internally. schema?: StandardSchemaV1;
* Existing call sites may omit it only when passing a prebuilt `form`. /**
*/ * Initial values used when `Form.Provider` creates the form internally.
defaults?: TDefaults; * Existing call sites may omit it only when passing a prebuilt `form`.
/** Called when validation passes. */ */
onValidSubmit?: (values: unknown, e: SubmitEvent) => void | Promise<void>; defaults?: TDefaults;
/** Called when validation fails. */ /** Called when validation passes. */
onInvalidSubmit?: (errors: FormErrors, e: SubmitEvent) => void; onValidSubmit?: (values: unknown, e: SubmitEvent) => void | Promise<void>;
/** Validation timing for internally created forms. @default 'progressive' */ /** Called when validation fails. */
validationBehaviour?: ValidationBehaviour; onInvalidSubmit?: (errors: FormErrors, e: SubmitEvent) => void;
/** /** Validation timing for internally created forms. @default 'progressive' */
* When the consumer wants the `<form>` to call a non-Form handler first validationBehaviour?: ValidationBehaviour;
* (e.g. SvelteKit `use:enhance` wires a custom handler on the /**
* underlying element), they can override this. The default forwards * When the consumer wants the `<form>` to call a non-Form handler first
* to `form.onsubmit`. * (e.g. SvelteKit `use:enhance` wires a custom handler on the
*/ * underlying element), they can override this. The default forwards
onsubmit?: (e: SubmitEvent) => void; * to `form.onsubmit`.
/** Corresponds to native `<form novalidate>`. @default true */
* (Defaults to `true` so the browser doesn't race soma's validation.) */ onsubmit?: (e: SubmitEvent) => void;
noValidate?: boolean; /** Corresponds to native `<form novalidate>`. @default true
/** * (Defaults to `true` so the browser doesn't race soma's validation.) */
* When `true`, after an invalid submit the first offending field noValidate?: boolean;
* receives focus. @default true /**
*/ * When `true`, after an invalid submit the first offending field
focusFirstError?: boolean; * receives focus. @default true
}, */
FormProviderSnippetProps focusFirstError?: boolean;
> & },
Without< FormProviderSnippetProps
Omit<import('svelte/elements').HTMLFormAttributes, 'onsubmit'>, > &
FormProviderSnippetProps Without<Omit<import('svelte/elements').HTMLFormAttributes, 'onsubmit'>, FormProviderSnippetProps>;
>;
// ── Submit ────────────────────────────────────────────────────────────────── // ── Submit ──────────────────────────────────────────────────────────────────
@ -121,15 +117,3 @@ export type FormErrorSummaryProps = WithChild<
FormErrorSummarySnippetProps FormErrorSummarySnippetProps
> & > &
Without<PrimitiveDivAttributes, {}>; Without<PrimitiveDivAttributes, {}>;
// ── Re-exports ─────────────────────────────────────────────────────────────
export type {
Form,
FormErrors,
FormIssue,
FormIssues,
FieldState,
CreateFormOpts,
ValidationBehaviour
} from '$libs/forms';

@ -1,8 +1,5 @@
<script lang="ts"> <script lang="ts">
import { import { readableActive, writableActive } from '$libs/reactive';
readableActive,
writableActive
} from '$libs/reactive';
import { createId } from '../../../id'; import { createId } from '../../../id';
import { SelectProvider } from '../select-provider.svelte'; import { SelectProvider } from '../select-provider.svelte';
import type { SelectProps } from '../types'; import type { SelectProps } from '../types';

@ -1,4 +1,4 @@
export { default as Provider } from './components/select-provider.svelte'; export { default as Provider } from './components/select.svelte';
export { default as Trigger } from './components/select-trigger.svelte'; export { default as Trigger } from './components/select-trigger.svelte';
export { default as Value } from './components/select-value.svelte'; export { default as Value } from './components/select-value.svelte';
export { default as Content } from './components/select-content.svelte'; export { default as Content } from './components/select-content.svelte';

@ -8,11 +8,11 @@ Table is for **flat tabular data**. Emits `role="table"` with grid-cell semantic
soma ships three WAI-ARIA patterns for tabular / list display. They are **not interchangeable** — pick by semantic intent: soma ships three WAI-ARIA patterns for tabular / list display. They are **not interchangeable** — pick by semantic intent:
| Component | ARIA role | Keyboard contract | Use when | | Component | ARIA role | Keyboard contract | Use when |
| -------------------------------------------- | ------------ | -------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | | ------------------------------------ | ---------- | ------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------- |
| **Table** (this) | `table` | Tab + click. No arrow-key row nav. | Flat tabular data. Sort/filter/paginate large lists. Row expansion is a **detail panel** (disclosure), not hierarchy. | | **Table** (this) | `table` | Tab + click. No arrow-key row nav. | Flat tabular data. Sort/filter/paginate large lists. Row expansion is a **detail panel** (disclosure), not hierarchy. |
| [`TreeGrid`](../tree-grid/README.md) | `treegrid` | Roving tabindex + ArrowUp/Down rows + ArrowRight/Left expand/collapse. | **Hierarchical** rows (parent + children of the same shape): file browsers, org charts, nested tasks. `aria-level` auto-derived. | | [`TreeGrid`](../tree-grid/README.md) | `treegrid` | Roving tabindex + ArrowUp/Down rows + ArrowRight/Left expand/collapse. | **Hierarchical** rows (parent + children of the same shape): file browsers, org charts, nested tasks. `aria-level` auto-derived. |
| [`GridList`](../grid-list/README.md) | `grid` | Roving tabindex + ArrowUp/Down rows + ArrowLeft/Right between focusable cells. | Flat **selectable** lists where rows contain multiple interactive elements (actions, links, per-row checkboxes). | | [`GridList`](../grid-list/README.md) | `grid` | Roving tabindex + ArrowUp/Down rows + ArrowLeft/Right between focusable cells. | Flat **selectable** lists where rows contain multiple interactive elements (actions, links, per-row checkboxes). |
**"Expandable rows" in Table = row detail panel**, not sub-rows. If you need true hierarchy → TreeGrid. Table emits `role="table"` and cannot honestly carry `aria-level` semantics. **"Expandable rows" in Table = row detail panel**, not sub-rows. If you need true hierarchy → TreeGrid. Table emits `role="table"` and cannot honestly carry `aria-level` semantics.
@ -21,7 +21,7 @@ soma ships three WAI-ARIA patterns for tabular / list display. They are **not in
```svelte ```svelte
<script> <script>
import { Table } from '$soma/components'; import { Table } from '$soma/components';
import { createTable, type ColumnDef } from '$soma/components/table'; import { createTable, type ColumnDef } from '$libs/datagrid';
const columns: ColumnDef<Person>[] = [ const columns: ColumnDef<Person>[] = [
{ accessorKey: 'name', header: 'Name', enableSorting: true, enableFiltering: true }, { accessorKey: 'name', header: 'Name', enableSorting: true, enableFiltering: true },
@ -70,17 +70,17 @@ soma ships three WAI-ARIA patterns for tabular / list display. They are **not in
## Parts ## Parts
| Part | Element | Description | | Part | Element | Description |
| -------------------- | ---------- | ---------------------------------------------------------------------------------- | | ------------------ | ---------- | -------------------------------------------------------------------------------------- |
| `Provider` | `<table>` | Root. Renders `<table>` with translated `aria-label`. | | `Provider` | `<table>` | Root. Renders `<table>` with translated `aria-label`. |
| `Header` | `<thead>` | Table header section. | | `Header` | `<thead>` | Table header section. |
| `Body` | `<tbody>` | Table body section. | | `Body` | `<tbody>` | Table body section. |
| `Footer` | `<tfoot>` | Table footer section. | | `Footer` | `<tfoot>` | Table footer section. |
| `ColumnHeader` | `<th>` | Column header. Emits `data-sortable`, `data-sorted`, `data-pinned`, sizing styles. | | `ColumnHeader` | `<th>` | Column header. Emits `data-sortable`, `data-sorted`, `data-pinned`, sizing styles. |
| `Row` | `<tr>` | Table row. Emits `data-selected`. | | `Row` | `<tr>` | Table row. Emits `data-selected`. |
| `Cell` | `<td>` | Table cell. Emits `data-pinned`, sizing styles, `aria-colindex`. | | `Cell` | `<td>` | Table cell. Emits `data-pinned`, sizing styles, `aria-colindex`. |
| `RowDetailTrigger` | `<button>` | Inside a Cell — toggles the row's detail panel. `aria-expanded` + `aria-controls`. | | `RowDetailTrigger` | `<button>` | Inside a Cell — toggles the row's detail panel. `aria-expanded` + `aria-controls`. |
| `RowDetail` | `<tr>` | Full-width disclosure panel rendered below the row when open. `<td colspan=N>` inside. | | `RowDetail` | `<tr>` | Full-width disclosure panel rendered below the row when open. `<td colspan=N>` inside. |
## State Manager (`createTable`) ## State Manager (`createTable`)
@ -176,34 +176,34 @@ interface ColumnDef<TData> {
| Provider (`<table>`) | `aria-label` | Translated label (default: 'Data table') | | Provider (`<table>`) | `aria-label` | Translated label (default: 'Data table') |
| ColumnHeader | `role` | `columnheader` | | ColumnHeader | `role` | `columnheader` |
| ColumnHeader | `aria-sort` | `ascending` \| `descending` \| `none` (only when sortable) | | ColumnHeader | `aria-sort` | `ascending` \| `descending` \| `none` (only when sortable) |
| Row | `role` | `row` | | Row | `role` | `row` |
| Row | `aria-rowindex` | 1-based row index | | Row | `aria-rowindex` | 1-based row index |
| Row | `aria-selected` | `true` \| `false` (when selection enabled) | | Row | `aria-selected` | `true` \| `false` (when selection enabled) |
| Cell | `role` | `gridcell` | | Cell | `role` | `gridcell` |
| Cell | `aria-colindex` | 1-based column index | | Cell | `aria-colindex` | 1-based column index |
| RowDetailTrigger | `aria-expanded` | `true` \| `false` — open state of the detail panel | | RowDetailTrigger | `aria-expanded` | `true` \| `false` — open state of the detail panel |
| RowDetailTrigger | `aria-controls` | id of the sibling `Table.RowDetail` | | RowDetailTrigger | `aria-controls` | id of the sibling `Table.RowDetail` |
| RowDetailTrigger | `aria-label` | Translated `Show details` / `Hide details` swap | | RowDetailTrigger | `aria-label` | Translated `Show details` / `Hide details` swap |
## Data Attributes ## Data Attributes
| Part | Attribute | Values | | Part | Attribute | Values |
| ------------ | -------------------------- | -------------------------------------------------------- | | ---------------- | ------------------------------- | ---------------------------------------------- |
| ColumnHeader | `data-table-column-header` | Always present | | ColumnHeader | `data-table-column-header` | Always present |
| ColumnHeader | `data-sortable` | Present when `enableSorting: true` | | ColumnHeader | `data-sortable` | Present when `enableSorting: true` |
| ColumnHeader | `data-sorted` | `asc` \| `desc` (when actively sorted) | | ColumnHeader | `data-sorted` | `asc` \| `desc` (when actively sorted) |
| ColumnHeader | `data-pinned` | `left` \| `right` (when pinned) | | ColumnHeader | `data-pinned` | `left` \| `right` (when pinned) |
| Row | `data-table-row` | Always present | | Row | `data-table-row` | Always present |
| Row | `data-selected` | Present when selected | | Row | `data-selected` | Present when selected |
| Cell | `data-table-cell` | Always present | | Cell | `data-table-cell` | Always present |
| Cell | `data-pinned` | `left` \| `right` (when column is pinned) | | Cell | `data-pinned` | `left` \| `right` (when column is pinned) |
| Header | `data-table-header` | Always present | | Header | `data-table-header` | Always present |
| Body | `data-table-body` | Always present | | Body | `data-table-body` | Always present |
| Footer | `data-table-footer` | Always present | | Footer | `data-table-footer` | Always present |
| RowDetailTrigger | `data-table-row-detail-trigger` | Always present | | RowDetailTrigger | `data-table-row-detail-trigger` | Always present |
| RowDetailTrigger | `data-state` | `open \| closed` | | RowDetailTrigger | `data-state` | `open \| closed` |
| RowDetail | `data-table-row-detail` | Always present | | RowDetail | `data-table-row-detail` | Always present |
| RowDetail | `data-state` | `open \| closed` (hidden from DOM when closed) | | RowDetail | `data-state` | `open \| closed` (hidden from DOM when closed) |
## Sorting ## Sorting
@ -370,9 +370,9 @@ Both parts take `{row}` explicitly. `Table.RowDetail` is a **sibling `<tr>`** of
table.toggleRowDetail(rowId); table.toggleRowDetail(rowId);
table.setRowDetailOpen({ '1': true, '3': true }); table.setRowDetailOpen({ '1': true, '3': true });
table.getIsRowDetailOpen(rowId); table.getIsRowDetailOpen(rowId);
table.getCanShowRowDetail(rowId); // honors getRowCanShowDetail config table.getCanShowRowDetail(rowId); // honors getRowCanShowDetail config
table.closeAllRowDetails(); table.closeAllRowDetails();
table.rowDetailOpen; // current state (read-only) table.rowDetailOpen; // current state (read-only)
``` ```
### Opting rows out ### Opting rows out
@ -389,27 +389,27 @@ const table = createTable({
## Comparison with reference libraries ## Comparison with reference libraries
| Feature | TanStack Table | React Aria | Soma Table | | Feature | TanStack Table | React Aria | Soma Table |
| --------------------------- | -------------------- | ---------- | --------------------------- | | ---------------------------- | -------------------- | ---------- | -------------------------------- |
| Framework | Agnostic | React only | Svelte (soma) | | Framework | Agnostic | React only | Svelte (soma) |
| Sorting (single) | Yes | Yes | Yes | | Sorting (single) | Yes | Yes | Yes |
| Sorting (multi) | Yes | No | Yes (Shift+click) | | Sorting (multi) | Yes | No | Yes (Shift+click) |
| Custom sort fn | Yes | No | Yes | | Custom sort fn | Yes | No | Yes |
| Server-side sort | Yes | Manual | Yes (manual mode) | | Server-side sort | Yes | Manual | Yes (manual mode) |
| Selection none/single/multi | Yes | Yes | Yes | | Selection none/single/multi | Yes | Yes | Yes |
| Select all / checkbox | Yes | Yes | Yes | | Select all / checkbox | Yes | Yes | Yes |
| Pagination (client) | Yes | No | Yes | | Pagination (client) | Yes | No | Yes |
| Pagination (server) | Yes | No | Yes (manual mode) | | Pagination (server) | Yes | No | Yes (manual mode) |
| ARIA table pattern | No (manual) | Yes (auto) | Yes (auto) | | ARIA table pattern | No (manual) | Yes (auto) | Yes (auto) |
| Keyboard select | No (manual) | Yes | Yes (Enter/Space on row) | | Keyboard select | No (manual) | Yes | Yes (Enter/Space on row) |
| `aria-sort` on headers | No (manual) | Yes | Yes | | `aria-sort` on headers | No (manual) | Yes | Yes |
| `data-*` attributes | No | No | Yes | | `data-*` attributes | No | No | Yes |
| Svelte components | Via adapter | No | Native | | Svelte components | Via adapter | No | Native |
| Column filtering | Yes | No | Yes (column + global) | | Column filtering | Yes | No | Yes (column + global) |
| Column visibility | Yes | No | Yes | | Column visibility | Yes | No | Yes |
| Column resizing | Yes | Partial | Yes (programmatic, no drag) | | Column resizing | Yes | Partial | Yes (programmatic, no drag) |
| Column pinning | Yes | No | Yes (left/right, sticky) | | Column pinning | Yes | No | Yes (left/right, sticky) |
| Row expansion (hierarchy) | Yes | No | **Use TreeGrid instead** | | Row expansion (hierarchy) | Yes | No | **Use TreeGrid instead** |
| Row expansion (detail panel)| Yes | No | Yes (`RowDetail`) | | Row expansion (detail panel) | Yes | No | Yes (`RowDetail`) |
| Grouping / aggregation | Yes | No | No | | Grouping / aggregation | Yes | No | No |
| Virtual scrolling | Via TanStack Virtual | No | Via composition with VirtualList | | Virtual scrolling | Via TanStack Virtual | No | Via composition with VirtualList |

@ -8,30 +8,6 @@ export { default as Cell } from './components/table-cell.svelte';
export { default as RowDetail } from './components/table-row-detail.svelte'; export { default as RowDetail } from './components/table-row-detail.svelte';
export { default as RowDetailTrigger } from './components/table-row-detail-trigger.svelte'; export { default as RowDetailTrigger } from './components/table-row-detail-trigger.svelte';
export { createTable, filterFns } from '$libs/datagrid';
export type { BuiltInFilterFn } from '$libs/datagrid';
export type {
ColumnDef,
SortingEntry,
SortingState,
PaginationState,
SelectionMode,
RowSelectionState,
ColumnVisibilityState,
ColumnPinningState,
ColumnPinningPosition,
ColumnSizingState,
RowDetailState,
ColumnFilterEntry,
ColumnFiltersState,
TableConfig,
TableInstance,
TableHeader,
TableRow,
TableCell
} from '$libs/datagrid';
export type { export type {
TableProviderProps as ProviderProps, TableProviderProps as ProviderProps,
TableHeaderProps as HeaderProps, TableHeaderProps as HeaderProps,

Loading…
Cancel
Save

Powered by TurnKey Linux.