@poirazis/supercomponents-shared 1.2.10 → 1.2.12

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poirazis/supercomponents-shared",
3
- "version": "1.2.10",
3
+ "version": "1.2.12",
4
4
  "description": "Shared Svelte components library",
5
5
  "type": "module",
6
6
  "packageManager": "bun@1.0.0",
@@ -36,7 +36,6 @@
36
36
  "svelte": "^5.0.0"
37
37
  },
38
38
  "dependencies": {
39
- "@budibase/types": "^3.24.4",
40
39
  "@jsrob/svelte-portal": "^0.2.1",
41
40
  "@phosphor-icons/web": "^2.1.2",
42
41
  "@sveltejs/svelte-virtual-list": "^3.0.1",
@@ -49,6 +48,7 @@
49
48
  "zod": "4.3.5"
50
49
  },
51
50
  "devDependencies": {
51
+ "@budibase/types": "^3.24.4",
52
52
  "@sveltejs/package": "^2.3.12",
53
53
  "@sveltejs/vite-plugin-svelte": "^4.0.1",
54
54
  "@tsconfig/svelte": "^5.0.4",
@@ -106,7 +106,7 @@
106
106
 
107
107
  <style>
108
108
  .super-field {
109
- min-width: 120px;
109
+ min-width: 80px;
110
110
  width: 100%;
111
111
  display: flex;
112
112
  flex-direction: column;
@@ -2,7 +2,7 @@
2
2
  import { setContext, getContext, createEventDispatcher } from "svelte";
3
3
  import type { Readable, Writable } from "svelte/store";
4
4
  import { derived, get, writable } from "svelte/store";
5
- import {
5
+ import type {
6
6
  DataFetchDatasource,
7
7
  FieldSchema,
8
8
  FieldType,
@@ -2,7 +2,7 @@
2
2
  import { getContext, setContext, onDestroy, tick } from "svelte";
3
3
  import fsm from "svelte-fsm";
4
4
  import { writable } from "svelte/store";
5
- import {
5
+ import type {
6
6
  LogicalOperator,
7
7
  EmptyFilterOption,
8
8
  SearchFilters,
@@ -589,7 +589,6 @@
589
589
  bind:open={showModal}
590
590
  bind:currentIndex
591
591
  bind:selectedIndices
592
- on:close={() => console.log("closed")}
593
592
  {canSelect}
594
593
  {canDelete}
595
594
  />
@@ -320,7 +320,6 @@
320
320
  bind:open={showModal}
321
321
  bind:currentIndex={modalImageIndex}
322
322
  bind:selectedIndices
323
- on:close={() => console.log("lightbox closed")}
324
323
  on:delete={(e) => {
325
324
  handleDelete(e.detail.index);
326
325
  }}
@@ -304,6 +304,7 @@
304
304
 
305
305
  &:hover:not(.disabled):not(.readonly):not(.inEdit) {
306
306
  border: 1px solid var(--spectrum-global-color-gray-400);
307
+ cursor: pointer;
307
308
  }
308
309
 
309
310
  &.disabled {
@@ -101,7 +101,7 @@
101
101
  dateFormat,
102
102
  fromTime,
103
103
  toTime,
104
- showTime
104
+ showTime,
105
105
  ) {
106
106
  if (!showTime) {
107
107
  return {
@@ -120,14 +120,7 @@
120
120
 
121
121
  // Date formatting helper function
122
122
  function formatDateRange(fromDate, toDate, dateFormat) {
123
- console.log("🔍 formatDateRange called with:", {
124
- fromDate,
125
- toDate,
126
- dateFormat,
127
- });
128
-
129
123
  if (!dateFormat || dateFormat === "default") {
130
- console.log("➡️ Using default format");
131
124
  return {
132
125
  from: fromDate.toDateString(),
133
126
  to: toDate.toDateString(),
@@ -138,30 +131,18 @@
138
131
  if (dateFormat === "MM/DD/YYYY") {
139
132
  const fromFormatted = `${(fromDate.getMonth() + 1).toString().padStart(2, "0")}/${fromDate.getDate().toString().padStart(2, "0")}/${fromDate.getFullYear()}`;
140
133
  const toFormatted = `${(toDate.getMonth() + 1).toString().padStart(2, "0")}/${toDate.getDate().toString().padStart(2, "0")}/${toDate.getFullYear()}`;
141
- console.log("✅ MM/DD/YYYY formatted:", {
142
- from: fromFormatted,
143
- to: toFormatted,
144
- });
145
134
  return { from: fromFormatted, to: toFormatted };
146
135
  }
147
136
 
148
137
  if (dateFormat === "DD/MM/YYYY") {
149
138
  const fromFormatted = `${fromDate.getDate().toString().padStart(2, "0")}/${(fromDate.getMonth() + 1).toString().padStart(2, "0")}/${fromDate.getFullYear()}`;
150
139
  const toFormatted = `${toDate.getDate().toString().padStart(2, "0")}/${(toDate.getMonth() + 1).toString().padStart(2, "0")}/${toDate.getFullYear()}`;
151
- console.log("✅ DD/MM/YYYY formatted:", {
152
- from: fromFormatted,
153
- to: toFormatted,
154
- });
155
140
  return { from: fromFormatted, to: toFormatted };
156
141
  }
157
142
 
158
143
  if (dateFormat === "YYYY-MM-DD") {
159
144
  const fromFormatted = `${fromDate.getFullYear()}-${(fromDate.getMonth() + 1).toString().padStart(2, "0")}-${fromDate.getDate().toString().padStart(2, "0")}`;
160
145
  const toFormatted = `${toDate.getFullYear()}-${(toDate.getMonth() + 1).toString().padStart(2, "0")}-${toDate.getDate().toString().padStart(2, "0")}`;
161
- console.log("✅ YYYY-MM-DD formatted:", {
162
- from: fromFormatted,
163
- to: toFormatted,
164
- });
165
146
  return { from: fromFormatted, to: toFormatted };
166
147
  }
167
148
 
@@ -182,22 +163,16 @@
182
163
  };
183
164
 
184
165
  const format = options[dateFormat];
185
- console.log("📅 Format object:", format);
186
166
 
187
167
  if (format) {
188
168
  const fromFormatted = fromDate.toLocaleDateString("en-US", format);
189
169
  const toFormatted = toDate.toLocaleDateString("en-US", format);
190
- console.log("✅ Formatted result:", {
191
- from: fromFormatted,
192
- to: toFormatted,
193
- });
194
170
  return {
195
171
  from: fromFormatted,
196
172
  to: toFormatted,
197
173
  };
198
174
  }
199
175
 
200
- console.log("⚠️ Format not found, using fallback");
201
176
  // Fallback to default
202
177
  return {
203
178
  from: fromDate.toDateString(),
@@ -240,7 +215,7 @@
240
215
  dateFormat,
241
216
  fromTime,
242
217
  fromTime,
243
- true
218
+ true,
244
219
  );
245
220
  fromFormatted = formatted.from;
246
221
  } else {
@@ -263,7 +238,7 @@
263
238
  dateFormat,
264
239
  toTime,
265
240
  toTime,
266
- true
241
+ true,
267
242
  );
268
243
  toFormatted = formatted.to;
269
244
  } else {
@@ -1,5 +1,5 @@
1
1
  <script>
2
- import { createEventDispatcher, getContext } from "svelte";
2
+ import { getContext, createEventDispatcher } from "svelte";
3
3
  import fsm from "svelte-fsm";
4
4
  import SuperPopover from "../SuperPopover/SuperPopover.svelte";
5
5
  import CellLinkPickerSelect from "./CellLinkPickerSelect.svelte";
@@ -66,7 +66,7 @@
66
66
  if (isDirty)
67
67
  dispatch(
68
68
  "change",
69
- returnSingle && localValue ? localValue[0] : localValue
69
+ returnSingle && localValue ? localValue[0] : localValue,
70
70
  );
71
71
 
72
72
  return "View";
@@ -190,10 +190,16 @@
190
190
  class:error={cellOptions.error}
191
191
  style:color={cellOptions.color}
192
192
  style:background={cellOptions.background}
193
- on:mousedown={editorState.toggle}
194
193
  on:focusin={cellState.focus}
195
194
  on:keydown|self={handleKeyboard}
196
195
  on:focusout={cellState.focusout}
196
+ on:mousedown={(e) => {
197
+ if (inEdit) {
198
+ // Prevent losing focus when clicking to open the picker
199
+ e.preventDefault();
200
+ editorState.toggle();
201
+ }
202
+ }}
197
203
  >
198
204
  {#if cellOptions?.icon}
199
205
  <i class={cellOptions.icon + " field-icon"}></i>
@@ -116,7 +116,7 @@
116
116
  Editing: {
117
117
  _enter() {
118
118
  originalValue = JSON.stringify(
119
- Array.isArray(value) ? value : value ? [value] : []
119
+ Array.isArray(value) ? value : value ? [value] : [],
120
120
  );
121
121
  inputValue = multi ? "" : labels[localValue[0]] || localValue[0] || "";
122
122
  // Open the popup if the focus in came from a TAB
@@ -230,7 +230,7 @@
230
230
  // Client-side filtering for non-datasource
231
231
  if (term) {
232
232
  filteredOptions = $options.filter((x) =>
233
- x?.toLocaleLowerCase().startsWith(term.toLocaleLowerCase())
233
+ x?.toLocaleLowerCase().startsWith(term.toLocaleLowerCase()),
234
234
  );
235
235
  } else {
236
236
  filteredOptions = $options;
@@ -403,7 +403,7 @@
403
403
  $options.forEach(
404
404
  (option, index) =>
405
405
  (obj[option] =
406
- optionColors[option] ?? colorsArray[index % colorsArray.length])
406
+ optionColors[option] ?? colorsArray[index % colorsArray.length]),
407
407
  );
408
408
  return obj;
409
409
  });
@@ -441,7 +441,7 @@
441
441
  ];
442
442
 
443
443
  let originalValue = JSON.stringify(
444
- Array.isArray(value) ? value : value ? [value] : []
444
+ Array.isArray(value) ? value : value ? [value] : [],
445
445
  );
446
446
 
447
447
  $: ({
@@ -492,7 +492,7 @@
492
492
  iconColumn,
493
493
  colorColumn,
494
494
  $dataSourceStore,
495
- customOptions
495
+ customOptions,
496
496
  );
497
497
 
498
498
  // We always keep an internal value as an array
@@ -542,7 +542,6 @@
542
542
  class:inline={role == "inlineInput"}
543
543
  class:tableCell={role == "tableCell"}
544
544
  class:formInput={role == "formInput"}
545
- style:cursor={inEdit ? "pointer" : "default"}
546
545
  on:focusin={cellState.focus}
547
546
  on:focusout={cellState.focusout}
548
547
  on:keydown={editorState.handleKeyboard}
@@ -151,7 +151,7 @@
151
151
  });
152
152
 
153
153
  Promise.all(
154
- missingIds.map((id) => API.fetchRow(relatedTableId, id, true))
154
+ missingIds.map((id) => API.fetchRow(relatedTableId, id, true)),
155
155
  )
156
156
  .then((rows) => {
157
157
  const newEnriched = rows.map((row) => ({
@@ -270,7 +270,6 @@
270
270
  useAnchorWidth
271
271
  open={$editorState == "Open"}
272
272
  on:close={(e) => {
273
- console.log("closing editor");
274
273
  editorState.close();
275
274
  }}
276
275
  >
@@ -1,6 +1,6 @@
1
- <script>
1
+ <script lang="ts">
2
2
  import { getContext, createEventDispatcher, tick } from "svelte";
3
- import { LogicalOperator, EmptyFilterOption } from "@budibase/types";
3
+ import type { LogicalOperator, EmptyFilterOption } from "@budibase/types";
4
4
 
5
5
  const { API, fetchData, QueryUtils } = getContext("sdk");
6
6
  const dispatch = createEventDispatcher();
@@ -257,7 +257,7 @@
257
257
  {#each relatedColumns as col}
258
258
  <div class="data-cell">{row[col.name] || ""}</div>
259
259
  {/each}
260
- <div class="data-cell check"><i class="ri-check-line" ></i></div>
260
+ <div class="data-cell check"><i class="ri-check-line"></i></div>
261
261
  </div>
262
262
  {/each}
263
263
 
@@ -278,7 +278,7 @@
278
278
  <div class="data-cell">{row[col.name] || ""}</div>
279
279
  {/each}
280
280
  <div class="data-cell check">
281
- <i class="ri-check-line" ></i>
281
+ <i class="ri-check-line"></i>
282
282
  </div>
283
283
  </div>
284
284
  {/if}
@@ -289,13 +289,13 @@
289
289
  {#if $optionsFetch?.loading}
290
290
  <div class="data-row loading">
291
291
  <div class="data-cell" style="grid-column: 1 / -1;">
292
- <i class="ri-loader-2-line rotating" ></i> Loading more...
292
+ <i class="ri-loader-2-line rotating"></i> Loading more...
293
293
  </div>
294
294
  </div>
295
295
  {:else if $optionsFetch?.loading && !$optionsFetch.loaded}
296
296
  <div class="data-row loading">
297
297
  <div class="data-cell" style="grid-column: 1 / -1;">
298
- <i class="ri-loader-2-line rotating" ></i> Loading...
298
+ <i class="ri-loader-2-line rotating"></i> Loading...
299
299
  </div>
300
300
  </div>
301
301
  {:else if !$optionsFetch?.loading && $optionsFetch?.loaded && !$optionsFetch.rows?.length}
@@ -319,7 +319,7 @@
319
319
  on:mousedown|preventDefault|stopPropagation={() => selectRow(row)}
320
320
  >
321
321
  {row.primaryDisplay || row[primaryDisplay]}
322
- <i class="ri-check-line" ></i>
322
+ <i class="ri-check-line"></i>
323
323
  </div>
324
324
  {/each}
325
325
 
@@ -337,20 +337,20 @@
337
337
  on:mousedown|preventDefault={() => selectRow(row)}
338
338
  >
339
339
  {row.primaryDisplay || row[primaryDisplay]}
340
- <i class="ri-check-line" ></i>
340
+ <i class="ri-check-line"></i>
341
341
  </div>
342
342
  {/if}
343
343
  {/each}
344
344
  {/key}
345
345
  {#if $optionsFetch?.loading}
346
346
  <div class="option loading">
347
- <i class="ri-loader-2-line rotating" ></i>
347
+ <i class="ri-loader-2-line rotating"></i>
348
348
  Loading more...
349
349
  </div>
350
350
  {/if}
351
351
  {:else if $optionsFetch?.loading && !$optionsFetch.loaded}
352
352
  <div class="option loading">
353
- <i class="ri-loader-2-line rotating" ></i>
353
+ <i class="ri-loader-2-line rotating"></i>
354
354
  Loading...
355
355
  </div>
356
356
  {:else}
@@ -1,7 +1,28 @@
1
1
  <script>
2
2
  import { createEventDispatcher, onMount, onDestroy } from "svelte";
3
3
  import fsm from "svelte-fsm";
4
- import IMask from "imask";
4
+ import {
5
+ Masked,
6
+ InputMask,
7
+ createMask,
8
+ MaskedPattern,
9
+ MaskedRegExp,
10
+ MaskedNumber,
11
+ MaskedDate,
12
+ MaskedEnum,
13
+ MaskedRange,
14
+ MaskedDynamic,
15
+ } from "imask";
16
+
17
+ // Register mask classes with Masked.overloads to ensure they're available for createMask
18
+ // This is required for imask 6.x to properly handle pattern-based masks
19
+ if (MaskedPattern && Masked.overloads) {
20
+ // Ensure MaskedPattern is available as an overload
21
+ if (!Masked.overloads.find((o) => o.mask === MaskedPattern)) {
22
+ Masked.overloads.unshift({ mask: MaskedPattern });
23
+ }
24
+ }
25
+
5
26
  const dispatch = createEventDispatcher();
6
27
 
7
28
  export let value;
@@ -23,9 +44,53 @@
23
44
  let inputMask;
24
45
  let inputElement;
25
46
 
47
+ function createMaskInstance(maskPattern) {
48
+ if (!maskPattern) return null;
49
+ try {
50
+ // For imask 6.x, explicitly create a MaskedPattern instance
51
+ // This avoids the "Masked class is not found" error by directly instantiating
52
+ const mask = new MaskedPattern({
53
+ mask: maskPattern,
54
+ lazy: false,
55
+ placeholderChar: "_",
56
+ });
57
+ return mask;
58
+ } catch (patternError) {
59
+ try {
60
+ // Fallback: try as a regex pattern
61
+ const mask = new MaskedRegExp({
62
+ mask: new RegExp(maskPattern),
63
+ lazy: false,
64
+ });
65
+ return mask;
66
+ } catch (regexError) {
67
+ try {
68
+ // Last fallback: use generic createMask
69
+ return createMask({
70
+ mask: maskPattern,
71
+ lazy: false,
72
+ });
73
+ } catch (createError) {
74
+ console.error(
75
+ "Failed to create mask - pattern:",
76
+ maskPattern,
77
+ "errors:",
78
+ {
79
+ patternError: patternError?.message,
80
+ regexError: regexError?.message,
81
+ createError: createError?.message,
82
+ },
83
+ );
84
+ return null;
85
+ }
86
+ }
87
+ }
88
+ }
89
+
26
90
  function applyMask(rawValue) {
27
91
  if (!mask || !rawValue) return rawValue;
28
- const tempMask = IMask.createMask({ mask: mask });
92
+ const tempMask = createMaskInstance(mask);
93
+ if (!tempMask) return rawValue;
29
94
  tempMask.unmaskedValue = rawValue;
30
95
  return tempMask.value;
31
96
  }
@@ -42,7 +107,11 @@
42
107
  return;
43
108
  }
44
109
 
45
- const tempMask = IMask.createMask({ mask: mask });
110
+ const tempMask = createMaskInstance(mask);
111
+ if (!tempMask) {
112
+ isComplete = false;
113
+ return;
114
+ }
46
115
  tempMask.resolve(localValue);
47
116
  isComplete = tempMask.isComplete;
48
117
  }
@@ -158,16 +227,18 @@
158
227
  // For input validation, check if typed key is valid for mask
159
228
  if (e.key.length === 1 && mask) {
160
229
  // Check if key matches mask pattern (e.g., for "00000", only digits)
161
- const tempMask = IMask.createMask({ mask: mask });
162
- const currentLength = (localValue || "").length;
163
- // Get the expected pattern for this position
164
- // For simplicity, if mask contains only digits or specific chars, check if key matches
165
- const placeholder =
166
- tempMask.blocks[0]?.placeholder ||
167
- (tempMask.mask.includes("0") ? "0" : null);
168
- if (placeholder === "0" && !/\d/.test(e.key)) {
169
- e.preventDefault();
170
- return;
230
+ const tempMask = createMaskInstance(mask);
231
+ if (tempMask) {
232
+ const currentLength = (localValue || "").length;
233
+ // Get the expected pattern for this position
234
+ // For simplicity, if mask contains only digits or specific chars, check if key matches
235
+ const placeholder =
236
+ tempMask.blocks?.[0]?.placeholder ||
237
+ (tempMask.mask?.includes("0") ? "0" : null);
238
+ if (placeholder === "0" && !/\d/.test(e.key)) {
239
+ e.preventDefault();
240
+ return;
241
+ }
171
242
  }
172
243
  }
173
244
  },
@@ -180,6 +251,7 @@
180
251
  $: error = cellOptions?.error;
181
252
  $: icon = error ? "ph ph-warning" : cellOptions?.icon;
182
253
  $: cellState.reset(value);
254
+ $: displayValue = inEdit ? localValue : applyMask(value);
183
255
 
184
256
  const focus = (node) => {
185
257
  node?.focus();
@@ -217,18 +289,41 @@
217
289
  };
218
290
  }
219
291
 
220
- inputMask = IMask(node, { mask: maskPattern });
221
- inputMask.unmaskedValue = localValue || "";
292
+ try {
293
+ // Try to create mask instance using MaskedPattern first
294
+ const maskInstance = createMaskInstance(maskPattern);
295
+ if (maskInstance) {
296
+ inputMask = new InputMask(node, { mask: maskPattern });
297
+ } else {
298
+ throw new Error("Failed to create mask instance");
299
+ }
222
300
 
223
- inputMask.on("accept", () => {
224
- localValue = inputMask.unmaskedValue;
225
- updateIsComplete();
226
- lastEdit = new Date();
227
- });
301
+ inputMask.unmaskedValue = localValue || "";
228
302
 
229
- inputMask.on("complete", () => {
230
- isComplete = true;
231
- });
303
+ inputMask.on("accept", () => {
304
+ localValue = inputMask.unmaskedValue;
305
+ updateIsComplete();
306
+ lastEdit = new Date();
307
+ });
308
+
309
+ inputMask.on("complete", () => {
310
+ isComplete = true;
311
+ });
312
+ } catch (e) {
313
+ console.error("Error initializing IMask:", e);
314
+ // Fallback to plain input without masking
315
+ const handleInput = (e) => {
316
+ localValue = node.value;
317
+ lastEdit = new Date();
318
+ };
319
+ node.addEventListener("input", handleInput);
320
+ node.value = localValue || "";
321
+ return {
322
+ destroy() {
323
+ node.removeEventListener("input", handleInput);
324
+ },
325
+ };
326
+ }
232
327
 
233
328
  return {
234
329
  destroy() {
@@ -236,6 +331,8 @@
236
331
  },
237
332
  };
238
333
  }
334
+
335
+ $: console.log(value, localValue, isComplete);
239
336
  </script>
240
337
 
241
338
  <!-- svelte-ignore a11y-no-noninteractive-tabindex -->
@@ -302,7 +399,7 @@
302
399
  on:focusin={cellState.focus}
303
400
  >
304
401
  <span>
305
- {applyMask(localValue) || placeholder}
402
+ {displayValue || placeholder}
306
403
  </span>
307
404
  </div>
308
405
  {/if}
@@ -74,7 +74,7 @@
74
74
  {#if container.icon}
75
75
  <i
76
76
  class={container.icon}
77
- style:font-size={tabsIconsOnly ? "20px" : null}
77
+ style:font-size={tabsIconsOnly ? "20px" : "inherit"}
78
78
  style:color={container.color}
79
79
  ></i>
80
80
  {/if}
@@ -121,13 +121,12 @@
121
121
  flex: auto;
122
122
  display: flex;
123
123
  gap: 1rem;
124
- padding: 0.35rem 0.5rem;
125
- border-bottom: 1px solid var(--spectrum-global-color-gray-200);
126
- border-top: 1px solid var(--spectrum-global-color-gray-200);
124
+ padding-bottom: 0.25rem;
125
+ border-bottom: 1px solid var(--spectrum-global-color-gray-300);
127
126
  }
128
127
 
129
128
  .tabs.buttons {
130
- gap: 0.5rem;
129
+ gap: 0.25rem;
131
130
  }
132
131
 
133
132
  .tabs.list {
@@ -170,8 +169,12 @@
170
169
  }
171
170
 
172
171
  .tab.button {
173
- border-radius: 4px;
174
- padding: 0.35rem 1rem;
172
+ border-radius: 0.25rem;
173
+ padding: 0.5rem 1rem;
174
+ font-weight: 600;
175
+ line-height: 14px;
176
+ border: 1px solid transparent;
177
+ height: 1.85rem;
175
178
  }
176
179
 
177
180
  .tab.button.vertical {
@@ -179,12 +182,17 @@
179
182
  }
180
183
 
181
184
  .tab.button:active:not(.disabled):not(.list-section) {
182
- background-color: var(--spectrum-global-color-gray-200);
185
+ background-color: rgb(
186
+ from var(--spectrum-global-color-gray-200) r g b / 0.85
187
+ );
183
188
  }
184
189
 
185
190
  .tab.button.selected {
186
191
  color: var(--spectrum-global-color-gray-800);
187
- background-color: var(--spectrum-global-color-gray-300);
192
+ border: 1px solid var(--spectrum-global-color-gray-300);
193
+ background-color: rgb(
194
+ from var(--spectrum-global-color-gray-200) r g b / 0.85
195
+ );
188
196
  }
189
197
 
190
198
  .tab.list {
@@ -234,11 +242,13 @@
234
242
 
235
243
  .tab:hover:not(.disabled):not(.list-title):not(.list-section) {
236
244
  cursor: pointer;
237
- color: var(--spectrum-global-color-gray-800);
238
245
  }
239
246
 
240
247
  .tab.button:hover:not(.selected) {
241
- background-color: var(--spectrum-global-color-gray-200);
248
+ background-color: rgb(
249
+ from var(--spectrum-global-color-gray-200) r g b / 0.65
250
+ );
251
+ border-color: var(--spectrum-global-color-gray-200);
242
252
  }
243
253
 
244
254
  .tab.selected {