@itrocks/list 0.13.4 → 0.16.3

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/README.md CHANGED
@@ -152,11 +152,12 @@ missing representative fields fail explicitly. Plural paths through a relationsh
152
152
  are refused before SQL.
153
153
 
154
154
  Direct collections display representative values separated by commas. A collection decorated with
155
- [`@Component()`](https://github.com/itrocks-ts/composition) uses its structured table output. The optional
156
- `@MultipleOutput('commas' | 'lines')` property decorator from `@itrocks/list/multiple-output` overrides this default.
157
- `'lines'` displays ordinary collections as a list and keeps component collections as a table. `'commas'` displays
158
- representative values on one line, including for components. `multipleOutputOf(type, property)` returns the effective
159
- mode and inherits explicit property metadata. For example:
155
+ [`@Component()`](https://github.com/itrocks-ts/composition) displays up to eight representative values separated by
156
+ commas. From nine values, it displays the count followed by the translated plural name of the destination type.
157
+ Component collections never render a nested table in a list cell. The optional
158
+ `@MultipleOutput('commas' | 'lines')` property decorator from `@itrocks/list/multiple-output` controls ordinary
159
+ collections; `'lines'` displays them as a list.
160
+ `multipleOutputOf(type, property)` returns the effective mode and inherits explicit property metadata. For example:
160
161
 
161
162
  ```ts
162
163
  import { MultipleOutput } from '@itrocks/list/multiple-output'
@@ -184,16 +185,35 @@ the dependency hook. The configured data source remains responsible for storage
184
185
  `GET /<business-route>/list?column=<path>&rowIds=<comma-separated-identifiers>` uses the HTML action and returns a JSON
185
186
  column descriptor with rendered cells keyed by root id. It intersects visible ids with the current filters and mandatory
186
187
  scope, makes one projection and performs no count. Invalid selections return 400. Full entity JSON remains available
187
- through `/list/json`. Column configuration saves use the established `columns` parameter and return 204.
188
+ through `/list/json`. Adding `columns=<ordered-paths>` saves the column configuration in the same request.
189
+ Configuration-only requests return 204. The browser serialises both kinds of request to preserve the latest order.
188
190
 
189
191
  The browser entry `@itrocks/list/property-select.js` exports `ListPropertySelect`, with explicit metadata, table
190
192
  addition, column persistence and narrow pane ports. The framework mounts it only on compatible lists and disposes it on
191
- navigation. It reserves pending paths, confirms accepted additions, reveals/highlights duplicates without moving focus,
192
- and checks row identity before insertion. Failed selection leaves the context intact. It loads only currently visible
193
- row ids; changing the row view while loading rejects the obsolete response with a retry message. Click requests await
194
- their data before committing a new column. Desktop drags create immediate placeholder columns through the public
195
- table external transaction. The header contains each
196
- label and its filter together, so it uses the table addition plugin's single-header contract.
193
+ navigation. It reserves pending paths and confirms accepted additions. The checkbox, its cell and the property name
194
+ toggle terminal and relation columns. The checkbox clears immediately before the red removal flash. Reselecting during that flash cancels removal,
195
+ checks the property again and highlights the retained column green, then saves the restored configuration.
196
+ The removal configuration is sent at the initial click, independently of the animation; deleting the cells sends no
197
+ additional request.
198
+ After a completed removal, a later click returns the column immediately right of its former left neighbour, or left of its former right neighbour if the left one is absent. If neither remains,
199
+ it is appended. Neighbours are kept only in this pane instance's memory and cleared on folding, closure or disposal;
200
+ they never enter session state. Drag placement continues to follow the drop position.
201
+ An explicit addition intention always requests addition: an existing column is revealed and highlighted green without removal.
202
+ Property names and checkbox cells toggle the same selection; chevrons and intermediate path segments navigate.
203
+ The consumer checks row identity before insertion. Failed selection leaves the context intact. It loads only currently
204
+ visible row ids through the current feed position; changing the row view while loading rejects the obsolete response with a
205
+ discreet red background. Clicks commit the translated full-path heading and filter locally, before any server response.
206
+ One asynchronous request
207
+ then saves the column order and loads the values; there is no separate admission request. A new drag calls the same
208
+ addition code as a click with `{ effects: false, hidden: true }`, then moves the committed column through the standard
209
+ table reorder operation with `{ adding: true, removal: true }`. Its combined request loads values immediately while
210
+ cells remain hidden, without width animation, flash or automatic scroll. On first pointer entry, the column appears
211
+ with any values already received and uses a green background and plus indicator. An outside drop deletes it through
212
+ the standard header-origin removal and saves once, even if the pointer never entered. Cancelling a new addition also
213
+ removes it. Dropping inside saves only a changed column order; it never reloads values.
214
+ The optional `request(query, signal)` port shares the list persistence queue.
215
+ Existing-column moves and removals only save the column configuration. The header contains each label and its filter
216
+ together, so it uses the table addition plugin's single-header contract.
197
217
 
198
218
  `npm test` runs the server contracts; `test/property-select.test.mjs` covers projection, representation, scope, path
199
219
  configuration, filters and ordering. Real framework/browser proof is tracked by the property-select L2-LIST delivery.
@@ -212,21 +232,25 @@ do not affect it. The rendered article supplies this opaque key to the browser.
212
232
  Writes echo the opaque `X-Property-Select-Session` token returned by a read. It cannot identify or authenticate a user;
213
233
  it prevents a mounted selector from writing its old state into a new session.
214
234
 
235
+ The initial HTML response carries the configured selector bootstrap, including metadata, template, state revision
236
+ and session generation. Mounting consumes this snapshot without application requests or state writes. Metadata is
237
+ shared by navigation, suggestions and selection; unchanged column paths do not rebuild suggestions.
238
+
215
239
  The public browser `@itrocks/list/selector-state.js` exports `HttpStateStore`, using same-origin credentials and
216
- no-store requests. `ListSelectorOptions.advice` supplies configured destinations. List column changes refresh used
217
- paths; only a confirmed new addition feeds the selector's recents. The browser displays recoverable persistence errors.
240
+ no-store requests. Its optional third constructor argument `{ generation, key, record }` supplies the initial read;
241
+ subsequent reads, including conflict recovery, use the server. `ListSelectorOptions.advice` supplies configured
242
+ destinations. List column changes refresh used paths; only a confirmed new addition feeds the selector's recents.
243
+ The browser displays recoverable persistence errors.
218
244
 
219
245
  ## External column transport
220
246
 
221
- The list consumer supplies immediate cells, authorises admission and loads the current visible ids through the same
222
- projection/rendering route used for click additions. `validate=1` on a `column` request checks representation and
223
- permission without selecting records; it prevents unsupported object and nested plural paths from being confirmed
224
- on drop.
225
- Admission is independent of the optional values request. A slow or failed values request leaves valid drops accepted;
226
- failed cells expose `Retry values` without another addition or recent entry.
247
+ The list consumer supplies cells containing a non-breaking space and loads all currently loaded row ids through
248
+ one combined configuration/projection request after the local commit. A failed values request leaves the column
249
+ in place, with a discreet red background on its data cells. The spaces remain; no error text, retry button or automatic
250
+ retry is added. The translated full path comes from the selector's displayed row and available branch metadata.
227
251
 
228
- Pending paths and the active drag are reserved before asynchronous work. Used paths retain their committed order
229
- throughout the drag, and configuration saves exclude provisional cells. New accepted drops feed recents; moves and
252
+ Pending paths and the active drag are reserved before asynchronous work. Used paths include the new column immediately
253
+ and retain their committed order throughout the drag. New accepted drops feed recents; moves and
230
254
  cancellations do not. Row-view changes and view disposal cancel transport. The desktop pane stays open, and capture is
231
255
  owned by the selector's surviving source controller. The consumer imports no home implementation, SQL or hydration code.
232
256
 
@@ -234,3 +258,17 @@ The consumer requests `pane.suspend({ mobileOnly: true })` only when a source ge
234
258
  host owns its responsive breakpoint. The token is restored after acceptance and column persistence, or after
235
259
  cancellation/rejection; it never focuses the search field. View disposal removes the registration and invalidates late
236
260
  restoration. Custom pane adapters may implement the same optional suspension argument without importing `home`.
261
+
262
+ `node test/browser-requests.mjs` checks request counts and real mouse gestures in Chromium with synthetic HTTP data.
263
+ It covers initial mount, click placeholders, hidden drag additions, values for 80 loaded rows before entry or drop,
264
+ green addition indicators, outside removal before and after entry, terminal toggles and reordering.
265
+ `node test/browser-removal-cancel.mjs` checks immediate unchecking and cancellation during the red flash through
266
+ checkbox, cell and name clicks, for terminal and relation columns, with an immediate removal save followed by a restored configuration save.
267
+ `node test/browser-column-positions.mjs` checks neighbour-based reinsertion in the real table, both fallbacks,
268
+ and memory expiry on closure, including closure during a pending removal. It starts its own synthetic HTTP fixture.
269
+ Set `PS_PLAYWRIGHT_MODULE` to an installed Playwright module when using a different runtime.
270
+
271
+ `node test/browser-toggle.mjs` exercises the real framework list against the synthetic recipe database on port 13316
272
+ (`PS_DATABASE_PORT` overrides it). It starts and stops its own application instance and checks desktop keyboard, touch,
273
+ reduced motion, horizontal reveal, removal and temporary-row transitions. `PS_TOGGLE_URL` reuses an existing instance
274
+ of that recipe instead. The synthetic database must already be running; this test never resets it.
package/build.js CHANGED
@@ -11,24 +11,27 @@ import { tableByElement } from '@itrocks/table/table.js';
11
11
  import { xTargetCall } from '@itrocks/xtarget/xtarget.js';
12
12
  build('article[data-action="list"] > form > table.objects', table => {
13
13
  let saving = Promise.resolve();
14
- const saveColumns = () => {
14
+ const request = (query, signal) => {
15
+ const form = table.closest('form');
16
+ const result = saving.then(() => fetch(`${form.action}?${query}`, { keepalive: true, signal }));
17
+ saving = result.then(() => { }, () => { });
18
+ return result;
19
+ };
20
+ const saveColumns = (paths) => {
15
21
  const columns = table.tHead?.rows[0].querySelectorAll(':scope > th[data-property]:not(.column-add-provisional)');
16
22
  const form = table.closest('form');
17
23
  if (!columns || !form)
18
24
  return Promise.resolve();
19
- const properties = Array.from(columns, column => encodeURIComponent(column.dataset.property ?? ''));
20
- const url = form.action + '?columns=' + properties.join(',');
21
- saving = saving.catch(() => { }).then(async () => {
22
- const response = await fetch(url, { keepalive: true });
25
+ const properties = paths ?? Array.from(columns, column => column.dataset.property ?? '');
26
+ return request(new URLSearchParams({ columns: properties.join(',') })).then(response => {
23
27
  if (!response.ok)
24
28
  throw new Error('Unable to save columns');
25
29
  });
26
- return saving;
27
30
  };
28
31
  const tableColumnReorder = new TableColumnReorder({
29
32
  isReorderable: header => header.dataset.property !== undefined,
30
- onRemove: saveColumns,
31
- onReorder: saveColumns
33
+ onRemove: () => saveColumns(),
34
+ onReorder: () => saveColumns()
32
35
  });
33
36
  const tableLink = new TableLink({
34
37
  call: url => xTargetCall(url, 'main'),
@@ -46,7 +49,7 @@ build('article[data-action="list"] > form > table.objects', table => {
46
49
  ]
47
50
  });
48
51
  table.dispatchEvent(new CustomEvent('itrocks:list-ready', {
49
- bubbles: true, detail: { addition, instance, saveColumns }
52
+ bubbles: true, detail: { addition, instance, request, saveColumns }
50
53
  }));
51
54
  table.addEventListener('click', event => {
52
55
  const element = event.target;
package/cjs/access.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import { Request } from '@itrocks/action-request';
2
+ import type { StateRecord } from '@itrocks/property-select';
2
3
  export type ListAccess = {
3
4
  authorise(path: string): Promise<void>;
5
+ bootstrap?(paths: string[], state: StateRecord): Promise<object>;
4
6
  root?: string;
5
7
  };
6
8
  export type ListDependencies = {
package/cjs/access.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"access.js","sourceRoot":"","sources":["../src/access.ts"],"names":[],"mappings":";;AAUA,sCAGC;AAED,gCAGC;AAVD,MAAM,YAAY,GAAqB,EAAE,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC,EAAE,CAAC,EAAE,CAAA;AAE9F,SAAgB,aAAa,CAAC,SAAoC;IAEjE,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,SAAS,CAAC,CAAA;AACvC,CAAC;AAED,SAAgB,UAAU,CAAC,OAAgB;IAE1C,OAAO,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;AACpC,CAAC"}
1
+ {"version":3,"file":"access.js","sourceRoot":"","sources":["../src/access.ts"],"names":[],"mappings":";;AAYA,sCAGC;AAED,gCAGC;AAVD,MAAM,YAAY,GAAqB,EAAE,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC,EAAE,CAAC,EAAE,CAAA;AAE9F,SAAgB,aAAa,CAAC,SAAoC;IAEjE,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,SAAS,CAAC,CAAA;AACvC,CAAC;AAED,SAAgB,UAAU,CAAC,OAAgB;IAE1C,OAAO,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;AACpC,CAAC"}
package/cjs/list.html CHANGED
@@ -15,7 +15,7 @@
15
15
 
16
16
  <!--#main-->
17
17
  <article data-action="list" data-class="{type.name}" data-route="{type.@route}" data-property-root="{?root}"
18
- data-selector-key="{?selectorKey}">
18
+ data-selector-key="{?selectorKey}" data-selector-bootstrap="{?selectorBootstrap}">
19
19
  <header>
20
20
  <h2>{type.@output.ucFirst} list</h2>
21
21
  <button class="add-column" hidden type="button" aria-label="Add column">+</button>
package/cjs/list.js CHANGED
@@ -52,11 +52,12 @@ const persist_1 = require("./persist");
52
52
  const persist_2 = require("./persist");
53
53
  const projection_1 = require("./projection");
54
54
  const selector_state_1 = require("./selector-state");
55
+ const selector_state_2 = require("./selector-state");
55
56
  const sort_1 = require("./sort");
56
57
  var access_2 = require("./access");
57
58
  Object.defineProperty(exports, "listDependsOn", { enumerable: true, get: function () { return access_2.listDependsOn; } });
58
59
  let List = (() => {
59
- let _classDecorators = [(0, action_3.Need)('Store', 'new'), (0, route_1.Route)('/list')];
60
+ let _classDecorators = [(0, action_2.Need)('Store', 'new'), (0, route_1.Route)('/list')];
60
61
  let _classDescriptor;
61
62
  let _classExtraInitializers = [];
62
63
  let _classThis;
@@ -88,7 +89,7 @@ let List = (() => {
88
89
  for (const field of column.fields ?? [])
89
90
  await access.authorise(`${column.name}.${field}`);
90
91
  }
91
- if (request.request.data.columns !== undefined) {
92
+ if (request.request.data.columns !== undefined && typeof request.request.data.column !== 'string') {
92
93
  (0, persist_2.save)(this, request.request, type);
93
94
  return this.htmlResponse('', 204);
94
95
  }
@@ -116,7 +117,7 @@ let List = (() => {
116
117
  const ids = request.request.data.rowIds;
117
118
  if (typeof ids !== 'string')
118
119
  throw new Error('Visible row identities are required');
119
- const result = await (0, columns_2.projectColumns)(type, [column], search, [new storage_2.Identifiers(ids ? ids.split(',') : [])]);
120
+ const result = await (0, columns_2.projectColumns)(type, [column], search, [new storage_1.Identifiers(ids ? ids.split(',') : [])]);
120
121
  return this.jsonResponse({
121
122
  label: column.label, path, sortable: column.sortable,
122
123
  rows: await Promise.all(result.rows.map(async (row) => ({
@@ -125,7 +126,7 @@ let List = (() => {
125
126
  });
126
127
  }
127
128
  catch (error) {
128
- const message = error instanceof storage_3.SelectionError && error.code === 'multiple-values'
129
+ const message = error instanceof storage_2.SelectionError && error.code === 'multiple-values'
129
130
  ? 'This path has multiple values and cannot be displayed as a column.'
130
131
  : error instanceof Error ? error.message : 'Column unavailable';
131
132
  return this.jsonResponse({ error: message }, 400);
@@ -135,19 +136,25 @@ let List = (() => {
135
136
  if (feed.offset) {
136
137
  return this.htmlTemplateResponse({ objects, type }, request, feed.template);
137
138
  }
138
- const count = await (0, storage_1.dataSource)().count(type, search);
139
+ const count = await (0, storage_3.dataSource)().count(type, search);
139
140
  const route = (0, route_2.routeOf)(this);
140
141
  const generalActions = [];
141
142
  const selectionActions = [];
142
- for (const action of (0, action_2.getActions)(type, route.slice(route.lastIndexOf('/') + 1))) {
143
+ for (const action of (0, action_3.getActions)(type, route.slice(route.lastIndexOf('/') + 1))) {
143
144
  const actions = (action.need === 'object') ? selectionActions : generalActions;
144
145
  actions.push(action);
145
146
  }
147
+ let selectorBootstrap;
148
+ if (access.bootstrap) {
149
+ const state = await (0, selector_state_1.selectorStateBootstrap)(request);
150
+ const metadata = await access.bootstrap([...columns].map(column => column.name), state.record);
151
+ selectorBootstrap = encodeURIComponent(JSON.stringify({ ...state, ...metadata }));
152
+ }
146
153
  return this.htmlTemplateResponse({ columns, count, generalActions, objects, root: access.root, search: filter.search,
147
- selectionActions, selectorKey: (0, selector_state_1.selectorStateKey)(request), type }, request, __dirname + '/list.html');
154
+ selectionActions, selectorBootstrap, selectorKey: (0, selector_state_2.selectorStateKey)(request), type }, request, __dirname + '/list.html');
148
155
  }
149
156
  async json(request, scope) {
150
- const objects = await (0, storage_1.dataSource)().search(request.type, scope);
157
+ const objects = await (0, storage_3.dataSource)().search(request.type, scope);
151
158
  return this.jsonResponse(objects);
152
159
  }
153
160
  };
package/cjs/list.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"list.js","sourceRoot":"","sources":["../src/list.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../src/list.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MultipleOutput = MultipleOutput;
4
4
  exports.multipleOutputOf = multipleOutputOf;
5
- const composition_1 = require("@itrocks/composition");
6
5
  const property_1 = require("@itrocks/decorator/property");
7
6
  const property_2 = require("@itrocks/decorator/property");
8
7
  const MULTIPLE_OUTPUT = Symbol('multiple-output');
@@ -10,7 +9,6 @@ function MultipleOutput(mode) {
10
9
  return (0, property_1.decorate)(MULTIPLE_OUTPUT, mode);
11
10
  }
12
11
  function multipleOutputOf(target, property) {
13
- return (0, property_2.decoratorOf)(target, property, MULTIPLE_OUTPUT)
14
- ?? ((0, composition_1.componentOf)(target, property) ? 'lines' : 'commas');
12
+ return (0, property_2.decoratorOf)(target, property, MULTIPLE_OUTPUT) ?? 'commas';
15
13
  }
16
14
  //# sourceMappingURL=multiple-output.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"multiple-output.js","sourceRoot":"","sources":["../src/multiple-output.ts"],"names":[],"mappings":";;AASA,wCAGC;AAED,4CAIC;AAjBD,sDAAmD;AACnD,0DAA0D;AAC1D,0DAA0D;AAI1D,MAAM,eAAe,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAA;AAEjD,SAAgB,cAAc,CAAmB,IAAwB;IAExE,OAAO,IAAA,mBAAQ,EAAI,eAAe,EAAE,IAAI,CAAC,CAAA;AAC1C,CAAC;AAED,SAAgB,gBAAgB,CAAmB,MAAuB,EAAE,QAAiB;IAE5F,OAAO,IAAA,sBAAW,EAAoC,MAAM,EAAE,QAAQ,EAAE,eAAe,CAAC;WACpF,CAAC,IAAA,yBAAW,EAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAA;AACzD,CAAC"}
1
+ {"version":3,"file":"multiple-output.js","sourceRoot":"","sources":["../src/multiple-output.ts"],"names":[],"mappings":";;AAQA,wCAGC;AAED,4CAGC;AAfD,0DAA0D;AAC1D,0DAA0D;AAI1D,MAAM,eAAe,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAA;AAEjD,SAAgB,cAAc,CAAmB,IAAwB;IAExE,OAAO,IAAA,mBAAQ,EAAI,eAAe,EAAE,IAAI,CAAC,CAAA;AAC1C,CAAC;AAED,SAAgB,gBAAgB,CAAmB,MAAuB,EAAE,QAAiB;IAE5F,OAAO,IAAA,sBAAW,EAAoC,MAAM,EAAE,QAAQ,EAAE,eAAe,CAAC,IAAI,QAAQ,CAAA;AACrG,CAAC"}
@@ -17,6 +17,7 @@ export declare class ListColumn {
17
17
  readonly multiple: boolean;
18
18
  readonly property: ReturnType<typeof resolvePropertyPath>['property'];
19
19
  readonly sortable: boolean;
20
+ readonly target?: Type;
20
21
  reverse: boolean;
21
22
  search: string;
22
23
  sort?: number;
package/cjs/projection.js CHANGED
@@ -5,6 +5,7 @@ exports.listRepresentationDependsOn = listRepresentationDependsOn;
5
5
  exports.representationFields = representationFields;
6
6
  const class_view_1 = require("@itrocks/class-view");
7
7
  const class_view_2 = require("@itrocks/class-view");
8
+ const class_view_3 = require("@itrocks/class-view");
8
9
  const composition_1 = require("@itrocks/composition");
9
10
  const core_transformers_1 = require("@itrocks/core-transformers");
10
11
  const core_transformers_2 = require("@itrocks/core-transformers");
@@ -29,7 +30,7 @@ function representationFields(type, ancestors = [], property) {
29
30
  const fields = dependencies.fields?.(type, branch, property);
30
31
  if (!fields && property && (0, transformer_4.resolveTransformer)(property.class.type, property.name, transformer_2.HTML, transformer_3.OUTPUT) !== core_transformers_2.storeOutput)
31
32
  throw new storage_1.SelectionError('unsupported-selection', 'Undeclared custom object representation');
32
- return (fields ?? (0, class_view_1.representativeOf)(type).map(String)).flatMap(path => {
33
+ return (fields ?? (0, class_view_2.representativeOf)(type).map(String)).flatMap(path => {
33
34
  const resolved = (0, reflect_path_2.resolvePropertyPath)(type, path);
34
35
  if (resolved.targetMultiplicity !== 'one')
35
36
  throw new storage_1.SelectionError('unsupported-selection', path);
@@ -46,6 +47,7 @@ class ListColumn {
46
47
  multiple;
47
48
  property;
48
49
  sortable;
50
+ target;
49
51
  reverse = false;
50
52
  search = '';
51
53
  sort;
@@ -60,6 +62,7 @@ class ListColumn {
60
62
  throw new storage_1.SelectionError(resolved.targetMultiplicity === 'many' ? 'multiple-values' : 'unsupported-selection', name);
61
63
  }
62
64
  this.property = new reflect_path_1.ReflectPropertyPath(root, name);
65
+ this.target = resolved.target;
63
66
  this.label = resolved.segments.map(property => (0, translate_1.tr)((0, property_view_1.displayOf)(property.class.type, property.name))).join('.');
64
67
  if (resolved.target && !this.multiple)
65
68
  this.fields = representationFields(resolved.target, [], resolved.property);
@@ -71,11 +74,18 @@ class ListColumn {
71
74
  return '<span class="unavailable">Unavailable</span>';
72
75
  if (this.fields && this.fields.some(field => !cell.loadedFields?.includes(field)))
73
76
  throw new storage_1.SelectionError('unsupported-selection', this.name);
74
- const mode = this.multiple ? (0, multiple_output_1.multipleOutputOf)(this.property.class.type, this.property.name) : undefined;
75
- if (this.multiple && (mode === 'commas')
76
- && (0, composition_1.componentOf)(this.property.class.type, this.property.name)) {
77
- return (await Promise.all(cell.value.map(class_view_2.representativeValueOf))).sort().join(', ');
77
+ if (this.multiple && (0, composition_1.componentOf)(this.property.class.type, this.property.name)) {
78
+ const values = cell.value;
79
+ if (values.length >= 9) {
80
+ const name = this.target
81
+ ? (0, class_view_1.displayOf)(this.target)
82
+ : (0, property_view_1.displayOf)(this.property.class.type, this.property.name);
83
+ const plural = name.endsWith('y') ? name.slice(0, -1) + 'ies' : name + 's';
84
+ return `${values.length} ${(0, translate_1.tr)(plural)}`;
85
+ }
86
+ return (await Promise.all(values.map(class_view_3.representativeValueOf))).sort().join(', ');
78
87
  }
88
+ const mode = this.multiple ? (0, multiple_output_1.multipleOutputOf)(this.property.class.type, this.property.name) : undefined;
79
89
  const lines = this.multiple && (mode === 'lines');
80
90
  return await (0, transformer_1.applyTransformer)(cell.value, this.property.class.type, this.property.name, transformer_2.HTML, transformer_3.OUTPUT, new core_transformers_1.HtmlContainer(false, !this.multiple || lines));
81
91
  }
@@ -1 +1 @@
1
- {"version":3,"file":"projection.js","sourceRoot":"","sources":["../src/projection.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"projection.js","sourceRoot":"","sources":["../src/projection.ts"],"names":[],"mappings":"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"}
@@ -8,6 +8,10 @@ export declare function listStateDependsOn(dependencies: {
8
8
  }): void;
9
9
  /** Keep all router-resolved identity segments; format and query are presentation parameters. */
10
10
  export declare function selectorStateKey(request: Request): string;
11
+ export declare function selectorStateBootstrap(request: Request): Promise<{
12
+ generation: string;
13
+ record: StateRecord;
14
+ }>;
11
15
  export declare class SessionStateStore {
12
16
  private readonly session;
13
17
  private readonly run;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SelectorStateAction = exports.SessionStateStore = void 0;
4
4
  exports.listStateDependsOn = listStateDependsOn;
5
5
  exports.selectorStateKey = selectorStateKey;
6
+ exports.selectorStateBootstrap = selectorStateBootstrap;
6
7
  const action_1 = require("@itrocks/action");
7
8
  const action_request_1 = require("@itrocks/action-request");
8
9
  const property_select_1 = require("@itrocks/property-select");
@@ -18,6 +19,15 @@ function listStateDependsOn(dependencies) {
18
19
  function selectorStateKey(request) {
19
20
  return request.route + (request.ids.length ? '/' + request.ids.join(',') : '') + '/' + request.action;
20
21
  }
22
+ function selectorStateBootstrap(request) {
23
+ return transaction(request.request.session, data => {
24
+ data.propertySelectGeneration ??= (0, node_crypto_1.randomUUID)();
25
+ return {
26
+ generation: data.propertySelectGeneration,
27
+ record: structuredClone(data.propertySelect?.[selectorStateKey(request)] ?? { revision: 0 })
28
+ };
29
+ });
30
+ }
21
31
  class SessionStateStore {
22
32
  session;
23
33
  run;
@@ -1 +1 @@
1
- {"version":3,"file":"selector-state.js","sourceRoot":"","sources":["../src/selector-state.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"selector-state.js","sourceRoot":"","sources":["../src/selector-state.ts"],"names":[],"mappings":"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"}
package/list.css CHANGED
@@ -41,7 +41,7 @@ table.objects tr td, table.objects tr th {
41
41
  padding: 0.6em;
42
42
  white-space: nowrap;
43
43
  }
44
- table.objects tr td:last-child, table.objects tr th:last-child {
44
+ table.objects tr td:nth-last-child(1 of :not([hidden])), table.objects tr th:nth-last-child(1 of :not([hidden])) {
45
45
  border-right: 1px solid #d8d8d8;
46
46
  }
47
47
  table.objects tr.properties > .select > input[name=select] {
@@ -51,7 +51,7 @@ table.objects > * > tr > .column-reorder {
51
51
  --column-reorder-tint: inset 0 0 0 100vmax rgb(0 0 0 / 2%);
52
52
  box-shadow: var(--column-reorder-tint);
53
53
  }
54
- table.objects > * > tr > .column-reorder.column-add-provisional {
54
+ table.objects > * > tr > .column-reorder.adding {
55
55
  --column-reorder-tint: inset 0 0 0 100vmax rgb(47 137 67 / 5%);
56
56
  }
57
57
  table.objects > * > tr > .column-reorder.moving {
@@ -84,10 +84,10 @@ table.objects > tbody:first-child > tr:nth-child(odd) > td {
84
84
  table.objects > thead > tr.properties > th {
85
85
  user-select: none;
86
86
  }
87
- table.objects > thead > tr.properties > th.moving, table.objects > thead > tr.properties > th.removing {
87
+ table.objects > thead > tr.properties > th.adding, table.objects > thead > tr.properties > th.moving, table.objects > thead > tr.properties > th.removing {
88
88
  z-index: 2;
89
89
  }
90
- table.objects > thead > tr.properties > th.moving::before, table.objects > thead > tr.properties > th.removing::before, table.objects > thead > tr.properties > th.column-add-provisional.column-reorder::before {
90
+ table.objects > thead > tr.properties > th.adding::before, table.objects > thead > tr.properties > th.moving::before, table.objects > thead > tr.properties > th.removing::before {
91
91
  content: "";
92
92
  display: inline-block;
93
93
  height: 1em;
@@ -108,7 +108,7 @@ table.objects > thead > tr.properties > th.removing::before {
108
108
  background: #d51d2c;
109
109
  mask-image: url("column-remove.svg");
110
110
  }
111
- table.objects > thead > tr.properties > th.column-add-provisional.column-reorder::before {
111
+ table.objects > thead > tr.properties > th.adding::before {
112
112
  background: #2f8943;
113
113
  mask-image: url("column-add.svg");
114
114
  }
package/package.json CHANGED
@@ -93,5 +93,5 @@
93
93
  "build:front": "tsc -p src/front/tsconfig.json",
94
94
  "test": "npm run build:cjs && node --test \"test/**/*.test.mjs\""
95
95
  },
96
- "version": "0.13.4"
96
+ "version": "0.16.3"
97
97
  }
@@ -1,8 +1,8 @@
1
1
  import { PropertySelectView } from '@itrocks/property-select/front/property-select.js';
2
2
  import type { ConsumerPort } from '@itrocks/property-select/property-select.js';
3
3
  import type { MetadataProvider } from '@itrocks/property-select/property-select.js';
4
- import type { PointerSample } from '@itrocks/property-select/property-select.js';
5
4
  import type { Outcome } from '@itrocks/property-select/property-select.js';
5
+ import type { PointerSample } from '@itrocks/property-select/property-select.js';
6
6
  import type { SelectionIntent } from '@itrocks/property-select/property-select.js';
7
7
  import { TableColumnAdd } from '@itrocks/table/column-add.js';
8
8
  export type PaneHandle = {
@@ -25,7 +25,8 @@ export type ListSelectorOptions = {
25
25
  addition: TableColumnAdd;
26
26
  metadata: MetadataProvider;
27
27
  mountSelector(content: HTMLElement, title: string): PaneHandle;
28
- saveColumns(): Promise<void>;
28
+ request?(query: URLSearchParams, signal: AbortSignal): Promise<Response>;
29
+ saveColumns(paths?: readonly string[]): Promise<void>;
29
30
  templateUrl?: string;
30
31
  };
31
32
  export declare class ListPropertySelect implements ConsumerPort {
@@ -33,22 +34,28 @@ export declare class ListPropertySelect implements ConsumerPort {
33
34
  private readonly options;
34
35
  private readonly abort;
35
36
  private readonly button;
37
+ private readonly content;
36
38
  private disposed;
37
39
  private drag?;
38
40
  private readonly observer;
39
41
  private readonly pane;
40
42
  private readonly pending;
43
+ private readonly removals;
44
+ private removedColumns;
45
+ private readonly unsubscribePane;
41
46
  readonly view: PropertySelectView;
42
47
  constructor(article: HTMLElement, options: ListSelectorOptions);
43
48
  private loadColumn;
44
49
  private add;
45
50
  begin(intent: SelectionIntent, sample: PointerSample): void;
51
+ private columnSource;
46
52
  cancel(id: string): void;
47
- private previewError;
53
+ private displayedPaths;
48
54
  dispose(): void;
49
55
  end(id: string, sample: PointerSample): Promise<Outcome>;
50
56
  mount(): Promise<boolean>;
51
57
  move(id: string, sample: PointerSample): void;
52
58
  paths(): string[];
59
+ private remove;
53
60
  select(intent: SelectionIntent, signal: AbortSignal): Promise<Outcome>;
54
61
  }
@@ -6,23 +6,36 @@ export class ListPropertySelect {
6
6
  options;
7
7
  abort = new AbortController();
8
8
  button;
9
+ content = document.createElement('div');
9
10
  disposed = false;
10
11
  drag;
11
12
  observer;
12
13
  pane;
13
14
  pending = new Map();
15
+ removals = new Map();
16
+ removedColumns = new Map();
17
+ unsubscribePane;
14
18
  view;
15
19
  constructor(article, options) {
16
20
  this.article = article;
17
21
  this.options = options;
18
- const content = document.createElement('div');
22
+ const content = this.content;
19
23
  this.button = article.querySelector('.add-column');
20
- this.pane = options.mountSelector(content, 'Add columns');
24
+ const initial = article.dataset.selectorBootstrap
25
+ ? JSON.parse(decodeURIComponent(article.dataset.selectorBootstrap)) : undefined;
26
+ const translate = (text) => initial?.translations?.[text] ?? text;
27
+ this.pane = options.mountSelector(content, translate('Add columns'));
28
+ this.unsubscribePane = this.pane.subscribe(state => {
29
+ if (!state.open || !state.present)
30
+ this.removedColumns = new Map();
31
+ });
21
32
  this.view = new PropertySelectView(content, {
22
33
  consumer: this, metadata: options.metadata, root: article.dataset.propertyRoot,
23
34
  advice: options.advice, stateKey: article.dataset.selectorKey, stateMode: 'session',
24
- stateStore: new HttpStateStore(), usedPaths: this.paths()
25
- }, { templateUrl: options.templateUrl });
35
+ stateStore: new HttpStateStore(undefined, undefined, initial && {
36
+ ...initial, key: article.dataset.selectorKey
37
+ }), translate, usedPaths: this.paths()
38
+ }, { template: initial?.template, templateUrl: options.templateUrl });
26
39
  this.observer = new MutationObserver(records => {
27
40
  if (this.drag && records.some(record => record.target.tagName === 'TBODY'))
28
41
  this.view.selector.cancel(this.drag.intent.id, 'row view changed');
@@ -37,10 +50,11 @@ export class ListPropertySelect {
37
50
  const table = this.article.querySelector('table.objects');
38
51
  const rows = [...table.tBodies[0].rows];
39
52
  const ids = rows.map(row => row.querySelector('input[name=id]').value);
40
- const query = new URLSearchParams({ column: path, rowIds: ids.join(',') });
41
- const response = await fetch(`${form.action}?${query}`, {
42
- signal: AbortSignal.any([signal, this.abort.signal])
43
- });
53
+ const query = new URLSearchParams({ column: path, columns: this.paths().join(','), rowIds: ids.join(',') });
54
+ const combined = AbortSignal.any([signal, this.abort.signal]);
55
+ const response = this.options.request
56
+ ? await this.options.request(query, combined)
57
+ : await fetch(`${form.action}?${query}`, { signal: combined });
44
58
  const result = await response.json();
45
59
  if (!response.ok)
46
60
  throw new Error(result.error ?? 'Column unavailable');
@@ -60,6 +74,16 @@ export class ListPropertySelect {
60
74
  input.name = `search.${encodeURIComponent(path).replaceAll('.', '%2E')}`;
61
75
  input.dataset.propertyFilter = path;
62
76
  input.setAttribute('aria-label', `Filter ${result.label}`);
77
+ const previous = [...table.tHead.rows[0].cells].find(header => header.dataset.property === path);
78
+ const previousInput = previous?.querySelector('input[data-property-filter]');
79
+ input.value = previousInput?.value ?? '';
80
+ if (previousInput && document.activeElement === previousInput)
81
+ requestAnimationFrame(() => {
82
+ if (!input.isConnected || document.activeElement !== document.body)
83
+ return;
84
+ input.focus();
85
+ input.setSelectionRange(previousInput.selectionStart, previousInput.selectionEnd);
86
+ });
63
87
  header.append(result.label, input);
64
88
  const cells = ids.map(id => {
65
89
  const cell = document.createElement('td');
@@ -68,70 +92,94 @@ export class ListPropertySelect {
68
92
  });
69
93
  return { cells, header };
70
94
  }
71
- async add(path, signal) {
72
- const content = await this.loadColumn(path, signal);
73
- const outcome = await this.options.addition.add({ create: () => content, id: path });
74
- await this.options.saveColumns();
75
- this.view.selector.setConfiguration({ usedPaths: this.paths() });
76
- return outcome;
95
+ add(path, signal, options = {}) {
96
+ const source = this.columnSource(path);
97
+ const operation = this.options.addition.begin(source, options);
98
+ try {
99
+ signal.throwIfAborted();
100
+ if (this.disposed)
101
+ throw new Error('List disposed');
102
+ const position = this.removedColumns.get(path);
103
+ if (position) {
104
+ const headers = [...this.article.querySelectorAll('thead [data-property]:not(.column-add-provisional)')];
105
+ const left = headers.find(header => header.dataset.property === position.left);
106
+ const right = headers.find(header => header.dataset.property === position.right);
107
+ const anchor = left ?? right;
108
+ if (anchor) {
109
+ let index = anchor.cellIndex + (left ? 1 : 0);
110
+ if (operation.header.cellIndex < index)
111
+ index--;
112
+ operation.moveTo(index);
113
+ }
114
+ }
115
+ const outcome = operation.commit();
116
+ this.removedColumns.delete(path);
117
+ this.view.selector.setConfiguration({ usedPaths: this.paths() });
118
+ return outcome;
119
+ }
120
+ catch (error) {
121
+ operation.cancel();
122
+ throw error;
123
+ }
77
124
  }
78
125
  begin(intent, sample) {
79
126
  if (this.disposed || this.drag || this.pending.size)
80
127
  throw new Error('A column operation is pending');
81
128
  const path = normalisePath(intent.path);
82
- const paths = this.paths();
83
- const result = this.view.selector.search.results.find(result => result.property.path === path);
84
- const property = result?.property || this.view.selector.context?.properties.find(property => property.path === path);
85
- const label = result ? [...result.segments.map(segment => segment.label), result.property.label].join('.')
86
- : property?.label || path;
129
+ const added = !this.paths().includes(path);
87
130
  const suspension = this.pane.suspend({ mobileOnly: true });
88
131
  try {
89
- let provisionalHeader;
90
- const operation = this.options.addition.beginExternal({
91
- id: path,
92
- accept: async (signal) => {
93
- const form = this.article.querySelector('form');
94
- const query = new URLSearchParams({ column: path, validate: '1' });
95
- const response = await fetch(`${form.action}?${query}`, {
96
- signal: AbortSignal.any([signal, this.abort.signal])
97
- });
98
- const result = await response.json();
99
- if (!response.ok || result.path !== path)
100
- throw new Error(result.error ?? 'Column unavailable');
101
- if (provisionalHeader?.isConnected && result.label)
102
- provisionalHeader.textContent = result.label;
103
- },
104
- create: () => {
105
- const header = document.createElement('th');
106
- provisionalHeader = header;
107
- header.dataset.property = path;
108
- header.dataset.sortable = 'false';
109
- header.textContent = label;
110
- const cells = [...this.article.querySelectorAll('table.objects tbody tr')].map(() => {
111
- const cell = document.createElement('td');
112
- cell.textContent = 'Loading…';
113
- return cell;
114
- });
115
- return { cells, header };
116
- },
117
- load: async (signal) => {
118
- try {
119
- return await this.loadColumn(path, signal);
120
- }
121
- catch (error) {
122
- if (!this.disposed && !signal.aborted)
123
- this.previewError(path);
124
- throw error;
125
- }
126
- }
127
- }, sample);
128
- this.drag = { intent, operation, paths, restore: () => suspension.restore() };
132
+ if (added)
133
+ this.add(path, this.abort.signal, { effects: false, hidden: true });
134
+ const paths = this.paths();
135
+ const operation = this.options.addition.beginExternal(this.columnSource(path), sample, { adding: added, removal: true });
136
+ this.drag = { added, intent, operation, paths, restore: () => suspension.restore() };
129
137
  }
130
138
  catch (error) {
131
139
  suspension.restore();
132
140
  throw error;
133
141
  }
134
142
  }
143
+ columnSource(path) {
144
+ const selector = this.view.selector;
145
+ const row = this.content.querySelector(`.ps-property[data-path="${CSS.escape(path)}"]`);
146
+ const result = selector.search.results.find(result => result.property.path === path);
147
+ const properties = selector.branchContexts.flatMap(context => context.properties);
148
+ const label = row?.title || selector.usedProperties.find(property => property.path === path)?.label
149
+ || path.split('.').map((name, index, names) => {
150
+ const prefix = names.slice(0, index + 1).join('.');
151
+ return properties.find(property => property.path === prefix)?.label
152
+ || result?.segments.find(segment => segment.path === prefix)?.label
153
+ || (prefix === path ? result?.property.label || row?.querySelector('.ps-main')?.textContent : '') || name;
154
+ }).join('.');
155
+ return {
156
+ id: path,
157
+ create: () => {
158
+ const header = document.createElement('th');
159
+ header.dataset.property = path;
160
+ header.dataset.sortable = 'false';
161
+ header.textContent = label;
162
+ const input = document.createElement('input');
163
+ input.name = `search.${encodeURIComponent(path).replaceAll('.', '%2E')}`;
164
+ input.dataset.propertyFilter = path;
165
+ input.setAttribute('aria-label', `Filter ${label}`);
166
+ header.append(input);
167
+ const cells = [...this.article.querySelectorAll('table.objects tbody tr')]
168
+ .map(() => {
169
+ const cell = document.createElement('td');
170
+ cell.textContent = '\u00a0';
171
+ return cell;
172
+ });
173
+ return { cells, header };
174
+ },
175
+ load: async (signal) => {
176
+ // Commit the placeholder before reading the column configuration.
177
+ await Promise.resolve();
178
+ signal.throwIfAborted();
179
+ return this.loadColumn(path, signal);
180
+ }
181
+ };
182
+ }
135
183
  cancel(id) {
136
184
  if (this.drag?.intent.id !== id)
137
185
  return;
@@ -141,24 +189,10 @@ export class ListPropertySelect {
141
189
  drag.restore();
142
190
  this.view.selector.setConfiguration({ usedPaths: this.paths() });
143
191
  }
144
- previewError(path) {
145
- const header = [...this.article.querySelectorAll('thead [data-property]')]
146
- .find(header => header.dataset.property === path);
147
- if (!header)
148
- return;
149
- for (const row of this.article.querySelectorAll('tbody tr'))
150
- row.cells[header.cellIndex].textContent = 'Unable to load values';
151
- if (header.querySelector('.column-retry'))
152
- return;
153
- const retry = document.createElement('button');
154
- retry.type = 'button';
155
- retry.className = 'column-retry';
156
- retry.textContent = 'Retry values';
157
- retry.addEventListener('click', event => {
158
- event.stopPropagation();
159
- void this.options.addition.retry(path);
160
- }, { signal: this.abort.signal });
161
- header.append(retry);
192
+ displayedPaths() {
193
+ return [...this.article.querySelectorAll('thead [data-property]:not(.column-add-provisional)')]
194
+ .map(header => header.dataset.property)
195
+ .filter(path => !this.removals.has(path) || this.removals.get(path).signal.aborted);
162
196
  }
163
197
  dispose() {
164
198
  if (this.disposed)
@@ -168,20 +202,30 @@ export class ListPropertySelect {
168
202
  this.disposed = true;
169
203
  this.abort.abort();
170
204
  this.observer.disconnect();
205
+ this.unsubscribePane();
206
+ this.removedColumns.clear();
171
207
  this.view.dispose();
172
208
  this.pane.remove();
173
209
  this.options.addition.dispose();
174
210
  this.button.hidden = true;
175
211
  this.pending.clear();
212
+ for (const removal of this.removals.values())
213
+ removal.abort();
214
+ this.removals.clear();
176
215
  }
177
216
  async end(id, sample) {
178
217
  const drag = this.drag;
179
218
  if (!drag || drag.intent.id !== id)
180
219
  throw new Error('Unknown column transport');
181
220
  try {
182
- const status = await drag.operation.finish(sample);
183
- if (status !== 'cancelled')
184
- await this.options.saveColumns();
221
+ let status = await drag.operation.finish(sample);
222
+ if (status !== 'cancelled') {
223
+ this.removedColumns.delete(drag.intent.path);
224
+ if (status === 'moved' && this.displayedPaths().join(',') !== drag.paths.join(','))
225
+ await this.options.saveColumns();
226
+ if (drag.added && status === 'moved')
227
+ status = 'added';
228
+ }
185
229
  if (this.disposed)
186
230
  return { ...drag.intent, status: 'cancelled' };
187
231
  if (this.drag === drag)
@@ -210,10 +254,42 @@ export class ListPropertySelect {
210
254
  this.drag.operation.move(sample);
211
255
  }
212
256
  paths() {
213
- if (this.drag)
214
- return [...this.drag.paths];
215
- return [...this.article.querySelectorAll('thead [data-property]:not(.column-add-provisional)')]
216
- .map(header => header.dataset.property);
257
+ return this.drag ? [...this.drag.paths] : this.displayedPaths();
258
+ }
259
+ async remove(path, signal) {
260
+ const positions = this.removedColumns;
261
+ const paths = this.paths();
262
+ const index = paths.indexOf(path);
263
+ const position = { left: paths[index - 1], right: paths[index + 1] };
264
+ const removal = new AbortController();
265
+ this.removals.set(path, removal);
266
+ // Publish the unchecked state before starting the table's removal flash.
267
+ this.view.selector.setConfiguration({ usedPaths: this.paths() });
268
+ try {
269
+ const saving = this.options.saveColumns(this.paths());
270
+ const animation = this.options.addition.remove(path, AbortSignal.any([signal, removal.signal]));
271
+ const [removed] = await Promise.all([animation, saving]);
272
+ if (!removed) {
273
+ if (removal.signal.aborted && !signal.aborted && !this.disposed) {
274
+ await this.options.saveColumns(this.paths());
275
+ return 'existing';
276
+ }
277
+ throw new Error('Column removal cancelled');
278
+ }
279
+ if (!this.disposed && positions === this.removedColumns && index >= 0)
280
+ positions.set(path, position);
281
+ return 'removed';
282
+ }
283
+ catch (error) {
284
+ removal.abort();
285
+ throw error;
286
+ }
287
+ finally {
288
+ if (this.removals.get(path) === removal)
289
+ this.removals.delete(path);
290
+ if (!this.disposed)
291
+ this.view.selector.setConfiguration({ usedPaths: this.paths() });
292
+ }
217
293
  }
218
294
  async select(intent, signal) {
219
295
  const path = normalisePath(intent.path);
@@ -223,13 +299,27 @@ export class ListPropertySelect {
223
299
  let status;
224
300
  const pending = this.pending.get(path);
225
301
  if (pending) {
226
- await pending;
302
+ const removal = this.removals.get(path);
303
+ if (removal && !removal.signal.aborted) {
304
+ removal.abort();
305
+ this.view.selector.setConfiguration({ usedPaths: this.paths() });
306
+ }
307
+ else if (removal && intent.action !== 'add') {
308
+ await pending;
309
+ return this.select(intent, signal);
310
+ }
311
+ const outcome = await pending;
312
+ if (removal && outcome === 'removed')
313
+ return this.select({ ...intent, action: 'add' }, signal);
227
314
  status = 'existing';
228
315
  }
229
- else if (this.paths().includes(path))
230
- status = 'existing';
231
316
  else {
232
- const operation = this.add(path, signal);
317
+ const existing = this.paths().includes(path);
318
+ const operation = existing && (intent.action !== 'add')
319
+ ? this.remove(path, signal)
320
+ : existing
321
+ ? Promise.resolve('existing')
322
+ : Promise.resolve(this.add(path, signal));
233
323
  this.pending.set(path, operation);
234
324
  try {
235
325
  status = await operation;
@@ -242,8 +332,11 @@ export class ListPropertySelect {
242
332
  signal.throwIfAborted();
243
333
  if (this.disposed)
244
334
  throw new Error('List disposed');
245
- this.options.addition.reveal(path);
246
- this.options.addition.highlight(path);
335
+ if (status !== 'removed' && this.paths().includes(path)) {
336
+ this.options.addition.reveal(path);
337
+ if (status === 'existing')
338
+ this.options.addition.highlight(path);
339
+ }
247
340
  return { ...intent, status };
248
341
  }
249
342
  catch (error) {
@@ -5,8 +5,13 @@ import type { StateStore } from '@itrocks/property-select/property-select.js';
5
5
  export declare class HttpStateStore implements StateStore {
6
6
  private readonly endpoint;
7
7
  private readonly fetcher;
8
+ private initial?;
8
9
  private generation?;
9
- constructor(endpoint?: string, fetcher?: typeof fetch);
10
+ constructor(endpoint?: string, fetcher?: typeof fetch, initial?: {
11
+ generation: string;
12
+ key: string;
13
+ record: StateRecord;
14
+ } | undefined);
10
15
  read(key: string, signal?: AbortSignal): Promise<StateRecord>;
11
16
  remove(key: string, revision: number): Promise<StateRecord>;
12
17
  write(key: string, state: SelectorState, revision: number): Promise<StateRecord>;
package/selector-state.js CHANGED
@@ -3,12 +3,21 @@ import { StateConflictError } from '@itrocks/property-select/property-select.js'
3
3
  export class HttpStateStore {
4
4
  endpoint;
5
5
  fetcher;
6
+ initial;
6
7
  generation;
7
- constructor(endpoint = '/property-select/state/json', fetcher = globalThis.fetch.bind(globalThis)) {
8
+ constructor(endpoint = '/property-select/state/json', fetcher = globalThis.fetch.bind(globalThis), initial) {
8
9
  this.endpoint = endpoint;
9
10
  this.fetcher = fetcher;
11
+ this.initial = initial;
10
12
  }
11
13
  read(key, signal) {
14
+ if (this.initial?.key === key) {
15
+ signal?.throwIfAborted();
16
+ const initial = this.initial;
17
+ this.initial = undefined;
18
+ this.generation = initial.generation;
19
+ return Promise.resolve(structuredClone(initial.record));
20
+ }
12
21
  return this.request('GET', key, undefined, undefined, signal);
13
22
  }
14
23
  remove(key, revision) {