jsl-ui 9.29.0 → 10.0.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.
Files changed (164) hide show
  1. package/docs/AutoSuggestComponent.md +17 -0
  2. package/docs/ButtonComponent.md +14 -0
  3. package/docs/CheckBoxComponent.md +12 -0
  4. package/docs/DateComponent.md +12 -0
  5. package/docs/DateRangeComponent.md +13 -0
  6. package/docs/DateTimeComponent.md +13 -0
  7. package/docs/DialogComponent.md +15 -0
  8. package/docs/ExpanderComponent.md +13 -0
  9. package/docs/FormComponent.md +15 -0
  10. package/docs/FormFieldComponent.md +15 -0
  11. package/docs/GridComponent.md +19 -0
  12. package/docs/InputComponent.md +15 -0
  13. package/docs/IntervalComponent.md +13 -0
  14. package/docs/LoadingComponent.md +12 -0
  15. package/docs/NavigationComponent.md +17 -0
  16. package/docs/Notification.md +14 -0
  17. package/docs/NotificationComponent.md +13 -0
  18. package/docs/NumberComponent.md +12 -0
  19. package/docs/OverlayComponent.md +12 -0
  20. package/docs/ProgressComponent.md +12 -0
  21. package/docs/README.md +24 -0
  22. package/docs/RibbonMenuComponent.md +14 -0
  23. package/docs/SelectComponent.md +15 -0
  24. package/docs/SplitterComponent.md +14 -0
  25. package/docs/StackPanelComponent.md +13 -0
  26. package/docs/TabsComponent.md +16 -0
  27. package/docs/TimeComponent.md +13 -0
  28. package/docs/TreeViewComponent.md +16 -0
  29. package/examples/showcase/checks-and-expanders.ts +163 -0
  30. package/examples/showcase/cultures.ts +39 -0
  31. package/examples/showcase/dates.ts +182 -0
  32. package/examples/showcase/dialogs.ts +184 -0
  33. package/examples/showcase/feedback-and-navigation.ts +174 -0
  34. package/examples/showcase/fields.ts +178 -0
  35. package/examples/showcase/fonts/Jost-Variable.ttf +0 -0
  36. package/examples/showcase/fonts/OFL-Jost.txt +93 -0
  37. package/examples/showcase/grids.ts +150 -0
  38. package/examples/showcase/index.html +60 -0
  39. package/examples/showcase/layout-and-navigation.ts +47 -0
  40. package/examples/showcase/nivona.css +98 -0
  41. package/examples/showcase/selects.ts +158 -0
  42. package/examples/showcase/showcase.css +231 -0
  43. package/examples/showcase/showcase.ts +214 -0
  44. package/examples/showcase/tabs.ts +161 -0
  45. package/examples/showcase/themes.css +83 -0
  46. package/examples/showcase/themes.ts +54 -0
  47. package/lib/components/IntervalComponent.d.ts +5 -0
  48. package/lib/components/IntervalComponent.js +29 -13
  49. package/lib/components/auto-suggest/AutoSuggestComponent.d.ts +11 -9
  50. package/lib/components/auto-suggest/AutoSuggestComponent.js +25 -38
  51. package/lib/components/button/ButtonComponent.d.ts +30 -1
  52. package/lib/components/button/ButtonComponent.js +85 -4
  53. package/lib/components/checkbox/CheckBoxComponent.d.ts +11 -1
  54. package/lib/components/checkbox/CheckBoxComponent.js +66 -56
  55. package/lib/components/checkbox/CheckBoxStyle.scss +72 -85
  56. package/lib/components/date/DateComponent.d.ts +10 -0
  57. package/lib/components/date/DateComponent.js +92 -44
  58. package/lib/components/date-range/DateRangeComponent.d.ts +14 -3
  59. package/lib/components/date-range/DateRangeComponent.js +96 -86
  60. package/lib/components/date-range/DateRangeStyle.scss +35 -11
  61. package/lib/components/date-time/DateTimeComponent.d.ts +8 -0
  62. package/lib/components/date-time/DateTimeComponent.js +64 -23
  63. package/lib/components/date-time/DateTimeStyle.scss +10 -7
  64. package/lib/components/dialog/DialogComponent.d.ts +21 -7
  65. package/lib/components/dialog/DialogComponent.js +179 -122
  66. package/lib/components/expander/ExpanderComponent.d.ts +15 -1
  67. package/lib/components/expander/ExpanderComponent.js +85 -64
  68. package/lib/components/expander/ExpanderStyle.scss +61 -47
  69. package/lib/components/form-field/FormFieldComponent.d.ts +45 -15
  70. package/lib/components/form-field/FormFieldComponent.js +249 -96
  71. package/lib/components/form-field/FormFieldStyle.scss +36 -87
  72. package/lib/components/form-field/create-control.d.ts +7 -0
  73. package/lib/components/form-field/create-control.js +48 -0
  74. package/lib/components/input/InputComponent.d.ts +18 -1
  75. package/lib/components/input/InputComponent.js +68 -93
  76. package/lib/components/loading/LoadingComponent.d.ts +9 -2
  77. package/lib/components/loading/LoadingComponent.js +13 -12
  78. package/lib/components/loading/LoadingStyle.css +19 -29
  79. package/lib/components/navigation/NavigationComponent.d.ts +34 -10
  80. package/lib/components/navigation/NavigationComponent.js +261 -33
  81. package/lib/components/navigation/NavigationStyle.scss +62 -226
  82. package/lib/components/notification/Notification.d.ts +37 -4
  83. package/lib/components/notification/Notification.js +160 -41
  84. package/lib/components/notification/Notification.scss +103 -19
  85. package/lib/components/number/NumberComponent.d.ts +16 -2
  86. package/lib/components/number/NumberComponent.js +54 -53
  87. package/lib/components/overlay/OverlayComponent.d.ts +13 -7
  88. package/lib/components/overlay/OverlayComponent.js +46 -114
  89. package/lib/components/overlay/overlay.css +18 -57
  90. package/lib/components/progress/ProgressComponent.d.ts +1 -0
  91. package/lib/components/progress/ProgressComponent.js +6 -6
  92. package/lib/components/progress/ProgressStyle.scss +5 -15
  93. package/lib/components/ribbon-menu/RibbonMenuComponent.js +2 -2
  94. package/lib/components/ribbon-menu/RibbonMenuStyle.scss +6 -76
  95. package/lib/components/select/SelectComponent.d.ts +33 -3
  96. package/lib/components/select/SelectComponent.js +312 -278
  97. package/lib/components/select/SelectDDAreaComponent.d.ts +13 -7
  98. package/lib/components/select/SelectDDAreaComponent.js +215 -256
  99. package/lib/components/select/SelectStyle.scss +204 -186
  100. package/lib/components/slider/nouislider.css +40 -54
  101. package/lib/components/stack-panel/SplitterComponent.d.ts +19 -3
  102. package/lib/components/stack-panel/SplitterComponent.js +94 -111
  103. package/lib/components/stack-panel/SplitterStyle.scss +9 -45
  104. package/lib/components/stack-panel/StackPanelComponent.js +3 -3
  105. package/lib/components/stack-panel/StackPanelStyle.scss +10 -52
  106. package/lib/components/tabs/TabsComponent.d.ts +17 -1
  107. package/lib/components/tabs/TabsComponent.js +247 -123
  108. package/lib/components/tabs/TabsStyle.scss +138 -75
  109. package/lib/components/time/TimeComponent.d.ts +5 -0
  110. package/lib/components/time/TimeComponent.js +61 -69
  111. package/lib/components/time/TimeComponent.scss +4 -4
  112. package/lib/components/tree-view/TreeViewComponent.d.ts +10 -4
  113. package/lib/components/tree-view/TreeViewComponent.js +65 -32
  114. package/lib/components/tree-view/TreeViewStyle.scss +12 -96
  115. package/lib/core/jq.js +11 -8
  116. package/lib/grid/slick-default-theme.css +107 -31
  117. package/lib/grid/slick.creator.js +23 -5
  118. package/lib/grid/slick.formatters.js +4 -3
  119. package/lib/grid/slick.grid.css +38 -26
  120. package/lib/grid/slick.grid.d.ts +1 -0
  121. package/lib/grid/slick.grid.js +2 -3
  122. package/lib/grid.css +3413 -454
  123. package/lib/index.css +2500 -1031
  124. package/lib/index.css.map +1 -1
  125. package/lib/index.d.ts +1 -0
  126. package/lib/index.js +1 -1
  127. package/lib/index.js.map +1 -1
  128. package/lib/interaction/moveable.d.ts +1 -0
  129. package/lib/interaction/moveable.js +8 -0
  130. package/lib/interaction/resizable.d.ts +1 -0
  131. package/lib/interaction/resizable.js +9 -0
  132. package/lib/ui/auto.suggest.css +31 -14
  133. package/lib/ui/auto.suggest.d.ts +1 -0
  134. package/lib/ui/auto.suggest.js +88 -18
  135. package/lib/ui/base.css +2 -48
  136. package/lib/ui/button.css +134 -0
  137. package/lib/ui/date-input.css +11 -0
  138. package/lib/ui/date.picker/css/tiny-date-picker.css +124 -325
  139. package/lib/ui/date.picker/date-picker-options.js +4 -3
  140. package/lib/ui/date.picker/lib/date-manip.js +9 -0
  141. package/lib/ui/date.picker/mode/base-mode.d.ts +2 -1
  142. package/lib/ui/date.picker/mode/base-mode.js +112 -22
  143. package/lib/ui/date.picker/mode/dropdown-mode.d.ts +2 -4
  144. package/lib/ui/date.picker/mode/dropdown-mode.js +29 -42
  145. package/lib/ui/date.picker/mode/index.d.ts +2 -1
  146. package/lib/ui/date.picker/mode/modal-mode.d.ts +2 -1
  147. package/lib/ui/date.picker/mode/modal-mode.js +4 -2
  148. package/lib/ui/date.picker/mode/permanent-mode.d.ts +2 -1
  149. package/lib/ui/date.picker/views/day-picker.js +24 -15
  150. package/lib/ui/date.picker/views/month-picker.js +1 -1
  151. package/lib/ui/date.picker/views/year-picker.js +3 -2
  152. package/lib/ui/date.picker.d.ts +2 -1
  153. package/lib/ui/dialog.css +144 -108
  154. package/lib/ui/dialog.d.ts +19 -1
  155. package/lib/ui/dialog.js +178 -60
  156. package/lib/ui/input.css +35 -0
  157. package/lib/ui/number.input.js +50 -37
  158. package/lib/ui/theme.css +28 -0
  159. package/package.json +12 -8
  160. package/lib/components/drop-down/DropDownComponent.d.ts +0 -27
  161. package/lib/components/drop-down/DropDownComponent.js +0 -60
  162. package/lib/components/expander/OldExpanderStyle.scss +0 -37
  163. package/lib/ui/drop.down.d.ts +0 -52
  164. package/lib/ui/drop.down.js +0 -2112
package/lib/ui/dialog.css CHANGED
@@ -1,109 +1,145 @@
1
- .jsl-dialog {
2
- position: relative;
3
- z-index: 2002;
4
- background:white;
5
- border-radius: 0.8rem;
6
- pointer-events: all;
7
- border: 2px solid #dddddd;
8
- top: 50%;
9
- left: 50%;
10
- transform: translate(-50%, -50%);
11
- }
12
-
13
- .jsl-dialog .jsl-button {
14
- vertical-align: middle;
15
- /* color: #fff;
16
- background-color: #3b99ff;
17
- border: 1px solid #3b99ff; */
18
- cursor: pointer;
19
- height: 2rem;
20
- box-sizing: border-box;
21
- letter-spacing: .1rem;
22
- text-align: center;
23
- white-space: nowrap;
24
- border-radius: .3rem;
25
- padding: 0 1rem;
26
- line-height: 2rem;
27
- text-decoration: none;
28
- display: inline-block;
29
- }
30
-
31
- /* .jsl-dialog .jsl-button.jsl-button-outline {
32
- color: #444;
33
- background: #fff;
34
- } */
35
-
36
- .dlg-close-btn {
37
- color: #555555;
38
- font-size: 2rem;
39
- line-height: 2.8rem;
40
- font-weight: bold;
41
- position: absolute;
42
- right: 0;
43
- bottom: 0;
44
- top: 0;
45
- width: 2.5rem;
46
- box-sizing: border-box;
47
- border-top-right-radius: 0.8rem;
48
- cursor: pointer;
49
- background: #d8d8d8;
50
- }
51
-
52
- .dlg-close-btn:hover {
53
- background: #B22121;
54
- color: white;
55
- }
56
-
57
- .jsl-dialog-overlay {
58
- position: fixed;
59
- left:0;
60
- top:0;
61
- bottom:0;
62
- right:0;
63
- z-index: 2001;
64
- background:rgba(0,0,0,0.8);
65
- height: 100vh;
66
- }
67
-
68
- .jsl-dialog > .dlg-header {
69
- box-sizing: content-box;
70
- position: relative;
71
- height: 2rem;
72
- padding: 0.6rem;
73
- border-bottom: 1px solid #ededed;
74
- background: #f8f8f8;
75
- font-size: 1.5rem;
76
- border-top-right-radius: 0.8rem;
77
- border-top-left-radius: 0.8rem;
78
- text-align: center;
79
- }
80
-
81
- .jsl-dialog > .dlg-body {
82
- padding: 1rem;
83
- box-sizing: border-box;
84
- overflow: auto;
85
- margin-bottom: 3rem;
86
- }
87
-
88
- .jsl-dialog > .dlg-footer {
89
- position: absolute;
90
- bottom: 0;
91
- left: 0;
92
- right: 0;
93
- height: 3rem;
94
- box-sizing: border-box;
95
- padding: 0.5rem;
96
- border-top: 1px solid #ededed;
97
- background: #f8f8f8;
98
- border-bottom-right-radius: 0.8rem;
99
- border-bottom-left-radius: 0.8rem;
100
- text-align: right;
101
- }
102
-
103
- .jsl-dialog > .dlg-footer button {
104
- margin-left: 1rem;
105
- }
106
-
107
- .jsl-dialog .slickgrid {
108
- border-radius: 0;
1
+ @import "./button.css";
2
+
3
+ .jsl-dialog-overlay {
4
+ position: fixed;
5
+ inset: 0;
6
+ z-index: var(--jsl-dialog-z-index, 2001);
7
+ background: var(--jsl-dialog-backdrop, var(--jsl-color-overlay));
8
+ }
9
+
10
+ .jsl-dialog {
11
+ position: absolute;
12
+ top: 50%;
13
+ left: 50%;
14
+ transform: translate(-50%, -50%);
15
+ display: flex;
16
+ flex-direction: column;
17
+ box-sizing: border-box;
18
+ width: 32rem;
19
+ max-width: calc(100% - 2rem);
20
+ max-height: calc(100% - 2rem);
21
+ border: 1px solid var(--jsl-dialog-border, var(--jsl-color-border-subtle));
22
+ border-radius: var(--jsl-dialog-radius, 0.75rem);
23
+ background: var(--jsl-dialog-surface, var(--jsl-color-surface));
24
+ color: var(--jsl-color-text);
25
+ box-shadow: var(--jsl-dialog-shadow, var(--jsl-shadow-dialog));
26
+ font: inherit;
27
+ line-height: 1.5;
28
+ pointer-events: auto;
29
+ isolation: isolate;
30
+ }
31
+
32
+ .jsl-dialog:focus { outline: none; }
33
+ .jsl-dialog.resizable { position: absolute; }
34
+ .jsl-dialog:focus-visible { outline: 2px solid var(--jsl-color-focus); outline-offset: 3px; }
35
+
36
+ .jsl-dialog > .dlg-header {
37
+ display: flex;
38
+ align-items: center;
39
+ gap: 1rem;
40
+ flex: 0 0 auto;
41
+ box-sizing: border-box;
42
+ min-width: 0;
43
+ padding: 1.125rem 1.5rem;
44
+ border-bottom: 1px solid var(--jsl-color-border-subtle);
45
+ border-radius: var(--jsl-dialog-radius, 0.75rem) var(--jsl-dialog-radius, 0.75rem) 0 0;
46
+ font-size: 1rem;
47
+ font-weight: 600;
48
+ line-height: 1.5;
49
+ }
50
+
51
+ .jsl-dialog .dlg-title { flex: 1; min-width: 0; overflow-wrap: anywhere; }
52
+ .jsl-dialog-moveable > .dlg-header { cursor: move; touch-action: none; }
53
+
54
+ .jsl-dialog .dlg-close-btn {
55
+ position: relative;
56
+ display: inline-flex;
57
+ align-items: center;
58
+ justify-content: center;
59
+ flex: 0 0 auto;
60
+ box-sizing: border-box;
61
+ width: 2rem;
62
+ height: 2rem;
63
+ margin: -0.25rem -0.5rem -0.25rem auto;
64
+ padding: 0;
65
+ border: 1px solid transparent;
66
+ border-radius: 0.375rem;
67
+ background: transparent;
68
+ color: var(--jsl-color-text-secondary);
69
+ font: inherit;
70
+ cursor: pointer;
71
+ }
72
+
73
+ .jsl-dialog .dlg-close-btn::before,
74
+ .jsl-dialog .dlg-close-btn::after {
75
+ content: "";
76
+ position: absolute;
77
+ width: 0.875rem;
78
+ height: 1.5px;
79
+ border-radius: 1px;
80
+ background: currentColor;
81
+ transform: rotate(45deg);
82
+ }
83
+ .jsl-dialog .dlg-close-btn::after { transform: rotate(-45deg); }
84
+ .jsl-dialog .dlg-close-btn:hover { background: var(--jsl-color-surface-hover); color: var(--jsl-color-text); }
85
+ .jsl-dialog .dlg-close-btn:focus-visible { outline: 2px solid var(--jsl-color-focus); outline-offset: 2px; }
86
+
87
+ .jsl-dialog > .dlg-body {
88
+ flex: 1 1 auto;
89
+ box-sizing: border-box;
90
+ min-height: 0;
91
+ min-width: 0;
92
+ padding: 1.5rem;
93
+ overflow: auto;
94
+ overflow-wrap: anywhere;
95
+ overscroll-behavior: contain;
96
+ }
97
+
98
+ .jsl-dialog > .dlg-footer {
99
+ flex: 0 0 auto;
100
+ box-sizing: border-box;
101
+ padding: 1rem 1.5rem;
102
+ border-top: 1px solid var(--jsl-color-border-subtle);
103
+ border-radius: 0 0 var(--jsl-dialog-radius, 0.75rem) var(--jsl-dialog-radius, 0.75rem);
104
+ background: var(--jsl-color-surface-subtle);
105
+ text-align: end;
106
+ }
107
+
108
+ .jsl-dialog > .dlg-footer > div,
109
+ .jsl-dialog > .dlg-footer > form {
110
+ display: flex;
111
+ flex-wrap: wrap;
112
+ align-items: center;
113
+ justify-content: flex-end;
114
+ gap: 0.5rem;
115
+ }
116
+ .jsl-dialog > .dlg-footer > button + button { margin-inline-start: 0.5rem; }
117
+ .jsl-dialog > .dlg-header[hidden], .jsl-dialog > .dlg-footer[hidden] { display: none; }
118
+ .jsl-dialog .slickgrid { border-radius: 0; }
119
+
120
+ .jsl-dialog.resizable > .dlg-res-handle.rs-r.rs-b {
121
+ width: 1rem;
122
+ height: 1rem;
123
+ right: 0.125rem;
124
+ bottom: 0.125rem;
125
+ background: transparent;
126
+ cursor: nwse-resize;
127
+ touch-action: none;
128
+ }
129
+ .jsl-dialog .dlg-res-handle::after {
130
+ content: "";
131
+ position: absolute;
132
+ right: 0.2rem;
133
+ bottom: 0.2rem;
134
+ width: 0.4rem;
135
+ height: 0.4rem;
136
+ border-right: 1px solid var(--jsl-color-text-muted);
137
+ border-bottom: 1px solid var(--jsl-color-text-muted);
138
+ }
139
+
140
+ @media (max-width: 480px) {
141
+ .jsl-dialog { max-width: calc(100% - 1.5rem); max-height: calc(100% - 1.5rem); }
142
+ .jsl-dialog > .dlg-header { padding: 1rem 1.125rem; }
143
+ .jsl-dialog > .dlg-body { padding: 1.125rem; }
144
+ .jsl-dialog > .dlg-footer { padding: 0.875rem 1.125rem; }
109
145
  }
@@ -11,12 +11,30 @@ export interface IDialogOptions {
11
11
  }
12
12
  export declare class JSLDialog {
13
13
  private options;
14
+ private static opened;
15
+ private static bodyOverflow;
16
+ private static scrollLocked;
14
17
  private overlay;
15
18
  private el;
16
- private onKeydownEvent;
19
+ private isOpen;
20
+ private closed;
21
+ private destroyed;
22
+ private isModal;
23
+ private closing;
24
+ private previousFocus;
25
+ private focusTimer;
17
26
  constructor(el: HTMLElement, options: IDialogOptions);
18
27
  open(modal?: boolean): void;
19
28
  close(): void;
29
+ /** Release listeners and modal state without calling onClose. */
30
+ destroy(): void;
20
31
  getOverlay(): HTMLElement;
32
+ private static top;
33
+ private static updateScrollLock;
34
+ private deactivate;
35
+ private canFocus;
36
+ private focusInitial;
37
+ private onOverlayPress;
38
+ private onKeydownEvent;
21
39
  }
22
40
  export declare function Dialog(input: HTMLElement | string, options?: IDialogOptions): JSLDialog;
package/lib/ui/dialog.js CHANGED
@@ -1,97 +1,215 @@
1
1
  import "./dialog.css";
2
2
  const defaultOptions = {
3
3
  autoOpen: false,
4
- autoFocus: "input,button,textarea",
4
+ autoFocus: "input,button,textarea,select,[tabindex]",
5
5
  closeOnOverlayClick: true,
6
6
  modal: true,
7
7
  closeOnEscape: true
8
8
  };
9
+ let nextDialogId = 0;
9
10
  export class JSLDialog {
10
11
  constructor(el, options) {
11
12
  this.options = options;
13
+ this.isOpen = false;
14
+ this.closed = false;
15
+ this.destroyed = false;
16
+ this.isModal = false;
17
+ this.closing = false;
18
+ this.onOverlayPress = (event) => {
19
+ if (event.target === this.overlay && JSLDialog.top() === this) {
20
+ this.close();
21
+ }
22
+ };
23
+ this.onKeydownEvent = (event) => {
24
+ if (JSLDialog.top() !== this || event.defaultPrevented || event.isComposing) {
25
+ return;
26
+ }
27
+ if ((event.key === "Escape" || event.keyCode === 27) && this.options.closeOnEscape) {
28
+ event.preventDefault();
29
+ event.stopImmediatePropagation();
30
+ this.close();
31
+ }
32
+ else if ((event.key === "Enter" || event.keyCode === 13) && this.options.OkOnEnter) {
33
+ const target = event.target;
34
+ // Preserve native activation, multiline editing, and editable rich content.
35
+ if (!this.el.contains(target) || target.closest("button,a,textarea,[contenteditable]:not([contenteditable=false])")) {
36
+ return;
37
+ }
38
+ const ok = this.el.querySelector(".dlg-ok-btn");
39
+ if (ok && !ok.disabled) {
40
+ event.preventDefault();
41
+ ok.click();
42
+ }
43
+ }
44
+ else if (event.key === "Tab" && this.isModal) {
45
+ const targets = Array.from(this.el.querySelectorAll('a[href],area[href],input:not([type="hidden"]),select,textarea,button,[tabindex],[contenteditable="true"]')).filter(element => element.tabIndex >= 0 && this.canFocus(element));
46
+ const first = targets[0];
47
+ const last = targets[targets.length - 1];
48
+ const active = document.activeElement;
49
+ if (!first) {
50
+ event.preventDefault();
51
+ this.el.focus();
52
+ }
53
+ else if (event.shiftKey && (active === first || !targets.some(element => element === active))) {
54
+ event.preventDefault();
55
+ last.focus();
56
+ }
57
+ else if (!event.shiftKey && (active === last || !targets.some(element => element === active))) {
58
+ event.preventDefault();
59
+ first.focus();
60
+ }
61
+ }
62
+ };
12
63
  this.overlay = el;
13
64
  this.el = el.firstElementChild;
65
+ if (!this.el.hasAttribute("role")) {
66
+ this.el.setAttribute("role", "dialog");
67
+ }
68
+ if (!this.el.hasAttribute("tabindex")) {
69
+ this.el.setAttribute("tabindex", "-1");
70
+ }
71
+ const header = this.el.querySelector(".dlg-header");
72
+ if (header && !this.el.hasAttribute("aria-labelledby") && !this.el.hasAttribute("aria-label")) {
73
+ header.id = header.id || "jsl-dialog-title-" + ++nextDialogId;
74
+ this.el.setAttribute("aria-labelledby", header.id);
75
+ }
14
76
  if (this.options.closeOnOverlayClick) {
15
- this.overlay.addEventListener("mousedown", (evt) => {
16
- if (evt.target === this.overlay) {
17
- this.close();
18
- }
19
- });
20
- this.overlay.addEventListener("touchstart", (evt) => {
21
- if (evt.target === this.overlay) {
22
- this.close();
23
- }
24
- });
77
+ this.overlay.addEventListener("mousedown", this.onOverlayPress);
78
+ this.overlay.addEventListener("touchstart", this.onOverlayPress);
25
79
  }
26
80
  }
27
81
  open(modal) {
28
- if ((modal !== undefined && !modal) || !this.options.modal) {
29
- this.overlay.style.background = "transparent";
30
- this.overlay.style.pointerEvents = "none";
82
+ var _a, _b, _c;
83
+ if (this.isOpen || this.destroyed) {
84
+ return;
31
85
  }
86
+ this.closed = false;
87
+ this.isOpen = true;
88
+ this.isModal = (_a = modal !== null && modal !== void 0 ? modal : this.options.modal) !== null && _a !== void 0 ? _a : true;
89
+ this.previousFocus = document.activeElement;
90
+ const top = JSLDialog.top();
91
+ const baseZ = Number(getComputedStyle(this.overlay).zIndex) || 2001;
92
+ this.overlay.style.zIndex = String(Math.max(baseZ, top ? Number(top.overlay.style.zIndex) + 1 : baseZ));
93
+ this.overlay.style.background = this.isModal ? "" : "transparent";
94
+ this.overlay.style.pointerEvents = this.isModal ? "" : "none";
32
95
  this.overlay.style.display = "block";
33
- const $footer = this.el.querySelector(".dlg-footer");
34
- const $body = this.el.querySelector(".dlg-body");
35
- if ($footer != null && $body != null) {
36
- // TODO ?
37
- }
38
- if (this.options.autoFocus) {
39
- setTimeout(() => {
40
- const firstInput = this.el.querySelector(this.options.autoFocus);
41
- if (firstInput != null) {
42
- firstInput.focus();
43
- }
44
- }, 0);
45
- }
46
- if (this.options.closeOnEscape || this.options.OkOnEnter) {
47
- this.onKeydownEvent = (args) => {
48
- var _a;
49
- if (args.keyCode === 27 && this.options.closeOnEscape) { // escape
50
- this.close();
51
- }
52
- else if (args.keyCode === 13 && this.options.OkOnEnter) { // ok
53
- const ok_btn = this.el.querySelector(".dlg-ok-btn");
54
- if (ok_btn != null) {
55
- (_a = document.activeElement) === null || _a === void 0 ? void 0 : _a.blur();
56
- ok_btn.click();
57
- }
58
- }
59
- };
60
- document.addEventListener("keydown", this.onKeydownEvent);
96
+ if (this.isModal) {
97
+ this.el.setAttribute("aria-modal", "true");
61
98
  }
62
- if (this.options.onOpen) {
63
- this.options.onOpen();
99
+ else {
100
+ this.el.removeAttribute("aria-modal");
64
101
  }
102
+ JSLDialog.opened.push(this);
103
+ JSLDialog.updateScrollLock();
104
+ document.addEventListener("keydown", this.onKeydownEvent);
105
+ this.focusTimer = window.setTimeout(() => {
106
+ this.focusTimer = undefined;
107
+ if (this.isOpen && JSLDialog.top() === this) {
108
+ this.focusInitial();
109
+ }
110
+ }, 0);
111
+ (_c = (_b = this.options).onOpen) === null || _c === void 0 ? void 0 : _c.call(_b);
65
112
  }
66
113
  close() {
67
- if (this.options.onClose) {
68
- if (this.options.onClose() === false) {
114
+ var _a, _b;
115
+ if (this.closed || this.destroyed || this.closing) {
116
+ return;
117
+ }
118
+ this.closing = true;
119
+ try {
120
+ if (((_b = (_a = this.options).onClose) === null || _b === void 0 ? void 0 : _b.call(_a)) === false) {
69
121
  return;
70
122
  }
123
+ this.closed = true;
124
+ this.deactivate();
71
125
  }
72
- this.overlay.style.display = "none";
73
- if (this.onKeydownEvent != null) {
74
- document.removeEventListener("keydown", this.onKeydownEvent);
126
+ finally {
127
+ this.closing = false;
128
+ }
129
+ }
130
+ /** Release listeners and modal state without calling onClose. */
131
+ destroy() {
132
+ if (this.destroyed) {
133
+ return;
75
134
  }
135
+ this.destroyed = true;
136
+ this.closed = true;
137
+ this.deactivate();
138
+ this.overlay.removeEventListener("mousedown", this.onOverlayPress);
139
+ this.overlay.removeEventListener("touchstart", this.onOverlayPress);
76
140
  }
77
141
  getOverlay() {
78
142
  return this.overlay;
79
143
  }
144
+ static top() {
145
+ return JSLDialog.opened[JSLDialog.opened.length - 1];
146
+ }
147
+ static updateScrollLock() {
148
+ const lock = JSLDialog.opened.some(dialog => dialog.isModal);
149
+ if (lock && !JSLDialog.scrollLocked) {
150
+ JSLDialog.bodyOverflow = document.body.style.overflow;
151
+ document.body.style.overflow = "hidden";
152
+ }
153
+ else if (!lock && JSLDialog.scrollLocked) {
154
+ document.body.style.overflow = JSLDialog.bodyOverflow;
155
+ }
156
+ JSLDialog.scrollLocked = lock;
157
+ }
158
+ deactivate() {
159
+ var _a;
160
+ if (!this.isOpen) {
161
+ return;
162
+ }
163
+ const wasTop = JSLDialog.top() === this;
164
+ this.isOpen = false;
165
+ window.clearTimeout(this.focusTimer);
166
+ document.removeEventListener("keydown", this.onKeydownEvent);
167
+ const index = JSLDialog.opened.indexOf(this);
168
+ if (index >= 0) {
169
+ JSLDialog.opened.splice(index, 1);
170
+ }
171
+ this.overlay.style.display = "none";
172
+ this.overlay.style.zIndex = "";
173
+ JSLDialog.updateScrollLock();
174
+ if (wasTop) {
175
+ const top = JSLDialog.top();
176
+ if (((_a = this.previousFocus) === null || _a === void 0 ? void 0 : _a.isConnected) && (!(top === null || top === void 0 ? void 0 : top.isModal) || top.el.contains(this.previousFocus))) {
177
+ this.previousFocus.focus({ preventScroll: true });
178
+ }
179
+ else {
180
+ top === null || top === void 0 ? void 0 : top.focusInitial();
181
+ }
182
+ }
183
+ }
184
+ canFocus(element) {
185
+ return !element.matches(":disabled") && !element.closest("[inert]") &&
186
+ element.getClientRects().length > 0 && getComputedStyle(element).visibility !== "hidden";
187
+ }
188
+ focusInitial() {
189
+ if (this.options.autoFocus) {
190
+ const containers = [this.el.querySelector(".dlg-body"), this.el.querySelector(".dlg-footer"), this.el];
191
+ for (const container of containers) {
192
+ const target = container && Array.from(container.querySelectorAll(this.options.autoFocus))
193
+ .find(element => this.canFocus(element));
194
+ if (target) {
195
+ target.focus({ preventScroll: true });
196
+ return;
197
+ }
198
+ }
199
+ }
200
+ if (this.isModal) {
201
+ this.el.focus({ preventScroll: true });
202
+ }
203
+ }
80
204
  }
205
+ JSLDialog.opened = [];
206
+ JSLDialog.scrollLocked = false;
81
207
  export function Dialog(input, options) {
82
208
  const o = { ...defaultOptions, ...options };
83
- let el;
84
- if (typeof input === "string") {
85
- el = document.querySelector(input);
86
- }
87
- else {
88
- el = input;
89
- }
209
+ const el = typeof input === "string" ? document.querySelector(input) : input;
90
210
  const result = new JSLDialog(el, o);
91
- if (!o.autoOpen) {
92
- el.style.display = "none";
93
- }
94
- else {
211
+ el.style.display = "none";
212
+ if (o.autoOpen) {
95
213
  result.open();
96
214
  }
97
215
  return result;
@@ -0,0 +1,35 @@
1
+ @import "./theme.css";
2
+
3
+ .jsl-input, .jsl-date-input {
4
+ box-sizing: border-box;
5
+ width: 14rem;
6
+ max-width: 100%;
7
+ min-width: 0;
8
+ height: 2.5rem;
9
+ padding: .5rem .75rem;
10
+ border: 1px solid var(--jsl-color-border);
11
+ border-radius: .5rem;
12
+ background-color: var(--jsl-color-surface);
13
+ color: var(--jsl-color-text);
14
+ font: inherit;
15
+ font-size: .875rem;
16
+ line-height: 1.4;
17
+ transition: border-color .15s;
18
+ }
19
+ .jsl-input:hover:not(:disabled), .jsl-date-input:hover:not(:disabled) { border-color: var(--jsl-color-text-muted); }
20
+ .jsl-input:focus, .jsl-date-input:focus {
21
+ outline: 2px solid var(--jsl-color-focus);
22
+ outline-offset: 2px;
23
+ border-color: var(--jsl-color-accent);
24
+ }
25
+ .jsl-input::placeholder, .jsl-date-input::placeholder { color: var(--jsl-color-text-muted); opacity: 1; }
26
+ .jsl-input:disabled, .jsl-date-input:disabled {
27
+ cursor: not-allowed;
28
+ background-color: var(--jsl-color-disabled-surface);
29
+ color: var(--jsl-color-disabled-text);
30
+ }
31
+ .jsl-input[aria-invalid="true"] { border-color: var(--jsl-color-danger); }
32
+ textarea.jsl-input { min-height: 6rem; height: auto; resize: vertical; }
33
+ .jsl-input[type="color"] { width: 4rem; padding: .25rem; cursor: pointer; }
34
+ .jsl-input[type="number"], .jsl-input.jsl-number { font-variant-numeric: tabular-nums; }
35
+ @media (prefers-reduced-motion: reduce) { .jsl-input, .jsl-date-input { transition: none; } }