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 @@
1
+ {"version":3,"file":"kt-tooltip.js","sources":["../../../../src/components/feedback/kt-tooltip/kt-tooltip.ts"],"sourcesContent":["import { css, html, type PropertyValues, type TemplateResult } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { KtElement, defineElement } from '#internal/kt-element';\nimport { uniqueId } from '#internal/events';\n\nexport type KtTooltipPlacement = 'top' | 'bottom' | 'left' | 'right';\n\n/** Marks the description node so it is never assigned to the default slot. */\nconst DESCRIPTION_SLOT = 'kt-tooltip-description';\n\n/**\n * A short label that appears on hover or focus.\n *\n * Wrap the thing it describes:\n *\n * ```html\n * <kt-tooltip text=\"Refresh the data\">\n * <kt-button icon=\"refresh-cw\" label=\"Refresh\"></kt-button>\n * </kt-tooltip>\n * ```\n *\n * A tooltip is a *description*, never the only name of a control. If the\n * trigger has no visible text, give it its own `label` too — a tooltip that has\n * to be hovered to be read leaves touch and screen-reader users with nothing.\n *\n * @element kt-tooltip\n *\n * @slot - The trigger.\n *\n * @csspart bubble - The tooltip bubble.\n */\nexport class KtTooltip extends KtElement {\n static override styles = [\n KtElement.styles,\n css`\n :host {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n }\n\n .bubble {\n position: absolute;\n z-index: var(--z-tooltip);\n max-width: 260px;\n padding: var(--padding-chip);\n /* Inverted against the page, so the bubble reads as floating in\n both themes — the raw ramp step this used to name is pure white\n under data-theme=\"light\". */\n color: var(--text-inverted);\n font: var(--font-code-regular);\n white-space: nowrap;\n background: var(--surface-inverted);\n border-radius: var(--radius-input);\n opacity: 0;\n pointer-events: none;\n transition: opacity 150ms var(--easing-standard);\n }\n\n .bubble.visible {\n opacity: 1;\n }\n\n .top {\n bottom: calc(100% + 6px);\n left: 50%;\n transform: translateX(-50%);\n }\n .bottom {\n top: calc(100% + 6px);\n left: 50%;\n transform: translateX(-50%);\n }\n .left {\n top: 50%;\n right: calc(100% + 6px);\n transform: translateY(-50%);\n }\n .right {\n top: 50%;\n left: calc(100% + 6px);\n transform: translateY(-50%);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .bubble {\n transition: none;\n }\n }\n `,\n ];\n\n private readonly descriptionId = uniqueId('kt-tooltip');\n private description: HTMLElement | undefined;\n\n @state()\n private visible = false;\n\n @property({ type: String })\n text = '';\n\n @property({ type: String, reflect: true })\n placement: KtTooltipPlacement = 'top';\n\n /** Suppresses the tooltip without removing it from the markup. */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.addEventListener('pointerenter', this.show);\n this.addEventListener('pointerleave', this.hide);\n this.addEventListener('focusin', this.show);\n this.addEventListener('focusout', this.hide);\n this.addEventListener('keydown', this.onKeyDown);\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('pointerenter', this.show);\n this.removeEventListener('pointerleave', this.hide);\n this.removeEventListener('focusin', this.show);\n this.removeEventListener('focusout', this.hide);\n this.removeEventListener('keydown', this.onKeyDown);\n this.description?.remove();\n }\n\n override willUpdate(changed: PropertyValues<this>): void {\n if (changed.has('text')) this.syncDescription();\n }\n\n /**\n * `aria-describedby` cannot reach across a shadow boundary: an id inside this\n * element's shadow root is invisible to a trigger sitting in the light DOM.\n *\n * So the description also exists as a light-DOM node, addressed to a slot\n * that does not exist — which keeps it out of the rendered output while\n * leaving it referenceable, since an explicit aria-describedby target is read\n * even when it is not displayed.\n */\n private syncDescription(): void {\n if (!this.text) {\n this.description?.remove();\n this.description = undefined;\n return;\n }\n\n if (!this.description) {\n this.description = document.createElement('span');\n this.description.id = this.descriptionId;\n this.description.slot = DESCRIPTION_SLOT;\n this.append(this.description);\n }\n this.description.textContent = this.text;\n\n for (const trigger of this.children) {\n if (trigger !== this.description)\n trigger.setAttribute('aria-describedby', this.descriptionId);\n }\n }\n\n private show = (): void => {\n if (!this.disabled && this.text) this.visible = true;\n };\n\n private hide = (): void => {\n this.visible = false;\n };\n\n /** WCAG 1.4.13: a pointer-triggered overlay must be dismissible from the keyboard. */\n private onKeyDown = (event: KeyboardEvent): void => {\n if (event.key === 'Escape' && this.visible) {\n event.stopPropagation();\n this.visible = false;\n }\n };\n\n override render(): TemplateResult {\n return html`<slot @slotchange=${this.syncDescription}></slot>\n <span\n part=\"bubble\"\n class=${classMap({ bubble: true, [this.placement]: true, visible: this.visible })}\n role=\"tooltip\"\n aria-hidden=${this.visible ? 'false' : 'true'}\n >${this.text}</span\n >`;\n }\n}\n\ndefineElement('kt-tooltip', KtTooltip);\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'kt-tooltip': KtTooltip;\n }\n}\n"],"names":["DESCRIPTION_SLOT","KtTooltip","KtElement","uniqueId","event","css","changed","trigger","html","classMap","__decorateClass","state","property","defineElement"],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ import { type TemplateResult } from 'lit';
2
+ import { KtElement } from '#internal/kt-element';
3
+ import '../../core/kt-icon/kt-icon.js';
4
+ import '../../core/kt-button/kt-button.js';
5
+ /**
6
+ * A file drop zone.
7
+ *
8
+ * Accepts a drop or a click, lists what was picked with sizes and types, and
9
+ * lets each entry be removed. It holds the files in memory and reports them —
10
+ * uploading is the application's business.
11
+ *
12
+ * @element kt-drag-drop
13
+ *
14
+ * @csspart base - The dashed drop zone.
15
+ * @csspart list - The list of chosen files.
16
+ *
17
+ * @fires kt-files-change - The selection changed. `detail: { files }`.
18
+ * @fires kt-files-rejected - Files were refused. `detail: { files, reason }`.
19
+ *
20
+ * @example
21
+ * ```html
22
+ * <kt-drag-drop accept="image/*" recommended-size="800×400px"></kt-drag-drop>
23
+ * ```
24
+ */
25
+ export declare class KtDragDrop extends KtElement {
26
+ static styles: import("lit").CSSResultGroup[];
27
+ private fileInput;
28
+ private dragging;
29
+ private files;
30
+ /**
31
+ * The prompt above the browse link.
32
+ *
33
+ * Named `heading`, not `title`: an element already has a `title`, and
34
+ * reusing it would put the prompt in a native tooltip on the whole zone.
35
+ */
36
+ heading: string;
37
+ /** The clickable-looking part of the prompt. */
38
+ linkText: string;
39
+ /** Optional hint, e.g. `800×400px`. */
40
+ recommendedSize: string;
41
+ multiple: boolean;
42
+ /** Same syntax as the native `accept`: `image/*`, `.pdf,.docx`. */
43
+ accept: string;
44
+ /** Largest accepted file, in bytes. Zero means no limit. */
45
+ maxSize: number;
46
+ disabled: boolean;
47
+ /** The files currently held, newest last. */
48
+ get selectedFiles(): readonly File[];
49
+ /** Empties the selection without firing a rejection. */
50
+ clear(): void;
51
+ /**
52
+ * `accept` is advisory on a native input — the OS dialog filters, but a
53
+ * dropped file bypasses it entirely — so the same rules are enforced here.
54
+ */
55
+ private accepts;
56
+ private addFiles;
57
+ private removeAt;
58
+ private browse;
59
+ private onZoneKeyDown;
60
+ private onDragOver;
61
+ private onDrop;
62
+ render(): TemplateResult;
63
+ }
64
+ declare global {
65
+ interface HTMLElementTagNameMap {
66
+ 'kt-drag-drop': KtDragDrop;
67
+ }
68
+ }
@@ -0,0 +1,287 @@
1
+ import { css as g, nothing as d, html as p } from "lit";
2
+ import { query as v, state as u, property as l } from "lit/decorators.js";
3
+ import { classMap as y } from "lit/directives/class-map.js";
4
+ import { K as f, d as b } from "../../../chunks/kt-element-CcMLO5e8.js";
5
+ import { e as c } from "../../../chunks/events-Bjl5Zmmq.js";
6
+ import "../../core/kt-icon/kt-icon.js";
7
+ import "../../core/kt-button/kt-button.js";
8
+ const m = ["B", "KB", "MB", "GB", "TB"];
9
+ function x(o) {
10
+ if (!Number.isFinite(o) || o < 0) return "";
11
+ let e = o, t = 0;
12
+ for (; e >= 1024 && t < m.length - 1; )
13
+ e /= 1024, t += 1;
14
+ return `${t === 0 ? String(Math.round(e)) : e.toFixed(1)} ${m[t]}`;
15
+ }
16
+ var $ = Object.defineProperty, s = (o, e, t, n) => {
17
+ for (var r = void 0, a = o.length - 1, h; a >= 0; a--)
18
+ (h = o[a]) && (r = h(e, t, r) || r);
19
+ return r && $(e, t, r), r;
20
+ };
21
+ class i extends f {
22
+ constructor() {
23
+ super(...arguments), this.dragging = !1, this.files = [], this.heading = "Drag and drop or", this.linkText = "browse your files", this.recommendedSize = "", this.multiple = !0, this.accept = "", this.maxSize = 0, this.disabled = !1;
24
+ }
25
+ static {
26
+ this.styles = [
27
+ f.styles,
28
+ g`
29
+ :host {
30
+ display: block;
31
+ user-select: none;
32
+ }
33
+
34
+ .zone {
35
+ display: flex;
36
+ flex-direction: column;
37
+ align-items: center;
38
+ justify-content: center;
39
+ gap: var(--gap-drag-drop);
40
+ padding: var(--padding-drag-drop);
41
+ border: var(--border-width) dashed var(--color-dark-24);
42
+ border-radius: var(--border-radius);
43
+ cursor: pointer;
44
+ transition:
45
+ border-color var(--duration-instant),
46
+ box-shadow var(--duration-instant);
47
+ }
48
+
49
+ .zone:hover {
50
+ border-color: var(--text-muted);
51
+ }
52
+
53
+ .zone:focus-visible {
54
+ outline: var(--outline-width) solid var(--color-primary-base);
55
+ outline-offset: 2px;
56
+ }
57
+
58
+ .dragover {
59
+ border-color: var(--color-primary-base);
60
+ box-shadow: 0 0 0 6px var(--color-primary-soft);
61
+ }
62
+
63
+ .prompt {
64
+ display: flex;
65
+ flex-direction: column;
66
+ align-items: center;
67
+ gap: var(--gap-button);
68
+ text-align: center;
69
+ }
70
+
71
+ .prompt-icon {
72
+ color: var(--text-muted);
73
+ }
74
+
75
+ .title {
76
+ margin: 0;
77
+ color: var(--color-primary-base);
78
+ font: var(--font-normal-medium);
79
+ }
80
+
81
+ .hint {
82
+ color: var(--text-muted);
83
+ font: var(--font-normal-small);
84
+ }
85
+
86
+ input[type='file'] {
87
+ display: none;
88
+ }
89
+
90
+ .list {
91
+ display: flex;
92
+ flex-direction: column;
93
+ gap: 8px;
94
+ width: 100%;
95
+ margin: 0;
96
+ padding: 0;
97
+ list-style: none;
98
+ }
99
+
100
+ .item {
101
+ display: flex;
102
+ align-items: center;
103
+ gap: 12px;
104
+ width: 100%;
105
+ padding: 12px;
106
+ background: var(--surface-raised);
107
+ border-radius: var(--border-radius);
108
+ cursor: default;
109
+ transition: background var(--duration-normal) var(--easing-standard);
110
+ }
111
+ .item:hover {
112
+ background: var(--surface-hover);
113
+ }
114
+
115
+ .preview {
116
+ display: flex;
117
+ flex: none;
118
+ align-items: center;
119
+ justify-content: center;
120
+ width: 48px;
121
+ height: 48px;
122
+ overflow: hidden;
123
+ color: var(--color-info-base);
124
+ background: var(--color-dark-14);
125
+ border-radius: 6px;
126
+ }
127
+
128
+ .info {
129
+ display: flex;
130
+ flex: 1;
131
+ flex-direction: column;
132
+ gap: 4px;
133
+ min-width: 0;
134
+ }
135
+
136
+ .name {
137
+ overflow: hidden;
138
+ color: var(--text-body);
139
+ font: var(--font-normal-medium);
140
+ white-space: nowrap;
141
+ text-overflow: ellipsis;
142
+ }
143
+
144
+ .details {
145
+ display: flex;
146
+ align-items: center;
147
+ gap: 6px;
148
+ color: var(--text-muted);
149
+ font: var(--font-normal-small);
150
+ }
151
+ `
152
+ ];
153
+ }
154
+ /** The files currently held, newest last. */
155
+ get selectedFiles() {
156
+ return this.files;
157
+ }
158
+ /** Empties the selection without firing a rejection. */
159
+ clear() {
160
+ this.files = [], c(this, "kt-files-change", { files: this.files });
161
+ }
162
+ /**
163
+ * `accept` is advisory on a native input — the OS dialog filters, but a
164
+ * dropped file bypasses it entirely — so the same rules are enforced here.
165
+ */
166
+ accepts(e) {
167
+ return this.maxSize > 0 && e.size > this.maxSize ? !1 : this.accept ? this.accept.split(",").map((t) => t.trim().toLowerCase()).filter(Boolean).some((t) => t.startsWith(".") ? e.name.toLowerCase().endsWith(t) : t.endsWith("/*") ? e.type.startsWith(t.slice(0, -1)) : e.type.toLowerCase() === t) : !0;
168
+ }
169
+ addFiles(e) {
170
+ if (!e || e.length === 0) return;
171
+ const t = this.multiple ? [...e] : [...e].slice(0, 1), n = t.filter((a) => this.accepts(a)), r = t.filter((a) => !this.accepts(a));
172
+ r.length > 0 && c(this, "kt-files-rejected", {
173
+ files: r,
174
+ reason: this.maxSize > 0 && r.some((a) => a.size > this.maxSize) ? "size" : "type"
175
+ }), n.length !== 0 && (this.files = this.multiple ? [...this.files, ...n] : n, c(this, "kt-files-change", { files: this.files }));
176
+ }
177
+ removeAt(e) {
178
+ this.files = this.files.filter((t, n) => n !== e), c(this, "kt-files-change", { files: this.files });
179
+ }
180
+ browse() {
181
+ this.disabled || this.fileInput?.click();
182
+ }
183
+ onZoneKeyDown(e) {
184
+ e.key !== "Enter" && e.key !== " " || (e.preventDefault(), this.browse());
185
+ }
186
+ onDragOver(e) {
187
+ this.disabled || (e.preventDefault(), this.dragging = !0);
188
+ }
189
+ onDrop(e) {
190
+ this.disabled || (e.preventDefault(), this.dragging = !1, this.addFiles(e.dataTransfer?.files ?? null));
191
+ }
192
+ render() {
193
+ return p`<div
194
+ part="base"
195
+ class=${y({ zone: !0, dragover: this.dragging })}
196
+ role="button"
197
+ tabindex=${this.disabled ? -1 : 0}
198
+ aria-disabled=${this.disabled ? "true" : d}
199
+ aria-label=${`${this.heading} ${this.linkText}`}
200
+ @click=${this.browse}
201
+ @keydown=${this.onZoneKeyDown}
202
+ @dragover=${this.onDragOver}
203
+ @dragleave=${() => {
204
+ this.dragging = !1;
205
+ }}
206
+ @drop=${this.onDrop}
207
+ >
208
+ <input
209
+ type="file"
210
+ ?multiple=${this.multiple}
211
+ accept=${this.accept || d}
212
+ @click=${(e) => e.stopPropagation()}
213
+ @change=${(e) => this.addFiles(e.target.files)}
214
+ />
215
+
216
+ <div class="prompt">
217
+ <span class="prompt-icon"><kt-icon name="file-up" size="24"></kt-icon></span>
218
+ <div>
219
+ <p class="title">${this.heading} ${this.linkText}</p>
220
+ ${this.recommendedSize ? p`<div class="hint">Recommended image size: ${this.recommendedSize}</div>` : d}
221
+ </div>
222
+ </div>
223
+
224
+ ${this.files.length > 0 ? p`<ul
225
+ part="list"
226
+ class="list"
227
+ aria-label="Selected files"
228
+ @click=${(e) => e.stopPropagation()}
229
+ >
230
+ ${this.files.map(
231
+ (e, t) => p`<li class="item">
232
+ <span class="preview"><kt-icon name="file" size="24"></kt-icon></span>
233
+ <span class="info">
234
+ <span class="name" title=${e.name}>${e.name}</span>
235
+ <span class="details">
236
+ <span>${x(e.size)}</span>
237
+ ${e.type ? p`<span>•</span><span>${e.type}</span>` : d}
238
+ </span>
239
+ </span>
240
+ <kt-button
241
+ variant="danger"
242
+ size="small"
243
+ icon="trash-2"
244
+ label=${`Remove ${e.name}`}
245
+ @click=${() => this.removeAt(t)}
246
+ ></kt-button>
247
+ </li>`
248
+ )}
249
+ </ul>` : d}
250
+ </div>`;
251
+ }
252
+ }
253
+ s([
254
+ v('input[type="file"]')
255
+ ], i.prototype, "fileInput");
256
+ s([
257
+ u()
258
+ ], i.prototype, "dragging");
259
+ s([
260
+ u()
261
+ ], i.prototype, "files");
262
+ s([
263
+ l({ type: String })
264
+ ], i.prototype, "heading");
265
+ s([
266
+ l({ type: String, attribute: "link-text" })
267
+ ], i.prototype, "linkText");
268
+ s([
269
+ l({ type: String, attribute: "recommended-size" })
270
+ ], i.prototype, "recommendedSize");
271
+ s([
272
+ l({ type: Boolean })
273
+ ], i.prototype, "multiple");
274
+ s([
275
+ l({ type: String })
276
+ ], i.prototype, "accept");
277
+ s([
278
+ l({ type: Number, attribute: "max-size" })
279
+ ], i.prototype, "maxSize");
280
+ s([
281
+ l({ type: Boolean, reflect: !0 })
282
+ ], i.prototype, "disabled");
283
+ b("kt-drag-drop", i);
284
+ export {
285
+ i as KtDragDrop
286
+ };
287
+ //# sourceMappingURL=kt-drag-drop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kt-drag-drop.js","sources":["../../../../src/internal/format.ts","../../../../src/components/forms/kt-drag-drop/kt-drag-drop.ts"],"sourcesContent":["/** Formatting helpers shared by elements that display data. */\n\nconst UNITS = ['B', 'KB', 'MB', 'GB', 'TB'] as const;\n\n/**\n * A human-readable file size.\n *\n * Uses 1024 steps, matching what every desktop file manager shows, and one\n * decimal above a kilobyte — \"1.4 MB\" reads; \"1468006 B\" does not.\n */\nexport function formatFileSize(bytes: number): string {\n if (!Number.isFinite(bytes) || bytes < 0) return '';\n\n let value = bytes;\n let unit = 0;\n while (value >= 1024 && unit < UNITS.length - 1) {\n value /= 1024;\n unit += 1;\n }\n\n const rounded = unit === 0 ? String(Math.round(value)) : value.toFixed(1);\n return `${rounded} ${UNITS[unit]}`;\n}\n","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 { formatFileSize } from '#internal/format';\nimport '../../core/kt-icon/kt-icon.js';\nimport '../../core/kt-button/kt-button.js';\n\n/**\n * A file drop zone.\n *\n * Accepts a drop or a click, lists what was picked with sizes and types, and\n * lets each entry be removed. It holds the files in memory and reports them —\n * uploading is the application's business.\n *\n * @element kt-drag-drop\n *\n * @csspart base - The dashed drop zone.\n * @csspart list - The list of chosen files.\n *\n * @fires kt-files-change - The selection changed. `detail: { files }`.\n * @fires kt-files-rejected - Files were refused. `detail: { files, reason }`.\n *\n * @example\n * ```html\n * <kt-drag-drop accept=\"image/*\" recommended-size=\"800×400px\"></kt-drag-drop>\n * ```\n */\nexport class KtDragDrop extends KtElement {\n static override styles = [\n KtElement.styles,\n css`\n :host {\n display: block;\n user-select: none;\n }\n\n .zone {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: var(--gap-drag-drop);\n padding: var(--padding-drag-drop);\n border: var(--border-width) dashed var(--color-dark-24);\n border-radius: var(--border-radius);\n cursor: pointer;\n transition:\n border-color var(--duration-instant),\n box-shadow var(--duration-instant);\n }\n\n .zone:hover {\n border-color: var(--text-muted);\n }\n\n .zone:focus-visible {\n outline: var(--outline-width) solid var(--color-primary-base);\n outline-offset: 2px;\n }\n\n .dragover {\n border-color: var(--color-primary-base);\n box-shadow: 0 0 0 6px var(--color-primary-soft);\n }\n\n .prompt {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--gap-button);\n text-align: center;\n }\n\n .prompt-icon {\n color: var(--text-muted);\n }\n\n .title {\n margin: 0;\n color: var(--color-primary-base);\n font: var(--font-normal-medium);\n }\n\n .hint {\n color: var(--text-muted);\n font: var(--font-normal-small);\n }\n\n input[type='file'] {\n display: none;\n }\n\n .list {\n display: flex;\n flex-direction: column;\n gap: 8px;\n width: 100%;\n margin: 0;\n padding: 0;\n list-style: none;\n }\n\n .item {\n display: flex;\n align-items: center;\n gap: 12px;\n width: 100%;\n padding: 12px;\n background: var(--surface-raised);\n border-radius: var(--border-radius);\n cursor: default;\n transition: background var(--duration-normal) var(--easing-standard);\n }\n .item:hover {\n background: var(--surface-hover);\n }\n\n .preview {\n display: flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 48px;\n height: 48px;\n overflow: hidden;\n color: var(--color-info-base);\n background: var(--color-dark-14);\n border-radius: 6px;\n }\n\n .info {\n display: flex;\n flex: 1;\n flex-direction: column;\n gap: 4px;\n min-width: 0;\n }\n\n .name {\n overflow: hidden;\n color: var(--text-body);\n font: var(--font-normal-medium);\n white-space: nowrap;\n text-overflow: ellipsis;\n }\n\n .details {\n display: flex;\n align-items: center;\n gap: 6px;\n color: var(--text-muted);\n font: var(--font-normal-small);\n }\n `,\n ];\n\n @query('input[type=\"file\"]')\n private fileInput!: HTMLInputElement;\n\n @state()\n private dragging = false;\n\n @state()\n private files: File[] = [];\n\n /**\n * The prompt above the browse link.\n *\n * Named `heading`, not `title`: an element already has a `title`, and\n * reusing it would put the prompt in a native tooltip on the whole zone.\n */\n @property({ type: String })\n heading = 'Drag and drop or';\n\n /** The clickable-looking part of the prompt. */\n @property({ type: String, attribute: 'link-text' })\n linkText = 'browse your files';\n\n /** Optional hint, e.g. `800×400px`. */\n @property({ type: String, attribute: 'recommended-size' })\n recommendedSize = '';\n\n @property({ type: Boolean })\n multiple = true;\n\n /** Same syntax as the native `accept`: `image/*`, `.pdf,.docx`. */\n @property({ type: String })\n accept = '';\n\n /** Largest accepted file, in bytes. Zero means no limit. */\n @property({ type: Number, attribute: 'max-size' })\n maxSize = 0;\n\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /** The files currently held, newest last. */\n get selectedFiles(): readonly File[] {\n return this.files;\n }\n\n /** Empties the selection without firing a rejection. */\n clear(): void {\n this.files = [];\n emit(this, 'kt-files-change', { files: this.files });\n }\n\n /**\n * `accept` is advisory on a native input — the OS dialog filters, but a\n * dropped file bypasses it entirely — so the same rules are enforced here.\n */\n private accepts(file: File): boolean {\n if (this.maxSize > 0 && file.size > this.maxSize) return false;\n if (!this.accept) return true;\n\n return this.accept\n .split(',')\n .map((pattern) => pattern.trim().toLowerCase())\n .filter(Boolean)\n .some((pattern) => {\n if (pattern.startsWith('.')) return file.name.toLowerCase().endsWith(pattern);\n if (pattern.endsWith('/*')) return file.type.startsWith(pattern.slice(0, -1));\n return file.type.toLowerCase() === pattern;\n });\n }\n\n private addFiles(incoming: FileList | null): void {\n if (!incoming || incoming.length === 0) return;\n\n const candidates = this.multiple ? [...incoming] : [...incoming].slice(0, 1);\n const accepted = candidates.filter((file) => this.accepts(file));\n const rejected = candidates.filter((file) => !this.accepts(file));\n\n if (rejected.length > 0) {\n emit(this, 'kt-files-rejected', {\n files: rejected,\n reason: this.maxSize > 0 && rejected.some((f) => f.size > this.maxSize) ? 'size' : 'type',\n });\n }\n if (accepted.length === 0) return;\n\n this.files = this.multiple ? [...this.files, ...accepted] : accepted;\n emit(this, 'kt-files-change', { files: this.files });\n }\n\n private removeAt(index: number): void {\n this.files = this.files.filter((_, position) => position !== index);\n emit(this, 'kt-files-change', { files: this.files });\n }\n\n private browse(): void {\n if (this.disabled) return;\n this.fileInput?.click();\n }\n\n private onZoneKeyDown(event: KeyboardEvent): void {\n if (event.key !== 'Enter' && event.key !== ' ') return;\n event.preventDefault();\n this.browse();\n }\n\n private onDragOver(event: DragEvent): void {\n if (this.disabled) return;\n event.preventDefault();\n this.dragging = true;\n }\n\n private onDrop(event: DragEvent): void {\n if (this.disabled) return;\n event.preventDefault();\n this.dragging = false;\n this.addFiles(event.dataTransfer?.files ?? null);\n }\n\n override render(): TemplateResult {\n return html`<div\n part=\"base\"\n class=${classMap({ zone: true, dragover: this.dragging })}\n role=\"button\"\n tabindex=${this.disabled ? -1 : 0}\n aria-disabled=${this.disabled ? 'true' : nothing}\n aria-label=${`${this.heading} ${this.linkText}`}\n @click=${this.browse}\n @keydown=${this.onZoneKeyDown}\n @dragover=${this.onDragOver}\n @dragleave=${() => {\n this.dragging = false;\n }}\n @drop=${this.onDrop}\n >\n <input\n type=\"file\"\n ?multiple=${this.multiple}\n accept=${this.accept || nothing}\n @click=${(event: Event) => event.stopPropagation()}\n @change=${(event: Event) => this.addFiles((event.target as HTMLInputElement).files)}\n />\n\n <div class=\"prompt\">\n <span class=\"prompt-icon\"><kt-icon name=\"file-up\" size=\"24\"></kt-icon></span>\n <div>\n <p class=\"title\">${this.heading} ${this.linkText}</p>\n ${\n this.recommendedSize\n ? html`<div class=\"hint\">Recommended image size: ${this.recommendedSize}</div>`\n : nothing\n }\n </div>\n </div>\n\n ${\n this.files.length > 0\n ? html`<ul\n part=\"list\"\n class=\"list\"\n aria-label=\"Selected files\"\n @click=${(event: Event) => event.stopPropagation()}\n >\n ${this.files.map(\n (file, index) =>\n html`<li class=\"item\">\n <span class=\"preview\"><kt-icon name=\"file\" size=\"24\"></kt-icon></span>\n <span class=\"info\">\n <span class=\"name\" title=${file.name}>${file.name}</span>\n <span class=\"details\">\n <span>${formatFileSize(file.size)}</span>\n ${file.type ? html`<span>•</span><span>${file.type}</span>` : nothing}\n </span>\n </span>\n <kt-button\n variant=\"danger\"\n size=\"small\"\n icon=\"trash-2\"\n label=${`Remove ${file.name}`}\n @click=${() => this.removeAt(index)}\n ></kt-button>\n </li>`,\n )}\n </ul>`\n : nothing\n }\n </div>`;\n }\n}\n\ndefineElement('kt-drag-drop', KtDragDrop);\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'kt-drag-drop': KtDragDrop;\n }\n}\n"],"names":["UNITS","formatFileSize","bytes","value","unit","KtDragDrop","KtElement","css","emit","file","pattern","incoming","candidates","accepted","rejected","f","index","_","position","event","html","classMap","nothing","__decorateClass","query","state","property","defineElement"],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ import { type PropertyValues, type TemplateResult } from 'lit';
2
+ import { KtElement } from '#internal/kt-element';
3
+ import '../../feedback/kt-skeleton/kt-skeleton.js';
4
+ /**
5
+ * A panel grouping related fields.
6
+ *
7
+ * It sits one step above the page on `--surface-form`, so the fields inside —
8
+ * filled at `--surface-field` — read as wells recessed into it rather than as
9
+ * boxes floating on it.
10
+ *
11
+ * **Put it inside your own `<form>`.** It renders a `<fieldset>`, not a form:
12
+ * Kanto fields are form-associated custom elements, and a control finds its
13
+ * form by walking its *own* tree. A `<form>` inside this element's shadow root
14
+ * would not own anything slotted into it, and `new FormData(form)` would come
15
+ * back empty. The `<form>` above stays in charge of submission, validation and
16
+ * reset; this owns the grouping and the look.
17
+ *
18
+ * @element kt-form
19
+ *
20
+ * @slot - The fields.
21
+ * @slot heading - Replaces the `heading` attribute, for markup.
22
+ * @slot footer - Actions, right-aligned. Hidden when empty.
23
+ *
24
+ * @csspart base - The `<fieldset>`.
25
+ * @csspart header - The heading and description.
26
+ * @csspart fields - The field column.
27
+ * @csspart footer - The action row.
28
+ *
29
+ * @example
30
+ * ```html
31
+ * <form>
32
+ * <kt-form heading="Identity" description="How we address you.">
33
+ * <kt-label-input label="Company" required>
34
+ * <kt-input name="company" required></kt-input>
35
+ * </kt-label-input>
36
+ * <kt-button slot="footer" type="submit">Save</kt-button>
37
+ * </kt-form>
38
+ * </form>
39
+ * ```
40
+ */
41
+ export declare class KtForm extends KtElement {
42
+ static styles: import("lit").CSSResultGroup[];
43
+ private fields;
44
+ private hasFooter;
45
+ /** Group heading. Also the fieldset's accessible name. */
46
+ heading: string;
47
+ description: string;
48
+ /** Replaces the fields with placeholders. */
49
+ loading: boolean;
50
+ /** Switches off every field in the panel. */
51
+ disabled: boolean;
52
+ /** How many placeholder fields `loading` draws. */
53
+ loadingFields: number;
54
+ updated(changed: PropertyValues<this>): void;
55
+ /**
56
+ * A native `<fieldset disabled>` switches off its descendants, but slotted
57
+ * fields are not descendants of the fieldset in their own tree — the shadow
58
+ * boundary sits between them — so the platform never reaches them. Walk the
59
+ * slotted controls and set it directly.
60
+ */
61
+ /**
62
+ * The initial `slotchange` is queued as a microtask and can land after the
63
+ * first render has settled, so read the slots once directly as well.
64
+ */
65
+ firstUpdated(): void;
66
+ private readSlots;
67
+ private onFooterSlotChange;
68
+ private syncDisabled;
69
+ render(): TemplateResult;
70
+ }
71
+ declare global {
72
+ interface HTMLElementTagNameMap {
73
+ 'kt-form': KtForm;
74
+ }
75
+ }
@@ -0,0 +1,187 @@
1
+ import { css as f, nothing as h, html as r } from "lit";
2
+ import { queryAssignedElements as c, state as g, property as a } from "lit/decorators.js";
3
+ import { K as p, d as m } from "../../../chunks/kt-element-CcMLO5e8.js";
4
+ import { h as y } from "../../../chunks/slots-BPbIdxAJ.js";
5
+ import "../../feedback/kt-skeleton/kt-skeleton.js";
6
+ var b = Object.defineProperty, s = (l, e, o, u) => {
7
+ for (var i = void 0, d = l.length - 1, n; d >= 0; d--)
8
+ (n = l[d]) && (i = n(e, o, i) || i);
9
+ return i && b(e, o, i), i;
10
+ };
11
+ class t extends p {
12
+ constructor() {
13
+ super(...arguments), this.hasFooter = !1, this.heading = "", this.description = "", this.loading = !1, this.disabled = !1, this.loadingFields = 3;
14
+ }
15
+ static {
16
+ this.styles = [
17
+ p.styles,
18
+ f`
19
+ :host {
20
+ display: block;
21
+ }
22
+
23
+ fieldset {
24
+ display: flex;
25
+ flex-direction: column;
26
+ gap: var(--gap-form);
27
+ min-width: 0;
28
+ margin: 0;
29
+ padding: var(--padding-card);
30
+ background-color: var(--surface-form);
31
+ border: var(--border-width) solid var(--border-subtle);
32
+ border-radius: var(--border-radius-card);
33
+ }
34
+
35
+ .header {
36
+ display: flex;
37
+ flex-direction: column;
38
+ gap: var(--gap-element);
39
+ }
40
+
41
+ /* A legend is the accessible name for the group, so it stays in the
42
+ accessibility tree even when there is nothing to show. */
43
+ legend {
44
+ padding: 0;
45
+ color: var(--text-body);
46
+ font: var(--font-title-h6);
47
+ }
48
+
49
+ legend.visually-hidden {
50
+ position: absolute;
51
+ width: 1px;
52
+ height: 1px;
53
+ overflow: hidden;
54
+ clip-path: inset(50%);
55
+ white-space: nowrap;
56
+ }
57
+
58
+ .description {
59
+ margin: 0;
60
+ color: var(--text-muted);
61
+ font: var(--font-normal-regular);
62
+ }
63
+
64
+ .fields {
65
+ display: flex;
66
+ flex-direction: column;
67
+ gap: var(--gap-form);
68
+ min-width: 0;
69
+ }
70
+
71
+ .placeholder {
72
+ display: flex;
73
+ flex-direction: column;
74
+ gap: 8px;
75
+ }
76
+
77
+ .footer {
78
+ display: flex;
79
+ flex-wrap: wrap;
80
+ align-items: center;
81
+ justify-content: flex-end;
82
+ gap: var(--gap-button);
83
+ }
84
+
85
+ /* Collapsed from JS: a wrapper around a <slot> always has the slot as a
86
+ child, so :has(*) cannot tell an empty slot from a filled one. */
87
+ .footer.empty {
88
+ display: none;
89
+ }
90
+
91
+ /* While loading, the real fields stay in the DOM — and keep their state
92
+ — but step aside for the placeholders. */
93
+ :host([loading]) ::slotted(*) {
94
+ display: none;
95
+ }
96
+
97
+ :host([disabled]) fieldset {
98
+ opacity: 0.6;
99
+ }
100
+ `
101
+ ];
102
+ }
103
+ updated(e) {
104
+ e.has("disabled") && this.syncDisabled();
105
+ }
106
+ /**
107
+ * A native `<fieldset disabled>` switches off its descendants, but slotted
108
+ * fields are not descendants of the fieldset in their own tree — the shadow
109
+ * boundary sits between them — so the platform never reaches them. Walk the
110
+ * slotted controls and set it directly.
111
+ */
112
+ /**
113
+ * The initial `slotchange` is queued as a microtask and can land after the
114
+ * first render has settled, so read the slots once directly as well.
115
+ */
116
+ firstUpdated() {
117
+ this.readSlots(), this.syncDisabled();
118
+ }
119
+ readSlots() {
120
+ this.hasFooter = y(
121
+ this.shadowRoot?.querySelector('slot[name="footer"]')
122
+ );
123
+ }
124
+ onFooterSlotChange() {
125
+ this.readSlots();
126
+ }
127
+ syncDisabled() {
128
+ for (const e of this.fields ?? []) {
129
+ "disabled" in e && (e.disabled = this.disabled);
130
+ for (const o of e.querySelectorAll("*"))
131
+ "disabled" in o && (o.disabled = this.disabled);
132
+ }
133
+ }
134
+ render() {
135
+ const e = !!this.heading || !!this.description;
136
+ return r`<fieldset part="base" ?disabled=${this.disabled}>
137
+ <legend class=${this.heading ? "" : "visually-hidden"}>
138
+ <slot name="heading">${this.heading || "Form section"}</slot>
139
+ </legend>
140
+
141
+ ${e && this.description ? r`<div part="header" class="header">
142
+ <p class="description">${this.description}</p>
143
+ </div>` : h}
144
+
145
+ <div part="fields" class="fields">
146
+ ${this.loading ? Array.from(
147
+ { length: this.loadingFields },
148
+ () => r`<div class="placeholder" aria-hidden="true">
149
+ <kt-skeleton width="30%" height="14px"></kt-skeleton>
150
+ <kt-skeleton variant="rect" height="40px"></kt-skeleton>
151
+ </div>`
152
+ ) : h}
153
+ <slot @slotchange=${this.syncDisabled}></slot>
154
+ </div>
155
+
156
+ <div part="footer" class=${this.hasFooter ? "footer" : "footer empty"}>
157
+ <slot name="footer" @slotchange=${this.onFooterSlotChange}></slot>
158
+ </div>
159
+ </fieldset>`;
160
+ }
161
+ }
162
+ s([
163
+ c()
164
+ ], t.prototype, "fields");
165
+ s([
166
+ g()
167
+ ], t.prototype, "hasFooter");
168
+ s([
169
+ a({ type: String })
170
+ ], t.prototype, "heading");
171
+ s([
172
+ a({ type: String })
173
+ ], t.prototype, "description");
174
+ s([
175
+ a({ type: Boolean, reflect: !0 })
176
+ ], t.prototype, "loading");
177
+ s([
178
+ a({ type: Boolean, reflect: !0 })
179
+ ], t.prototype, "disabled");
180
+ s([
181
+ a({ type: Number, attribute: "loading-fields" })
182
+ ], t.prototype, "loadingFields");
183
+ m("kt-form", t);
184
+ export {
185
+ t as KtForm
186
+ };
187
+ //# sourceMappingURL=kt-form.js.map