@bexis2/bexis2-core-ui 0.4.102 → 0.4.103

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
@@ -1,5 +1,9 @@
1
1
  # bexis-core-ui
2
- ## 0.4.101
2
+ ## 0.4.103
3
+ - Big Table
4
+ - fix DB communication
5
+
6
+ ## 0.4.102
3
7
  - NumericInput
4
8
  - add integerOnly flag to prevent add numbers instead of integers
5
9
 
@@ -59,6 +59,7 @@ let {
59
59
  } = config;
60
60
  const clientDb = config.clientDb ?? false;
61
61
  const clientDbSeedData = config.clientDbSeedData ?? [];
62
+ const clientDbRefresh = config.clientDbRefresh ?? null;
62
63
  const initialServerCount = Number(config.__initialServerCount ?? 0);
63
64
  let searchValue = "";
64
65
  let isFetching = false;
@@ -425,7 +426,8 @@ onMount(async () => {
425
426
  clientDbInitSource = [];
426
427
  const result = await updateTableWithParams();
427
428
  return result;
428
- }).catch(() => {
429
+ }).catch((err) => {
430
+ console.error("ClientDB init failed:", err);
429
431
  clientDbReady = false;
430
432
  });
431
433
  } else if (!_clientDbInstance) {
@@ -438,6 +440,11 @@ onMount(async () => {
438
440
  });
439
441
  $: serverSide && sortServer($sortKeys[0]?.order, $sortKeys[0]?.id);
440
442
  $: $hiddenColumnIds = shownColumns.filter((col) => !col.visible).map((col) => col.id);
443
+ let lastRefresh = 0;
444
+ $: if (clientDbEnabled && clientDbRefresh && $clientDbRefresh !== lastRefresh) {
445
+ lastRefresh = $clientDbRefresh;
446
+ updateTableWithParams();
447
+ }
441
448
  </script>
442
449
 
443
450
  <div class="grid gap-2 overflow-auto" class:w-fit={!fitToScreen} class:w-full={fitToScreen}>
@@ -1,7 +1,9 @@
1
+ export function openDB(name: any): Promise<any>;
1
2
  export default class ClientDB {
2
3
  constructor(tableId: any);
3
4
  tableId: any;
4
5
  db: any;
6
+ _ensureDB(): Promise<any>;
5
7
  init(rows: any): Promise<{
6
8
  tableId: any;
7
9
  count: any;
@@ -18,5 +20,8 @@ export default class ClientDB {
18
20
  total: number;
19
21
  }>;
20
22
  clear(): Promise<void>;
23
+ ensureIndex(columnName: any): Promise<void>;
24
+ getByIndex(columnName: any, value: any): Promise<any>;
25
+ put(record: any): Promise<any>;
21
26
  destroy(): void;
22
27
  }
@@ -1,16 +1,46 @@
1
1
  // Simple client-side DB wrapper using IndexedDB directly (no worker)
2
2
  const DB_PREFIX = 'table-db-';
3
3
 
4
- function openDB(name) {
4
+ export function openDB(name) {
5
+ const dbName = DB_PREFIX + name;
5
6
  return new Promise((resolve, reject) => {
6
- const req = indexedDB.open(DB_PREFIX + name);
7
+ const req = indexedDB.open(dbName);
7
8
  req.onupgradeneeded = () => {
8
9
  const db = req.result;
9
10
  if (!db.objectStoreNames.contains('rows')) {
10
11
  db.createObjectStore('rows', { keyPath: '__id', autoIncrement: true });
11
12
  }
12
13
  };
13
- req.onsuccess = () => resolve(req.result);
14
+ req.onsuccess = () => {
15
+ const db = req.result;
16
+
17
+ db.onversionchange = () => {
18
+ db.close();
19
+ };
20
+
21
+ if (!db.objectStoreNames.contains('rows')) {
22
+ const currentVersion = db.version;
23
+ db.close();
24
+ const upgradeReq = indexedDB.open(dbName, currentVersion + 1);
25
+ upgradeReq.onupgradeneeded = () => {
26
+ const upgradeDb = upgradeReq.result;
27
+ if (!upgradeDb.objectStoreNames.contains('rows')) {
28
+ upgradeDb.createObjectStore('rows', { keyPath: '__id', autoIncrement: true });
29
+ }
30
+ };
31
+ upgradeReq.onsuccess = () => {
32
+ const result = upgradeReq.result;
33
+ result.onversionchange = () => {
34
+ result.close();
35
+ };
36
+ resolve(result);
37
+ };
38
+ upgradeReq.onerror = () => reject(upgradeReq.error);
39
+ upgradeReq.onblocked = () => reject(new Error(`IndexedDB upgrade blocked for "${dbName}" — close other tabs using this database`));
40
+ } else {
41
+ resolve(db);
42
+ }
43
+ };
14
44
  req.onerror = () => reject(req.error);
15
45
  });
16
46
  }
@@ -137,8 +167,21 @@ export default class ClientDB {
137
167
  this.db = null;
138
168
  }
139
169
 
170
+ async _ensureDB() {
171
+ if (this.db) {
172
+ return this.db;
173
+ }
174
+ this.db = await openDB(this.tableId);
175
+ const dbInstance = this.db;
176
+ dbInstance.onversionchange = () => {
177
+ dbInstance.close();
178
+ this.db = null;
179
+ };
180
+ return this.db;
181
+ }
182
+
140
183
  async init(rows) {
141
- this.db = this.db || (await openDB(this.tableId));
184
+ await this._ensureDB();
142
185
  await clearStore(this.db);
143
186
 
144
187
  const CHUNK = 1000;
@@ -153,7 +196,7 @@ export default class ClientDB {
153
196
  }
154
197
 
155
198
  async query({ q = '', filters = [], order = [], offset = 0, limit = 100 } = {}) {
156
- this.db = this.db || (await openDB(this.tableId));
199
+ await this._ensureDB();
157
200
 
158
201
  const tx = this.db.transaction('rows', 'readonly');
159
202
  const store = tx.objectStore('rows');
@@ -223,10 +266,77 @@ export default class ClientDB {
223
266
  }
224
267
 
225
268
  async clear() {
226
- this.db = this.db || (await openDB(this.tableId));
269
+ await this._ensureDB();
227
270
  await clearStore(this.db);
228
271
  }
229
272
 
273
+ async ensureIndex(columnName) {
274
+ const indexName = `__r.by${columnName}`;
275
+ await this._ensureDB();
276
+
277
+ const exists = await new Promise((resolve, reject) => {
278
+ const tx = this.db.transaction('rows', 'readonly');
279
+ const store = tx.objectStore('rows');
280
+ resolve(store.indexNames.contains(indexName));
281
+ tx.onerror = () => reject(tx.error);
282
+ });
283
+
284
+ if (exists) return;
285
+
286
+ const dbName = DB_PREFIX + this.tableId;
287
+ const currentVersion = this.db.version;
288
+ this.db.close();
289
+ this.db = null;
290
+
291
+ await new Promise((resolve, reject) => {
292
+ const upgradeReq = indexedDB.open(dbName, currentVersion + 1);
293
+ upgradeReq.onupgradeneeded = (event) => {
294
+ const upgradeDb = event.target.result;
295
+ const store = event.target.transaction.objectStore('rows');
296
+ if (!store.indexNames.contains(indexName)) {
297
+ store.createIndex(indexName, `__r.${columnName}`);
298
+ }
299
+ };
300
+ upgradeReq.onsuccess = () => {
301
+ upgradeReq.result.close();
302
+ resolve();
303
+ };
304
+ upgradeReq.onerror = () => reject(upgradeReq.error);
305
+ upgradeReq.onblocked = () =>
306
+ reject(new Error(`IndexedDB upgrade blocked for "${dbName}" — close other tabs using this database`));
307
+ });
308
+
309
+ await this._ensureDB();
310
+ }
311
+
312
+ async getByIndex(columnName, value) {
313
+ await this._ensureDB();
314
+ const indexName = `__r.by${columnName}`;
315
+
316
+ return new Promise((resolve, reject) => {
317
+ const tx = this.db.transaction('rows', 'readonly');
318
+ const store = tx.objectStore('rows');
319
+ if (!store.indexNames.contains(indexName)) {
320
+ resolve(undefined);
321
+ return;
322
+ }
323
+ const req = store.index(indexName).getAll(value);
324
+ req.onsuccess = () => resolve(req.result[0]);
325
+ req.onerror = () => resolve(undefined);
326
+ });
327
+ }
328
+
329
+ async put(record) {
330
+ await this._ensureDB();
331
+ return new Promise((resolve, reject) => {
332
+ const tx = this.db.transaction('rows', 'readwrite');
333
+ const store = tx.objectStore('rows');
334
+ const req = store.put(record);
335
+ req.onsuccess = () => resolve(req.result);
336
+ req.onerror = () => reject(req.error);
337
+ });
338
+ }
339
+
230
340
  destroy() {
231
341
  if (this.db) {
232
342
  this.db.close();
@@ -0,0 +1,100 @@
1
+ [data-theme='bexis2theme'] {
2
+ /* =~= Theme Properties =~= */
3
+ --base-font-family: system-ui;
4
+ --base-font-color: var(--color-surface-900);
5
+ --base-font-color-dark: 255 255 255;
6
+ /*--theme-rounded-base: 4px;
7
+ --theme-rounded-container: 4px;
8
+ --theme-border-base: 1px;*/
9
+ --radius-base: 4px;
10
+ --radius-container: 4px;
11
+ --default-border-width: 1px;
12
+ --default-divide-width: 1px;
13
+ --default-ring-width: 1px;
14
+ /* =~= Theme On-X Colors =~= */
15
+ --on-primary: 255 255 255;
16
+ --on-secondary: 255 255 255;
17
+ --on-tertiary: 0 0 0;
18
+ --on-success: 255 255 255;
19
+ --on-warning: 255 255 255;
20
+ --on-error: 255 255 255;
21
+ --on-surface: 0 0 0;
22
+ /* =~= Theme Colors =~= */
23
+ /* primary | #45b2a1 */
24
+ --color-primary-50: #e3f3f1;
25
+ --color-primary-100: #daf0ec;
26
+ --color-primary-200: #d1ece8;
27
+ --color-primary-300: #b5e0d9;
28
+ --color-primary-400: #7dc9bd;
29
+ --color-primary-500: #45b2a1;
30
+ --color-primary-600: #3ea091;
31
+ --color-primary-700: #348679;
32
+ --color-primary-800: #296b61;
33
+ --color-primary-900: #22574f;
34
+ /* secondary | #ff9700 */
35
+ --color-secondary-50: #ffefd9;
36
+ --color-secondary-100: #ffeacc;
37
+ --color-secondary-200: #ffe5bf;
38
+ --color-secondary-300: #ffd599;
39
+ --color-secondary-400: #ffb64d;
40
+ --color-secondary-500: #ff9700;
41
+ --color-secondary-600: #e68800;
42
+ --color-secondary-700: #bf7100;
43
+ --color-secondary-800: #995b00;
44
+ --color-secondary-900: #7d4a00;
45
+ /* tertiary | #bee1da */
46
+ --color-tertiary-50: #f5fbf9;
47
+ --color-tertiary-100: #f2f9f8;
48
+ --color-tertiary-200: #eff8f6;
49
+ --color-tertiary-300: #e5f3f0;
50
+ --color-tertiary-400: #d2eae5;
51
+ --color-tertiary-500: #bee1da;
52
+ --color-tertiary-600: #abcbc4;
53
+ --color-tertiary-700: #8fa9a4;
54
+ --color-tertiary-800: #728783;
55
+ --color-tertiary-900: #5d6e6b;
56
+ /* success | #4BB543 */
57
+ --color-success-50: #e4f4e3;
58
+ --color-success-100: #dbf0d9;
59
+ --color-success-200: #d2edd0;
60
+ --color-success-300: #b7e1b4;
61
+ --color-success-400: #81cb7b;
62
+ --color-success-500: #4bb543;
63
+ --color-success-600: #44a33c;
64
+ --color-success-700: #388832;
65
+ --color-success-800: #2d6d28;
66
+ --color-success-900: #255921;
67
+ /* warning | #EAB308 */
68
+ --color-warning-50: #fcf4da;
69
+ --color-warning-100: #fbf0ce;
70
+ --color-warning-200: #faecc1;
71
+ --color-warning-300: #f7e19c;
72
+ --color-warning-400: #f0ca52;
73
+ --color-warning-500: #eab308;
74
+ --color-warning-600: #d3a107;
75
+ --color-warning-700: #b08606;
76
+ --color-warning-800: #8c6b05;
77
+ --color-warning-900: #735804;
78
+ /* error | #FF0000 */
79
+ --color-error-50: #ffd9d9;
80
+ --color-error-100: #ffcccc;
81
+ --color-error-200: #ffbfbf;
82
+ --color-error-300: #ff9999;
83
+ --color-error-400: #ff4d4d;
84
+ --color-error-500: #ff0000;
85
+ --color-error-600: #e60000;
86
+ --color-error-700: #bf0000;
87
+ --color-error-800: #990000;
88
+ --color-error-900: #7d0000;
89
+ /* surface | #c7c7c7 */
90
+ --color-surface-50: #f7f7f7;
91
+ --color-surface-100: #f4f4f4;
92
+ --color-surface-200: #f1f1f1;
93
+ --color-surface-300: #e9e9e9;
94
+ --color-surface-400: #d8d8d8;
95
+ --color-surface-500: #c7c7c7;
96
+ --color-surface-600: #b3b3b3;
97
+ --color-surface-700: #959595;
98
+ --color-surface-800: #777777;
99
+ --color-surface-900: #626262;
100
+ }
package/dist/index.d.ts CHANGED
@@ -43,6 +43,7 @@ export { Notification };
43
43
  export { TablePlaceholder };
44
44
  export { positionType, pageContentLayoutType, decimalCharacterType, orientationType, textMarkerType, textSeperatorType } from './models/Enums';
45
45
  export { Table, TableFilter, columnFilter, searchFilter };
46
+ export { default as ClientDB } from './components/Table/clientDB.js';
46
47
  export { Facets };
47
48
  export type { FacetGroup, FacetOption, SelectedFacetGroup };
48
49
  export { CodeEditor };
package/dist/index.js CHANGED
@@ -58,6 +58,7 @@ export { TablePlaceholder };
58
58
  export { positionType, pageContentLayoutType, decimalCharacterType, orientationType, textMarkerType, textSeperatorType } from './models/Enums';
59
59
  // Table
60
60
  export { Table, TableFilter, columnFilter, searchFilter };
61
+ export { default as ClientDB } from './components/Table/clientDB.js';
61
62
  // Facets
62
63
  export { Facets };
63
64
  // CodeEditor
@@ -0,0 +1,2 @@
1
+ import type { CustomThemeConfig } from '@skeletonlabs/tw-plugin';
2
+ export declare const bexis2theme: CustomThemeConfig;
@@ -0,0 +1,112 @@
1
+ export const bexis2theme = {
2
+ name: 'bexis2theme',
3
+ properties: {
4
+ // =~= Theme Properties =~=
5
+ '--theme-font-family-base': `system-ui`,
6
+ '--theme-font-family-heading': `system-ui`,
7
+ '--theme-font-color-base': 'var(--color-surface-900)',
8
+ '--theme-font-color-dark': '#ffffff',
9
+ '--theme-rounded-base': '4px',
10
+ '--theme-rounded-container': '4px',
11
+ '--theme-border-base': '1px',
12
+ // =~= Theme On-X Colors =~=
13
+ '--on-primary': '255 255 255',
14
+ '--on-secondary': '255 255 255',
15
+ '--on-tertiary': '0 0 0',
16
+ '--on-success': '255 255 255',
17
+ '--on-warning': '255 255 255',
18
+ '--on-error': '255 255 255',
19
+ '--on-surface': '255 255 255',
20
+ // =~= Theme Colors =~=
21
+ // primary | #45b2a1
22
+ '--color-primary-50': '#e3f3f1',
23
+ '--color-primary-100': '#daf0ec',
24
+ '--color-primary-200': '#d1ece8',
25
+ '--color-primary-300': '#b5e0d9',
26
+ '--color-primary-400': '#7dc9bd',
27
+ '--color-primary-500': '#45b2a1',
28
+ '--color-primary-600': '#3ea091',
29
+ '--color-primary-700': '#348679',
30
+ '--color-primary-800': '#296b61',
31
+ '--color-primary-900': '#22574f',
32
+ // secondary | #ff9700
33
+ '--color-secondary-50': '#ffefd9',
34
+ '--color-secondary-100': '#ffeacc',
35
+ '--color-secondary-200': '#ffe5bf',
36
+ '--color-secondary-300': '#ffd599',
37
+ '--color-secondary-400': '#ffb64d',
38
+ '--color-secondary-500': '#ff9700',
39
+ '--color-secondary-600': '#e68800',
40
+ '--color-secondary-700': '#bf7100',
41
+ '--color-secondary-800': '#995b00',
42
+ '--color-secondary-900': '#7d4a00',
43
+ // tertiary | #bee1da
44
+ '--color-tertiary-50': '#f5fbf9',
45
+ '--color-tertiary-100': '#f2f9f8',
46
+ '--color-tertiary-200': '#eff8f6',
47
+ '--color-tertiary-300': '#e5f3f0',
48
+ '--color-tertiary-400': '#d2eae5',
49
+ '--color-tertiary-500': '#bee1da',
50
+ '--color-tertiary-600': '#abcbc4',
51
+ '--color-tertiary-700': '#8fa9a4',
52
+ '--color-tertiary-800': '#728783',
53
+ '--color-tertiary-900': '#5d6e6b',
54
+ // success | #4BB543
55
+ '--color-success-50': '#e4f4e3',
56
+ '--color-success-100': '#dbf0d9',
57
+ '--color-success-200': '#d2edd0',
58
+ '--color-success-300': '#b7e1b4',
59
+ '--color-success-400': '#81cb7b',
60
+ '--color-success-500': '#4bb543',
61
+ '--color-success-600': '#44a33c',
62
+ '--color-success-700': '#388832',
63
+ '--color-success-800': '#2d6d28',
64
+ '--color-success-900': '#255921',
65
+ // warning | #EAB308
66
+ '--color-warning-50': '#fcf4da',
67
+ '--color-warning-100': '#fbf0ce',
68
+ '--color-warning-200': '#faecc1',
69
+ '--color-warning-300': '#f7e19c',
70
+ '--color-warning-400': '#f0ca52',
71
+ '--color-warning-500': '#eab308',
72
+ '--color-warning-600': '#d3a107',
73
+ '--color-warning-700': '#b08606',
74
+ '--color-warning-800': '#8c6b05',
75
+ '--color-warning-900': '#735804',
76
+ // error | #FF0000
77
+ '--color-error-50': '#ffd9d9',
78
+ '--color-error-100': '#ffcccc',
79
+ '--color-error-200': '#ffbfbf',
80
+ '--color-error-300': '#ff9999',
81
+ '--color-error-400': '#ff4d4d',
82
+ '--color-error-500': '#ff0000',
83
+ '--color-error-600': '#e60000',
84
+ '--color-error-700': '#bf0000',
85
+ '--color-error-800': '#990000',
86
+ '--color-error-900': '#7d0000',
87
+ // surface | #c7c7c7
88
+ '--color-surface-50': '#f7f7f7',
89
+ '--color-surface-100': '#f4f4f4',
90
+ '--color-surface-200': '#f1f1f1',
91
+ '--color-surface-300': '#e9e9e9',
92
+ '--color-surface-400': '#d8d8d8',
93
+ '--color-surface-500': '#c7c7c7',
94
+ '--color-surface-600': '#b3b3b3',
95
+ '--color-surface-700': '#959595',
96
+ '--color-surface-800': '#777777',
97
+ '--color-surface-900': '#626262'
98
+ },
99
+ properties_dark: {
100
+ // surface | #2e2e2e
101
+ '--color-surface-50': '#e0e0e0',
102
+ '--color-surface-100': '#d5d5d5',
103
+ '--color-surface-200': '#cbcbcb',
104
+ '--color-surface-300': '#ababab',
105
+ '--color-surface-400': '#6d6d6d',
106
+ '--color-surface-500': '#2e2e2e',
107
+ '--color-surface-600': '#292929',
108
+ '--color-surface-700': '#232323',
109
+ '--color-surface-800': '#1c1c1c',
110
+ '--color-surface-900': '#171717'
111
+ }
112
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bexis2/bexis2-core-ui",
3
- "version": "0.4.102",
3
+ "version": "0.4.103",
4
4
  "private": false,
5
5
  "description": "Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte).",
6
6
  "keywords": [
@@ -56,6 +56,7 @@
56
56
  // `clientDb` is optional and may not be part of the `TableConfig` type
57
57
  const clientDb = (config as any).clientDb ?? false;
58
58
  const clientDbSeedData = (config as any).clientDbSeedData ?? [];
59
+ const clientDbRefresh = (config as any).clientDbRefresh ?? null;
59
60
  const initialServerCount = Number((config as any).__initialServerCount ?? 0);
60
61
 
61
62
  let searchValue = '';
@@ -529,9 +530,10 @@
529
530
  const result = await updateTableWithParams();
530
531
  return result;
531
532
  })
532
- .catch(() => {
533
- clientDbReady = false;
534
- });
533
+ .catch((err) => {
534
+ console.error('ClientDB init failed:', err);
535
+ clientDbReady = false;
536
+ });
535
537
  } else if (!_clientDbInstance) {
536
538
  _clientDbInstance = new ClientDB(tableId);
537
539
  }
@@ -544,6 +546,11 @@
544
546
  });
545
547
  $: serverSide && sortServer($sortKeys[0]?.order, $sortKeys[0]?.id);
546
548
  $: $hiddenColumnIds = shownColumns.filter((col) => !col.visible).map((col) => col.id);
549
+ let lastRefresh = 0;
550
+ $: if (clientDbEnabled && clientDbRefresh && $clientDbRefresh !== lastRefresh) {
551
+ lastRefresh = $clientDbRefresh;
552
+ updateTableWithParams();
553
+ }
547
554
  </script>
548
555
 
549
556
  <div class="grid gap-2 overflow-auto" class:w-fit={!fitToScreen} class:w-full={fitToScreen}>
@@ -1,16 +1,46 @@
1
1
  // Simple client-side DB wrapper using IndexedDB directly (no worker)
2
2
  const DB_PREFIX = 'table-db-';
3
3
 
4
- function openDB(name) {
4
+ export function openDB(name) {
5
+ const dbName = DB_PREFIX + name;
5
6
  return new Promise((resolve, reject) => {
6
- const req = indexedDB.open(DB_PREFIX + name);
7
+ const req = indexedDB.open(dbName);
7
8
  req.onupgradeneeded = () => {
8
9
  const db = req.result;
9
10
  if (!db.objectStoreNames.contains('rows')) {
10
11
  db.createObjectStore('rows', { keyPath: '__id', autoIncrement: true });
11
12
  }
12
13
  };
13
- req.onsuccess = () => resolve(req.result);
14
+ req.onsuccess = () => {
15
+ const db = req.result;
16
+
17
+ db.onversionchange = () => {
18
+ db.close();
19
+ };
20
+
21
+ if (!db.objectStoreNames.contains('rows')) {
22
+ const currentVersion = db.version;
23
+ db.close();
24
+ const upgradeReq = indexedDB.open(dbName, currentVersion + 1);
25
+ upgradeReq.onupgradeneeded = () => {
26
+ const upgradeDb = upgradeReq.result;
27
+ if (!upgradeDb.objectStoreNames.contains('rows')) {
28
+ upgradeDb.createObjectStore('rows', { keyPath: '__id', autoIncrement: true });
29
+ }
30
+ };
31
+ upgradeReq.onsuccess = () => {
32
+ const result = upgradeReq.result;
33
+ result.onversionchange = () => {
34
+ result.close();
35
+ };
36
+ resolve(result);
37
+ };
38
+ upgradeReq.onerror = () => reject(upgradeReq.error);
39
+ upgradeReq.onblocked = () => reject(new Error(`IndexedDB upgrade blocked for "${dbName}" — close other tabs using this database`));
40
+ } else {
41
+ resolve(db);
42
+ }
43
+ };
14
44
  req.onerror = () => reject(req.error);
15
45
  });
16
46
  }
@@ -137,8 +167,21 @@ export default class ClientDB {
137
167
  this.db = null;
138
168
  }
139
169
 
170
+ async _ensureDB() {
171
+ if (this.db) {
172
+ return this.db;
173
+ }
174
+ this.db = await openDB(this.tableId);
175
+ const dbInstance = this.db;
176
+ dbInstance.onversionchange = () => {
177
+ dbInstance.close();
178
+ this.db = null;
179
+ };
180
+ return this.db;
181
+ }
182
+
140
183
  async init(rows) {
141
- this.db = this.db || (await openDB(this.tableId));
184
+ await this._ensureDB();
142
185
  await clearStore(this.db);
143
186
 
144
187
  const CHUNK = 1000;
@@ -153,7 +196,7 @@ export default class ClientDB {
153
196
  }
154
197
 
155
198
  async query({ q = '', filters = [], order = [], offset = 0, limit = 100 } = {}) {
156
- this.db = this.db || (await openDB(this.tableId));
199
+ await this._ensureDB();
157
200
 
158
201
  const tx = this.db.transaction('rows', 'readonly');
159
202
  const store = tx.objectStore('rows');
@@ -223,10 +266,77 @@ export default class ClientDB {
223
266
  }
224
267
 
225
268
  async clear() {
226
- this.db = this.db || (await openDB(this.tableId));
269
+ await this._ensureDB();
227
270
  await clearStore(this.db);
228
271
  }
229
272
 
273
+ async ensureIndex(columnName) {
274
+ const indexName = `__r.by${columnName}`;
275
+ await this._ensureDB();
276
+
277
+ const exists = await new Promise((resolve, reject) => {
278
+ const tx = this.db.transaction('rows', 'readonly');
279
+ const store = tx.objectStore('rows');
280
+ resolve(store.indexNames.contains(indexName));
281
+ tx.onerror = () => reject(tx.error);
282
+ });
283
+
284
+ if (exists) return;
285
+
286
+ const dbName = DB_PREFIX + this.tableId;
287
+ const currentVersion = this.db.version;
288
+ this.db.close();
289
+ this.db = null;
290
+
291
+ await new Promise((resolve, reject) => {
292
+ const upgradeReq = indexedDB.open(dbName, currentVersion + 1);
293
+ upgradeReq.onupgradeneeded = (event) => {
294
+ const upgradeDb = event.target.result;
295
+ const store = event.target.transaction.objectStore('rows');
296
+ if (!store.indexNames.contains(indexName)) {
297
+ store.createIndex(indexName, `__r.${columnName}`);
298
+ }
299
+ };
300
+ upgradeReq.onsuccess = () => {
301
+ upgradeReq.result.close();
302
+ resolve();
303
+ };
304
+ upgradeReq.onerror = () => reject(upgradeReq.error);
305
+ upgradeReq.onblocked = () =>
306
+ reject(new Error(`IndexedDB upgrade blocked for "${dbName}" — close other tabs using this database`));
307
+ });
308
+
309
+ await this._ensureDB();
310
+ }
311
+
312
+ async getByIndex(columnName, value) {
313
+ await this._ensureDB();
314
+ const indexName = `__r.by${columnName}`;
315
+
316
+ return new Promise((resolve, reject) => {
317
+ const tx = this.db.transaction('rows', 'readonly');
318
+ const store = tx.objectStore('rows');
319
+ if (!store.indexNames.contains(indexName)) {
320
+ resolve(undefined);
321
+ return;
322
+ }
323
+ const req = store.index(indexName).getAll(value);
324
+ req.onsuccess = () => resolve(req.result[0]);
325
+ req.onerror = () => resolve(undefined);
326
+ });
327
+ }
328
+
329
+ async put(record) {
330
+ await this._ensureDB();
331
+ return new Promise((resolve, reject) => {
332
+ const tx = this.db.transaction('rows', 'readwrite');
333
+ const store = tx.objectStore('rows');
334
+ const req = store.put(record);
335
+ req.onsuccess = () => resolve(req.result);
336
+ req.onerror = () => reject(req.error);
337
+ });
338
+ }
339
+
230
340
  destroy() {
231
341
  if (this.db) {
232
342
  this.db.close();
@@ -0,0 +1,100 @@
1
+ [data-theme='bexis2theme'] {
2
+ /* =~= Theme Properties =~= */
3
+ --base-font-family: system-ui;
4
+ --base-font-color: var(--color-surface-900);
5
+ --base-font-color-dark: 255 255 255;
6
+ /*--theme-rounded-base: 4px;
7
+ --theme-rounded-container: 4px;
8
+ --theme-border-base: 1px;*/
9
+ --radius-base: 4px;
10
+ --radius-container: 4px;
11
+ --default-border-width: 1px;
12
+ --default-divide-width: 1px;
13
+ --default-ring-width: 1px;
14
+ /* =~= Theme On-X Colors =~= */
15
+ --on-primary: 255 255 255;
16
+ --on-secondary: 255 255 255;
17
+ --on-tertiary: 0 0 0;
18
+ --on-success: 255 255 255;
19
+ --on-warning: 255 255 255;
20
+ --on-error: 255 255 255;
21
+ --on-surface: 0 0 0;
22
+ /* =~= Theme Colors =~= */
23
+ /* primary | #45b2a1 */
24
+ --color-primary-50: #e3f3f1;
25
+ --color-primary-100: #daf0ec;
26
+ --color-primary-200: #d1ece8;
27
+ --color-primary-300: #b5e0d9;
28
+ --color-primary-400: #7dc9bd;
29
+ --color-primary-500: #45b2a1;
30
+ --color-primary-600: #3ea091;
31
+ --color-primary-700: #348679;
32
+ --color-primary-800: #296b61;
33
+ --color-primary-900: #22574f;
34
+ /* secondary | #ff9700 */
35
+ --color-secondary-50: #ffefd9;
36
+ --color-secondary-100: #ffeacc;
37
+ --color-secondary-200: #ffe5bf;
38
+ --color-secondary-300: #ffd599;
39
+ --color-secondary-400: #ffb64d;
40
+ --color-secondary-500: #ff9700;
41
+ --color-secondary-600: #e68800;
42
+ --color-secondary-700: #bf7100;
43
+ --color-secondary-800: #995b00;
44
+ --color-secondary-900: #7d4a00;
45
+ /* tertiary | #bee1da */
46
+ --color-tertiary-50: #f5fbf9;
47
+ --color-tertiary-100: #f2f9f8;
48
+ --color-tertiary-200: #eff8f6;
49
+ --color-tertiary-300: #e5f3f0;
50
+ --color-tertiary-400: #d2eae5;
51
+ --color-tertiary-500: #bee1da;
52
+ --color-tertiary-600: #abcbc4;
53
+ --color-tertiary-700: #8fa9a4;
54
+ --color-tertiary-800: #728783;
55
+ --color-tertiary-900: #5d6e6b;
56
+ /* success | #4BB543 */
57
+ --color-success-50: #e4f4e3;
58
+ --color-success-100: #dbf0d9;
59
+ --color-success-200: #d2edd0;
60
+ --color-success-300: #b7e1b4;
61
+ --color-success-400: #81cb7b;
62
+ --color-success-500: #4bb543;
63
+ --color-success-600: #44a33c;
64
+ --color-success-700: #388832;
65
+ --color-success-800: #2d6d28;
66
+ --color-success-900: #255921;
67
+ /* warning | #EAB308 */
68
+ --color-warning-50: #fcf4da;
69
+ --color-warning-100: #fbf0ce;
70
+ --color-warning-200: #faecc1;
71
+ --color-warning-300: #f7e19c;
72
+ --color-warning-400: #f0ca52;
73
+ --color-warning-500: #eab308;
74
+ --color-warning-600: #d3a107;
75
+ --color-warning-700: #b08606;
76
+ --color-warning-800: #8c6b05;
77
+ --color-warning-900: #735804;
78
+ /* error | #FF0000 */
79
+ --color-error-50: #ffd9d9;
80
+ --color-error-100: #ffcccc;
81
+ --color-error-200: #ffbfbf;
82
+ --color-error-300: #ff9999;
83
+ --color-error-400: #ff4d4d;
84
+ --color-error-500: #ff0000;
85
+ --color-error-600: #e60000;
86
+ --color-error-700: #bf0000;
87
+ --color-error-800: #990000;
88
+ --color-error-900: #7d0000;
89
+ /* surface | #c7c7c7 */
90
+ --color-surface-50: #f7f7f7;
91
+ --color-surface-100: #f4f4f4;
92
+ --color-surface-200: #f1f1f1;
93
+ --color-surface-300: #e9e9e9;
94
+ --color-surface-400: #d8d8d8;
95
+ --color-surface-500: #c7c7c7;
96
+ --color-surface-600: #b3b3b3;
97
+ --color-surface-700: #959595;
98
+ --color-surface-800: #777777;
99
+ --color-surface-900: #626262;
100
+ }
package/src/lib/index.ts CHANGED
@@ -113,6 +113,7 @@ export {
113
113
 
114
114
  // Table
115
115
  export { Table, TableFilter, columnFilter, searchFilter };
116
+ export { default as ClientDB } from './components/Table/clientDB.js';
116
117
 
117
118
  // Facets
118
119
  export { Facets };
@@ -0,0 +1,114 @@
1
+ import type { CustomThemeConfig } from '@skeletonlabs/tw-plugin';
2
+
3
+ export const bexis2theme: CustomThemeConfig = {
4
+ name: 'bexis2theme',
5
+ properties: {
6
+ // =~= Theme Properties =~=
7
+ '--theme-font-family-base': `system-ui`,
8
+ '--theme-font-family-heading': `system-ui`,
9
+ '--theme-font-color-base': 'var(--color-surface-900)',
10
+ '--theme-font-color-dark': '#ffffff',
11
+ '--theme-rounded-base': '4px',
12
+ '--theme-rounded-container': '4px',
13
+ '--theme-border-base': '1px',
14
+ // =~= Theme On-X Colors =~=
15
+ '--on-primary': '255 255 255',
16
+ '--on-secondary': '255 255 255',
17
+ '--on-tertiary': '0 0 0',
18
+ '--on-success': '255 255 255',
19
+ '--on-warning': '255 255 255',
20
+ '--on-error': '255 255 255',
21
+ '--on-surface': '255 255 255',
22
+ // =~= Theme Colors =~=
23
+ // primary | #45b2a1
24
+ '--color-primary-50': '#e3f3f1',
25
+ '--color-primary-100': '#daf0ec',
26
+ '--color-primary-200': '#d1ece8',
27
+ '--color-primary-300': '#b5e0d9',
28
+ '--color-primary-400': '#7dc9bd',
29
+ '--color-primary-500': '#45b2a1',
30
+ '--color-primary-600': '#3ea091',
31
+ '--color-primary-700': '#348679',
32
+ '--color-primary-800': '#296b61',
33
+ '--color-primary-900': '#22574f',
34
+ // secondary | #ff9700
35
+ '--color-secondary-50': '#ffefd9',
36
+ '--color-secondary-100': '#ffeacc',
37
+ '--color-secondary-200': '#ffe5bf',
38
+ '--color-secondary-300': '#ffd599',
39
+ '--color-secondary-400': '#ffb64d',
40
+ '--color-secondary-500': '#ff9700',
41
+ '--color-secondary-600': '#e68800',
42
+ '--color-secondary-700': '#bf7100',
43
+ '--color-secondary-800': '#995b00',
44
+ '--color-secondary-900': '#7d4a00',
45
+ // tertiary | #bee1da
46
+ '--color-tertiary-50': '#f5fbf9',
47
+ '--color-tertiary-100': '#f2f9f8',
48
+ '--color-tertiary-200': '#eff8f6',
49
+ '--color-tertiary-300': '#e5f3f0',
50
+ '--color-tertiary-400': '#d2eae5',
51
+ '--color-tertiary-500': '#bee1da',
52
+ '--color-tertiary-600': '#abcbc4',
53
+ '--color-tertiary-700': '#8fa9a4',
54
+ '--color-tertiary-800': '#728783',
55
+ '--color-tertiary-900': '#5d6e6b',
56
+ // success | #4BB543
57
+ '--color-success-50': '#e4f4e3',
58
+ '--color-success-100': '#dbf0d9',
59
+ '--color-success-200': '#d2edd0',
60
+ '--color-success-300': '#b7e1b4',
61
+ '--color-success-400': '#81cb7b',
62
+ '--color-success-500': '#4bb543',
63
+ '--color-success-600': '#44a33c',
64
+ '--color-success-700': '#388832',
65
+ '--color-success-800': '#2d6d28',
66
+ '--color-success-900': '#255921',
67
+ // warning | #EAB308
68
+ '--color-warning-50': '#fcf4da',
69
+ '--color-warning-100': '#fbf0ce',
70
+ '--color-warning-200': '#faecc1',
71
+ '--color-warning-300': '#f7e19c',
72
+ '--color-warning-400': '#f0ca52',
73
+ '--color-warning-500': '#eab308',
74
+ '--color-warning-600': '#d3a107',
75
+ '--color-warning-700': '#b08606',
76
+ '--color-warning-800': '#8c6b05',
77
+ '--color-warning-900': '#735804',
78
+ // error | #FF0000
79
+ '--color-error-50': '#ffd9d9',
80
+ '--color-error-100': '#ffcccc',
81
+ '--color-error-200': '#ffbfbf',
82
+ '--color-error-300': '#ff9999',
83
+ '--color-error-400': '#ff4d4d',
84
+ '--color-error-500': '#ff0000',
85
+ '--color-error-600': '#e60000',
86
+ '--color-error-700': '#bf0000',
87
+ '--color-error-800': '#990000',
88
+ '--color-error-900': '#7d0000',
89
+ // surface | #c7c7c7
90
+ '--color-surface-50': '#f7f7f7',
91
+ '--color-surface-100': '#f4f4f4',
92
+ '--color-surface-200': '#f1f1f1',
93
+ '--color-surface-300': '#e9e9e9',
94
+ '--color-surface-400': '#d8d8d8',
95
+ '--color-surface-500': '#c7c7c7',
96
+ '--color-surface-600': '#b3b3b3',
97
+ '--color-surface-700': '#959595',
98
+ '--color-surface-800': '#777777',
99
+ '--color-surface-900': '#626262'
100
+ },
101
+ properties_dark: {
102
+ // surface | #2e2e2e
103
+ '--color-surface-50': '#e0e0e0',
104
+ '--color-surface-100': '#d5d5d5',
105
+ '--color-surface-200': '#cbcbcb',
106
+ '--color-surface-300': '#ababab',
107
+ '--color-surface-400': '#6d6d6d',
108
+ '--color-surface-500': '#2e2e2e',
109
+ '--color-surface-600': '#292929',
110
+ '--color-surface-700': '#232323',
111
+ '--color-surface-800': '#1c1c1c',
112
+ '--color-surface-900': '#171717'
113
+ }
114
+ };