@warkypublic/svelix 0.1.39 → 0.1.41
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/components/BetterMenu/BetterMenuAsyncButton.svelte +41 -24
- package/dist/components/BetterMenu/BetterMenuAsyncButton.svelte.d.ts +1 -1
- package/dist/components/BetterMenu/types.d.ts +2 -1
- package/dist/components/ContentEditor/subcomponents/AudioPlayer.svelte +2 -3
- package/dist/components/ContentEditor/subcomponents/ImageViewer.svelte +2 -3
- package/dist/components/ContentEditor/subcomponents/VideoPlayer.svelte +2 -3
- package/dist/components/Former/FormerButtonArea.svelte +3 -2
- package/dist/components/Former/FormerDrawer.svelte +130 -124
- package/dist/components/Former/FormerDrawer.svelte.d.ts +1 -1
- package/dist/components/FormerControllers/InlineWrapper.svelte +4 -34
- package/dist/components/Gridler/adapters/GridlerResolveSpecAdapter.d.ts +1 -0
- package/dist/components/Gridler/adapters/GridlerResolveSpecAdapter.js +6 -3
- package/dist/components/Gridler/adapters/GridlerRestHeaderSpecAdapter.d.ts +1 -0
- package/dist/components/Gridler/adapters/GridlerRestHeaderSpecAdapter.js +6 -3
- package/dist/components/Gridler/components/GridlerFull.svelte +2 -0
- package/dist/components/Gridler/components/GridlerFullWithFormerPreview.svelte +340 -0
- package/dist/components/Gridler/components/GridlerFullWithFormerPreview.svelte.d.ts +3 -0
- package/dist/components/Gridler/components/GridlerSearch.svelte +2 -4
- package/dist/components/Gridler/components/GridlerSearchToggle.svelte +2 -4
- package/dist/components/Gridler/types.d.ts +19 -0
- package/dist/components/Icons/IconAdd.svelte +8 -0
- package/dist/components/Icons/IconAdd.svelte.d.ts +7 -0
- package/dist/components/Icons/IconAlertCircle.svelte +9 -0
- package/dist/components/Icons/IconAlertCircle.svelte.d.ts +7 -0
- package/dist/components/Icons/IconAlertTriangle.svelte +9 -0
- package/dist/components/Icons/IconAlertTriangle.svelte.d.ts +7 -0
- package/dist/components/Icons/IconCamera.svelte +8 -0
- package/dist/components/Icons/IconCamera.svelte.d.ts +7 -0
- package/dist/components/Icons/IconClose.svelte +7 -0
- package/dist/components/Icons/IconClose.svelte.d.ts +7 -0
- package/dist/components/Icons/IconEdit.svelte +8 -0
- package/dist/components/Icons/IconEdit.svelte.d.ts +7 -0
- package/dist/components/Icons/IconFilter.svelte +7 -0
- package/dist/components/Icons/IconFilter.svelte.d.ts +7 -0
- package/dist/components/Icons/IconSearch.svelte +8 -0
- package/dist/components/Icons/IconSearch.svelte.d.ts +7 -0
- package/dist/components/Icons/IconSort.svelte +11 -0
- package/dist/components/Icons/IconSort.svelte.d.ts +8 -0
- package/dist/components/Icons/IconTrash.svelte +10 -0
- package/dist/components/Icons/IconTrash.svelte.d.ts +7 -0
- package/dist/components/Icons/index.d.ts +11 -0
- package/dist/components/Icons/index.js +11 -0
- package/dist/components/Icons/strings.d.ts +11 -0
- package/dist/components/Icons/strings.js +15 -0
- package/dist/components/Screenshot/Screenshot.svelte +2 -15
- package/dist/components/SvarkGrid/components/SvarkHeaderFilterCell.svelte +4 -13
- package/dist/components/Types/generic_grid.d.ts +18 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +1 -0
- package/llm/COMPONENT_GUIDE.md +98 -0
- package/llm/README.md +93 -0
- package/package.json +46 -47
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare const iconAddSvg = "<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" style=\"flex-shrink:0\" aria-hidden=\"true\"><circle cx=\"12\" cy=\"12\" r=\"9\"/><path d=\"M12 8v8M8 12h8\"/></svg>";
|
|
2
|
+
export declare const iconEditSvg = "<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" style=\"flex-shrink:0\" aria-hidden=\"true\"><path d=\"M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7\"/><path d=\"m18.5 2.5 3 3L12 15l-4 1 1-4 9.5-9.5z\"/></svg>";
|
|
3
|
+
export declare const iconTrashSvg = "<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" style=\"flex-shrink:0\" aria-hidden=\"true\"><path d=\"M3 6h18\"/><path d=\"M8 6V4a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v2\"/><path d=\"M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6\"/><path d=\"M10 11v6M14 11v6\"/></svg>";
|
|
4
|
+
export declare const iconSearchSvg = "<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" style=\"flex-shrink:0\" aria-hidden=\"true\"><circle cx=\"11\" cy=\"11\" r=\"7\"/><path d=\"m21 21-4.35-4.35\"/></svg>";
|
|
5
|
+
export declare const iconCloseSvg = "<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" style=\"flex-shrink:0\" aria-hidden=\"true\"><path d=\"M18 6 6 18M6 6l12 12\"/></svg>";
|
|
6
|
+
export declare const iconAlertCircleSvg = "<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" style=\"flex-shrink:0\" aria-hidden=\"true\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"/><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"/></svg>";
|
|
7
|
+
export declare const iconAlertTriangleSvg = "<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" style=\"flex-shrink:0\" aria-hidden=\"true\"><path d=\"m10.29 3.86-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.71-3.14l-8-14a2 2 0 0 0-3.42 0z\"/><line x1=\"12\" y1=\"9\" x2=\"12\" y2=\"13\"/><line x1=\"12\" y1=\"17\" x2=\"12.01\" y2=\"17\"/></svg>";
|
|
8
|
+
export declare const iconFilterSvg = "<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\" style=\"flex-shrink:0\" aria-hidden=\"true\"><path d=\"M3 5a1 1 0 0 1 1-1h16a1 1 0 0 1 .8 1.6L14 13.5V19a1 1 0 0 1-1.45.9l-3-1.5A1 1 0 0 1 9 17.5v-4L3.2 5.6A1 1 0 0 1 3 5Z\"/></svg>";
|
|
9
|
+
export declare const iconCameraSvg = "<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" style=\"flex-shrink:0\" aria-hidden=\"true\"><path d=\"M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z\"/><circle cx=\"12\" cy=\"13\" r=\"3\"/></svg>";
|
|
10
|
+
export declare const iconSortAscSvg = "<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\" style=\"flex-shrink:0\" aria-hidden=\"true\"><path d=\"M7 14l5-5 5 5H7z\"/></svg>";
|
|
11
|
+
export declare const iconSortDescSvg = "<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\" style=\"flex-shrink:0\" aria-hidden=\"true\"><path d=\"M7 10l5 5 5-5H7z\"/></svg>";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// SVG HTML strings for use with {@html} or the `icon?: string` prop on menu items.
|
|
2
|
+
// Each string renders at 16×16 px and inherits colour via currentColor.
|
|
3
|
+
const S = `width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="flex-shrink:0" aria-hidden="true"`;
|
|
4
|
+
const F = `width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="flex-shrink:0" aria-hidden="true"`;
|
|
5
|
+
export const iconAddSvg = `<svg ${S}><circle cx="12" cy="12" r="9"/><path d="M12 8v8M8 12h8"/></svg>`;
|
|
6
|
+
export const iconEditSvg = `<svg ${S}><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="m18.5 2.5 3 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>`;
|
|
7
|
+
export const iconTrashSvg = `<svg ${S}><path d="M3 6h18"/><path d="M8 6V4a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v2"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/><path d="M10 11v6M14 11v6"/></svg>`;
|
|
8
|
+
export const iconSearchSvg = `<svg ${S}><circle cx="11" cy="11" r="7"/><path d="m21 21-4.35-4.35"/></svg>`;
|
|
9
|
+
export const iconCloseSvg = `<svg ${S}><path d="M18 6 6 18M6 6l12 12"/></svg>`;
|
|
10
|
+
export const iconAlertCircleSvg = `<svg ${S}><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>`;
|
|
11
|
+
export const iconAlertTriangleSvg = `<svg ${S}><path d="m10.29 3.86-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.71-3.14l-8-14a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>`;
|
|
12
|
+
export const iconFilterSvg = `<svg ${F}><path d="M3 5a1 1 0 0 1 1-1h16a1 1 0 0 1 .8 1.6L14 13.5V19a1 1 0 0 1-1.45.9l-3-1.5A1 1 0 0 1 9 17.5v-4L3.2 5.6A1 1 0 0 1 3 5Z"/></svg>`;
|
|
13
|
+
export const iconCameraSvg = `<svg ${S}><path d="M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z"/><circle cx="12" cy="13" r="3"/></svg>`;
|
|
14
|
+
export const iconSortAscSvg = `<svg ${F}><path d="M7 14l5-5 5 5H7z"/></svg>`;
|
|
15
|
+
export const iconSortDescSvg = `<svg ${F}><path d="M7 10l5 5 5-5H7z"/></svg>`;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { CaptureScreen } from "./Screenshot.util";
|
|
3
|
+
import IconCamera from '../Icons/IconCamera.svelte';
|
|
3
4
|
|
|
4
5
|
let screenshot = $state("");
|
|
5
6
|
|
|
@@ -17,21 +18,7 @@
|
|
|
17
18
|
onclick={capture}
|
|
18
19
|
class="flex items-center gap-2 rounded bg-blue-500 px-4 py-2 text-white transition-colors hover:bg-blue-600"
|
|
19
20
|
>
|
|
20
|
-
<
|
|
21
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
22
|
-
width="20"
|
|
23
|
-
height="20"
|
|
24
|
-
viewBox="0 0 24 24"
|
|
25
|
-
fill="none"
|
|
26
|
-
stroke="currentColor"
|
|
27
|
-
stroke-width="2"
|
|
28
|
-
stroke-linecap="round"
|
|
29
|
-
stroke-linejoin="round"
|
|
30
|
-
aria-hidden="true"
|
|
31
|
-
>
|
|
32
|
-
<path d="M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z" />
|
|
33
|
-
<circle cx="12" cy="13" r="3" />
|
|
34
|
-
</svg>
|
|
21
|
+
<IconCamera size={20} />
|
|
35
22
|
Capture Screenshot
|
|
36
23
|
</button>
|
|
37
24
|
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
import type { BetterMenuStore } from '../../BetterMenu/store';
|
|
5
5
|
import type { GridColumnFilters } from '../../Types/generic_grid';
|
|
6
6
|
import SvarkColumnFilterForm from './SvarkColumnFilterForm.svelte';
|
|
7
|
+
import IconSort from '../../Icons/IconSort.svelte';
|
|
8
|
+
import IconFilter from '../../Icons/IconFilter.svelte';
|
|
7
9
|
|
|
8
10
|
type IApi = any;
|
|
9
11
|
type IColumn = any;
|
|
@@ -96,13 +98,7 @@
|
|
|
96
98
|
{#if typeof sortMark.index !== 'undefined'}
|
|
97
99
|
<span class="svark-sort-index">{sortMark.index + 1}</span>
|
|
98
100
|
{/if}
|
|
99
|
-
<
|
|
100
|
-
{#if sortMark.order === 'asc'}
|
|
101
|
-
<path fill="currentColor" d="M7 14l5-5 5 5H7z" />
|
|
102
|
-
{:else}
|
|
103
|
-
<path fill="currentColor" d="M7 10l5 5 5-5H7z" />
|
|
104
|
-
{/if}
|
|
105
|
-
</svg>
|
|
101
|
+
<IconSort direction={sortMark.order} size={14} />
|
|
106
102
|
</div>
|
|
107
103
|
{/if}
|
|
108
104
|
|
|
@@ -117,12 +113,7 @@
|
|
|
117
113
|
onclick={onIconClick}
|
|
118
114
|
data-testid={`svarkgrid-filter-${columnId}`}
|
|
119
115
|
>
|
|
120
|
-
<
|
|
121
|
-
<path
|
|
122
|
-
fill="currentColor"
|
|
123
|
-
d="M3 5a1 1 0 0 1 1-1h16a1 1 0 0 1 .8 1.6L14 13.5V19a1 1 0 0 1-1.45.9l-3-1.5A1 1 0 0 1 9 17.5v-4L3.2 5.6A1 1 0 0 1 3 5Z"
|
|
124
|
-
/>
|
|
125
|
-
</svg>
|
|
116
|
+
<IconFilter size={14} />
|
|
126
117
|
</button>
|
|
127
118
|
{/if}
|
|
128
119
|
</div>
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Options as ResolveSpecOptions } from '@warkypublic/resolvespec-js';
|
|
1
2
|
export type GridColumnFormat = "text" | "number" | "currency" | "percentage" | "date" | "datetime" | "markdown" | "image" | "uri" | "bubble" | "drilldown";
|
|
2
3
|
/**
|
|
3
4
|
* GridEventType represents the various events that can occur on the grid level, such as clicking, hovering, loading, scrolling, resizing, and changes to sorting, filtering, searching, selection, column arrangement, data, and settings. These events can be used to trigger callbacks for handling user interactions and updates to the grid.
|
|
@@ -72,6 +73,23 @@ export interface GridCommonProps<RowDataType = unknown, CellType = unknown> {
|
|
|
72
73
|
uniqueID?: string;
|
|
73
74
|
headers?: Record<string, string>;
|
|
74
75
|
hotfields?: string[];
|
|
76
|
+
/**
|
|
77
|
+
* Default ResolveSpec options sent with every request. Grid-controlled sort, filters, limit,
|
|
78
|
+
* cursor, and columns always take precedence over values set here.
|
|
79
|
+
*
|
|
80
|
+
* Key fields:
|
|
81
|
+
* - `preload` — eager-load relations. Each entry specifies `relation`, optional `columns`,
|
|
82
|
+
* `filters`, `sort`, `limit`, `recursive`, `sql_joins`, etc.
|
|
83
|
+
* - `omit_columns` — columns to exclude from the response.
|
|
84
|
+
* - `computedColumns` — server-side computed expressions: `{ name, expression }`.
|
|
85
|
+
* - `customOperators` — raw SQL WHERE fragments (AND-combined): `{ name, sql }`.
|
|
86
|
+
* - `parameters` — named query parameters passed to the server: `{ name, value, sequence? }`.
|
|
87
|
+
* - `filters` — default server-side filters applied before any grid filters.
|
|
88
|
+
* - `sort` — default sort order, overridden when the user sorts a column.
|
|
89
|
+
* - `fetch_row_number` — column name whose row number is returned in metadata.
|
|
90
|
+
* - `offset` — static row offset (cursor pagination is used by the adapter; avoid mixing).
|
|
91
|
+
*/
|
|
92
|
+
extraOptions?: Partial<ResolveSpecOptions>;
|
|
75
93
|
};
|
|
76
94
|
data?: RowDataType[] | (() => Promise<RowDataType[]>);
|
|
77
95
|
onDataChange?: (data: RowDataType[]) => Promise<void>;
|
package/dist/components/index.js
CHANGED
package/llm/COMPONENT_GUIDE.md
CHANGED
|
@@ -478,6 +478,104 @@ Story behavior worth preserving:
|
|
|
478
478
|
- search highlighting and fixed columns are first-class usage patterns
|
|
479
479
|
- theme overrides are an expected integration point, not a niche feature
|
|
480
480
|
|
|
481
|
+
### GridlerFull: server-driven Gridler with adapters
|
|
482
|
+
|
|
483
|
+
`GridlerFull` wraps `Gridler` and handles paging, sorting, filtering, and search against a
|
|
484
|
+
ResolveSpec or HeaderSpec API. Configure via `dataSource` + `dataSourceOptions`.
|
|
485
|
+
|
|
486
|
+
```svelte
|
|
487
|
+
<script lang="ts">
|
|
488
|
+
import { GridlerFull } from '@warkypublic/svelix';
|
|
489
|
+
import type { GridlerColumn } from '@warkypublic/svelix';
|
|
490
|
+
|
|
491
|
+
const columns: GridlerColumn[] = [
|
|
492
|
+
{ id: 'id', title: 'ID', width: 60 },
|
|
493
|
+
{ id: 'name', title: 'Name', width: 180 },
|
|
494
|
+
{ id: 'email', title: 'Email', width: 220 },
|
|
495
|
+
];
|
|
496
|
+
</script>
|
|
497
|
+
|
|
498
|
+
<GridlerFull
|
|
499
|
+
{columns}
|
|
500
|
+
dataSource="resolvespec"
|
|
501
|
+
dataSourceOptions={{
|
|
502
|
+
url: 'https://api.example.com',
|
|
503
|
+
authToken: 'Bearer …',
|
|
504
|
+
schema: 'public',
|
|
505
|
+
entity: 'users',
|
|
506
|
+
uniqueID: 'id',
|
|
507
|
+
hotfields: ['role'],
|
|
508
|
+
extraOptions: {
|
|
509
|
+
preload: [
|
|
510
|
+
{
|
|
511
|
+
relation: 'department',
|
|
512
|
+
columns: ['id', 'name'],
|
|
513
|
+
},
|
|
514
|
+
],
|
|
515
|
+
filters: [{ column: 'active', operator: 'eq', value: true }],
|
|
516
|
+
sort: [{ column: 'created_at', direction: 'desc' }],
|
|
517
|
+
computedColumns: [{ name: 'full_name', expression: "first_name || ' ' || last_name" }],
|
|
518
|
+
customOperators: [{ name: 'tenant', sql: "tenant_id = '123'" }],
|
|
519
|
+
parameters: [{ name: 'p_role', value: 'admin' }],
|
|
520
|
+
},
|
|
521
|
+
}}
|
|
522
|
+
height={480}
|
|
523
|
+
pageSize={50}
|
|
524
|
+
/>
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
#### `dataSource` values
|
|
528
|
+
|
|
529
|
+
| Value | Adapter class | Transport |
|
|
530
|
+
|----------------|----------------------------------|--------------------|
|
|
531
|
+
| `resolvespec` | `GridlerResolveSpecAdapter` | JSON request body |
|
|
532
|
+
| `headerspec` | `GridlerRestHeaderSpecAdapter` | HTTP headers |
|
|
533
|
+
|
|
534
|
+
#### `dataSourceOptions.extraOptions` — all fields
|
|
535
|
+
|
|
536
|
+
These are `Partial<Options>` from `@warkypublic/resolvespec-js`. Grid-controlled values
|
|
537
|
+
(sort, filters, limit, cursor, columns) always win over anything set here.
|
|
538
|
+
|
|
539
|
+
| Field | Type | Purpose |
|
|
540
|
+
|-------------------|-----------------------|------------------------------------------------------------------|
|
|
541
|
+
| `preload` | `PreloadOption[]` | Eager-load related entities. See `PreloadOption` fields below. |
|
|
542
|
+
| `omit_columns` | `string[]` | Exclude these columns from every response. |
|
|
543
|
+
| `computedColumns` | `ComputedColumn[]` | Server-side SQL expressions: `{ name, expression }`. |
|
|
544
|
+
| `customOperators` | `CustomOperator[]` | Raw SQL WHERE fragments (AND-combined): `{ name, sql }`. |
|
|
545
|
+
| `parameters` | `Parameter[]` | Named query params: `{ name, value, sequence? }`. |
|
|
546
|
+
| `filters` | `FilterOption[]` | Default filters prepended before any grid column filters. |
|
|
547
|
+
| `sort` | `SortOption[]` | Default sort, overridden when the user clicks a column header. |
|
|
548
|
+
| `fetch_row_number`| `string` | Column whose absolute row number is returned in metadata. |
|
|
549
|
+
| `offset` | `number` | Static row offset — avoid mixing with cursor pagination. |
|
|
550
|
+
|
|
551
|
+
##### `PreloadOption` key fields
|
|
552
|
+
|
|
553
|
+
| Field | Purpose |
|
|
554
|
+
|----------------------|------------------------------------------------------|
|
|
555
|
+
| `relation` | Relation name (required). |
|
|
556
|
+
| `table_name` | Override the table resolved from the relation. |
|
|
557
|
+
| `columns` | Columns to select on the related table. |
|
|
558
|
+
| `omit_columns` | Columns to exclude on the related table. |
|
|
559
|
+
| `filters` | Filters applied to the related table. |
|
|
560
|
+
| `sort` | Sort order for the related rows. |
|
|
561
|
+
| `limit` | Max related rows per parent row. |
|
|
562
|
+
| `recursive` | Self-referential recursive load. |
|
|
563
|
+
| `primary_key` | Override primary key used for the join. |
|
|
564
|
+
| `related_key` | Foreign key on the related table. |
|
|
565
|
+
| `foreign_key` | Foreign key on the parent table. |
|
|
566
|
+
| `recursive_child_key`| Key used for the recursive child join. |
|
|
567
|
+
| `sql_joins` | Raw SQL JOIN clauses. |
|
|
568
|
+
| `join_aliases` | Aliases for the SQL joins. |
|
|
569
|
+
| `computed_ql` | Map of computed column name → SQL expression. |
|
|
570
|
+
| `where` | Raw SQL WHERE fragment for the relation. |
|
|
571
|
+
| `updatable` | Marks the preloaded relation as updatable. |
|
|
572
|
+
|
|
573
|
+
Key behaviors:
|
|
574
|
+
- `extraOptions` is stored on the adapter at construction time; changing `dataSourceOptions` recreates the adapter and triggers a full refetch.
|
|
575
|
+
- Call-time `extraOptions` passed directly to `readPage` override the config-level defaults; specific params (sort, filters, limit, cursor, columns) override both.
|
|
576
|
+
- `hotfields` are fetched alongside column fields but not rendered — use them for fields needed by filters or computed logic.
|
|
577
|
+
- Use `headerspec` when the API endpoint only accepts query options via HTTP headers instead of a JSON body.
|
|
578
|
+
|
|
481
579
|
### SvarkGrid: adapter-backed tabular data
|
|
482
580
|
|
|
483
581
|
Based on:
|
package/llm/README.md
CHANGED
|
@@ -18,6 +18,99 @@ This folder contains AI-readable documentation that ships with the package.
|
|
|
18
18
|
- [plans/canvasgrid.md](./plans/canvasgrid.md)
|
|
19
19
|
- [gridler-events.md](./gridler-events.md)
|
|
20
20
|
|
|
21
|
+
## Implementation Patterns
|
|
22
|
+
|
|
23
|
+
### Standard Entity Page
|
|
24
|
+
|
|
25
|
+
GridlerFull and FormerDrawer are siblings. GridlerFull handles display/filtering; its `menuItems` and row events (`onRowDblClick`, `onRowContextMenu`) open a `FormerDrawer`. The drawer receives `request` (`insert` | `update` | `delete`), `bind:values`, and an `onAPICall` handler. Field controls go inside a `{#snippet children(state)}` block.
|
|
26
|
+
|
|
27
|
+
```svelte
|
|
28
|
+
<script lang="ts">
|
|
29
|
+
import GridlerFull from '@warkypublic/svelix/GridlerFull';
|
|
30
|
+
import FormerDrawer from '@warkypublic/svelix/FormerDrawer';
|
|
31
|
+
import TextInputCtrl from '@warkypublic/svelix/TextInputCtrl';
|
|
32
|
+
import NativeSelectCtrl from '@warkypublic/svelix/NativeSelectCtrl';
|
|
33
|
+
import type { FormRequestType } from '@warkypublic/svelix/Former';
|
|
34
|
+
import { iconAddSvg, iconEditSvg, iconTrashSvg } from '@warkypublic/svelix/Icons';
|
|
35
|
+
|
|
36
|
+
let drawerOpen = $state(false);
|
|
37
|
+
let formMode = $state<FormRequestType>('update');
|
|
38
|
+
let formValues = $state<MyRow | undefined>(undefined);
|
|
39
|
+
let selectedItems = $state<Record<string, unknown>[]>([]);
|
|
40
|
+
|
|
41
|
+
function openForm(mode: FormRequestType, row?: MyRow) {
|
|
42
|
+
formMode = mode;
|
|
43
|
+
formValues = row ? { ...row } : { id: 0, name: '' };
|
|
44
|
+
drawerOpen = true;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const menuItems = [
|
|
48
|
+
{ id: 'add', label: 'Add', icon: iconAddSvg, kind: 'item', onselect: () => openForm('insert') },
|
|
49
|
+
{ id: 'sep', label: '', kind: 'separator' },
|
|
50
|
+
{ id: 'edit', label: 'Edit', icon: iconEditSvg, kind: 'item', onselect: () => openForm('update', selectedItems[0] as MyRow) },
|
|
51
|
+
{ id: 'delete', label: 'Delete', icon: iconTrashSvg, kind: 'item', onselect: () => openForm('delete', selectedItems[0] as MyRow) },
|
|
52
|
+
];
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
<GridlerFull
|
|
56
|
+
{columns}
|
|
57
|
+
{data}
|
|
58
|
+
uniqueID="id"
|
|
59
|
+
{menuItems}
|
|
60
|
+
onRowDblClick={(_row, rowData) => openForm('update', rowData as MyRow)}
|
|
61
|
+
onSelectedItemsChange={(items) => (selectedItems = items)}
|
|
62
|
+
/>
|
|
63
|
+
|
|
64
|
+
<FormerDrawer
|
|
65
|
+
bind:opened={drawerOpen}
|
|
66
|
+
bind:values={formValues}
|
|
67
|
+
request={formMode}
|
|
68
|
+
uniqueKeyField="id"
|
|
69
|
+
layout={{ title: 'Employee', buttonArea: 'bottom' }}
|
|
70
|
+
onAPICall={async (_mode, _req, data) => { /* call backend */ return data; }}
|
|
71
|
+
afterSave={(data) => { /* update local rows state */ }}
|
|
72
|
+
onClose={() => { drawerOpen = false; }}
|
|
73
|
+
>
|
|
74
|
+
{#snippet children(state)}
|
|
75
|
+
{@const isReadonly = state.request === 'delete'}
|
|
76
|
+
<TextInputCtrl
|
|
77
|
+
label="Name" name="name"
|
|
78
|
+
value={state.values?.name ?? ''}
|
|
79
|
+
disabled={isReadonly}
|
|
80
|
+
onchange={(v) => state.setState('values', { ...state.values, name: v })}
|
|
81
|
+
/>
|
|
82
|
+
<NativeSelectCtrl
|
|
83
|
+
label="Status" name="status"
|
|
84
|
+
value={state.values?.status ?? ''}
|
|
85
|
+
{options}
|
|
86
|
+
disabled={isReadonly}
|
|
87
|
+
onchange={(v) => state.setState('values', { ...state.values, status: v })}
|
|
88
|
+
/>
|
|
89
|
+
{/snippet}
|
|
90
|
+
</FormerDrawer>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Component roles
|
|
94
|
+
|
|
95
|
+
- **GridlerFull** — data grid with burger menu (`menuItems`), row events (`onRowDblClick`, `onRowContextMenu`, `onSelectedItemsChange`), filtering and pagination
|
|
96
|
+
- **FormerDrawer** — slide-out drawer form for Add/Edit/Delete; `request` controls mode; fields go in `{#snippet children(state)}`; `state.setState('values', ...)` updates field values; `onAPICall` is the save handler; `afterSave` updates local state
|
|
97
|
+
- **FormerControllers** — `TextInputCtrl`, `NumberInputCtrl`, `NativeSelectCtrl`, etc.; use `disabled` for delete readonly mode
|
|
98
|
+
- **ErrorBoundary** — wraps async components to catch render and fetch errors
|
|
99
|
+
- **ContentEditor** — edit JSON, Markdown, code, or documents as a FormerDrawer field
|
|
100
|
+
- **VTree** — hierarchical/tree data display
|
|
101
|
+
- **BetterMenu** — context menus or nav menus
|
|
102
|
+
- **Boxer** — single or multi-value lookup control backed by a data source; used as a FormerDrawer field
|
|
103
|
+
- **GlobalStateStore** — central store for all app state and API data
|
|
104
|
+
- **resolvespec-js** — connects components to the backend via specs passed to GridlerFull, FormerDrawer, Boxer, etc.
|
|
105
|
+
|
|
106
|
+
### Data flow
|
|
107
|
+
|
|
108
|
+
```text
|
|
109
|
+
GlobalStateStore ↔ resolvespec-js ↔ Backend API
|
|
110
|
+
↑
|
|
111
|
+
GridlerFull / FormerDrawer / Boxer
|
|
112
|
+
```
|
|
113
|
+
|
|
21
114
|
## Installed package paths
|
|
22
115
|
|
|
23
116
|
When `@warkypublic/svelix` is installed, this documentation is available at:
|
package/package.json
CHANGED
|
@@ -1,26 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@warkypublic/svelix",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.41",
|
|
4
4
|
"description": "Svelte 5 component library with Skeleton UI and Tailwind CSS",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"dev": "vite dev",
|
|
8
|
-
"build": "vite build && pnpm run package",
|
|
9
|
-
"preview": "vite preview",
|
|
10
|
-
"package": "svelte-kit sync && svelte-package && mkdir -p dist/css && cp src/lib/css/tailwind-source.css dist/css/tailwind-source.css && publint",
|
|
11
|
-
"prepublishOnly": "npm run package",
|
|
12
|
-
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
|
13
|
-
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
|
14
|
-
"storybook": "storybook dev -p 6006",
|
|
15
|
-
"build-storybook": "storybook build",
|
|
16
|
-
"lint": "eslint .",
|
|
17
|
-
"lint:fix": "eslint . --fix",
|
|
18
|
-
"test": "vitest run --project unit",
|
|
19
|
-
"test:unit": "vitest run --project unit",
|
|
20
|
-
"test:watch": "vitest --project unit",
|
|
21
|
-
"test:e2e": "playwright test",
|
|
22
|
-
"test:e2e:ui": "playwright test --ui"
|
|
23
|
-
},
|
|
24
6
|
"exports": {
|
|
25
7
|
".": {
|
|
26
8
|
"types": "./dist/index.d.ts",
|
|
@@ -44,43 +26,43 @@
|
|
|
44
26
|
},
|
|
45
27
|
"devDependencies": {
|
|
46
28
|
"@changesets/cli": "^2.31.0",
|
|
47
|
-
"@chromatic-com/storybook": "^5.1
|
|
48
|
-
"@eslint/compat": "^2.0
|
|
29
|
+
"@chromatic-com/storybook": "^5.2.1",
|
|
30
|
+
"@eslint/compat": "^2.1.0",
|
|
49
31
|
"@eslint/js": "^10.0.1",
|
|
50
|
-
"@playwright/test": "^1.
|
|
51
|
-
"@sentry/svelte": "^10.
|
|
32
|
+
"@playwright/test": "^1.60.0",
|
|
33
|
+
"@sentry/svelte": "^10.53.1",
|
|
52
34
|
"@skeletonlabs/skeleton": "^4.15.2",
|
|
53
35
|
"@skeletonlabs/skeleton-svelte": "^4.15.2",
|
|
54
|
-
"@storybook/addon-a11y": "^10.
|
|
55
|
-
"@storybook/addon-docs": "^10.
|
|
36
|
+
"@storybook/addon-a11y": "^10.4.0",
|
|
37
|
+
"@storybook/addon-docs": "^10.4.0",
|
|
56
38
|
"@storybook/addon-svelte-csf": "^5.1.2",
|
|
57
|
-
"@storybook/addon-vitest": "^10.
|
|
58
|
-
"@storybook/sveltekit": "^10.
|
|
39
|
+
"@storybook/addon-vitest": "^10.4.0",
|
|
40
|
+
"@storybook/sveltekit": "^10.4.0",
|
|
59
41
|
"@storybook/test": "^8.6.15",
|
|
60
42
|
"@sveltejs/adapter-auto": "^7.0.1",
|
|
61
|
-
"@sveltejs/kit": "^2.
|
|
43
|
+
"@sveltejs/kit": "^2.60.1",
|
|
62
44
|
"@sveltejs/package": "^2.5.7",
|
|
63
|
-
"@sveltejs/vite-plugin-svelte": "^7.
|
|
64
|
-
"@tailwindcss/vite": "^4.
|
|
45
|
+
"@sveltejs/vite-plugin-svelte": "^7.1.2",
|
|
46
|
+
"@tailwindcss/vite": "^4.3.0",
|
|
65
47
|
"@tanstack/svelte-virtual": "^3.13.24",
|
|
66
|
-
"@types/node": "^25.
|
|
67
|
-
"@vitest/browser-playwright": "^4.1.
|
|
68
|
-
"@vitest/coverage-v8": "^4.1.
|
|
69
|
-
"eslint": "^10.
|
|
48
|
+
"@types/node": "^25.8.0",
|
|
49
|
+
"@vitest/browser-playwright": "^4.1.6",
|
|
50
|
+
"@vitest/coverage-v8": "^4.1.6",
|
|
51
|
+
"eslint": "^10.4.0",
|
|
70
52
|
"eslint-plugin-svelte": "^3.17.1",
|
|
71
|
-
"globals": "^17.
|
|
72
|
-
"playwright": "^1.
|
|
73
|
-
"publint": "^0.3.
|
|
74
|
-
"storybook": "^10.
|
|
75
|
-
"svelte": "^5.55.
|
|
76
|
-
"svelte-check": "^4.4.
|
|
77
|
-
"tailwindcss": "^4.
|
|
53
|
+
"globals": "^17.6.0",
|
|
54
|
+
"playwright": "^1.60.0",
|
|
55
|
+
"publint": "^0.3.21",
|
|
56
|
+
"storybook": "^10.4.0",
|
|
57
|
+
"svelte": "^5.55.7",
|
|
58
|
+
"svelte-check": "^4.4.8",
|
|
59
|
+
"tailwindcss": "^4.3.0",
|
|
78
60
|
"tslib": "^2.8.1",
|
|
79
61
|
"typescript": "^6.0.3",
|
|
80
|
-
"typescript-eslint": "^8.59.
|
|
81
|
-
"vite": "^8.0.
|
|
62
|
+
"typescript-eslint": "^8.59.3",
|
|
63
|
+
"vite": "^8.0.13",
|
|
82
64
|
"vite-plugin-monaco-editor": "^1.1.0",
|
|
83
|
-
"vitest": "^4.1.
|
|
65
|
+
"vitest": "^4.1.6"
|
|
84
66
|
},
|
|
85
67
|
"svelte": "./dist/index.js",
|
|
86
68
|
"types": "./dist/index.d.ts",
|
|
@@ -99,8 +81,25 @@
|
|
|
99
81
|
"@warkypublic/artemis-kit": "^1.0.10",
|
|
100
82
|
"carta-md": "^4.11.2",
|
|
101
83
|
"github-markdown-css": "^5.9.0",
|
|
102
|
-
"isomorphic-dompurify": "^3.
|
|
103
|
-
"katex": "^0.16.
|
|
84
|
+
"isomorphic-dompurify": "^3.13.0",
|
|
85
|
+
"katex": "^0.16.47",
|
|
104
86
|
"monaco-editor": "^0.55.1"
|
|
87
|
+
},
|
|
88
|
+
"scripts": {
|
|
89
|
+
"dev": "vite dev",
|
|
90
|
+
"build": "vite build && pnpm run package",
|
|
91
|
+
"preview": "vite preview",
|
|
92
|
+
"package": "svelte-kit sync && svelte-package && mkdir -p dist/css && cp src/lib/css/tailwind-source.css dist/css/tailwind-source.css && publint",
|
|
93
|
+
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
|
94
|
+
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
|
95
|
+
"storybook": "storybook dev -p 6006",
|
|
96
|
+
"build-storybook": "storybook build",
|
|
97
|
+
"lint": "eslint .",
|
|
98
|
+
"lint:fix": "eslint . --fix",
|
|
99
|
+
"test": "vitest run --project unit",
|
|
100
|
+
"test:unit": "vitest run --project unit",
|
|
101
|
+
"test:watch": "vitest --project unit",
|
|
102
|
+
"test:e2e": "playwright test",
|
|
103
|
+
"test:e2e:ui": "playwright test --ui"
|
|
105
104
|
}
|
|
106
|
-
}
|
|
105
|
+
}
|