@webitel/ui-sdk 26.6.83 → 26.6.85

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.
@@ -1,4 +1,4 @@
1
- import "./components-B2L1ZiHW.js";
1
+ import "./components-BuLx9sx8.js";
2
2
  import { t as e } from "./_plugin-vue_export-helper-B3ysoDQm.js";
3
3
  import { l as t } from "./enums-De8CDKZ1.js";
4
4
  import { t as n } from "./wt-button-dC4nOW56.js";
@@ -3,10 +3,10 @@ import { d as t, f as n, l as r, r as i } from "./enums-De8CDKZ1.js";
3
3
  import { a, i as o, n as s, r as c, t as l } from "./toZonedTime-B8L5kbse.js";
4
4
  import { t as u } from "./vue-i18n-Db_oYfO8.js";
5
5
  import { t as d } from "./useValidation-DGl2otXJ.js";
6
- import { computed as f, createBlock as p, createCommentVNode as m, createElementBlock as ee, createElementVNode as h, createTextVNode as g, createVNode as _, defineComponent as v, guardReactiveProps as y, mergeModels as b, mergeProps as x, nextTick as S, normalizeProps as C, onMounted as w, onUnmounted as T, openBlock as E, renderSlot as D, resolveComponent as O, toDisplayString as k, toRefs as A, unref as j, useModel as M, useTemplateRef as N, vShow as P, watch as F, withCtx as I, withDirectives as L } from "vue";
7
- import R from "primevue/datepicker";
6
+ import { computed as f, createBlock as p, createCommentVNode as m, createElementBlock as ee, createElementVNode as h, createTextVNode as g, createVNode as _, defineComponent as v, guardReactiveProps as y, mergeModels as b, mergeProps as x, nextTick as S, normalizeProps as C, onMounted as w, onUnmounted as T, openBlock as E, renderSlot as D, resolveComponent as O, toDisplayString as k, toRefs as A, unref as j, useModel as M, useTemplateRef as N, vShow as P, withCtx as F, withDirectives as I } from "vue";
7
+ import L from "primevue/datepicker";
8
8
  //#region node_modules/date-fns-tz/dist/esm/fromZonedTime/index.js
9
- function z(e, t, n) {
9
+ function R(e, t, n) {
10
10
  if (typeof e == "string" && !e.match(c)) return s(e, {
11
11
  ...n,
12
12
  timeZone: t
@@ -16,6 +16,34 @@ function z(e, t, n) {
16
16
  return new Date(r + i);
17
17
  }
18
18
  //#endregion
19
+ //#region src/components/wt-datepicker/_internals/composables/useOverlayAnchor.ts
20
+ function z() {
21
+ let e = null;
22
+ function t(e, t) {
23
+ e.style.width !== t && (e.style.width = t, e.style.minWidth = "");
24
+ }
25
+ function n(e, t, n) {
26
+ e.style.transformOrigin !== t && (e.style.transformOrigin = t, e.style.top = n);
27
+ }
28
+ function r(r) {
29
+ e?.disconnect();
30
+ let i = r.style.width, a = r.style.transformOrigin, o = r.style.top;
31
+ e = new MutationObserver(() => {
32
+ t(r, i), n(r, a, o);
33
+ }), e.observe(r, {
34
+ attributes: !0,
35
+ attributeFilter: ["style"]
36
+ });
37
+ }
38
+ function i() {
39
+ e?.disconnect(), e = null;
40
+ }
41
+ return T(i), {
42
+ lock: r,
43
+ unlock: i
44
+ };
45
+ }
46
+ //#endregion
19
47
  //#region src/components/wt-datepicker/_internals/composables/usePreventZeroPad.ts
20
48
  function B(e) {
21
49
  let t = null;
@@ -48,24 +76,15 @@ function B(e) {
48
76
  }
49
77
  //#endregion
50
78
  //#region src/components/wt-datepicker/_internals/composables/useRestoreOnBlur.ts
51
- function V(e, t, n) {
52
- let r = null;
53
- function i() {
54
- F(e, (e) => {
55
- e !== null && (r = e);
56
- }, { immediate: !0 });
57
- }
58
- function a() {
59
- if (n()) return;
60
- let e = t();
61
- e && e.rawValue === null && r !== null && S(() => {
62
- e.updateModel(new Date(r.getTime()));
79
+ function V(e, t) {
80
+ function n() {
81
+ if (t()) return;
82
+ let n = e();
83
+ n && n.rawValue === null && S(() => {
84
+ n.updateModel(/* @__PURE__ */ new Date());
63
85
  });
64
86
  }
65
- return {
66
- onBlur: a,
67
- watchRestoreOnBlurLastValidValue: i
68
- };
87
+ return { onBlur: n };
69
88
  }
70
89
  //#endregion
71
90
  //#region src/components/wt-datepicker/wt-datepicker.vue?vue&type=script&setup=true&lang.ts
@@ -195,14 +214,12 @@ var H = { class: "wt-datepicker" }, U = { class: "wt-datepicker__button-bar" },
195
214
  s.value = null;
196
215
  return;
197
216
  }
198
- let t = o.timezone ? z(e, o.timezone) : e;
217
+ let t = o.timezone ? R(e, o.timezone) : e;
199
218
  s.value = t.getTime();
200
219
  }
201
220
  }), b = N("datepicker"), w = `datepicker-${Math.random().toString(36).slice(2, 11)}`;
202
221
  B(() => b.value?.$el?.querySelector("input"));
203
- let { onBlur: T, watchRestoreOnBlurLastValidValue: F } = V(v, () => b.value, () => !!o.clearable);
204
- F();
205
- let J = f(() => o.placholder || `dd/mm/yyyy ${o.showTime ? "hh:mm" : ""}`), Y = () => {
222
+ let { onBlur: T } = V(() => b.value, () => !!o.clearable), J = f(() => o.placholder || `dd/mm/yyyy ${o.showTime ? "hh:mm" : ""}`), { lock: Y, unlock: X } = z(), Z = () => {
206
223
  if (o.showTime && v.value) {
207
224
  let e = v.value;
208
225
  S(() => {
@@ -212,23 +229,25 @@ var H = { class: "wt-datepicker" }, U = { class: "wt-datepicker__button-bar" },
212
229
  setTimeout(() => {
213
230
  b.value?.alignOverlay();
214
231
  let e = b.value?.overlay;
215
- e && (e.style.minWidth = "");
232
+ e && (e.style.minWidth = "", Y(e));
216
233
  }, 0);
217
- }, X = f(() => o.required ? `${o.label}*` : o.label), { v: Z, customValidators: Q } = A(o), { isValidation: te, invalid: ne, validationText: $, validationTextColor: re } = d({
218
- v: Z,
219
- customValidators: Q
234
+ }, Q = () => {
235
+ X();
236
+ }, te = f(() => o.required ? `${o.label}*` : o.label), { v: ne, customValidators: re } = A(o), { isValidation: ie, invalid: ae, validationText: $, validationTextColor: oe } = d({
237
+ v: ne,
238
+ customValidators: re
220
239
  });
221
240
  return (a, o) => {
222
241
  let s = O("wt-label"), l = O("wt-button"), u = O("wt-icon-btn"), d = O("wt-message");
223
242
  return E(), ee("div", H, [
224
243
  _(s, x(e.labelProps, { disabled: e.disabled }, {
225
244
  for: w,
226
- invalid: j(ne)
245
+ invalid: j(ae)
227
246
  }), {
228
- default: I(() => [D(a.$slots, "label", C(y({ label: e.label })), () => [g(k(X.value), 1)], !0)], void 0, !0),
247
+ default: F(() => [D(a.$slots, "label", C(y({ label: e.label })), () => [g(k(te.value), 1)], !0)], void 0, !0),
229
248
  _: 3
230
249
  }, 16, ["disabled", "invalid"]),
231
- _(j(R), {
250
+ _(j(L), {
232
251
  ref_key: "datepicker",
233
252
  ref: b,
234
253
  id: w,
@@ -254,29 +273,30 @@ var H = { class: "wt-datepicker" }, U = { class: "wt-datepicker__button-bar" },
254
273
  minute: { class: "typo-body-2" },
255
274
  panel: { style: { maxWidth: "380px" } }
256
275
  },
257
- onShow: Y,
276
+ onShow: Z,
277
+ onHide: Q,
258
278
  onBlur: j(T)
259
279
  }, {
260
- buttonbar: I(({ todayCallback: i, clearCallback: a }) => [h("div", U, [_(l, {
280
+ buttonbar: F(({ todayCallback: i, clearCallback: a }) => [h("div", U, [_(l, {
261
281
  color: j(n).SECONDARY,
262
282
  variant: j(t).OUTLINED,
263
283
  size: j(r).SM,
264
284
  onClick: i
265
285
  }, {
266
- default: I(() => [g(k(j(c)("reusable.today")), 1)], void 0, !0),
286
+ default: F(() => [g(k(j(c)("reusable.today")), 1)], void 0, !0),
267
287
  _: 1
268
288
  }, 8, [
269
289
  "color",
270
290
  "variant",
271
291
  "size",
272
292
  "onClick"
273
- ]), L(_(l, {
293
+ ]), I(_(l, {
274
294
  color: j(n).SECONDARY,
275
295
  variant: j(t).OUTLINED,
276
296
  size: j(r).SM,
277
297
  onClick: a
278
298
  }, {
279
- default: I(() => [g(k(j(c)("reusable.clear")), 1)], void 0, !0),
299
+ default: F(() => [g(k(j(c)("reusable.clear")), 1)], void 0, !0),
280
300
  _: 1
281
301
  }, 8, [
282
302
  "color",
@@ -284,35 +304,35 @@ var H = { class: "wt-datepicker" }, U = { class: "wt-datepicker__button-bar" },
284
304
  "size",
285
305
  "onClick"
286
306
  ]), [[P, e.clearable && v.value]])])]),
287
- prevbutton: I(({ actionCallback: e }) => [_(u, {
307
+ prevbutton: F(({ actionCallback: e }) => [_(u, {
288
308
  icon: "arrow-left",
289
309
  onClick: e
290
310
  }, null, 8, ["onClick"])]),
291
- nextbutton: I(({ actionCallback: e }) => [_(u, {
311
+ nextbutton: F(({ actionCallback: e }) => [_(u, {
292
312
  icon: "arrow-right",
293
313
  onClick: e
294
314
  }, null, 8, ["onClick"])]),
295
- clearicon: I(({ clearCallback: e }) => [_(u, {
315
+ clearicon: F(({ clearCallback: e }) => [_(u, {
296
316
  icon: "close",
297
317
  class: "wt-datepicker__clear-icon",
298
318
  onClick: e
299
319
  }, null, 8, ["onClick"])]),
300
- hourincrementbutton: I(({ callbacks: e }) => [h("span", {
320
+ hourincrementbutton: F(({ callbacks: e }) => [h("span", {
301
321
  onMousedown: e.mousedown,
302
322
  onMouseup: e.mouseup,
303
323
  onMouseleave: e.mouseleave
304
324
  }, [_(u, { icon: "arrow-up" })], 40, W)]),
305
- hourdecrementbutton: I(({ callbacks: e }) => [h("span", {
325
+ hourdecrementbutton: F(({ callbacks: e }) => [h("span", {
306
326
  onMousedown: e.mousedown,
307
327
  onMouseup: e.mouseup,
308
328
  onMouseleave: e.mouseleave
309
329
  }, [_(u, { icon: "arrow-down" })], 40, G)]),
310
- minuteincrementbutton: I(({ callbacks: e }) => [h("span", {
330
+ minuteincrementbutton: F(({ callbacks: e }) => [h("span", {
311
331
  onMousedown: e.mousedown,
312
332
  onMouseup: e.mouseup,
313
333
  onMouseleave: e.mouseleave
314
334
  }, [_(u, { icon: "arrow-up" })], 40, K)]),
315
- minutedecrementbutton: I(({ callbacks: e }) => [h("span", {
335
+ minutedecrementbutton: F(({ callbacks: e }) => [h("span", {
316
336
  onMousedown: e.mousedown,
317
337
  onMouseup: e.mouseup,
318
338
  onMouseleave: e.mouseleave
@@ -329,13 +349,13 @@ var H = { class: "wt-datepicker" }, U = { class: "wt-datepicker__button-bar" },
329
349
  "show-clear",
330
350
  "onBlur"
331
351
  ]),
332
- j(te) && j($) ? (E(), p(d, {
352
+ j(ie) && j($) ? (E(), p(d, {
333
353
  key: 0,
334
- color: j(re),
354
+ color: j(oe),
335
355
  variant: j(i).SIMPLE,
336
356
  size: j(r).SM
337
357
  }, {
338
- default: I(() => [g(k(j($)), 1)], void 0, !0),
358
+ default: F(() => [g(k(j($)), 1)], void 0, !0),
339
359
  _: 1
340
360
  }, 8, [
341
361
  "color",
@@ -345,6 +365,6 @@ var H = { class: "wt-datepicker" }, U = { class: "wt-datepicker__button-bar" },
345
365
  ]);
346
366
  };
347
367
  }
348
- }), [["__scopeId", "data-v-4be684aa"]]);
368
+ }), [["__scopeId", "data-v-d1bf89b4"]]);
349
369
  //#endregion
350
370
  export { J as default };
@@ -1,4 +1,4 @@
1
- import { C as e, i as t } from "./components-B2L1ZiHW.js";
1
+ import { C as e, i as t } from "./components-BuLx9sx8.js";
2
2
  import { t as n } from "./_plugin-vue_export-helper-B3ysoDQm.js";
3
3
  import { t as r } from "./displayText-CtaxzaBz.js";
4
4
  import { Fragment as i, computed as a, createCommentVNode as o, createElementBlock as s, createTextVNode as c, createVNode as l, defineComponent as u, openBlock as d, renderList as f, renderSlot as p, toDisplayString as m, unref as h, withCtx as g } from "vue";
@@ -1,5 +1,5 @@
1
1
  import { n as e, r as t } from "./clients-IxWZVjVW.js";
2
- import { n } from "./components-B2L1ZiHW.js";
2
+ import { n } from "./components-BuLx9sx8.js";
3
3
  import { t as r } from "./vue-i18n-Db_oYfO8.js";
4
4
  import { createBlock as i, createTextVNode as a, createVNode as o, defineComponent as s, inject as c, mergeProps as l, onMounted as u, openBlock as d, ref as f, resolveComponent as p, toDisplayString as m, unref as h, withCtx as g } from "vue";
5
5
  //#endregion
@@ -1,5 +1,5 @@
1
1
  import { t as e } from "./clients-IxWZVjVW.js";
2
- import { a as t, o as n, r, s as i } from "./components-B2L1ZiHW.js";
2
+ import { a as t, o as n, r, s as i } from "./components-BuLx9sx8.js";
3
3
  import { t as a } from "./enums-De8CDKZ1.js";
4
4
  import { t as o } from "./vue-i18n-Db_oYfO8.js";
5
5
  import { computed as s, createBlock as c, createCommentVNode as l, createVNode as u, defineComponent as d, mergeModels as f, mergeProps as p, openBlock as m, renderSlot as h, resolveComponent as g, unref as _, useModel as v } from "vue";
@@ -1,4 +1,4 @@
1
- import { w as e } from "./components-B2L1ZiHW.js";
1
+ import { w as e } from "./components-BuLx9sx8.js";
2
2
  import { t } from "./_plugin-vue_export-helper-B3ysoDQm.js";
3
3
  import { l as n } from "./enums-De8CDKZ1.js";
4
4
  import "./wt-button-dC4nOW56.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webitel/ui-sdk",
3
- "version": "26.6.83",
3
+ "version": "26.6.85",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "dev": "npm run docs:dev",
@@ -9,6 +9,6 @@
9
9
  min-width: 0;
10
10
  border-radius: var(--wt-card-border-radius);
11
11
  padding: var(--wt-card-padding);
12
- box-shadow: var(--elevation-5);
12
+ box-shadow: var(--elevation-3);
13
13
  }
14
14
  </style>
@@ -0,0 +1,56 @@
1
+ import { onUnmounted } from 'vue';
2
+
3
+ // Prevents PrimeVue's currentView watcher from:
4
+ // - widening the overlay when switching to the month/year grid
5
+ // - flipping the overlay between above/below the input when panel height changes
6
+ export function useOverlayAnchor() {
7
+ let observer: MutationObserver | null = null;
8
+
9
+ // https://webitel.atlassian.net/browse/WTEL-9906
10
+ function lockWidth(panel: HTMLElement, lockedWidth: string) {
11
+ if (panel.style.width !== lockedWidth) {
12
+ panel.style.width = lockedWidth;
13
+ panel.style.minWidth = '';
14
+ }
15
+ }
16
+
17
+ // https://webitel.atlassian.net/browse/WTEL-9860?focusedCommentId=766440
18
+ function lockSide(panel: HTMLElement, lockedSide: string, lockedTop: string) {
19
+ if (panel.style.transformOrigin !== lockedSide) {
20
+ panel.style.transformOrigin = lockedSide;
21
+ panel.style.top = lockedTop;
22
+ }
23
+ }
24
+
25
+ function lock(panel: HTMLElement) {
26
+ observer?.disconnect();
27
+
28
+ const lockedWidth = panel.style.width;
29
+ const lockedSide = panel.style.transformOrigin; // 'top' = below input, 'bottom' = above
30
+ const lockedTop = panel.style.top;
31
+
32
+ observer = new MutationObserver(() => {
33
+ lockWidth(panel, lockedWidth);
34
+ lockSide(panel, lockedSide, lockedTop);
35
+ });
36
+
37
+ observer.observe(panel, {
38
+ attributes: true,
39
+ attributeFilter: [
40
+ 'style',
41
+ ],
42
+ });
43
+ }
44
+
45
+ function unlock() {
46
+ observer?.disconnect();
47
+ observer = null;
48
+ }
49
+
50
+ onUnmounted(unlock);
51
+
52
+ return {
53
+ lock,
54
+ unlock,
55
+ };
56
+ }
@@ -5,7 +5,7 @@ import { nextTick, type WritableComputedRef, watch } from 'vue';
5
5
  *
6
6
  * https://webitel.atlassian.net/browse/WTEL-9880
7
7
  *
8
- * When the datepicker is not clearable, restores the last valid value on blur
8
+ * When the datepicker is not clearable, set current date value on blur
9
9
  * if the user left the field empty or typed an invalid date.
10
10
  *
11
11
  * Since the parent model never becomes null (null writes are blocked in the
@@ -14,40 +14,24 @@ import { nextTick, type WritableComputedRef, watch } from 'vue';
14
14
  * redraws the input.
15
15
  */
16
16
  export function useRestoreOnBlur(
17
- modelValue: WritableComputedRef<Date | null>,
18
17
  getDatepicker: () => {
19
18
  rawValue: Date | null;
20
19
  updateModel: (v: Date) => void;
21
20
  } | null,
22
21
  isClearable: () => boolean,
23
22
  ) {
24
- let lastValid: Date | null = null;
25
-
26
- function watchRestoreOnBlurLastValidValue() {
27
- watch(
28
- modelValue,
29
- (value) => {
30
- if (value !== null) lastValid = value;
31
- },
32
- {
33
- immediate: true,
34
- },
35
- );
36
- }
37
-
38
23
  function onBlur() {
39
24
  if (isClearable()) return;
40
25
  const datePickerEl = getDatepicker();
41
26
  if (!datePickerEl) return;
42
- if (datePickerEl.rawValue === null && lastValid !== null) {
27
+ if (datePickerEl.rawValue === null) {
43
28
  nextTick(() => {
44
- datePickerEl.updateModel(new Date(lastValid.getTime()));
29
+ datePickerEl.updateModel(new Date());
45
30
  });
46
31
  }
47
32
  }
48
33
 
49
34
  return {
50
35
  onBlur,
51
- watchRestoreOnBlurLastValidValue,
52
36
  };
53
37
  }
@@ -49,6 +49,7 @@
49
49
  }
50
50
  }"
51
51
  @show="onPanelShow"
52
+ @hide="onPanelHide"
52
53
  @blur="onBlur"
53
54
  >
54
55
  <template #buttonbar="{ todayCallback, clearCallback }">
@@ -152,6 +153,7 @@ import {
152
153
  MessageVariant,
153
154
  } from '../../enums';
154
155
  import { useValidation } from '../../mixins/validationMixin/useValidation';
156
+ import { useOverlayAnchor } from './_internals/composables/useOverlayAnchor';
155
157
  import { usePreventZeroPad } from './_internals/composables/usePreventZeroPad';
156
158
  import { useRestoreOnBlur } from './_internals/composables/useRestoreOnBlur';
157
159
 
@@ -208,18 +210,17 @@ const datepickerId = `datepicker-${Math.random().toString(36).slice(2, 11)}`;
208
210
 
209
211
  usePreventZeroPad(() => datepicker.value?.$el?.querySelector('input'));
210
212
 
211
- const { onBlur, watchRestoreOnBlurLastValidValue } = useRestoreOnBlur(
212
- modelValue,
213
+ const { onBlur } = useRestoreOnBlur(
213
214
  () => datepicker.value,
214
215
  () => !!props.clearable,
215
216
  );
216
217
 
217
- watchRestoreOnBlurLastValidValue();
218
-
219
218
  const getPlaceholder = computed(() => {
220
219
  return props.placholder || `dd/mm/yyyy ${props.showTime ? 'hh:mm' : ''}`;
221
220
  });
222
221
 
222
+ const { lock: lockOverlay, unlock: unlockOverlay } = useOverlayAnchor();
223
+
223
224
  // PrimeVue initializes its internal currentHour/currentMinute from new Date() when the
224
225
  // overlay opens, ignoring the model value. Re-assigning the same value forces a re-sync.
225
226
  const onPanelShow = () => {
@@ -234,10 +235,16 @@ const onPanelShow = () => {
234
235
  setTimeout(() => {
235
236
  datepicker.value?.alignOverlay();
236
237
  const panel = datepicker.value?.overlay;
237
- if (panel) panel.style.minWidth = '';
238
+ if (!panel) return;
239
+ panel.style.minWidth = '';
240
+ lockOverlay(panel);
238
241
  }, 0);
239
242
  };
240
243
 
244
+ const onPanelHide = () => {
245
+ unlockOverlay();
246
+ };
247
+
241
248
  const requiredLabel = computed(() => {
242
249
  return props.required ? `${props.label}*` : props.label;
243
250
  });
@@ -16,6 +16,8 @@ export const MimeTypes = {
16
16
  APPLICATION_MSWORD: 'application/msword',
17
17
  APPLICATION_DOCX:
18
18
  'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
19
+ APPLICATION_XLSX:
20
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
19
21
  } as const;
20
22
 
21
23
  export type MimeTypes = (typeof MimeTypes)[keyof typeof MimeTypes];
@@ -0,0 +1,4 @@
1
+ export declare function useOverlayAnchor(): {
2
+ lock: (panel: HTMLElement) => void;
3
+ unlock: () => void;
4
+ };
@@ -1,10 +1,9 @@
1
- import { type WritableComputedRef } from 'vue';
2
1
  /**
3
2
  * @author @HlukhovYe
4
3
  *
5
4
  * https://webitel.atlassian.net/browse/WTEL-9880
6
5
  *
7
- * When the datepicker is not clearable, restores the last valid value on blur
6
+ * When the datepicker is not clearable, set current date value on blur
8
7
  * if the user left the field empty or typed an invalid date.
9
8
  *
10
9
  * Since the parent model never becomes null (null writes are blocked in the
@@ -12,10 +11,9 @@ import { type WritableComputedRef } from 'vue';
12
11
  * call PrimeVue's internal updateModel() directly so it resyncs rawValue and
13
12
  * redraws the input.
14
13
  */
15
- export declare function useRestoreOnBlur(modelValue: WritableComputedRef<Date | null>, getDatepicker: () => {
14
+ export declare function useRestoreOnBlur(getDatepicker: () => {
16
15
  rawValue: Date | null;
17
16
  updateModel: (v: Date) => void;
18
17
  } | null, isClearable: () => boolean): {
19
18
  onBlur: () => void;
20
- watchRestoreOnBlurLastValidValue: () => void;
21
19
  };
@@ -12,5 +12,6 @@ export declare const MimeTypes: {
12
12
  readonly APPLICATION_PDF: "application/pdf";
13
13
  readonly APPLICATION_MSWORD: "application/msword";
14
14
  readonly APPLICATION_DOCX: "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
15
+ readonly APPLICATION_XLSX: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
15
16
  };
16
17
  export type MimeTypes = (typeof MimeTypes)[keyof typeof MimeTypes];