@contributte/datagrid 7.0.0 → 7.1.0

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
@@ -47,7 +47,7 @@ For details on how to use this package, check out our [documentation](.docs).
47
47
 
48
48
  | State | Version | Branch | Nette | PHP |
49
49
  |--------|-----------|----------|--------|---------|
50
- | dev | `^7.1.x` | `master` | `3.2+` | `>=8.3` |
50
+ | dev | `^7.1.x` | `master` | `3.2+` | `>=8.2` |
51
51
  | stable | `^7.0.0` | `master` | `3.2+` | `>=8.1` |
52
52
  | stable | `^6.10.0` | `master` | `3.0+` | `>=7.2` |
53
53
 
@@ -15,8 +15,7 @@ import type {
15
15
  SuccessEventDetail as BaseSuccessEventDetail,
16
16
  } from "../types";
17
17
  import { Datagrid } from "../datagrid";
18
- import { BeforeEvent, ErrorEvent, Payload as NajaPayload, SuccessEvent } from "naja/dist/Naja";
19
- import { InteractionEvent } from "naja/dist/core/UIHandler";
18
+ import { BeforeEvent, ErrorEvent, Payload as NajaPayload, SuccessEvent, InteractionEvent } from "naja";
20
19
 
21
20
  export interface BaseRequestParams extends AjaxBaseRequestParams, Request {
22
21
  url: string;
@@ -1,7 +1,5 @@
1
- /*
2
- * Use bootstrap and fontawesome from the CDN.
3
- */
4
1
  @import 'vanillajs-datepicker/dist/css/datepicker-bs5.css';
5
2
  @import "tom-select/dist/css/tom-select.css";
6
- @import './happy.css';
3
+ @import "tom-select/dist/css/tom-select.bootstrap5.css";
7
4
  @import './datagrid.css';
5
+ @import './tom-select.css';
@@ -272,10 +272,6 @@
272
272
  vertical-align: middle
273
273
  }
274
274
 
275
- [data-datagrid-name] table th.col-checkbox .happy-checkbox, [data-datagrid-name] table td.col-checkbox .happy-checkbox {
276
- margin-right: 0
277
- }
278
-
279
275
  [data-datagrid-name] table th.col-checkbox.col-checkbox-first, [data-datagrid-name] table td.col-checkbox.col-checkbox-first {
280
276
  border-top-color: transparent
281
277
  }
@@ -567,45 +563,41 @@
567
563
  user-select: none
568
564
  }
569
565
 
570
- [data-datagrid-name] .col-checkbox .happy-checkbox {
571
- margin-top: 2px
572
- }
573
-
574
566
  [data-datagrid-name] .datagrid-column-status-option-icon {
575
567
  float: right
576
568
  }
577
569
 
578
570
  @media (min-width: 768px) {
579
- [data-datagrid-name] .ublaboo-datagrid-th-form-inline .form-group {
571
+ [data-datagrid-name] .datagrid-th-form-inline .form-group {
580
572
  display: inline-block;
581
573
  margin-bottom: 0;
582
574
  vertical-align: middle
583
575
  }
584
576
 
585
- [data-datagrid-name] .ublaboo-datagrid-th-form-inline .form-control {
577
+ [data-datagrid-name] .datagrid-th-form-inline .form-control {
586
578
  display: inline-block;
587
579
  width: auto;
588
580
  vertical-align: middle
589
581
  }
590
582
 
591
- [data-datagrid-name] .ublaboo-datagrid-th-form-inline .form-control[hidden] {
583
+ [data-datagrid-name] .datagrid-th-form-inline .form-control[hidden] {
592
584
  display: none;
593
585
  }
594
586
 
595
- .ublaboo-datagrid-th-form-inline .form-control[hidden] {
587
+ .datagrid-th-form-inline .form-control[hidden] {
596
588
  display: none;
597
589
  }
598
590
 
599
- [data-datagrid-name] .ublaboo-datagrid-th-form-inline .input-group {
591
+ [data-datagrid-name] .datagrid-th-form-inline .input-group {
600
592
  display: inline-table;
601
593
  vertical-align: middle
602
594
  }
603
595
 
604
- [data-datagrid-name] .ublaboo-datagrid-th-form-inline .input-group .form-control {
596
+ [data-datagrid-name] .datagrid-th-form-inline .input-group .form-control {
605
597
  width: auto
606
598
  }
607
599
 
608
- [data-datagrid-name] .ublaboo-datagrid-th-form-inline .input-group > .form-control {
600
+ [data-datagrid-name] .datagrid-th-form-inline .input-group > .form-control {
609
601
  width: 100%
610
602
  }
611
603
 
@@ -613,23 +605,23 @@
613
605
  height: calc(1.5em + 0.5rem + 2px);
614
606
  }
615
607
 
616
- [data-datagrid-name] .ublaboo-datagrid-th-form-inline .control-label {
608
+ [data-datagrid-name] .datagrid-th-form-inline .control-label {
617
609
  margin-bottom: 0;
618
610
  vertical-align: middle
619
611
  }
620
612
 
621
- [data-datagrid-name] .ublaboo-datagrid-th-form-inline .radio, [data-datagrid-name] .ublaboo-datagrid-th-form-inline .checkbox {
613
+ [data-datagrid-name] .datagrid-th-form-inline .radio, [data-datagrid-name] .datagrid-th-form-inline .checkbox {
622
614
  display: inline-block;
623
615
  margin-top: 0;
624
616
  margin-bottom: 0;
625
617
  vertical-align: middle
626
618
  }
627
619
 
628
- [data-datagrid-name] .ublaboo-datagrid-th-form-inline .radio label, [data-datagrid-name] .ublaboo-datagrid-th-form-inline .checkbox label {
620
+ [data-datagrid-name] .datagrid-th-form-inline .radio label, [data-datagrid-name] .datagrid-th-form-inline .checkbox label {
629
621
  padding-left: 0
630
622
  }
631
623
 
632
- [data-datagrid-name] .ublaboo-datagrid-th-form-inline .radio input[type="radio"], [data-datagrid-name] .ublaboo-datagrid-th-form-inline .checkbox input[type="checkbox"] {
624
+ [data-datagrid-name] .datagrid-th-form-inline .radio input[type="radio"], [data-datagrid-name] .datagrid-th-form-inline .checkbox input[type="checkbox"] {
633
625
  position: relative;
634
626
  margin-left: 0
635
627
  }
@@ -0,0 +1,3 @@
1
+ .datagrid .form-select-sm .ts-control {
2
+ padding: 0.25rem 0.5rem !important;
3
+ }
@@ -6,8 +6,7 @@ import {
6
6
  ConfirmPlugin,
7
7
  createDatagrids,
8
8
  DatepickerPlugin,
9
- Happy,
10
- HappyPlugin,
9
+ EditablePlugin,
11
10
  InlinePlugin,
12
11
  ItemDetailPlugin,
13
12
  NetteFormsPlugin,
@@ -39,10 +38,10 @@ document.addEventListener("DOMContentLoaded", () => {
39
38
  new AutosubmitPlugin(),
40
39
  new CheckboxPlugin(),
41
40
  new ConfirmPlugin(),
41
+ new EditablePlugin(),
42
42
  new InlinePlugin(),
43
43
  new ItemDetailPlugin(),
44
44
  new NetteFormsPlugin(netteForms),
45
- new HappyPlugin(new Happy()),
46
45
  new SortablePlugin(new SortableJS()),
47
46
  new DatepickerPlugin(new VanillaDatepicker({ buttonClass: 'btn' })),
48
47
  new SelectpickerPlugin(new TomSelect(Select)),
@@ -5,7 +5,7 @@ import {
5
5
  AutosubmitPlugin,
6
6
  CheckboxPlugin,
7
7
  ConfirmPlugin,
8
- HappyPlugin,
8
+ EditablePlugin,
9
9
  InlinePlugin,
10
10
  NetteFormsPlugin,
11
11
  SelectpickerPlugin,
@@ -13,7 +13,7 @@ import {
13
13
  } from "./plugins";
14
14
  import { SortableJS } from "./integrations";
15
15
  import { DatepickerPlugin } from "./plugins";
16
- import { Happy, TomSelect, VanillaDatepicker } from "./integrations";
16
+ import { TomSelect, VanillaDatepicker } from "./integrations";
17
17
 
18
18
  export class Datagrid extends EventTarget {
19
19
  private static readonly defaultOptions: DatagridOptions = {
@@ -215,9 +215,9 @@ export const createFullDatagrids = (ajax: Ajax, _options: Partial<DatagridsOptio
215
215
  new AutosubmitPlugin(),
216
216
  new CheckboxPlugin(),
217
217
  new ConfirmPlugin(),
218
+ new EditablePlugin(),
218
219
  new InlinePlugin(),
219
220
  new NetteFormsPlugin(),
220
- new HappyPlugin(new Happy()),
221
221
  new SortablePlugin(new SortableJS()),
222
222
  new DatepickerPlugin(new VanillaDatepicker()),
223
223
  new SelectpickerPlugin(new TomSelect(Select))
@@ -1,4 +1,3 @@
1
- export * from "./happy";
2
1
  export * from "./sortable-js";
3
2
  export * from "./tom-select";
4
3
  export * from "./vanilla-datepicker";
@@ -14,17 +14,16 @@ export class TomSelect implements Selectpicker {
14
14
  const Select = this.select ?? window()?.TomSelect ?? null;
15
15
 
16
16
  if (Select) {
17
- for (const element of elements) {
18
- // Check if TomSelect is already initialized on the element
19
- if (element.tomselect) {
20
- continue;
17
+ elements.forEach(element => {
18
+ if(element.hasAttribute('data-Tom-Initialised')){
19
+ return;
21
20
  }
21
+ element.setAttribute('data-Tom-Initialised','true');
22
22
 
23
23
  new Select(
24
24
  element as TomInput,
25
- typeof this.opts === "function" ? this.opts(element) : this.opts
26
- )
27
- }
25
+ typeof this.opts === "function" ? this.opts(element) : this.opts)
26
+ })
28
27
  }
29
28
  }
30
29
  }
@@ -0,0 +1,7 @@
1
+ declare module 'tom-select/dist/types/types' {
2
+ export type RecursivePartial<T> = {
3
+ [P in keyof T]?: RecursivePartial<T[P]>;
4
+ };
5
+ export type TomInput = HTMLInputElement | HTMLSelectElement;
6
+ export interface TomSettings { /* minimal needed interface */ }
7
+ }
@@ -30,10 +30,8 @@ export class AutosubmitPlugin implements DatagridPlugin {
30
30
  if (!inputEl) {
31
31
  inputEl = pageSelectEl.parentElement?.querySelector("button[type=submit]");
32
32
  }
33
- console.log({ inputEl });
34
33
  if (!(inputEl instanceof HTMLElement)) return;
35
34
  const form = inputEl.closest('form');
36
- console.log({ form });
37
35
  form && datagrid.ajax.submitForm(form);
38
36
  });
39
37
  });
@@ -5,6 +5,14 @@ export const CheckboxAttribute = "data-check";
5
5
 
6
6
  export class CheckboxPlugin implements DatagridPlugin {
7
7
  onDatagridInit(datagrid: Datagrid): boolean {
8
+ datagrid.ajax.addEventListener('complete', (event) => {
9
+ this.init(datagrid);
10
+ });
11
+
12
+ return this.init(datagrid);
13
+ }
14
+
15
+ private init(datagrid: Datagrid): boolean {
8
16
  let lastCheckbox = null;
9
17
 
10
18
  datagrid.el.addEventListener("click", e => {
@@ -36,15 +44,18 @@ export class CheckboxPlugin implements DatagridPlugin {
36
44
  }
37
45
  });
38
46
 
39
- let checkboxes = datagrid.el.querySelectorAll<HTMLInputElement>(`input[data-check='${datagrid.name}']`);
47
+ const checkboxes = Array.from(datagrid.el.querySelectorAll<HTMLInputElement>(`input[data-check='${datagrid.name}']:not([data-check-all])`));
48
+ const selectAll = datagrid.el.querySelector<HTMLInputElement>(`input[data-check='${datagrid.name}'][data-check-all]`);
49
+
40
50
  const select = datagrid.el.querySelector<HTMLSelectElement>("select[name='group_action[group_action]']");
41
51
  const actionButtons = document.querySelectorAll<HTMLInputElement | HTMLButtonElement>(
42
52
  ".row-group-actions *[type='submit']"
43
53
  );
44
54
  const counter = document.querySelector<HTMLElement>(".datagrid-selected-rows-count");
45
55
 
46
- // Handling a checkbox click + select all checkbox
47
- checkboxes.forEach(checkEl => {
56
+ [...checkboxes, selectAll].forEach(checkEl => {
57
+ if (!checkEl) return;
58
+
48
59
  checkEl.addEventListener("change", () => {
49
60
  // Select all
50
61
  const isSelectAll = checkEl.hasAttribute("data-check-all");
@@ -53,7 +64,6 @@ export class CheckboxPlugin implements DatagridPlugin {
53
64
 
54
65
  checkboxes.forEach(checkbox => (checkbox.checked = checkEl.checked));
55
66
 
56
- // todo: refactor not to repeat this code twice
57
67
  actionButtons.forEach(button => (button.disabled = !checkEl.checked));
58
68
 
59
69
  if (select) {
@@ -61,18 +71,17 @@ export class CheckboxPlugin implements DatagridPlugin {
61
71
  }
62
72
 
63
73
  if (counter) {
64
- const total = Array.from(checkboxes).filter(c => !c.hasAttribute("data-check-all")).length;
74
+ const total = checkboxes.length;
65
75
  counter.innerText = `${checkEl.checked ? total : 0}/${total}`;
66
76
  }
67
77
  return;
68
78
  } else {
69
- const selectAll = datagrid.el.querySelector<HTMLInputElement>(`input[data-check='${datagrid.name}'][data-check-all]`);
70
79
  if (selectAll) {
71
- selectAll.checked = Array.from(checkboxes).filter(c => !c.hasAttribute("data-check-all")).every(c => c.checked);
80
+ selectAll.checked = checkboxes.every(c => c.checked);
72
81
  }
73
82
  }
74
83
 
75
- const checkedBoxes = Array.from(checkboxes).filter(checkbox => checkbox.checked && !checkEl.hasAttribute("data-check-all"));
84
+ const checkedBoxes = checkboxes.filter(c => c.checked);
76
85
  const hasChecked = checkedBoxes.length >= 1;
77
86
 
78
87
  actionButtons.forEach(button => (button.disabled = !hasChecked));
@@ -14,105 +14,119 @@ export const EditableAttrsAttribute = "datagrid-editable-attrs";
14
14
 
15
15
  export class EditablePlugin implements DatagridPlugin {
16
16
  onDatagridInit(datagrid: Datagrid): boolean {
17
+ datagrid.ajax.addEventListener('success', (event) => {
18
+ this.initEditableCells(datagrid);
19
+ });
20
+
21
+ this.initEditableCells(datagrid);
22
+
23
+ return true;
24
+ }
25
+
26
+ initEditableCells(datagrid: Datagrid) {
27
+
17
28
  datagrid.el.querySelectorAll<HTMLElement>(`[${EditableUrlAttribute}]`).forEach(cell => {
18
- if (cell instanceof HTMLAnchorElement || cell.classList.contains("datagrid-inline-edit")) return;
19
-
20
- if (!cell.classList.contains("editing")) {
21
- cell.classList.add("editing");
22
- const originalValue = cell.innerHTML.replace(/<\/?br>/g, "\n");
23
- const valueToEdit = cell.getAttribute(EditableValueAttribute) ?? originalValue;
24
-
25
- cell.setAttribute("originalValue", originalValue);
26
- cell.setAttribute("valueToEdit", valueToEdit);
27
-
28
- const type = cell.getAttribute(EditableTypeAttribute) ?? "text";
29
-
30
- let input: HTMLElement;
31
-
32
- switch (type) {
33
- case "textarea":
34
- cell.innerHTML = `<textarea rows="${calculateCellLines(cell)}">${valueToEdit}</textarea>`;
35
- input = cell.querySelector("textarea")!;
36
- break;
37
- case "select":
38
- input = cell.querySelector(cell.getAttribute(EditableElementAttribute) ?? "")!;
39
- input
40
- .querySelectorAll(`option[value='${valueToEdit}']`)
41
- .forEach(input => input.setAttribute("selected", "true"));
42
- break;
43
- default:
44
- cell.innerHTML = `<input type='${type}' />`;
45
- input = cell.querySelector("input")!;
46
- }
47
29
 
48
- const attributes = JSON.parse(cell.getAttribute(EditableAttrsAttribute) ?? "{}");
49
- for (const key in attributes) {
50
- const value = attributes[key];
51
- input.setAttribute(key, value);
52
- }
30
+ cell.addEventListener("click", e => {
31
+
32
+ if (cell instanceof HTMLAnchorElement || cell.classList.contains("datagrid-inline-edit")) return;
33
+
34
+ if (!cell.classList.contains("editing")) {
35
+ cell.classList.add("editing");
36
+ const originalValue = cell.innerHTML.replace(/<\/?br>/g, "\n");
37
+ const valueToEdit = cell.getAttribute(EditableValueAttribute) ?? originalValue;
38
+
39
+ cell.setAttribute("originalValue", originalValue);
40
+ cell.setAttribute("valueToEdit", valueToEdit);
41
+
42
+ const type = cell.getAttribute(EditableTypeAttribute) ?? "text";
43
+
44
+ let input: HTMLElement;
45
+
46
+ switch (type) {
47
+ case "textarea":
48
+ cell.innerHTML = `<textarea rows="${calculateCellLines(cell)}">${valueToEdit}</textarea>`;
49
+ input = cell.querySelector("textarea")!;
50
+ break;
51
+ case "select":
52
+ input = cell.querySelector(cell.getAttribute(EditableElementAttribute) ?? "")!;
53
+ input
54
+ .querySelectorAll(`option[value='${valueToEdit}']`)
55
+ .forEach(input => input.setAttribute("selected", "true"));
56
+ break;
57
+ default:
58
+ cell.innerHTML = `<input type='${type}' />`;
59
+ input = cell.querySelector("input")!;
60
+ input.setAttribute("value", valueToEdit.trim());
61
+ }
62
+
63
+ const attributes = JSON.parse(cell.getAttribute(EditableAttrsAttribute) ?? "{}");
64
+ for (const key in attributes) {
65
+ const value = attributes[key];
66
+ input.setAttribute(key, value);
67
+ }
53
68
 
54
- cell.classList.remove("edited");
55
-
56
- const submitCell = async (el: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement) => {
57
- let value = el.value;
58
- if (value !== valueToEdit) {
59
- try {
60
- const response = await datagrid.ajax.request({
61
- url: cell.getAttribute(EditableUrlAttribute) ?? "",
62
- method: "POST",
63
- data: {
64
- value,
65
- },
66
- }) as any;
67
-
68
- if (type === "select") {
69
- cell.innerHTML = cell.querySelector(`option[value='${value}']`)?.innerHTML ?? "";
70
- } else {
71
- if (response._datagrid_editable_new_value) {
72
- value = response._datagrid_editable_new_value;
69
+ cell.classList.remove("edited");
70
+
71
+ const submitCell = async (el: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement) => {
72
+ let value = el.value;
73
+ if (value !== valueToEdit) {
74
+ try {
75
+ const response = await datagrid.ajax.request({
76
+ url: cell.getAttribute(EditableUrlAttribute) ?? "",
77
+ method: "POST",
78
+ data: {
79
+ value,
80
+ },
81
+ }) as any;
82
+
83
+ if (type === "select") {
84
+ cell.innerHTML = cell.querySelector(`option[value='${value}']`)?.innerHTML ?? "";
85
+ } else {
86
+ if (response._datagrid_editable_new_value) {
87
+ value = response._datagrid_editable_new_value;
88
+ }
89
+ cell.innerHTML = value;
73
90
  }
74
- cell.innerHTML = value;
91
+ cell.classList.add("edited");
92
+ } catch {
93
+ cell.innerHTML = originalValue;
94
+ cell.classList.add("edited-error");
75
95
  }
76
- cell.classList.add("edited");
77
- } catch {
96
+ } else {
78
97
  cell.innerHTML = originalValue;
79
- cell.classList.add("edited-error");
80
98
  }
81
- } else {
82
- cell.innerHTML = originalValue;
83
- }
84
99
 
85
- cell.classList.remove("editing");
86
- };
87
-
88
- cell
89
- .querySelectorAll<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>(
90
- "input, textarea, select"
91
- )
92
- .forEach(el => {
93
- el.addEventListener("blur", () => submitCell(el));
94
- el.addEventListener("keydown", e => {
95
- if (isEnter(e as KeyboardEvent)) {
96
- e.stopPropagation();
97
- e.preventDefault();
98
- return submitCell(el);
99
- }
100
+ cell.classList.remove("editing");
101
+ };
102
+
103
+ cell
104
+ .querySelectorAll<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>(
105
+ "input, textarea, select"
106
+ )
107
+ .forEach(el => {
108
+ el.addEventListener("blur", () => submitCell(el));
109
+ el.addEventListener("keydown", e => {
110
+ if (isEnter(e as KeyboardEvent)) {
111
+ e.stopPropagation();
112
+ e.preventDefault();
113
+ return submitCell(el);
114
+ }
100
115
 
101
- if (isEsc(e as KeyboardEvent)) {
102
- e.stopPropagation();
103
- e.preventDefault();
104
- cell.classList.remove("editing");
105
- cell.innerHTML = originalValue;
116
+ if (isEsc(e as KeyboardEvent)) {
117
+ e.stopPropagation();
118
+ e.preventDefault();
119
+ cell.classList.remove("editing");
120
+ cell.innerHTML = originalValue;
121
+ }
122
+ });
123
+
124
+ if (el instanceof HTMLSelectElement) {
125
+ el.addEventListener("change", () => submitCell(el));
106
126
  }
107
127
  });
108
-
109
- if (el instanceof HTMLSelectElement) {
110
- el.addEventListener("change", () => submitCell(el));
111
- }
112
- });
113
- }
128
+ }
129
+ });
114
130
  });
115
-
116
- return true;
117
131
  }
118
132
  }
@@ -15,12 +15,22 @@ export class TreeViewPlugin implements DatagridPlugin {
15
15
  if (childrenBlock.classList.contains('showed')) {
16
16
  childrenBlock.innerHTML = '';
17
17
  childrenBlock.classList.remove('showed');
18
- rowBlock.querySelector(`a.chevron`).style.transform = "rotate(0deg)";
18
+ if (rowBlock) {
19
+ const chevron = rowBlock.querySelector<HTMLAnchorElement>(`a.chevron`);
20
+ if (chevron) {
21
+ chevron.style.transform = "rotate(0deg)";
22
+ }
23
+ }
19
24
  return;
20
25
  }
21
26
 
22
27
  childrenBlock.classList.add('showed');
23
- rowBlock.querySelector(`a.chevron`).style.transform = "rotate(90deg)";
28
+ if (rowBlock) {
29
+ const chevron = rowBlock.querySelector<HTMLAnchorElement>(`a.chevron`);
30
+ if (chevron) {
31
+ chevron.style.transform = "rotate(90deg)";
32
+ }
33
+ }
24
34
  const snippets = payload.snippets;
25
35
  for (const snippetName in snippets) {
26
36
  const snippet = snippets[snippetName];
@@ -1,5 +1,4 @@
1
1
  export * from "./integrations/datepicker";
2
- export * from "./integrations/happy";
3
2
  export * from "./integrations/nette-forms"
4
3
  export * from "./integrations/selectpicker";
5
4
  export * from "./integrations/sortable";
@@ -7,12 +7,20 @@ export class NetteFormsPlugin implements DatagridPlugin {
7
7
  }
8
8
 
9
9
  onDatagridInit(datagrid: Datagrid): boolean {
10
+ datagrid.ajax.addEventListener('complete', (event) => {
11
+ this.initNetteForms(datagrid);
12
+ });
13
+
14
+ this.initNetteForms(datagrid);
15
+
16
+ return true;
17
+ }
18
+
19
+ private initNetteForms(datagrid: Datagrid): void {
10
20
  const nette = this.nette ?? window().Nette ?? null;
11
21
 
12
22
  if (nette) {
13
23
  datagrid.el.querySelectorAll<HTMLFormElement>("form").forEach(form => nette.initForm(form));
14
24
  }
15
-
16
- return true;
17
25
  }
18
26
  }
@@ -1,4 +1,3 @@
1
- import { Happy } from "../integrations";
2
1
  import TomSelect from "tom-select";
3
2
 
4
3
  export interface Nette {
@@ -13,7 +12,6 @@ export interface ExtendedWindow extends Window {
13
12
  jQuery?: any;
14
13
  Nette?: Nette;
15
14
  TomSelect?: Constructor<TomSelect>;
16
- happy?: Happy;
17
15
  }
18
16
 
19
17
  // https://github.com/naja-js/naja/blob/384d298a9199bf778985d1bcf5747fe8de305b22/src/utils.ts