@lavalogic/scoria 0.37.20 → 0.37.22

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.
@@ -115,11 +115,32 @@
115
115
  tableContext.endFocus(focusDetails.coordinates);
116
116
  }}
117
117
  >
118
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
118
119
  <div
119
120
  class="slot-wrapper"
120
121
  class:multifocus={focusDetails.isMultiFocused}
121
122
  class:multifocus-start={focusDetails.isMultiFocusStart}
122
123
  bind:this={cellRef}
124
+ onmousedown={(e) => {
125
+ // Suppress the click-side effects that cause the table to
126
+ // jump horizontally on Action button clicks:
127
+ // 1. `preventDefault()` cancels the browser's default
128
+ // mousedown -> focus on the inner `<button>`, which
129
+ // otherwise calls `scrollIntoView` against the button's
130
+ // underlying position (far right of the row, since the
131
+ // Actions column is sticky-pinned right).
132
+ // 2. `stopPropagation()` keeps the event out of the outer
133
+ // `.focusable` cell handler, which would otherwise call
134
+ // `tableContext.startFocus(...)` and trigger Table.svelte's
135
+ // focusStart $effect -> another `scrollIntoView`. Even
136
+ // with the pinned-cell-skip in that effect, focus state
137
+ // changes feed back into other scroll-restore paths.
138
+ // The Action's own `onclick` fires regardless (click is dispatched
139
+ // on mouseup independent of mousedown handling), so the popup
140
+ // toggle still works.
141
+ e.preventDefault();
142
+ e.stopPropagation();
143
+ }}
123
144
  >
124
145
  <!-- TODO {isMultiFocusStart} -->
125
146
  <Action
@@ -360,7 +360,11 @@
360
360
  handler(e);
361
361
  }}
362
362
  ondblclick={() => {
363
- tableContext.autoResize(header.column.columnDef).catch(devCatch);
363
+ // Reset the column back to its factory-default width
364
+ // (clears the user-resized flag too, so the grid
365
+ // track returns to its original `minmax(W, 1fr)` /
366
+ // fixed-`${W}px` branch as configured).
367
+ header.column.columnDef.resetWidth();
364
368
  }}
365
369
  class="resizer right"
366
370
  class:isResizing={header.column.getIsResizing()}
@@ -358,6 +358,9 @@
358
358
  --button-padding-horizontal: 0.6rem;
359
359
  --button-padding-vertical: 0.42rem;
360
360
  }
361
+ .spread_row .block.records-per-page {
362
+ --input-width: 3.5rem;
363
+ }
361
364
  .spread_row span,
362
365
  .spread_row label {
363
366
  white-space: nowrap;
@@ -162,6 +162,17 @@ export declare abstract class ColumnDef<T extends object, in FilterFnType = neve
162
162
  * track, false = `minmax(width, 1fr)` flex track. */
163
163
  get widthIsFixed(): boolean;
164
164
  set widthIsFixed(v: boolean);
165
+ private readonly _originalWidth;
166
+ private readonly _originalMaxWidth;
167
+ private readonly _originalWidthIsFixed;
168
+ /**
169
+ * Reset this column's width-related state back to the values the
170
+ * factory created it with. Clears `userResized` so the grid track
171
+ * goes back to its flexible / fixed branch as originally configured.
172
+ * Used by the header resize handle's double-click to give consumers
173
+ * a single-action "restore default size" affordance.
174
+ */
175
+ resetWidth(): void;
165
176
  private _isResizing;
166
177
  /** Whether the resize handle is currently active. */
167
178
  get isResizing(): boolean;
@@ -36,9 +36,12 @@ export class ColumnDef {
36
36
  this.accessorFn = $derived(props.accessorFn);
37
37
  this._minSize = $state(props.minSize ?? 48);
38
38
  this._width = $state(props.width ?? props.minSize ?? 48);
39
+ this._originalWidth = props.width ?? props.minSize ?? 48;
39
40
  this._maxWidth = $state(props.maxWidth);
41
+ this._originalMaxWidth = props.maxWidth;
40
42
  this._wrapValue = $state(props.wrapValue ?? false);
41
43
  this._widthIsFixed = $state(props.widthIsFixed ?? false);
44
+ this._originalWidthIsFixed = props.widthIsFixed ?? false;
42
45
  this.isEditable = $derived(props.isEditable ?? (() => Promise.resolve(false)));
43
46
  this.resizable = $derived(props.resizable ?? true);
44
47
  this.header = $derived(props.header);
@@ -119,6 +122,26 @@ export class ColumnDef {
119
122
  set widthIsFixed(v) {
120
123
  this._widthIsFixed = v;
121
124
  }
125
+ // Snapshots of width / maxWidth / widthIsFixed taken at construction
126
+ // time. The user can revert any in-place mutation (drag-resize,
127
+ // programmatic write) back to these values via `resetWidth()`. They
128
+ // are plain fields (not `$state`) because they never change.
129
+ _originalWidth;
130
+ _originalMaxWidth;
131
+ _originalWidthIsFixed;
132
+ /**
133
+ * Reset this column's width-related state back to the values the
134
+ * factory created it with. Clears `userResized` so the grid track
135
+ * goes back to its flexible / fixed branch as originally configured.
136
+ * Used by the header resize handle's double-click to give consumers
137
+ * a single-action "restore default size" affordance.
138
+ */
139
+ resetWidth() {
140
+ this._width = this._originalWidth;
141
+ this._maxWidth = this._originalMaxWidth;
142
+ this._widthIsFixed = this._originalWidthIsFixed;
143
+ this._userResized = false;
144
+ }
122
145
  _isResizing = $state(false);
123
146
  /** Whether the resize handle is currently active. */
124
147
  get isResizing() {
@@ -107,6 +107,44 @@ export function createTable(options) {
107
107
  if (options.initialState) {
108
108
  applyInitialState(ctx, options.initialState);
109
109
  }
110
+ // ── 9. Auto-pin structural columns ──────────────────────────────
111
+ // `col.actions` (the ellipsis menu) and `col.rowSelection` (the
112
+ // select-row checkbox) are conventionally pinned to the right and
113
+ // left respectively across every table in the app, so apply that
114
+ // pin automatically here. The caller can override either pin via
115
+ // `initialState.columnPinning` (which runs first above), or via
116
+ // the live `setColumnPinning` updater on the table context.
117
+ const autoPinLeft = new Map();
118
+ const autoPinRight = new Map();
119
+ for (const spec of specs) {
120
+ const d = specsById.get(spec.id);
121
+ if (!d) {
122
+ continue;
123
+ }
124
+ const def = unwrapColumnSpec(d).def;
125
+ if (spec.kind === 'actions') {
126
+ autoPinRight.set(spec.id, def.width);
127
+ }
128
+ else if (spec.kind === 'rowSelection') {
129
+ autoPinLeft.set(spec.id, def.width);
130
+ }
131
+ }
132
+ if (autoPinLeft.size > 0 || autoPinRight.size > 0) {
133
+ const current = ctx.columnPinning;
134
+ const nextLeft = new Map(current.left ?? []);
135
+ const nextRight = new Map(current.right ?? []);
136
+ for (const [id, width] of autoPinLeft) {
137
+ if (!nextLeft.has(id) && !nextRight.has(id)) {
138
+ nextLeft.set(id, width);
139
+ }
140
+ }
141
+ for (const [id, width] of autoPinRight) {
142
+ if (!nextLeft.has(id) && !nextRight.has(id)) {
143
+ nextRight.set(id, width);
144
+ }
145
+ }
146
+ ctx.columnPinning = { left: nextLeft, right: nextRight };
147
+ }
110
148
  // ── 9. Build the structured Table instance ─────────────────────
111
149
  const table = Object.freeze({
112
150
  get name() {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lavalogic/scoria",
3
3
  "description": "Svelte components used for the FloWMS Web Frontend",
4
- "version": "0.37.20",
4
+ "version": "0.37.22",
5
5
  "publishConfig": {
6
6
  "access": "restricted"
7
7
  },