@lavalogic/scoria 0.40.3 → 0.40.5

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.
@@ -49,6 +49,8 @@ set it up at the app root.
49
49
  border-radius: 4px;
50
50
  font-weight: 500;
51
51
  white-space: pre-wrap;
52
+ max-width: min(28rem, 90vw);
53
+ overflow-wrap: anywhere;
52
54
  }
53
55
  .tooltip-wrapper.top-arrow {
54
56
  left: var(--x, 0);
@@ -9,7 +9,7 @@
9
9
  import HorizontalTabGroupButton from './HorizontalTabGroupButton.svelte';
10
10
  import type { HorizontalTabGroupProps } from './HorizontalTabGroupProps.js';
11
11
  import TextInput from './TextInput.svelte';
12
- const {
12
+ let {
13
13
  tabComponent,
14
14
  tabs,
15
15
  selected,
@@ -18,10 +18,11 @@
18
18
  dense = false,
19
19
  filterable = false,
20
20
  filterFn,
21
+ searchValue = $bindable(''),
22
+ searchInfo,
23
+ searchPlaceholder,
21
24
  }: HorizontalTabGroupProps<CommonDenominator> = $props();
22
25
 
23
- let searchValue = $state('');
24
-
25
26
  // Debounce only the search value, not the tabs array. This way a parent
26
27
  // rebuilding `tabs` shows the new list immediately, while typing still
27
28
  // pays the 300ms cost.
@@ -51,9 +52,15 @@
51
52
  <div class="searchbar">
52
53
  <TextInput
53
54
  bind:value={searchValue}
54
- placeholder="Search any keyword to find matches{ellipses}"
55
+ placeholder={searchPlaceholder ?? `Search any keyword to find matches${ellipses}`}
55
56
  rightIcon={{ name: 'search-1', colour: Colour['$ui-blue-4'] }}
56
57
  />
58
+ {#if searchInfo}
59
+ <span class="search-info">
60
+ <!-- eslint-disable-next-line @typescript-eslint/no-confusing-void-expression -->
61
+ {@render searchInfo()}
62
+ </span>
63
+ {/if}
57
64
  </div>
58
65
  {/if}
59
66
  </div>
@@ -81,11 +88,24 @@
81
88
 
82
89
  <style>.searchbar {
83
90
  display: flex;
91
+ flex-flow: row nowrap;
92
+ align-items: center;
93
+ gap: 0.5rem;
84
94
  width: 100%;
85
95
  padding: 0.5rem;
86
96
  background-color: #ffffff;
87
97
  min-width: 20.625rem;
88
98
  }
99
+ .searchbar :global(> *:first-child) {
100
+ flex: 1 1 auto;
101
+ min-width: 0;
102
+ }
103
+
104
+ .search-info {
105
+ display: inline-flex;
106
+ flex: 0 0 auto;
107
+ align-items: center;
108
+ }
89
109
 
90
110
  .wrapper {
91
111
  box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.1333333333);
@@ -2,7 +2,7 @@ import type { HorizontalTabGroupProps } from './HorizontalTabGroupProps.js';
2
2
  declare function $$render<CommonDenominator>(): {
3
3
  props: HorizontalTabGroupProps<CommonDenominator>;
4
4
  exports: {};
5
- bindings: "";
5
+ bindings: "searchValue";
6
6
  slots: {};
7
7
  events: {};
8
8
  };
@@ -10,7 +10,7 @@ declare class __sveltets_Render<CommonDenominator> {
10
10
  props(): ReturnType<typeof $$render<CommonDenominator>>['props'];
11
11
  events(): ReturnType<typeof $$render<CommonDenominator>>['events'];
12
12
  slots(): ReturnType<typeof $$render<CommonDenominator>>['slots'];
13
- bindings(): "";
13
+ bindings(): "searchValue";
14
14
  exports(): {};
15
15
  }
16
16
  interface $$IsomorphicComponent {
@@ -35,6 +35,14 @@ interface HorizontalTabGroupPropsBase<CommonDenominator> {
35
35
  filterable?: boolean;
36
36
  /** Predicate used to filter tabs on each keystroke (debounced by 300ms). */
37
37
  filterFn?: (item: TabOption<CommonDenominator>, filterValue: string) => boolean;
38
+ /** Bindable current value of the search box. Lets the parent read/drive
39
+ * the search term (e.g. to highlight matches elsewhere). */
40
+ searchValue?: string;
41
+ /** Optional content rendered beside the search input (e.g. an info icon
42
+ * with a tooltip). Only shown when `filterable`. */
43
+ searchInfo?: Snippet;
44
+ /** Override the search box placeholder. */
45
+ searchPlaceholder?: string;
38
46
  }
39
47
  export interface HorizontalTabGroupPropsWithoutSearch<CommonDenominator> extends HorizontalTabGroupPropsBase<CommonDenominator> {
40
48
  filterable?: false;
@@ -1,6 +1,7 @@
1
1
  <svelte:options runes />
2
2
 
3
3
  <script lang="ts">
4
+ import { page } from '$app/state';
4
5
  import { Colour } from '../../scss/colours.js';
5
6
  import { Size } from '../../Types/Internal/Size.js';
6
7
  import Icon from '../Icon.svelte';
@@ -9,6 +10,21 @@
9
10
  import ServiceMenuItem from './ServiceMenuItem.svelte';
10
11
 
11
12
  const { title, items, icon }: NavServiceMenuListProps = $props();
13
+
14
+ // Only the single most-specific item is active: the longest item path that
15
+ // the current URL matches. Without this a nested route (e.g.
16
+ // /reports/manage-reports) would also light up its parent item (/reports).
17
+ const activePath = $derived.by(() => {
18
+ const pathname = page.url.pathname;
19
+ let best: string | null = null;
20
+ for (const { item } of items) {
21
+ const path = item.path;
22
+ if (path && pathname.includes(path) && (best === null || path.length > best.length)) {
23
+ best = path;
24
+ }
25
+ }
26
+ return best;
27
+ });
12
28
  </script>
13
29
 
14
30
  <div
@@ -35,7 +51,10 @@
35
51
  role="list"
36
52
  >
37
53
  {#each items as { item } (item.label)}
38
- <ServiceMenuItem {item} />
54
+ <ServiceMenuItem
55
+ {item}
56
+ selected={item.path != null && item.path === activePath}
57
+ />
39
58
  {/each}
40
59
  </div>
41
60
  </div>
@@ -85,7 +85,12 @@
85
85
  const firstCell = $derived(leftCells.at(0) ?? centreCells.at(0) ?? rightCells.at(0));
86
86
  const rowIndex = $derived(firstCell?.row.visibleIndex);
87
87
  let id = $state<RowIdType | undefined>();
88
- const highlighted = $derived(id != undefined && tableContext.highlightedItems.has(id));
88
+ // Transient click/copy highlight OR the declarative, persistent
89
+ // `highlightRow` predicate (reactive; survives data/pagination resets).
90
+ const highlighted = $derived(
91
+ (id != undefined && tableContext.highlightedItems.has(id)) ||
92
+ (tableContext.highlightRow ? tableContext.highlightRow(row.original, rowIndex ?? 0) : false)
93
+ );
89
94
 
90
95
  $effect(() => {
91
96
  void row.original;
@@ -60,6 +60,8 @@ export declare class TableContext<T extends object, RowIdType extends Primitive>
60
60
  allowAdvancedFiltering: boolean;
61
61
  toolbarPosition: ToolbarPosition;
62
62
  displayFooter: boolean;
63
+ /** Declarative persistent row-highlight predicate (see CreateTableOptions). */
64
+ readonly highlightRow: TableInitOptions<T, RowIdType>['highlightRow'];
63
65
  selectionExtractor: TableInitOptions<T, RowIdType>['selectionExtractor'];
64
66
  getUserId: () => string | undefined;
65
67
  private _onEditCell;
@@ -86,7 +88,9 @@ export declare class TableContext<T extends object, RowIdType extends Primitive>
86
88
  * `init`.
87
89
  */
88
90
  static init<T extends object, RowIdType extends Primitive>(defaultColumnDefs: DefsWrapper<T>, tableName: string, dataRepo: IDataRepository<T>, options: TableInitOptions<T, RowIdType>): TableContext<T, RowIdType>;
89
- protected constructor(INTERNAL_ONLY: symbol, defaultColumnDefs: DefsWrapper<T>, tableName: string, dataRepo: IDataRepository<T>, allowCopy: boolean, enableResize: boolean, allowColumnReordering: boolean, allowQuickFiltering: boolean, showQuickFilterByDefault: boolean, allowAdvancedFiltering: boolean, toolbarPosition: ToolbarPosition, displayFooter: boolean, selectionExtractor: TableInitOptions<T, RowIdType>['selectionExtractor'], getUserId: () => string | undefined, _onEditCell: TableInitOptions<T, RowIdType>['onEditCell'],
91
+ protected constructor(INTERNAL_ONLY: symbol, defaultColumnDefs: DefsWrapper<T>, tableName: string, dataRepo: IDataRepository<T>, allowCopy: boolean, enableResize: boolean, allowColumnReordering: boolean, allowQuickFiltering: boolean, showQuickFilterByDefault: boolean, allowAdvancedFiltering: boolean, toolbarPosition: ToolbarPosition, displayFooter: boolean,
92
+ /** Declarative persistent row-highlight predicate (see CreateTableOptions). */
93
+ highlightRow: TableInitOptions<T, RowIdType>['highlightRow'], selectionExtractor: TableInitOptions<T, RowIdType>['selectionExtractor'], getUserId: () => string | undefined, _onEditCell: TableInitOptions<T, RowIdType>['onEditCell'],
90
94
  /**
91
95
  * Stable per-table identifier supplied by the host app, or
92
96
  * `undefined` when remote saved views are disabled. Stored only;
@@ -107,6 +107,7 @@ export class TableContext {
107
107
  allowAdvancedFiltering;
108
108
  toolbarPosition;
109
109
  displayFooter;
110
+ highlightRow;
110
111
  selectionExtractor;
111
112
  getUserId;
112
113
  _onEditCell;
@@ -123,7 +124,7 @@ export class TableContext {
123
124
  * `init`.
124
125
  */
125
126
  static init(defaultColumnDefs, tableName, dataRepo, options) {
126
- const context = new this(InternalSymbol, defaultColumnDefs, tableName, dataRepo, options.allowCopy ?? DEFAULT_TABLE_INIT_OPTIONS.allowCopy, options.enableResize ?? DEFAULT_TABLE_INIT_OPTIONS.enableResize, options.allowColumnReordering ?? DEFAULT_TABLE_INIT_OPTIONS.allowColumnReordering, options.allowQuickFiltering ?? DEFAULT_TABLE_INIT_OPTIONS.allowQuickFiltering, options.showQuickFilterByDefault ?? DEFAULT_TABLE_INIT_OPTIONS.showQuickFilterByDefault, options.allowAdvancedFiltering ?? DEFAULT_TABLE_INIT_OPTIONS.allowAdvancedFiltering, options.toolbar ?? DEFAULT_TABLE_INIT_OPTIONS.toolbar, options.displayFooter ?? DEFAULT_TABLE_INIT_OPTIONS.displayFooter,
127
+ const context = new this(InternalSymbol, defaultColumnDefs, tableName, dataRepo, options.allowCopy ?? DEFAULT_TABLE_INIT_OPTIONS.allowCopy, options.enableResize ?? DEFAULT_TABLE_INIT_OPTIONS.enableResize, options.allowColumnReordering ?? DEFAULT_TABLE_INIT_OPTIONS.allowColumnReordering, options.allowQuickFiltering ?? DEFAULT_TABLE_INIT_OPTIONS.allowQuickFiltering, options.showQuickFilterByDefault ?? DEFAULT_TABLE_INIT_OPTIONS.showQuickFilterByDefault, options.allowAdvancedFiltering ?? DEFAULT_TABLE_INIT_OPTIONS.allowAdvancedFiltering, options.toolbar ?? DEFAULT_TABLE_INIT_OPTIONS.toolbar, options.displayFooter ?? DEFAULT_TABLE_INIT_OPTIONS.displayFooter, options.highlightRow,
127
128
  // Fallback identity extractor when no `selectionExtractor` is
128
129
  // supplied (some consumers build an options object directly
129
130
  // without one). Returning the row object preserves identity
@@ -134,7 +135,9 @@ export class TableContext {
134
135
  return context;
135
136
  }
136
137
  // #region constructor
137
- constructor(INTERNAL_ONLY, defaultColumnDefs, tableName, dataRepo, allowCopy, enableResize, allowColumnReordering, allowQuickFiltering, showQuickFilterByDefault, allowAdvancedFiltering, toolbarPosition, displayFooter, selectionExtractor, getUserId, _onEditCell = () => {
138
+ constructor(INTERNAL_ONLY, defaultColumnDefs, tableName, dataRepo, allowCopy, enableResize, allowColumnReordering, allowQuickFiltering, showQuickFilterByDefault, allowAdvancedFiltering, toolbarPosition, displayFooter,
139
+ /** Declarative persistent row-highlight predicate (see CreateTableOptions). */
140
+ highlightRow, selectionExtractor, getUserId, _onEditCell = () => {
138
141
  console.warn('Cannot edit immutable table');
139
142
  },
140
143
  /**
@@ -159,6 +162,7 @@ export class TableContext {
159
162
  this.allowAdvancedFiltering = allowAdvancedFiltering;
160
163
  this.toolbarPosition = toolbarPosition;
161
164
  this.displayFooter = displayFooter;
165
+ this.highlightRow = highlightRow;
162
166
  this.selectionExtractor = selectionExtractor;
163
167
  this.getUserId = getUserId;
164
168
  this._onEditCell = _onEditCell;
@@ -28,6 +28,8 @@ export interface TableInitOptions<T extends object, Identifier extends Primitive
28
28
  allowAdvancedFiltering?: boolean;
29
29
  toolbar?: ToolbarPosition;
30
30
  displayFooter?: boolean;
31
+ /** Declarative persistent row-highlight predicate. See CreateTableOptions. */
32
+ highlightRow?: (item: T, index: number) => boolean;
31
33
  onEditCell?: (item: T, coords: CellCoordinates, value: unknown) => void | Promise<void>;
32
34
  getUserId: () => string | undefined;
33
35
  /** Stable per-table identifier supplied by the host app. Identifies
@@ -59,6 +59,15 @@ export interface CreateTableOptions<TRow extends object, TRowId extends Primitiv
59
59
  toolbar?: 'top' | 'right' | 'left' | 'none';
60
60
  /** Whether to render the footer. Defaults to true. */
61
61
  showFooter?: boolean;
62
+ /**
63
+ * Declarative, persistent row highlight. When provided, every row for
64
+ * which this returns true is rendered highlighted — reactively and
65
+ * independently of the transient click/copy highlight, so it survives
66
+ * data/pagination changes (the latter clears the interaction highlight).
67
+ * Read reactive state inside the predicate (e.g. a search term) to drive
68
+ * the highlight from outside the table. Synchronous. Defaults to none.
69
+ */
70
+ highlightRow?: (row: TRow, index: number) => boolean;
62
71
  /** Whether copy operations are enabled. Defaults to true. */
63
72
  allowCopy?: boolean;
64
73
  /** Whether columns may be user-resized. Defaults to true. */
@@ -76,6 +76,7 @@ export function createTable(options) {
76
76
  allowAdvancedFiltering: options.allowAdvancedFilter,
77
77
  toolbar: translateToolbar(options.toolbar),
78
78
  displayFooter: options.showFooter,
79
+ highlightRow: options.highlightRow,
79
80
  onEditCell,
80
81
  datatableUuid: options.datatableUuid,
81
82
  remoteLayouts: options.remoteLayouts,
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.40.3",
4
+ "version": "0.40.5",
5
5
  "publishConfig": {
6
6
  "access": "restricted"
7
7
  },