runeforge 0.0.57 → 0.0.59

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 (69) hide show
  1. package/README.md +51 -0
  2. package/dist/components/crud/EmbeddedField.svelte +33 -5
  3. package/dist/components/crud/EmbeddedField.svelte.d.ts +6 -1
  4. package/dist/components/crud/Field.svelte +76 -423
  5. package/dist/components/crud/Field.svelte.d.ts +5 -1
  6. package/dist/components/crud/GenericCRUD.svelte +4 -4
  7. package/dist/components/crud/GenericCRUD.svelte.d.ts +4 -1
  8. package/dist/components/crud/SearchInput.svelte +1 -1
  9. package/dist/components/crud/SearchInput.svelte.d.ts +1 -1
  10. package/dist/components/crud/fields/BooleanField.svelte +38 -0
  11. package/dist/components/crud/fields/BooleanField.svelte.d.ts +33 -0
  12. package/dist/components/crud/fields/DatetimeField.svelte +250 -0
  13. package/dist/components/crud/fields/DatetimeField.svelte.d.ts +34 -0
  14. package/dist/components/crud/fields/DefaultField.svelte +67 -0
  15. package/dist/components/crud/fields/DefaultField.svelte.d.ts +34 -0
  16. package/dist/components/crud/fields/FileField.svelte +70 -0
  17. package/dist/components/crud/fields/FileField.svelte.d.ts +34 -0
  18. package/dist/components/crud/fields/MultiSelectField.svelte +70 -0
  19. package/dist/components/crud/fields/MultiSelectField.svelte.d.ts +34 -0
  20. package/dist/components/crud/fields/SelectField.svelte +67 -0
  21. package/dist/components/crud/fields/SelectField.svelte.d.ts +34 -0
  22. package/dist/components/crud/fields/TextareaField.svelte +55 -0
  23. package/dist/components/crud/fields/TextareaField.svelte.d.ts +34 -0
  24. package/dist/components/crud/fields/TreeField.svelte +63 -0
  25. package/dist/components/crud/fields/TreeField.svelte.d.ts +33 -0
  26. package/dist/components/crud/utils/embedded.d.ts +1 -1
  27. package/dist/components/crud/utils/grouping.d.ts +1 -1
  28. package/dist/components/crud/utils/resolution.d.ts +1 -1
  29. package/dist/components/crud/utils/resolution.js +6 -2
  30. package/dist/components/crud/utils/validation.d.ts +1 -1
  31. package/dist/components/crud/utils/validation.js +10 -0
  32. package/dist/components/crud/views/Create.svelte +37 -30
  33. package/dist/components/crud/views/Create.svelte.d.ts +2 -1
  34. package/dist/components/crud/views/Read.svelte +19 -12
  35. package/dist/components/crud/views/Read.svelte.d.ts +2 -1
  36. package/dist/components/crud/views/Update.svelte +28 -21
  37. package/dist/components/crud/views/Update.svelte.d.ts +2 -1
  38. package/dist/components/crud/views/list/List.svelte +3 -3
  39. package/dist/components/crud/views/list/List.svelte.d.ts +3 -1
  40. package/dist/components/crud/views/list/Modals.svelte +1 -1
  41. package/dist/components/crud/views/list/Modals.svelte.d.ts +1 -1
  42. package/dist/components/crud/views/list/Table.svelte +3 -6
  43. package/dist/components/crud/views/list/Table.svelte.d.ts +3 -1
  44. package/dist/components/crud/views/list/Toolbar.svelte +3 -4
  45. package/dist/components/crud/views/list/Toolbar.svelte.d.ts +3 -1
  46. package/dist/components/table/ColumnFilter.svelte +1 -1
  47. package/dist/components/table/ColumnFilter.svelte.d.ts +1 -1
  48. package/dist/components/table/PaginatedTable.svelte +1 -1
  49. package/dist/components/table/PaginatedTable.svelte.d.ts +1 -1
  50. package/dist/components/table/TableBody.svelte +1 -1
  51. package/dist/components/table/TableBody.svelte.d.ts +1 -1
  52. package/dist/components/table/TableHeader.svelte +1 -1
  53. package/dist/components/table/TableHeader.svelte.d.ts +1 -1
  54. package/dist/components/table/export.d.ts +1 -1
  55. package/dist/components/table/state.svelte.d.ts +1 -1
  56. package/dist/components/table/utils.d.ts +1 -1
  57. package/dist/index.d.ts +5 -1
  58. package/dist/types/attribute.d.ts +56 -4
  59. package/dist/types/{crud.d.ts → crud/actions.d.ts} +0 -123
  60. package/dist/types/crud/columns.d.ts +23 -0
  61. package/dist/types/crud/columns.js +1 -0
  62. package/dist/types/crud/fields.d.ts +48 -0
  63. package/dist/types/crud/fields.js +1 -0
  64. package/dist/types/crud/list-config.d.ts +23 -0
  65. package/dist/types/crud/list-config.js +1 -0
  66. package/dist/types/crud/reorder.d.ts +45 -0
  67. package/dist/types/crud/reorder.js +1 -0
  68. package/package.json +1 -1
  69. /package/dist/types/{crud.js → crud/actions.js} +0 -0
@@ -6,12 +6,11 @@
6
6
  import { defaultIconSet } from '../../../../icons/sets/default.js';
7
7
  import type {
8
8
  ActionConfiguration,
9
- ColumnDefinition,
10
9
  CustomBulkAction,
11
- ExportConfiguration,
12
- SearchConfiguration,
13
10
  ViewBasedCustomBulkAction
14
- } from '../../../../types/crud.js';
11
+ } from '../../../../types/crud/actions.js';
12
+ import type { ColumnDefinition } from '../../../../types/crud/columns.js';
13
+ import type { ExportConfiguration, SearchConfiguration } from '../../../../types/crud/list-config.js';
15
14
  import type { ServerPagination, TableQuery } from '../../../../types/table.js';
16
15
  import { getStrings } from '../../../../i18n/context.js';
17
16
  import SearchInput from '../../SearchInput.svelte';
@@ -1,4 +1,6 @@
1
- import type { ActionConfiguration, ColumnDefinition, CustomBulkAction, ExportConfiguration, SearchConfiguration } from '../../../../types/crud.js';
1
+ import type { ActionConfiguration, CustomBulkAction } from '../../../../types/crud/actions.js';
2
+ import type { ColumnDefinition } from '../../../../types/crud/columns.js';
3
+ import type { ExportConfiguration, SearchConfiguration } from '../../../../types/crud/list-config.js';
2
4
  import type { ServerPagination, TableQuery } from '../../../../types/table.js';
3
5
  declare function $$render<T extends object = Record<string, unknown>>(): {
4
6
  props: {
@@ -13,7 +13,7 @@
13
13
  });
14
14
  import type { DistinctEntry } from '../../types/table.js';
15
15
  import type { FilterState } from './state.svelte.js';
16
- import type { ColumnDefinition } from '../../types/crud.js';
16
+ import type { ColumnDefinition } from '../../types/crud/columns.js';
17
17
 
18
18
  let {
19
19
  column,
@@ -1,6 +1,6 @@
1
1
  import type { DistinctEntry } from '../../types/table.js';
2
2
  import type { FilterState } from './state.svelte.js';
3
- import type { ColumnDefinition } from '../../types/crud.js';
3
+ import type { ColumnDefinition } from '../../types/crud/columns.js';
4
4
  declare function $$render<T extends object>(): {
5
5
  props: {
6
6
  column: ColumnDefinition<T>;
@@ -17,7 +17,7 @@
17
17
  TableQuery
18
18
  } from '../../types/table.js';
19
19
  import { tick, type Snippet } from 'svelte';
20
- import type { ColumnDefinition } from '../../types/crud.js';
20
+ import type { ColumnDefinition } from '../../types/crud/columns.js';
21
21
  import { getStrings } from '../../i18n/context.js';
22
22
 
23
23
  const strings = getStrings();
@@ -1,7 +1,7 @@
1
1
  import { SvelteSet } from 'svelte/reactivity';
2
2
  import type { FilterSnapshot, ReorderOptions, ServerPagination, SortDirection, TableQuery } from '../../types/table.js';
3
3
  import { type Snippet } from 'svelte';
4
- import type { ColumnDefinition } from '../../types/crud.js';
4
+ import type { ColumnDefinition } from '../../types/crud/columns.js';
5
5
  declare function $$render<T extends object = Record<string, unknown>>(): {
6
6
  props: {
7
7
  data?: T[];
@@ -1,7 +1,7 @@
1
1
  <script lang="ts" generics="T extends object">
2
2
  import type { Snippet } from 'svelte';
3
3
  import type { SvelteSet } from 'svelte/reactivity';
4
- import type { ColumnDefinition } from '../../types/crud.js';
4
+ import type { ColumnDefinition } from '../../types/crud/columns.js';
5
5
  import type { IndexedRow, ReorderOptions } from '../../types/table.js';
6
6
  import { sortableRows, type SortEndIndices } from './sortable.js';
7
7
  import { moveIndexedRows } from './utils.js';
@@ -1,6 +1,6 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  import type { SvelteSet } from 'svelte/reactivity';
3
- import type { ColumnDefinition } from '../../types/crud.js';
3
+ import type { ColumnDefinition } from '../../types/crud/columns.js';
4
4
  import type { IndexedRow, ReorderOptions } from '../../types/table.js';
5
5
  declare function $$render<T extends object>(): {
6
6
  props: {
@@ -3,7 +3,7 @@
3
3
  import ColumnFilter from './ColumnFilter.svelte';
4
4
  import { isSortable, isFilterable } from './utils.js';
5
5
  import type { DistinctEntry } from '../../types/table.js';
6
- import type { ColumnDefinition } from '../../types/crud.js';
6
+ import type { ColumnDefinition } from '../../types/crud/columns.js';
7
7
  import type { SortState, FilterState } from './state.svelte.js';
8
8
  import { getStrings } from '../../i18n/context.js';
9
9
 
@@ -1,5 +1,5 @@
1
1
  import type { DistinctEntry } from '../../types/table.js';
2
- import type { ColumnDefinition } from '../../types/crud.js';
2
+ import type { ColumnDefinition } from '../../types/crud/columns.js';
3
3
  import type { SortState, FilterState } from './state.svelte.js';
4
4
  declare function $$render<T extends object>(): {
5
5
  props: {
@@ -1,4 +1,4 @@
1
- import type { ColumnDefinition } from '../../types/crud.js';
1
+ import type { ColumnDefinition } from '../../types/crud/columns.js';
2
2
  /**
3
3
  * Minimal duck-typed subset of the SheetJS (`xlsx`) module API used for
4
4
  * building a workbook. Runeforge never imports `xlsx` itself — the consumer
@@ -1,5 +1,5 @@
1
1
  import { SvelteMap, SvelteSet } from 'svelte/reactivity';
2
- import type { ColumnDefinition } from '../../types/crud.js';
2
+ import type { ColumnDefinition } from '../../types/crud/columns.js';
3
3
  import type { FilterSnapshot, IndexedRow, SortDirection } from '../../types/table.js';
4
4
  export declare class SortState {
5
5
  column: string | null;
@@ -1,4 +1,4 @@
1
- import type { ColumnDefinition } from '../../types/crud.js';
1
+ import type { ColumnDefinition } from '../../types/crud/columns.js';
2
2
  import type { DistinctEntry, IndexedRow } from '../../types/table.js';
3
3
  export declare function cellRenderedText<T extends object>(row: T, col: ColumnDefinition<T>): string;
4
4
  export declare function isSortable<T extends object>(col: ColumnDefinition<T>): boolean;
package/dist/index.d.ts CHANGED
@@ -2,7 +2,11 @@ export type { BreadcrumbItem } from './types/breadcrumb.js';
2
2
  export { AttributeType } from './types/attribute.js';
3
3
  export type { AttributeMetadata, InterfaceMetadata, SelectOption, OptionsResolver, FormatterResolver, EmbeddedItemLabelResolver } from './types/attribute.js';
4
4
  export type { CellProps, CellComponent, CellFormatter, SortDirection, IndexedRow, DistinctEntry, PaginatedEnvelope, ServerPagination, FilterSnapshot, TableQuery, ReorderOptions } from './types/table.js';
5
- export type { ColumnDefinition, FieldDefinition, ActionConfiguration, CustomAction, BaseCustomBulkAction, ViewBasedCustomBulkAction, EndpointBasedCustomBulkAction, CustomBulkAction, RowAction, SearchConfiguration, ExportConfiguration, ReorderConfiguration, ListActions, ListConfig } from './types/crud.js';
5
+ export type { ColumnDefinition } from './types/crud/columns.js';
6
+ export type { FieldDefinition } from './types/crud/fields.js';
7
+ export type { ActionConfiguration, CustomAction, BaseCustomBulkAction, ViewBasedCustomBulkAction, EndpointBasedCustomBulkAction, CustomBulkAction, RowAction, ListActions } from './types/crud/actions.js';
8
+ export type { SearchConfiguration, ExportConfiguration, ListConfig } from './types/crud/list-config.js';
9
+ export type { ReorderConfiguration } from './types/crud/reorder.js';
6
10
  export type { RuneforgeConfig } from './config/context.js';
7
11
  export { setConfig, getConfig } from './config/context.js';
8
12
  export type { CRUDIconSet, IconComponent } from './icons/types.js';
@@ -25,15 +25,46 @@ export type SelectOption = {
25
25
  };
26
26
  export type OptionsResolver = SelectOption[] | ((data: any) => SelectOption[]);
27
27
  export type FormatterResolver = (data?: any) => CellFormatter<any, any>;
28
- export type DependentOptionsResolver = (data: any, record: Record<string, unknown>) => SelectOption[];
28
+ /** `parent` is only ever populated for a sub-field nested inside an
29
+ * `embedded` field — the outer form's own record, distinct from `record`
30
+ * (the embedded item's own draft). Undefined for a top-level field. */
31
+ export type DependentOptionsResolver = (data: any, record: Record<string, unknown>, parent?: Record<string, unknown>) => SelectOption[];
29
32
  export type SearchResolver = (query: string) => Promise<SelectOption[]>;
30
- export type DisabledResolver = (record: Record<string, unknown>) => boolean;
31
- export type HiddenResolver = (record: Record<string, unknown>) => boolean;
32
- export type RequiredResolver = (record: Record<string, unknown>) => boolean;
33
+ /** See `DependentOptionsResolver` re: `parent`. */
34
+ export type DisabledResolver = (record: Record<string, unknown>, parent?: Record<string, unknown>) => boolean;
35
+ /** See `DependentOptionsResolver` re: `parent`. */
36
+ export type HiddenResolver = (record: Record<string, unknown>, parent?: Record<string, unknown>) => boolean;
37
+ /** See `DependentOptionsResolver` re: `parent`. */
38
+ export type RequiredResolver = (record: Record<string, unknown>, parent?: Record<string, unknown>) => boolean;
39
+ /** Embedded fields only: called once right after the parent record's
40
+ * `dependsOn` attribute changes value (not on every parent mutation) —
41
+ * receives the embedded list's current items and the parent record, and
42
+ * returns the list that should replace it. Return the same array reference
43
+ * unchanged when nothing needs to happen; a new array (e.g. `items.filter(…)`)
44
+ * prunes/adjusts now-invalid items instead of leaving them silently stale. */
45
+ export type EmbeddedRevalidateResolver = (items: Record<string, unknown>[], parent: Record<string, unknown>) => Record<string, unknown>[];
33
46
  export type SeedResolver = (instance: any) => unknown;
34
47
  /** Embedded fields only: renders a short summary for one item in the list.
35
48
  * Falls back to a dash-joined summary of the item's sub-field values. */
36
49
  export type EmbeddedItemLabelResolver = (item: Record<string, unknown>) => string;
50
+ export type ValidateResolver = (value: unknown, record: Record<string, unknown>) => string | undefined;
51
+ /** Sets a field's value from within a `FieldButtonAction.run` callback —
52
+ * usually the same field the button sits next to, but any sibling attribute
53
+ * works too. */
54
+ export type FieldSetter = (attribute: string, value: unknown) => void;
55
+ /** A button rendered next to a field's label that runs entirely client-side
56
+ * — no submit, no request — instead of persisting a model attribute of its
57
+ * own. See `AttributeMetadata.actions`. */
58
+ export type FieldButtonAction = {
59
+ label: string;
60
+ icon?: any;
61
+ class?: string;
62
+ /** Hide the button in certain conditions. Re-evaluated live, same as `disabled`. */
63
+ condition?: (record: Record<string, unknown>) => boolean;
64
+ /** Receives the field's current value, the form's full draft record, and a
65
+ * setter to write back into this field (or a sibling one). */
66
+ run: (value: unknown, record: Record<string, unknown>, setField: FieldSetter) => void;
67
+ };
37
68
  export type AttributeMetadata = {
38
69
  label?: string;
39
70
  type?: AttributeType;
@@ -91,16 +122,37 @@ export type AttributeMetadata = {
91
122
  minLength?: number;
92
123
  maxLength?: number;
93
124
  pattern?: string;
125
+ /** Custom validation, run after this field's built-in rules
126
+ * (required/min/max/minLength/maxLength/pattern) pass, and only when none
127
+ * of them already failed. Receives the field's submitted value and the
128
+ * full draft record (including sibling fields currently in the form), so
129
+ * the same hook covers a lone-field rule and a cross-field rule alike —
130
+ * e.g. an `extension_date` that must be later than the record's
131
+ * `submission_date`. Return an error message, or `undefined` when the
132
+ * value is valid. */
133
+ validate?: ValidateResolver;
94
134
  /** Textarea fields only: the HTML `rows` attribute, controlling height. */
95
135
  rows?: number;
96
136
  /** Embedded fields only: schema for each item added through the "+" modal. */
97
137
  fields?: InterfaceMetadata<any>;
98
138
  /** Embedded fields only: short label for an item in the list. */
99
139
  itemLabel?: EmbeddedItemLabelResolver;
140
+ /** Embedded fields only: re-derives the embedded list whenever the parent
141
+ * record's `dependsOn` attribute changes — see `EmbeddedRevalidateResolver`.
142
+ * Requires `dependsOn`; ignored without it. */
143
+ revalidate?: EmbeddedRevalidateResolver;
144
+ /** Embedded fields only: parent record attribute that `revalidate` reacts
145
+ * to. Only that one attribute is watched — changes to anything else in the
146
+ * parent record don't trigger `revalidate`. */
147
+ dependsOn?: string;
100
148
  /** Tree fields only: whether parent nodes start expanded. Defaults to `true`. */
101
149
  defaultExpanded?: boolean;
102
150
  /** Fields sharing the same `row` string render side by side on desktop and
103
151
  * stacked on mobile — see the Field rows section. Only merges fields that
104
152
  * are also in the same `groupedAs` bucket (or both ungrouped). */
105
153
  row?: string;
154
+ /** Extra buttons rendered next to this field's label — e.g. a "Capitalize"
155
+ * button that transforms the field's own value client-side. See "Field
156
+ * actions" in the README. */
157
+ actions?: FieldButtonAction[];
106
158
  };
@@ -1,63 +1,4 @@
1
1
  import type { Component } from 'svelte';
2
- import type { FullAutoFill } from 'svelte/elements';
3
- import type { AttributeType, SearchResolver, RequiredResolver, SelectOption } from './attribute.js';
4
- import type { CellComponent, CellFormatter, SortableModule, TableQuery } from './table.js';
5
- import type { XlsxModule } from '../components/table/export.js';
6
- export type ColumnDefinition<T extends object = Record<string, unknown>> = {
7
- [K in keyof T & string]: {
8
- attribute: K;
9
- title?: string;
10
- type?: AttributeType;
11
- component?: CellComponent<T, T[K]>;
12
- formatter?: CellFormatter<T, T[K]>;
13
- sortable?: boolean;
14
- filterable?: boolean;
15
- /** Static, exhaustive filter choices — see `AttributeMetadata.filterOptions`. */
16
- filterOptions?: SelectOption[];
17
- /** Embedded columns only: sub-field definitions for each item, used to
18
- * render a default cell summary and to expand the column into one
19
- * sub-column per field on CSV/XLSX export. */
20
- fields?: FieldDefinition<Record<string, unknown>>[];
21
- /** Embedded columns only: short label for an item, reused from the form
22
- * field's `itemLabel` for the default cell summary. */
23
- itemLabel?: (item: Record<string, unknown>) => string;
24
- };
25
- }[keyof T & string];
26
- export interface FieldDefinition<T extends object = Record<string, unknown>> {
27
- attribute: keyof T & string;
28
- title?: string;
29
- type?: AttributeType;
30
- required?: boolean | RequiredResolver;
31
- autocomplete?: FullAutoFill;
32
- placeholder?: string;
33
- default?: any;
34
- options?: SelectOption[];
35
- dependentOptions?: (record: Record<string, unknown>) => SelectOption[];
36
- search?: SearchResolver;
37
- disabled?: (record: Record<string, unknown>) => boolean;
38
- hidden?: boolean | ((record: Record<string, unknown>) => boolean);
39
- seed?: (instance: any) => unknown;
40
- /** Read-only rendering only (the Read view, and any other readonly Field) */
41
- formatter?: (value: unknown, record: Record<string, unknown>) => string;
42
- groupedAs?: string;
43
- min?: number;
44
- max?: number;
45
- integer?: boolean;
46
- minLength?: number;
47
- maxLength?: number;
48
- pattern?: string;
49
- /** Textarea fields only: the HTML `rows` attribute, controlling height. */
50
- rows?: number;
51
- /** Embedded fields only: sub-field definitions for each item, built from
52
- * the metadata's `fields`. */
53
- fields?: FieldDefinition<Record<string, unknown>>[];
54
- /** Embedded fields only: short label for an item in the list. */
55
- itemLabel?: (item: Record<string, unknown>) => string;
56
- /** Tree fields only: whether parent nodes start expanded. Defaults to `true`. */
57
- defaultExpanded?: boolean;
58
- /** Fields sharing the same `row` string render side by side. */
59
- row?: string;
60
- }
61
2
  /** A create-form button whose visibility, label and styling can all be
62
3
  * overridden — `enabled` falls back to the button's own default (see
63
4
  * `continue`/`duplication` on `ActionConfiguration`), `label` falls back to
@@ -180,59 +121,6 @@ export interface EndpointBasedCustomBulkAction<T extends object = Record<string,
180
121
  * `'endpoint'` brings `endpoint`/`confirm` and forbids `view` — see
181
122
  * `ViewBasedCustomBulkAction` / `EndpointBasedCustomBulkAction`. */
182
123
  export type CustomBulkAction<T extends object = Record<string, unknown>> = ViewBasedCustomBulkAction<T> | EndpointBasedCustomBulkAction<T>;
183
- export interface SearchConfiguration {
184
- param?: string;
185
- placeholder?: string;
186
- debounceMs?: number;
187
- }
188
- export interface ExportConfiguration<T extends object = Record<string, unknown>> {
189
- callback?: (query: TableQuery) => Promise<T[]>;
190
- xlsx?: XlsxModule;
191
- }
192
- /** Turns on drag-to-reorder rows in the list view — off by default, enabled
193
- * by providing this object (`enabled: false` keeps the configuration in
194
- * place but disables dragging, e.g. temporarily). Not supported alongside
195
- * [server-side pagination](#server-side-pagination-sorting--filtering): the
196
- * whole row set needs to be reachable client-side for indices to stay
197
- * meaningful, so `reorder` is ignored whenever a `PaginatedEnvelope` is used. */
198
- export interface ReorderConfiguration<T extends object = Record<string, unknown>> {
199
- enabled?: boolean;
200
- /** The attribute that stores each row's order index. Establishes the
201
- * default ascending order (when `compare` is absent) and is written to
202
- * its new sequential 0-based value on every row whose position changes
203
- * after a drag. */
204
- attribute: keyof T & string;
205
- /** Resolved `sortablejs` default export, e.g. `import Sortable from
206
- * 'sortablejs'`. Runeforge never bundles `sortablejs` itself — install it
207
- * separately and pass it in, so the dependency stays fully optional. */
208
- sortable: SortableModule;
209
- /** Overrides the plain `attribute`-ascending order for composite orders
210
- * — e.g. a row's true resting position depends first on a related
211
- * record's own order, and only then on this row's `attribute`. Takes
212
- * full ownership of row order while reorder is active (column-header
213
- * sorting is unavailable, same as the plain `attribute` case). */
214
- compare?: (a: T, b: T) => number;
215
- /** POSTed once per drag that settles with at least one changed row — a
216
- * single request, not one per row — then the list is refreshed. FormData
217
- * field `changes` carries a JSON-encoded array of `{ id, value }` pairs,
218
- * one per row whose `attribute` changed (`value` being its new
219
- * sequential position). Provide this or `callback`. */
220
- endpoint?: string;
221
- /** Alternative to `endpoint`: receives the rows whose `attribute` value
222
- * changed, already updated to their new index. */
223
- callback?: (items: T[]) => void | Promise<void>;
224
- /** Drag-handle icon shown at the start of each row. Falls back to the
225
- * active icon set's `grip` icon. */
226
- icon?: any;
227
- /** Lets dragging one row of the current checkbox selection move the
228
- * whole selection together, via SortableJS's `MultiDrag` plugin (must be
229
- * mounted on the `sortable` module you pass in). Off by default. */
230
- multiDrag?: boolean;
231
- /** While dragging, hovering over the edge zone for this long flips a
232
- * page instead of requiring one long drag across the whole list.
233
- * Default `2000`. */
234
- pageFlipThresholdMs?: number;
235
- }
236
124
  /** Groups the list view's row-level and selection-level custom actions —
237
125
  * `custom` replaces the old top-level `actions` prop, `bulk` replaces
238
126
  * `customBulkActions`. */
@@ -242,14 +130,3 @@ export interface ListActions<T extends object = Record<string, unknown>> {
242
130
  /** Extra actions on the current selection — see Custom bulk actions. */
243
131
  bulk?: CustomBulkAction<T>[];
244
132
  }
245
- /** Groups the list view's opt-in behaviors. Replaces the old top-level
246
- * `search`, `enableExport`/`onExport`/`xlsx` props. */
247
- export interface ListConfig<T extends object = Record<string, unknown>> {
248
- /** Free-text search box — see Free-text search. */
249
- search?: SearchConfiguration;
250
- /** CSV/Excel export. Presence of this object enables the export button —
251
- * even as an empty `{}` — replacing the old `enableExport` boolean. */
252
- export?: ExportConfiguration<T>;
253
- /** Drag-to-reorder rows — see Reordering rows. */
254
- reorder?: ReorderConfiguration<T>;
255
- }
@@ -0,0 +1,23 @@
1
+ import type { AttributeType, SelectOption } from '../attribute.js';
2
+ import type { CellComponent, CellFormatter } from '../table.js';
3
+ import type { FieldDefinition } from './fields.js';
4
+ export type ColumnDefinition<T extends object = Record<string, unknown>> = {
5
+ [K in keyof T & string]: {
6
+ attribute: K;
7
+ title?: string;
8
+ type?: AttributeType;
9
+ component?: CellComponent<T, T[K]>;
10
+ formatter?: CellFormatter<T, T[K]>;
11
+ sortable?: boolean;
12
+ filterable?: boolean;
13
+ /** Static, exhaustive filter choices — see `AttributeMetadata.filterOptions`. */
14
+ filterOptions?: SelectOption[];
15
+ /** Embedded columns only: sub-field definitions for each item, used to
16
+ * render a default cell summary and to expand the column into one
17
+ * sub-column per field on CSV/XLSX export. */
18
+ fields?: FieldDefinition<Record<string, unknown>>[];
19
+ /** Embedded columns only: short label for an item, reused from the form
20
+ * field's `itemLabel` for the default cell summary. */
21
+ itemLabel?: (item: Record<string, unknown>) => string;
22
+ };
23
+ }[keyof T & string];
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,48 @@
1
+ import type { FullAutoFill } from 'svelte/elements';
2
+ import type { AttributeType, SearchResolver, RequiredResolver, DisabledResolver, HiddenResolver, EmbeddedRevalidateResolver, SelectOption, FieldButtonAction } from '../attribute.js';
3
+ export interface FieldDefinition<T extends object = Record<string, unknown>> {
4
+ attribute: keyof T & string;
5
+ title?: string;
6
+ type?: AttributeType;
7
+ required?: boolean | RequiredResolver;
8
+ autocomplete?: FullAutoFill;
9
+ placeholder?: string;
10
+ default?: any;
11
+ options?: SelectOption[];
12
+ /** Resolved form of `AttributeMetadata.dependentOptions` — `data` is
13
+ * already baked in by `buildFieldDefinitions`, so only `record`/`parent`
14
+ * remain live parameters. */
15
+ dependentOptions?: (record: Record<string, unknown>, parent?: Record<string, unknown>) => SelectOption[];
16
+ search?: SearchResolver;
17
+ disabled?: DisabledResolver;
18
+ hidden?: boolean | HiddenResolver;
19
+ seed?: (instance: any) => unknown;
20
+ /** Read-only rendering only (the Read view, and any other readonly Field) */
21
+ formatter?: (value: unknown, record: Record<string, unknown>) => string;
22
+ groupedAs?: string;
23
+ min?: number;
24
+ max?: number;
25
+ integer?: boolean;
26
+ minLength?: number;
27
+ maxLength?: number;
28
+ pattern?: string;
29
+ /** See `AttributeMetadata.validate`. */
30
+ validate?: (value: unknown, record: Record<string, unknown>) => string | undefined;
31
+ /** Textarea fields only: the HTML `rows` attribute, controlling height. */
32
+ rows?: number;
33
+ /** Embedded fields only: sub-field definitions for each item, built from
34
+ * the metadata's `fields`. */
35
+ fields?: FieldDefinition<Record<string, unknown>>[];
36
+ /** Embedded fields only: short label for an item in the list. */
37
+ itemLabel?: (item: Record<string, unknown>) => string;
38
+ /** Embedded fields only: see `AttributeMetadata.revalidate`. */
39
+ revalidate?: EmbeddedRevalidateResolver;
40
+ /** Embedded fields only: see `AttributeMetadata.dependsOn`. */
41
+ dependsOn?: string;
42
+ /** Tree fields only: whether parent nodes start expanded. Defaults to `true`. */
43
+ defaultExpanded?: boolean;
44
+ /** Fields sharing the same `row` string render side by side. */
45
+ row?: string;
46
+ /** See `AttributeMetadata.actions`. */
47
+ actions?: FieldButtonAction[];
48
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,23 @@
1
+ import type { TableQuery } from '../table.js';
2
+ import type { XlsxModule } from '../../components/table/export.js';
3
+ import type { ReorderConfiguration } from './reorder.js';
4
+ export interface SearchConfiguration {
5
+ param?: string;
6
+ placeholder?: string;
7
+ debounceMs?: number;
8
+ }
9
+ export interface ExportConfiguration<T extends object = Record<string, unknown>> {
10
+ callback?: (query: TableQuery) => Promise<T[]>;
11
+ xlsx?: XlsxModule;
12
+ }
13
+ /** Groups the list view's opt-in behaviors. Replaces the old top-level
14
+ * `search`, `enableExport`/`onExport`/`xlsx` props. */
15
+ export interface ListConfig<T extends object = Record<string, unknown>> {
16
+ /** Free-text search box — see Free-text search. */
17
+ search?: SearchConfiguration;
18
+ /** CSV/Excel export. Presence of this object enables the export button —
19
+ * even as an empty `{}` — replacing the old `enableExport` boolean. */
20
+ export?: ExportConfiguration<T>;
21
+ /** Drag-to-reorder rows — see Reordering rows. */
22
+ reorder?: ReorderConfiguration<T>;
23
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,45 @@
1
+ import type { SortableModule } from '../table.js';
2
+ /** Turns on drag-to-reorder rows in the list view — off by default, enabled
3
+ * by providing this object (`enabled: false` keeps the configuration in
4
+ * place but disables dragging, e.g. temporarily). Not supported alongside
5
+ * [server-side pagination](#server-side-pagination-sorting--filtering): the
6
+ * whole row set needs to be reachable client-side for indices to stay
7
+ * meaningful, so `reorder` is ignored whenever a `PaginatedEnvelope` is used. */
8
+ export interface ReorderConfiguration<T extends object = Record<string, unknown>> {
9
+ enabled?: boolean;
10
+ /** The attribute that stores each row's order index. Establishes the
11
+ * default ascending order (when `compare` is absent) and is written to
12
+ * its new sequential 0-based value on every row whose position changes
13
+ * after a drag. */
14
+ attribute: keyof T & string;
15
+ /** Resolved `sortablejs` default export, e.g. `import Sortable from
16
+ * 'sortablejs'`. Runeforge never bundles `sortablejs` itself — install it
17
+ * separately and pass it in, so the dependency stays fully optional. */
18
+ sortable: SortableModule;
19
+ /** Overrides the plain `attribute`-ascending order for composite orders
20
+ * — e.g. a row's true resting position depends first on a related
21
+ * record's own order, and only then on this row's `attribute`. Takes
22
+ * full ownership of row order while reorder is active (column-header
23
+ * sorting is unavailable, same as the plain `attribute` case). */
24
+ compare?: (a: T, b: T) => number;
25
+ /** POSTed once per drag that settles with at least one changed row — a
26
+ * single request, not one per row — then the list is refreshed. FormData
27
+ * field `changes` carries a JSON-encoded array of `{ id, value }` pairs,
28
+ * one per row whose `attribute` changed (`value` being its new
29
+ * sequential position). Provide this or `callback`. */
30
+ endpoint?: string;
31
+ /** Alternative to `endpoint`: receives the rows whose `attribute` value
32
+ * changed, already updated to their new index. */
33
+ callback?: (items: T[]) => void | Promise<void>;
34
+ /** Drag-handle icon shown at the start of each row. Falls back to the
35
+ * active icon set's `grip` icon. */
36
+ icon?: any;
37
+ /** Lets dragging one row of the current checkbox selection move the
38
+ * whole selection together, via SortableJS's `MultiDrag` plugin (must be
39
+ * mounted on the `sortable` module you pass in). Off by default. */
40
+ multiDrag?: boolean;
41
+ /** While dragging, hovering over the edge zone for this long flips a
42
+ * page instead of requiring one long drag across the whole list.
43
+ * Default `2000`. */
44
+ pageFlipThresholdMs?: number;
45
+ }
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "runeforge",
3
- "version": "0.0.57",
3
+ "version": "0.0.59",
4
4
  "description": "SvelteKit toolkit for building metadata-driven CRUD interfaces with tables, forms, and actions",
5
5
  "license": "MIT",
6
6
  "author": "Ezequiel Puerta",
File without changes