kanto-ds 1.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 (192) hide show
  1. package/LICENSE +26 -0
  2. package/README.md +155 -0
  3. package/dist/assets/fonts/README.md +19 -0
  4. package/dist/assets/fonts/manrope/OFL.txt +93 -0
  5. package/dist/assets/fonts/manrope/manrope-cyrillic-ext-wght-normal.woff2 +0 -0
  6. package/dist/assets/fonts/manrope/manrope-cyrillic-wght-normal.woff2 +0 -0
  7. package/dist/assets/fonts/manrope/manrope-latin-ext-wght-normal.woff2 +0 -0
  8. package/dist/assets/fonts/manrope/manrope-latin-wght-normal.woff2 +0 -0
  9. package/dist/assets/fonts/mulish/OFL.txt +93 -0
  10. package/dist/assets/fonts/mulish/mulish-cyrillic-ext-wght-italic.woff2 +0 -0
  11. package/dist/assets/fonts/mulish/mulish-cyrillic-ext-wght-normal.woff2 +0 -0
  12. package/dist/assets/fonts/mulish/mulish-cyrillic-wght-italic.woff2 +0 -0
  13. package/dist/assets/fonts/mulish/mulish-cyrillic-wght-normal.woff2 +0 -0
  14. package/dist/assets/fonts/mulish/mulish-latin-ext-wght-italic.woff2 +0 -0
  15. package/dist/assets/fonts/mulish/mulish-latin-ext-wght-normal.woff2 +0 -0
  16. package/dist/assets/fonts/mulish/mulish-latin-wght-italic.woff2 +0 -0
  17. package/dist/assets/fonts/mulish/mulish-latin-wght-normal.woff2 +0 -0
  18. package/dist/assets/fonts/source_code_pro/OFL.txt +93 -0
  19. package/dist/assets/fonts/source_code_pro/SourceCodePro-Regular.woff2 +0 -0
  20. package/dist/chunks/dialog-CPIfFIlF.js +29 -0
  21. package/dist/chunks/dialog-CPIfFIlF.js.map +1 -0
  22. package/dist/chunks/events-Bjl5Zmmq.js +18 -0
  23. package/dist/chunks/events-Bjl5Zmmq.js.map +1 -0
  24. package/dist/chunks/form-control-CxjBTt1c.js +17 -0
  25. package/dist/chunks/form-control-CxjBTt1c.js.map +1 -0
  26. package/dist/chunks/kt-element-CcMLO5e8.js +28 -0
  27. package/dist/chunks/kt-element-CcMLO5e8.js.map +1 -0
  28. package/dist/chunks/listbox-CUXYn_3S.js +101 -0
  29. package/dist/chunks/listbox-CUXYn_3S.js.map +1 -0
  30. package/dist/chunks/registry-X4LS9J5K.js +30 -0
  31. package/dist/chunks/registry-X4LS9J5K.js.map +1 -0
  32. package/dist/chunks/slots-BPbIdxAJ.js +7 -0
  33. package/dist/chunks/slots-BPbIdxAJ.js.map +1 -0
  34. package/dist/chunks/toaster-PmdKSV5x.js +40 -0
  35. package/dist/chunks/toaster-PmdKSV5x.js.map +1 -0
  36. package/dist/components/core/kt-avatar/kt-avatar.d.ts +49 -0
  37. package/dist/components/core/kt-avatar/kt-avatar.js +156 -0
  38. package/dist/components/core/kt-avatar/kt-avatar.js.map +1 -0
  39. package/dist/components/core/kt-badge/kt-badge.d.ts +77 -0
  40. package/dist/components/core/kt-badge/kt-badge.js +254 -0
  41. package/dist/components/core/kt-badge/kt-badge.js.map +1 -0
  42. package/dist/components/core/kt-button/kt-button.d.ts +71 -0
  43. package/dist/components/core/kt-button/kt-button.js +271 -0
  44. package/dist/components/core/kt-button/kt-button.js.map +1 -0
  45. package/dist/components/core/kt-card/kt-card.d.ts +62 -0
  46. package/dist/components/core/kt-card/kt-card.js +230 -0
  47. package/dist/components/core/kt-card/kt-card.js.map +1 -0
  48. package/dist/components/core/kt-code/kt-code.d.ts +55 -0
  49. package/dist/components/core/kt-code/kt-code.js +155 -0
  50. package/dist/components/core/kt-code/kt-code.js.map +1 -0
  51. package/dist/components/core/kt-icon/kt-icon.d.ts +44 -0
  52. package/dist/components/core/kt-icon/kt-icon.js +85 -0
  53. package/dist/components/core/kt-icon/kt-icon.js.map +1 -0
  54. package/dist/components/core/kt-kbd/kt-kbd.d.ts +38 -0
  55. package/dist/components/core/kt-kbd/kt-kbd.js +89 -0
  56. package/dist/components/core/kt-kbd/kt-kbd.js.map +1 -0
  57. package/dist/components/data/kt-chart/kt-chart.d.ts +99 -0
  58. package/dist/components/data/kt-chart/kt-chart.js +406 -0
  59. package/dist/components/data/kt-chart/kt-chart.js.map +1 -0
  60. package/dist/components/data/kt-meter/kt-meter.d.ts +63 -0
  61. package/dist/components/data/kt-meter/kt-meter.js +177 -0
  62. package/dist/components/data/kt-meter/kt-meter.js.map +1 -0
  63. package/dist/components/data/kt-pagination/kt-pagination.d.ts +35 -0
  64. package/dist/components/data/kt-pagination/kt-pagination.js +88 -0
  65. package/dist/components/data/kt-pagination/kt-pagination.js.map +1 -0
  66. package/dist/components/data/kt-stat/kt-stat.d.ts +60 -0
  67. package/dist/components/data/kt-stat/kt-stat.js +137 -0
  68. package/dist/components/data/kt-stat/kt-stat.js.map +1 -0
  69. package/dist/components/data/kt-table/kt-table.d.ts +99 -0
  70. package/dist/components/data/kt-table/kt-table.js +340 -0
  71. package/dist/components/data/kt-table/kt-table.js.map +1 -0
  72. package/dist/components/data/kt-timeline/kt-timeline.d.ts +78 -0
  73. package/dist/components/data/kt-timeline/kt-timeline.js +252 -0
  74. package/dist/components/data/kt-timeline/kt-timeline.js.map +1 -0
  75. package/dist/components/feedback/kt-alert/kt-alert.d.ts +46 -0
  76. package/dist/components/feedback/kt-alert/kt-alert.js +180 -0
  77. package/dist/components/feedback/kt-alert/kt-alert.js.map +1 -0
  78. package/dist/components/feedback/kt-empty-state/kt-empty-state.d.ts +40 -0
  79. package/dist/components/feedback/kt-empty-state/kt-empty-state.js +100 -0
  80. package/dist/components/feedback/kt-empty-state/kt-empty-state.js.map +1 -0
  81. package/dist/components/feedback/kt-progress-bar/kt-progress-bar.d.ts +53 -0
  82. package/dist/components/feedback/kt-progress-bar/kt-progress-bar.js +212 -0
  83. package/dist/components/feedback/kt-progress-bar/kt-progress-bar.js.map +1 -0
  84. package/dist/components/feedback/kt-skeleton/kt-skeleton.d.ts +43 -0
  85. package/dist/components/feedback/kt-skeleton/kt-skeleton.js +117 -0
  86. package/dist/components/feedback/kt-skeleton/kt-skeleton.js.map +1 -0
  87. package/dist/components/feedback/kt-toast/kt-toast.d.ts +57 -0
  88. package/dist/components/feedback/kt-toast/kt-toast.js +231 -0
  89. package/dist/components/feedback/kt-toast/kt-toast.js.map +1 -0
  90. package/dist/components/feedback/kt-toast-container/kt-toast-container.d.ts +60 -0
  91. package/dist/components/feedback/kt-toast-container/kt-toast-container.js +100 -0
  92. package/dist/components/feedback/kt-toast-container/kt-toast-container.js.map +1 -0
  93. package/dist/components/feedback/kt-toast-container/toaster.d.ts +37 -0
  94. package/dist/components/feedback/kt-tooltip/kt-tooltip.d.ts +57 -0
  95. package/dist/components/feedback/kt-tooltip/kt-tooltip.js +138 -0
  96. package/dist/components/feedback/kt-tooltip/kt-tooltip.js.map +1 -0
  97. package/dist/components/forms/kt-drag-drop/kt-drag-drop.d.ts +68 -0
  98. package/dist/components/forms/kt-drag-drop/kt-drag-drop.js +287 -0
  99. package/dist/components/forms/kt-drag-drop/kt-drag-drop.js.map +1 -0
  100. package/dist/components/forms/kt-form/kt-form.d.ts +75 -0
  101. package/dist/components/forms/kt-form/kt-form.js +187 -0
  102. package/dist/components/forms/kt-form/kt-form.js.map +1 -0
  103. package/dist/components/forms/kt-input/kt-input.d.ts +112 -0
  104. package/dist/components/forms/kt-input/kt-input.js +556 -0
  105. package/dist/components/forms/kt-input/kt-input.js.map +1 -0
  106. package/dist/components/forms/kt-input-menu/kt-input-menu.d.ts +60 -0
  107. package/dist/components/forms/kt-input-menu/kt-input-menu.js +313 -0
  108. package/dist/components/forms/kt-input-menu/kt-input-menu.js.map +1 -0
  109. package/dist/components/forms/kt-label-input/kt-label-input.d.ts +42 -0
  110. package/dist/components/forms/kt-label-input/kt-label-input.js +69 -0
  111. package/dist/components/forms/kt-label-input/kt-label-input.js.map +1 -0
  112. package/dist/components/forms/kt-select/kt-select.d.ts +80 -0
  113. package/dist/components/forms/kt-select/kt-select.js +334 -0
  114. package/dist/components/forms/kt-select/kt-select.js.map +1 -0
  115. package/dist/components/forms/kt-textarea/kt-textarea.d.ts +62 -0
  116. package/dist/components/forms/kt-textarea/kt-textarea.js +239 -0
  117. package/dist/components/forms/kt-textarea/kt-textarea.js.map +1 -0
  118. package/dist/components/forms/kt-toggle/kt-toggle.d.ts +53 -0
  119. package/dist/components/forms/kt-toggle/kt-toggle.js +170 -0
  120. package/dist/components/forms/kt-toggle/kt-toggle.js.map +1 -0
  121. package/dist/components/navigation/kt-breadcrumb/kt-breadcrumb.d.ts +45 -0
  122. package/dist/components/navigation/kt-breadcrumb/kt-breadcrumb.js +93 -0
  123. package/dist/components/navigation/kt-breadcrumb/kt-breadcrumb.js.map +1 -0
  124. package/dist/components/navigation/kt-header/kt-header.d.ts +67 -0
  125. package/dist/components/navigation/kt-header/kt-header.js +195 -0
  126. package/dist/components/navigation/kt-header/kt-header.js.map +1 -0
  127. package/dist/components/navigation/kt-page-header/kt-page-header.d.ts +48 -0
  128. package/dist/components/navigation/kt-page-header/kt-page-header.js +111 -0
  129. package/dist/components/navigation/kt-page-header/kt-page-header.js.map +1 -0
  130. package/dist/components/navigation/kt-segmented-control/kt-segmented-control.d.ts +63 -0
  131. package/dist/components/navigation/kt-segmented-control/kt-segmented-control.js +228 -0
  132. package/dist/components/navigation/kt-segmented-control/kt-segmented-control.js.map +1 -0
  133. package/dist/components/navigation/kt-sub-menu-navigation/kt-sub-menu-navigation.d.ts +94 -0
  134. package/dist/components/navigation/kt-sub-menu-navigation/kt-sub-menu-navigation.js +265 -0
  135. package/dist/components/navigation/kt-sub-menu-navigation/kt-sub-menu-navigation.js.map +1 -0
  136. package/dist/components/navigation/kt-tabs/kt-tabs.d.ts +64 -0
  137. package/dist/components/navigation/kt-tabs/kt-tabs.js +175 -0
  138. package/dist/components/navigation/kt-tabs/kt-tabs.js.map +1 -0
  139. package/dist/components/navigation/kt-toggle-button/kt-toggle-button.d.ts +50 -0
  140. package/dist/components/navigation/kt-toggle-button/kt-toggle-button.js +191 -0
  141. package/dist/components/navigation/kt-toggle-button/kt-toggle-button.js.map +1 -0
  142. package/dist/components/navigation/kt-toggle-button-group/kt-toggle-button-group.d.ts +55 -0
  143. package/dist/components/navigation/kt-toggle-button-group/kt-toggle-button-group.js +128 -0
  144. package/dist/components/navigation/kt-toggle-button-group/kt-toggle-button-group.js.map +1 -0
  145. package/dist/components/overlays/kt-collapsible/kt-collapsible.d.ts +42 -0
  146. package/dist/components/overlays/kt-collapsible/kt-collapsible.js +107 -0
  147. package/dist/components/overlays/kt-collapsible/kt-collapsible.js.map +1 -0
  148. package/dist/components/overlays/kt-confirm-dialog/kt-confirm-dialog.d.ts +56 -0
  149. package/dist/components/overlays/kt-confirm-dialog/kt-confirm-dialog.js +155 -0
  150. package/dist/components/overlays/kt-confirm-dialog/kt-confirm-dialog.js.map +1 -0
  151. package/dist/components/overlays/kt-dropdown/kt-dropdown.d.ts +64 -0
  152. package/dist/components/overlays/kt-dropdown/kt-dropdown.js +212 -0
  153. package/dist/components/overlays/kt-dropdown/kt-dropdown.js.map +1 -0
  154. package/dist/components/overlays/kt-modal/kt-modal.d.ts +61 -0
  155. package/dist/components/overlays/kt-modal/kt-modal.js +207 -0
  156. package/dist/components/overlays/kt-modal/kt-modal.js.map +1 -0
  157. package/dist/components/overlays/kt-side-panel/kt-side-panel.d.ts +52 -0
  158. package/dist/components/overlays/kt-side-panel/kt-side-panel.js +178 -0
  159. package/dist/components/overlays/kt-side-panel/kt-side-panel.js.map +1 -0
  160. package/dist/icons/defaults.d.ts +25 -0
  161. package/dist/icons/index.d.ts +3 -0
  162. package/dist/icons/index.js +37 -0
  163. package/dist/icons/index.js.map +1 -0
  164. package/dist/icons/registry.d.ts +38 -0
  165. package/dist/index.d.ts +81 -0
  166. package/dist/index.js +96 -0
  167. package/dist/index.js.map +1 -0
  168. package/dist/internal/countries.d.ts +37 -0
  169. package/dist/internal/dialog.d.ts +22 -0
  170. package/dist/internal/events.d.ts +14 -0
  171. package/dist/internal/form-control.d.ts +27 -0
  172. package/dist/internal/format.d.ts +8 -0
  173. package/dist/internal/kt-element.d.ts +22 -0
  174. package/dist/internal/listbox.d.ts +36 -0
  175. package/dist/internal/slots.d.ts +10 -0
  176. package/dist/react/index.d.ts +208 -0
  177. package/dist/react/index.js +314 -0
  178. package/dist/react/index.js.map +1 -0
  179. package/dist/styles.css +13 -0
  180. package/dist/tokens/README.md +63 -0
  181. package/dist/tokens/base.css +79 -0
  182. package/dist/tokens/colors.css +125 -0
  183. package/dist/tokens/fonts.css +136 -0
  184. package/dist/tokens/index.css +12 -0
  185. package/dist/tokens/responsive.css +108 -0
  186. package/dist/tokens/spacing.css +66 -0
  187. package/dist/tokens/theme-light.css +144 -0
  188. package/dist/tokens/typography.css +41 -0
  189. package/dist/vue/index.d.ts +143 -0
  190. package/dist/vue/index.js +56 -0
  191. package/dist/vue/index.js.map +1 -0
  192. package/package.json +296 -0
@@ -0,0 +1,212 @@
1
+ import { css as v, nothing as f, html as a } from "lit";
2
+ import { query as b, state as g, property as n } from "lit/decorators.js";
3
+ import { classMap as h } from "lit/directives/class-map.js";
4
+ import { K as m, d as y } from "../../../chunks/kt-element-CcMLO5e8.js";
5
+ import { e as l } from "../../../chunks/events-Bjl5Zmmq.js";
6
+ import { o as w } from "../../../chunks/listbox-CUXYn_3S.js";
7
+ var x = Object.defineProperty, r = (p, t, i, s) => {
8
+ for (var e = void 0, d = p.length - 1, c; d >= 0; d--)
9
+ (c = p[d]) && (e = c(t, i, e) || e);
10
+ return e && x(t, i, e), e;
11
+ };
12
+ const u = 230;
13
+ class o extends m {
14
+ constructor() {
15
+ super(...arguments), this.open = !1, this.placement = "bottom", this.options = [], this.value = null, this.preferredPlacement = "bottom", this.disabled = !1, this.emptyText = "No results", this.reposition = () => {
16
+ const i = (this.triggerWrapper ?? this).getBoundingClientRect(), s = window.innerHeight - i.bottom, e = i.top;
17
+ this.placement = this.preferredPlacement === "top" ? e >= u || e >= s ? "top" : "bottom" : s >= u || s >= e ? "bottom" : "top";
18
+ }, this.onDocumentPointerDown = (t) => {
19
+ t.composedPath().includes(this) || this.hide();
20
+ }, this.onDocumentKeyDown = (t) => {
21
+ t.key === "Escape" && this.hide();
22
+ };
23
+ }
24
+ static {
25
+ this.styles = [
26
+ m.styles,
27
+ v`
28
+ :host {
29
+ position: relative;
30
+ display: inline-block;
31
+ }
32
+
33
+ .trigger {
34
+ border-radius: var(--radius-input);
35
+ cursor: pointer;
36
+ }
37
+
38
+ :host([disabled]) .trigger {
39
+ cursor: not-allowed;
40
+ opacity: 0.6;
41
+ }
42
+
43
+ .panel {
44
+ position: absolute;
45
+ top: calc(100% + 6px);
46
+ left: 0;
47
+ z-index: var(--z-dropdown);
48
+ box-sizing: border-box;
49
+ width: 224px;
50
+ max-height: 224px;
51
+ margin: 0;
52
+ padding: var(--padding-expand);
53
+ background: var(--surface-raised);
54
+ border-radius: var(--radius-input);
55
+ transform: translateY(-6px);
56
+ transform-origin: top left;
57
+ visibility: hidden;
58
+ opacity: 0;
59
+ transition:
60
+ opacity var(--duration-normal) var(--easing-standard),
61
+ transform var(--duration-normal) var(--easing-standard);
62
+ }
63
+
64
+ .panel.top {
65
+ top: auto;
66
+ bottom: calc(100% + 6px);
67
+ transform: translateY(6px);
68
+ transform-origin: bottom left;
69
+ }
70
+
71
+ .panel.open {
72
+ visibility: visible;
73
+ opacity: 1;
74
+ transform: translateY(0);
75
+ }
76
+
77
+ .list {
78
+ display: flex;
79
+ flex-direction: column;
80
+ gap: var(--gap-element);
81
+ max-height: 208px;
82
+ margin: 0;
83
+ padding: 0;
84
+ overflow: auto;
85
+ list-style: none;
86
+ scrollbar-width: thin;
87
+ }
88
+
89
+ .option {
90
+ padding: var(--padding-expand-item);
91
+ color: var(--text-muted);
92
+ font: var(--font-normal-regular);
93
+ border-radius: var(--radius-input);
94
+ cursor: pointer;
95
+ }
96
+ .option:hover {
97
+ background: var(--surface-hover);
98
+ }
99
+
100
+ .option.selected {
101
+ color: var(--text-body);
102
+ font-weight: 600;
103
+ background: var(--color-dark-23);
104
+ }
105
+
106
+ .option.disabled {
107
+ opacity: 0.5;
108
+ pointer-events: none;
109
+ }
110
+
111
+ .empty {
112
+ padding: var(--padding-expand-item);
113
+ color: var(--text-muted);
114
+ font: var(--font-normal-small);
115
+ cursor: default;
116
+ }
117
+ `
118
+ ];
119
+ }
120
+ /** Whether the panel is showing. */
121
+ get isOpen() {
122
+ return this.open;
123
+ }
124
+ connectedCallback() {
125
+ super.connectedCallback(), document.addEventListener("pointerdown", this.onDocumentPointerDown), document.addEventListener("keydown", this.onDocumentKeyDown), window.addEventListener("resize", this.reposition);
126
+ }
127
+ disconnectedCallback() {
128
+ super.disconnectedCallback(), document.removeEventListener("pointerdown", this.onDocumentPointerDown), document.removeEventListener("keydown", this.onDocumentKeyDown), window.removeEventListener("resize", this.reposition);
129
+ }
130
+ /** Opens the panel. */
131
+ show() {
132
+ this.disabled || this.open || (this.reposition(), this.open = !0, l(this, "kt-open"));
133
+ }
134
+ /** Closes the panel. */
135
+ hide() {
136
+ this.open && (this.open = !1, l(this, "kt-close"));
137
+ }
138
+ /** Opens or closes it. */
139
+ toggle() {
140
+ this.open ? this.hide() : this.show();
141
+ }
142
+ choose(t) {
143
+ t.disabled || (this.value = t.id, this.hide(), l(this, "kt-select", { value: t.id, option: t }));
144
+ }
145
+ render() {
146
+ return a`<div
147
+ part="trigger"
148
+ class="trigger"
149
+ aria-haspopup="menu"
150
+ aria-expanded=${this.open ? "true" : "false"}
151
+ @click=${this.toggle}
152
+ >
153
+ <slot name="trigger"></slot>
154
+ </div>
155
+
156
+ <div
157
+ part="panel"
158
+ class=${h({ panel: !0, open: this.open, top: this.placement === "top" })}
159
+ role=${this.options.length > 0 ? "menu" : "group"}
160
+ aria-hidden=${this.open ? "false" : "true"}
161
+ >
162
+ ${this.options.length > 0 ? a`<ul class="list">
163
+ ${this.options.map(
164
+ (t) => a`<li
165
+ part="option"
166
+ class=${h({
167
+ option: !0,
168
+ selected: t.id === this.value,
169
+ disabled: !!t.disabled
170
+ })}
171
+ role="menuitem"
172
+ aria-disabled=${t.disabled ? "true" : f}
173
+ @click=${() => this.choose(t)}
174
+ >
175
+ ${w(t)}
176
+ </li>`
177
+ )}
178
+ </ul>` : a`<slot name="panel">
179
+ <div class="empty">${this.emptyText}</div>
180
+ </slot>`}
181
+ </div>`;
182
+ }
183
+ }
184
+ r([
185
+ b(".trigger")
186
+ ], o.prototype, "triggerWrapper");
187
+ r([
188
+ g()
189
+ ], o.prototype, "open");
190
+ r([
191
+ g()
192
+ ], o.prototype, "placement");
193
+ r([
194
+ n({ attribute: !1 })
195
+ ], o.prototype, "options");
196
+ r([
197
+ n({ type: String })
198
+ ], o.prototype, "value");
199
+ r([
200
+ n({ type: String, attribute: "preferred-placement" })
201
+ ], o.prototype, "preferredPlacement");
202
+ r([
203
+ n({ type: Boolean, reflect: !0 })
204
+ ], o.prototype, "disabled");
205
+ r([
206
+ n({ type: String, attribute: "empty-text" })
207
+ ], o.prototype, "emptyText");
208
+ y("kt-dropdown", o);
209
+ export {
210
+ o as KtDropdown
211
+ };
212
+ //# sourceMappingURL=kt-dropdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kt-dropdown.js","sources":["../../../../src/components/overlays/kt-dropdown/kt-dropdown.ts"],"sourcesContent":["import { css, html, nothing, type TemplateResult } from 'lit';\nimport { property, query, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { KtElement, defineElement } from '#internal/kt-element';\nimport { emit } from '#internal/events';\nimport { optionLabel, type KtOption } from '#internal/listbox';\n\nexport type KtDropdownPlacement = 'bottom' | 'top';\n\n/** Panel height plus the 6px offset, used to decide whether it fits below. */\nconst PANEL_SPACE = 224 + 6;\n\n/**\n * A panel anchored to a trigger.\n *\n * The generic overlay: pass `options` for a menu, or slot anything into\n * `panel` for arbitrary content. For choosing a value in a form, reach for\n * `<kt-select>` or `<kt-input-menu>` instead — they carry the listbox\n * semantics this one deliberately does not assume.\n *\n * @element kt-dropdown\n *\n * @slot trigger - What opens the panel.\n * @slot panel - Panel contents, when `options` is not used.\n *\n * @csspart trigger - The trigger wrapper.\n * @csspart panel - The floating panel.\n * @csspart option - A menu row.\n *\n * @fires kt-select - A menu row was chosen. `detail: { value, option }`.\n * @fires kt-open - The panel opened.\n * @fires kt-close - The panel closed.\n */\nexport class KtDropdown extends KtElement {\n static override styles = [\n KtElement.styles,\n css`\n :host {\n position: relative;\n display: inline-block;\n }\n\n .trigger {\n border-radius: var(--radius-input);\n cursor: pointer;\n }\n\n :host([disabled]) .trigger {\n cursor: not-allowed;\n opacity: 0.6;\n }\n\n .panel {\n position: absolute;\n top: calc(100% + 6px);\n left: 0;\n z-index: var(--z-dropdown);\n box-sizing: border-box;\n width: 224px;\n max-height: 224px;\n margin: 0;\n padding: var(--padding-expand);\n background: var(--surface-raised);\n border-radius: var(--radius-input);\n transform: translateY(-6px);\n transform-origin: top left;\n visibility: hidden;\n opacity: 0;\n transition:\n opacity var(--duration-normal) var(--easing-standard),\n transform var(--duration-normal) var(--easing-standard);\n }\n\n .panel.top {\n top: auto;\n bottom: calc(100% + 6px);\n transform: translateY(6px);\n transform-origin: bottom left;\n }\n\n .panel.open {\n visibility: visible;\n opacity: 1;\n transform: translateY(0);\n }\n\n .list {\n display: flex;\n flex-direction: column;\n gap: var(--gap-element);\n max-height: 208px;\n margin: 0;\n padding: 0;\n overflow: auto;\n list-style: none;\n scrollbar-width: thin;\n }\n\n .option {\n padding: var(--padding-expand-item);\n color: var(--text-muted);\n font: var(--font-normal-regular);\n border-radius: var(--radius-input);\n cursor: pointer;\n }\n .option:hover {\n background: var(--surface-hover);\n }\n\n .option.selected {\n color: var(--text-body);\n font-weight: 600;\n background: var(--color-dark-23);\n }\n\n .option.disabled {\n opacity: 0.5;\n pointer-events: none;\n }\n\n .empty {\n padding: var(--padding-expand-item);\n color: var(--text-muted);\n font: var(--font-normal-small);\n cursor: default;\n }\n `,\n ];\n\n @query('.trigger')\n private triggerWrapper!: HTMLElement;\n\n @state()\n private open = false;\n\n /** Where the panel actually landed, after checking the room available. */\n @state()\n private placement: KtDropdownPlacement = 'bottom';\n\n /** Menu rows. Leave empty and slot into `panel` for custom content. */\n @property({ attribute: false })\n options: readonly KtOption[] = [];\n\n /** Marks one row as current. */\n @property({ type: String })\n value: string | number | null = null;\n\n /** Where to put the panel when there is room on both sides. */\n @property({ type: String, attribute: 'preferred-placement' })\n preferredPlacement: KtDropdownPlacement = 'bottom';\n\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n @property({ type: String, attribute: 'empty-text' })\n emptyText = 'No results';\n\n /** Whether the panel is showing. */\n get isOpen(): boolean {\n return this.open;\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n document.addEventListener('pointerdown', this.onDocumentPointerDown);\n document.addEventListener('keydown', this.onDocumentKeyDown);\n window.addEventListener('resize', this.reposition);\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n document.removeEventListener('pointerdown', this.onDocumentPointerDown);\n document.removeEventListener('keydown', this.onDocumentKeyDown);\n window.removeEventListener('resize', this.reposition);\n }\n\n /**\n * Flips the panel above the trigger when there is not enough room below,\n * preferring whichever side has more space if neither fits.\n */\n private reposition = (): void => {\n const anchor = this.triggerWrapper ?? this;\n const rect = anchor.getBoundingClientRect();\n const below = window.innerHeight - rect.bottom;\n const above = rect.top;\n\n this.placement =\n this.preferredPlacement === 'top'\n ? above >= PANEL_SPACE || above >= below\n ? 'top'\n : 'bottom'\n : below >= PANEL_SPACE || below >= above\n ? 'bottom'\n : 'top';\n };\n\n private onDocumentPointerDown = (event: Event): void => {\n if (event.composedPath().includes(this)) return;\n this.hide();\n };\n\n private onDocumentKeyDown = (event: KeyboardEvent): void => {\n if (event.key === 'Escape') this.hide();\n };\n\n /** Opens the panel. */\n show(): void {\n if (this.disabled || this.open) return;\n this.reposition();\n this.open = true;\n emit(this, 'kt-open');\n }\n\n /** Closes the panel. */\n hide(): void {\n if (!this.open) return;\n this.open = false;\n emit(this, 'kt-close');\n }\n\n /** Opens or closes it. */\n toggle(): void {\n if (this.open) this.hide();\n else this.show();\n }\n\n private choose(option: KtOption): void {\n if (option.disabled) return;\n this.value = option.id;\n this.hide();\n emit(this, 'kt-select', { value: option.id, option });\n }\n\n override render(): TemplateResult {\n return html`<div\n part=\"trigger\"\n class=\"trigger\"\n aria-haspopup=\"menu\"\n aria-expanded=${this.open ? 'true' : 'false'}\n @click=${this.toggle}\n >\n <slot name=\"trigger\"></slot>\n </div>\n\n <div\n part=\"panel\"\n class=${classMap({ panel: true, open: this.open, top: this.placement === 'top' })}\n role=${this.options.length > 0 ? 'menu' : 'group'}\n aria-hidden=${this.open ? 'false' : 'true'}\n >\n ${\n this.options.length > 0\n ? html`<ul class=\"list\">\n ${this.options.map(\n (option) =>\n html`<li\n part=\"option\"\n class=${classMap({\n option: true,\n selected: option.id === this.value,\n disabled: Boolean(option.disabled),\n })}\n role=\"menuitem\"\n aria-disabled=${option.disabled ? 'true' : nothing}\n @click=${() => this.choose(option)}\n >\n ${optionLabel(option)}\n </li>`,\n )}\n </ul>`\n : html`<slot name=\"panel\">\n <div class=\"empty\">${this.emptyText}</div>\n </slot>`\n }\n </div>`;\n }\n}\n\ndefineElement('kt-dropdown', KtDropdown);\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'kt-dropdown': KtDropdown;\n }\n}\n"],"names":["PANEL_SPACE","KtDropdown","KtElement","rect","below","above","event","css","emit","option","html","classMap","nothing","optionLabel","__decorateClass","query","state","property","defineElement"],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ import { type PropertyValues, type TemplateResult } from 'lit';
2
+ import { KtElement } from '#internal/kt-element';
3
+ import '../../core/kt-button/kt-button.js';
4
+ export type KtModalSize = 'small' | 'medium' | 'large' | 'full';
5
+ /**
6
+ * A centred dialog for anything that is not a yes/no question.
7
+ *
8
+ * `<kt-confirm-dialog>` asks one thing and offers two answers. This one holds
9
+ * content — a compose window, a command palette, a picker — and lets you put
10
+ * whatever you like in the footer.
11
+ *
12
+ * Built on the native `<dialog>`, so the top layer, focus containment, page
13
+ * inertness and Escape all come from the platform rather than from a focus trap
14
+ * that leaks.
15
+ *
16
+ * @element kt-modal
17
+ *
18
+ * @slot - The body.
19
+ * @slot header - Replaces the `heading` attribute.
20
+ * @slot footer - Actions. Hidden when empty.
21
+ *
22
+ * @csspart dialog - The `<dialog>`.
23
+ * @csspart header - The header row.
24
+ * @csspart body - The scrolling body.
25
+ * @csspart footer - The action row.
26
+ *
27
+ * @fires kt-close - Dismissal requested. Cancelable, for an unsaved-changes guard.
28
+ *
29
+ * @example
30
+ * ```html
31
+ * <kt-modal open heading="Compose">
32
+ * <kt-textarea rows="6"></kt-textarea>
33
+ * <kt-button slot="footer" type="submit">Send</kt-button>
34
+ * </kt-modal>
35
+ * ```
36
+ */
37
+ export declare class KtModal extends KtElement {
38
+ static styles: import("lit").CSSResultGroup[];
39
+ private dialog;
40
+ open: boolean;
41
+ heading: string;
42
+ description: string;
43
+ size: KtModalSize;
44
+ /** Hides the close button. Escape still works — a modal you cannot leave is a trap. */
45
+ noCloseButton: boolean;
46
+ /** Stops a backdrop click from dismissing. */
47
+ noBackdropClose: boolean;
48
+ private hasFooter;
49
+ updated(changed: PropertyValues<this>): void;
50
+ private readFooter;
51
+ /** Asks to close. A cancelled `kt-close` keeps the modal open. */
52
+ requestClose(): void;
53
+ private onDialogClose;
54
+ private onDialogClick;
55
+ render(): TemplateResult;
56
+ }
57
+ declare global {
58
+ interface HTMLElementTagNameMap {
59
+ 'kt-modal': KtModal;
60
+ }
61
+ }
@@ -0,0 +1,207 @@
1
+ import { css as g, nothing as r, html as s } from "lit";
2
+ import { query as f, property as i } from "lit/decorators.js";
3
+ import { K as h, d as m } from "../../../chunks/kt-element-CcMLO5e8.js";
4
+ import { e as u } from "../../../chunks/events-Bjl5Zmmq.js";
5
+ import { h as v } from "../../../chunks/slots-BPbIdxAJ.js";
6
+ import { o as c, c as y, i as b } from "../../../chunks/dialog-CPIfFIlF.js";
7
+ import "../../core/kt-button/kt-button.js";
8
+ var x = Object.defineProperty, e = (l, t, d, C) => {
9
+ for (var a = void 0, n = l.length - 1, p; n >= 0; n--)
10
+ (p = l[n]) && (a = p(t, d, a) || a);
11
+ return a && x(t, d, a), a;
12
+ };
13
+ class o extends h {
14
+ constructor() {
15
+ super(...arguments), this.open = !1, this.heading = "", this.description = "", this.size = "medium", this.noCloseButton = !1, this.noBackdropClose = !1, this.hasFooter = !1;
16
+ }
17
+ static {
18
+ this.styles = [
19
+ h.styles,
20
+ g`
21
+ :host {
22
+ display: contents;
23
+ }
24
+
25
+ dialog {
26
+ display: flex;
27
+ flex-direction: column;
28
+ gap: var(--gap-modal);
29
+ box-sizing: border-box;
30
+ width: 560px;
31
+ max-width: calc(100vw - 48px);
32
+ max-height: calc(100vh - 96px);
33
+ padding: var(--padding-modal);
34
+ color: var(--text-body);
35
+ background: var(--surface-card);
36
+ border: var(--border-width) solid var(--border-subtle);
37
+ border-radius: var(--radius-modal);
38
+ opacity: 0;
39
+ transform: translateY(8px);
40
+ transition:
41
+ transform var(--duration-normal) var(--easing-standard),
42
+ opacity var(--duration-normal) var(--easing-standard),
43
+ overlay var(--duration-normal) allow-discrete,
44
+ display var(--duration-normal) allow-discrete;
45
+ }
46
+
47
+ :host([size='small']) dialog {
48
+ width: 400px;
49
+ }
50
+ :host([size='large']) dialog {
51
+ width: 760px;
52
+ }
53
+ :host([size='full']) dialog {
54
+ width: calc(100vw - 48px);
55
+ height: calc(100vh - 96px);
56
+ }
57
+
58
+ dialog[open] {
59
+ opacity: 1;
60
+ transform: translateY(0);
61
+ }
62
+
63
+ @starting-style {
64
+ dialog[open] {
65
+ opacity: 0;
66
+ transform: translateY(8px);
67
+ }
68
+ }
69
+
70
+ dialog::backdrop {
71
+ background: var(--color-backdrop, rgba(0, 0, 0, 0.45));
72
+ }
73
+
74
+ .header {
75
+ display: flex;
76
+ align-items: flex-start;
77
+ justify-content: space-between;
78
+ gap: var(--gap-card);
79
+ }
80
+
81
+ .titles {
82
+ display: flex;
83
+ flex-direction: column;
84
+ gap: 4px;
85
+ min-width: 0;
86
+ }
87
+
88
+ h2 {
89
+ margin: 0;
90
+ color: var(--text-body);
91
+ font: var(--font-title-h6);
92
+ }
93
+
94
+ .description {
95
+ margin: 0;
96
+ color: var(--text-muted);
97
+ font: var(--font-normal-regular);
98
+ }
99
+
100
+ .body {
101
+ flex: 1 1 auto;
102
+ min-height: 0;
103
+ overflow: auto;
104
+ scrollbar-width: thin;
105
+ }
106
+
107
+ .footer {
108
+ display: flex;
109
+ flex-wrap: wrap;
110
+ align-items: center;
111
+ justify-content: flex-end;
112
+ gap: var(--gap-button);
113
+ }
114
+
115
+ .footer.empty {
116
+ display: none;
117
+ }
118
+
119
+ @media (prefers-reduced-motion: reduce) {
120
+ dialog {
121
+ transition: none;
122
+ }
123
+ }
124
+ `
125
+ ];
126
+ }
127
+ updated(t) {
128
+ t.has("open") && (this.open ? c(this.dialog) : y(this.dialog)), this.readFooter();
129
+ }
130
+ readFooter() {
131
+ const t = v(
132
+ this.shadowRoot?.querySelector('slot[name="footer"]')
133
+ );
134
+ t !== this.hasFooter && (this.hasFooter = t, this.requestUpdate());
135
+ }
136
+ /** Asks to close. A cancelled `kt-close` keeps the modal open. */
137
+ requestClose() {
138
+ if (u(this, "kt-close").defaultPrevented) {
139
+ this.dialog.open || c(this.dialog);
140
+ return;
141
+ }
142
+ this.open = !1;
143
+ }
144
+ onDialogClose() {
145
+ this.open && this.requestClose();
146
+ }
147
+ onDialogClick(t) {
148
+ this.noBackdropClose || b(this.dialog, t) && this.requestClose();
149
+ }
150
+ render() {
151
+ const t = !!this.heading || !!this.description;
152
+ return s`<dialog
153
+ part="dialog"
154
+ aria-label=${this.heading || r}
155
+ @close=${this.onDialogClose}
156
+ @click=${this.onDialogClick}
157
+ >
158
+ ${t || !this.noCloseButton ? s`<div part="header" class="header">
159
+ <div class="titles">
160
+ <slot name="header">
161
+ ${this.heading ? s`<h2>${this.heading}</h2>` : r}
162
+ </slot>
163
+ ${this.description ? s`<p class="description">${this.description}</p>` : r}
164
+ </div>
165
+ ${this.noCloseButton ? r : s`<kt-button
166
+ variant="secondary-no-bg"
167
+ size="small"
168
+ icon="x"
169
+ label="Close"
170
+ @click=${this.requestClose}
171
+ ></kt-button>`}
172
+ </div>` : r}
173
+
174
+ <div part="body" class="body"><slot></slot></div>
175
+
176
+ <div part="footer" class=${this.hasFooter ? "footer" : "footer empty"}>
177
+ <slot name="footer" @slotchange=${this.readFooter}></slot>
178
+ </div>
179
+ </dialog>`;
180
+ }
181
+ }
182
+ e([
183
+ f("dialog")
184
+ ], o.prototype, "dialog");
185
+ e([
186
+ i({ type: Boolean, reflect: !0 })
187
+ ], o.prototype, "open");
188
+ e([
189
+ i({ type: String })
190
+ ], o.prototype, "heading");
191
+ e([
192
+ i({ type: String })
193
+ ], o.prototype, "description");
194
+ e([
195
+ i({ type: String, reflect: !0 })
196
+ ], o.prototype, "size");
197
+ e([
198
+ i({ type: Boolean, attribute: "no-close-button" })
199
+ ], o.prototype, "noCloseButton");
200
+ e([
201
+ i({ type: Boolean, attribute: "no-backdrop-close" })
202
+ ], o.prototype, "noBackdropClose");
203
+ m("kt-modal", o);
204
+ export {
205
+ o as KtModal
206
+ };
207
+ //# sourceMappingURL=kt-modal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kt-modal.js","sources":["../../../../src/components/overlays/kt-modal/kt-modal.ts"],"sourcesContent":["import { css, html, nothing, type PropertyValues, type TemplateResult } from 'lit';\nimport { property, query } from 'lit/decorators.js';\nimport { KtElement, defineElement } from '#internal/kt-element';\nimport { emit } from '#internal/events';\nimport { hasAssignedContent } from '#internal/slots';\nimport { closeDialog, isBackdropClick, openModal } from '#internal/dialog';\nimport '../../core/kt-button/kt-button.js';\n\nexport type KtModalSize = 'small' | 'medium' | 'large' | 'full';\n\n/**\n * A centred dialog for anything that is not a yes/no question.\n *\n * `<kt-confirm-dialog>` asks one thing and offers two answers. This one holds\n * content — a compose window, a command palette, a picker — and lets you put\n * whatever you like in the footer.\n *\n * Built on the native `<dialog>`, so the top layer, focus containment, page\n * inertness and Escape all come from the platform rather than from a focus trap\n * that leaks.\n *\n * @element kt-modal\n *\n * @slot - The body.\n * @slot header - Replaces the `heading` attribute.\n * @slot footer - Actions. Hidden when empty.\n *\n * @csspart dialog - The `<dialog>`.\n * @csspart header - The header row.\n * @csspart body - The scrolling body.\n * @csspart footer - The action row.\n *\n * @fires kt-close - Dismissal requested. Cancelable, for an unsaved-changes guard.\n *\n * @example\n * ```html\n * <kt-modal open heading=\"Compose\">\n * <kt-textarea rows=\"6\"></kt-textarea>\n * <kt-button slot=\"footer\" type=\"submit\">Send</kt-button>\n * </kt-modal>\n * ```\n */\nexport class KtModal extends KtElement {\n static override styles = [\n KtElement.styles,\n css`\n :host {\n display: contents;\n }\n\n dialog {\n display: flex;\n flex-direction: column;\n gap: var(--gap-modal);\n box-sizing: border-box;\n width: 560px;\n max-width: calc(100vw - 48px);\n max-height: calc(100vh - 96px);\n padding: var(--padding-modal);\n color: var(--text-body);\n background: var(--surface-card);\n border: var(--border-width) solid var(--border-subtle);\n border-radius: var(--radius-modal);\n opacity: 0;\n transform: translateY(8px);\n transition:\n transform var(--duration-normal) var(--easing-standard),\n opacity var(--duration-normal) var(--easing-standard),\n overlay var(--duration-normal) allow-discrete,\n display var(--duration-normal) allow-discrete;\n }\n\n :host([size='small']) dialog {\n width: 400px;\n }\n :host([size='large']) dialog {\n width: 760px;\n }\n :host([size='full']) dialog {\n width: calc(100vw - 48px);\n height: calc(100vh - 96px);\n }\n\n dialog[open] {\n opacity: 1;\n transform: translateY(0);\n }\n\n @starting-style {\n dialog[open] {\n opacity: 0;\n transform: translateY(8px);\n }\n }\n\n dialog::backdrop {\n background: var(--color-backdrop, rgba(0, 0, 0, 0.45));\n }\n\n .header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: var(--gap-card);\n }\n\n .titles {\n display: flex;\n flex-direction: column;\n gap: 4px;\n min-width: 0;\n }\n\n h2 {\n margin: 0;\n color: var(--text-body);\n font: var(--font-title-h6);\n }\n\n .description {\n margin: 0;\n color: var(--text-muted);\n font: var(--font-normal-regular);\n }\n\n .body {\n flex: 1 1 auto;\n min-height: 0;\n overflow: auto;\n scrollbar-width: thin;\n }\n\n .footer {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: flex-end;\n gap: var(--gap-button);\n }\n\n .footer.empty {\n display: none;\n }\n\n @media (prefers-reduced-motion: reduce) {\n dialog {\n transition: none;\n }\n }\n `,\n ];\n\n @query('dialog')\n private dialog!: HTMLDialogElement;\n\n @property({ type: Boolean, reflect: true })\n open = false;\n\n @property({ type: String })\n heading = '';\n\n @property({ type: String })\n description = '';\n\n @property({ type: String, reflect: true })\n size: KtModalSize = 'medium';\n\n /** Hides the close button. Escape still works — a modal you cannot leave is a trap. */\n @property({ type: Boolean, attribute: 'no-close-button' })\n noCloseButton = false;\n\n /** Stops a backdrop click from dismissing. */\n @property({ type: Boolean, attribute: 'no-backdrop-close' })\n noBackdropClose = false;\n\n private hasFooter = false;\n\n override updated(changed: PropertyValues<this>): void {\n if (changed.has('open')) {\n if (this.open) openModal(this.dialog);\n else closeDialog(this.dialog);\n }\n this.readFooter();\n }\n\n private readFooter(): void {\n const next = hasAssignedContent(\n this.shadowRoot?.querySelector<HTMLSlotElement>('slot[name=\"footer\"]'),\n );\n if (next === this.hasFooter) return;\n this.hasFooter = next;\n this.requestUpdate();\n }\n\n /** Asks to close. A cancelled `kt-close` keeps the modal open. */\n requestClose(): void {\n const proceed = emit(this, 'kt-close');\n if (proceed.defaultPrevented) {\n if (!this.dialog.open) openModal(this.dialog);\n return;\n }\n this.open = false;\n }\n\n private onDialogClose(): void {\n if (this.open) this.requestClose();\n }\n\n private onDialogClick(event: MouseEvent): void {\n if (this.noBackdropClose) return;\n if (isBackdropClick(this.dialog, event)) this.requestClose();\n }\n\n override render(): TemplateResult {\n const hasHeader = Boolean(this.heading) || Boolean(this.description);\n\n return html`<dialog\n part=\"dialog\"\n aria-label=${this.heading || nothing}\n @close=${this.onDialogClose}\n @click=${this.onDialogClick}\n >\n ${\n hasHeader || !this.noCloseButton\n ? html`<div part=\"header\" class=\"header\">\n <div class=\"titles\">\n <slot name=\"header\">\n ${this.heading ? html`<h2>${this.heading}</h2>` : nothing}\n </slot>\n ${this.description ? html`<p class=\"description\">${this.description}</p>` : nothing}\n </div>\n ${\n this.noCloseButton\n ? nothing\n : html`<kt-button\n variant=\"secondary-no-bg\"\n size=\"small\"\n icon=\"x\"\n label=\"Close\"\n @click=${this.requestClose}\n ></kt-button>`\n }\n </div>`\n : nothing\n }\n\n <div part=\"body\" class=\"body\"><slot></slot></div>\n\n <div part=\"footer\" class=${this.hasFooter ? 'footer' : 'footer empty'}>\n <slot name=\"footer\" @slotchange=${this.readFooter}></slot>\n </div>\n </dialog>`;\n }\n}\n\ndefineElement('kt-modal', KtModal);\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'kt-modal': KtModal;\n }\n}\n"],"names":["KtModal","KtElement","css","changed","openModal","closeDialog","next","hasAssignedContent","emit","event","isBackdropClick","hasHeader","html","nothing","__decorateClass","query","property","defineElement"],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ import { type PropertyValues, type TemplateResult } from 'lit';
2
+ import { KtElement } from '#internal/kt-element';
3
+ import '../../core/kt-button/kt-button.js';
4
+ /**
5
+ * A drawer that slides in from the right, for viewing or editing one record
6
+ * without leaving the list behind it.
7
+ *
8
+ * Built on the native `<dialog>`: the panel lands in the top layer, focus is
9
+ * trapped inside it, the page behind goes inert, and Escape closes it — none of
10
+ * which the fixed-position div this replaces did.
11
+ *
12
+ * @element kt-side-panel
13
+ *
14
+ * @slot - The panel body.
15
+ * @slot footer - Pinned below the body.
16
+ *
17
+ * @csspart dialog - The `<dialog>`.
18
+ * @csspart header - The header row.
19
+ * @csspart body - The scrolling body.
20
+ *
21
+ * @fires kt-close - The panel was dismissed. Cancelable: cancel it to keep the
22
+ * panel open, for an unsaved-changes prompt.
23
+ *
24
+ * @example
25
+ * ```html
26
+ * <kt-side-panel open eyebrow="Details" heading="Entity 4812">
27
+ * <p>…</p>
28
+ * </kt-side-panel>
29
+ * ```
30
+ */
31
+ export declare class KtSidePanel extends KtElement {
32
+ static styles: import("lit").CSSResultGroup[];
33
+ private dialog;
34
+ open: boolean;
35
+ /** Small uppercase label above the heading — "Details", "Editing". */
36
+ eyebrow: string;
37
+ heading: string;
38
+ /** Suppresses dismissal by backdrop click. Escape still works, by design. */
39
+ noBackdropClose: boolean;
40
+ updated(changed: PropertyValues<this>): void;
41
+ /** Asks to close. A cancelled `kt-close` keeps the panel open. */
42
+ requestClose(): void;
43
+ /** Escape and the native close both land here. */
44
+ private onDialogClose;
45
+ private onDialogClick;
46
+ render(): TemplateResult;
47
+ }
48
+ declare global {
49
+ interface HTMLElementTagNameMap {
50
+ 'kt-side-panel': KtSidePanel;
51
+ }
52
+ }