@chromvoid/uikit 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (246) hide show
  1. package/LICENSE +8 -0
  2. package/README.md +96 -0
  3. package/dist/components/cv-accordion-item.d.ts +69 -0
  4. package/dist/components/cv-accordion-item.js +176 -0
  5. package/dist/components/cv-accordion.d.ts +79 -0
  6. package/dist/components/cv-accordion.js +310 -0
  7. package/dist/components/cv-alert-dialog.d.ts +86 -0
  8. package/dist/components/cv-alert-dialog.js +393 -0
  9. package/dist/components/cv-alert.d.ts +48 -0
  10. package/dist/components/cv-alert.js +156 -0
  11. package/dist/components/cv-badge.d.ts +56 -0
  12. package/dist/components/cv-badge.js +280 -0
  13. package/dist/components/cv-breadcrumb-item.d.ts +35 -0
  14. package/dist/components/cv-breadcrumb-item.js +64 -0
  15. package/dist/components/cv-breadcrumb.d.ts +39 -0
  16. package/dist/components/cv-breadcrumb.js +160 -0
  17. package/dist/components/cv-button.d.ts +83 -0
  18. package/dist/components/cv-button.js +541 -0
  19. package/dist/components/cv-callout.d.ts +32 -0
  20. package/dist/components/cv-callout.js +221 -0
  21. package/dist/components/cv-card.d.ts +48 -0
  22. package/dist/components/cv-card.js +269 -0
  23. package/dist/components/cv-carousel-slide.d.ts +25 -0
  24. package/dist/components/cv-carousel-slide.js +51 -0
  25. package/dist/components/cv-carousel.d.ts +96 -0
  26. package/dist/components/cv-carousel.js +457 -0
  27. package/dist/components/cv-checkbox.d.ts +84 -0
  28. package/dist/components/cv-checkbox.js +274 -0
  29. package/dist/components/cv-combobox-group.d.ts +15 -0
  30. package/dist/components/cv-combobox-group.js +34 -0
  31. package/dist/components/cv-combobox-option.d.ts +30 -0
  32. package/dist/components/cv-combobox-option.js +66 -0
  33. package/dist/components/cv-combobox.d.ts +135 -0
  34. package/dist/components/cv-combobox.js +834 -0
  35. package/dist/components/cv-command-item.d.ts +30 -0
  36. package/dist/components/cv-command-item.js +68 -0
  37. package/dist/components/cv-command-palette.d.ts +105 -0
  38. package/dist/components/cv-command-palette.js +578 -0
  39. package/dist/components/cv-context-menu.d.ts +98 -0
  40. package/dist/components/cv-context-menu.js +515 -0
  41. package/dist/components/cv-copy-button.d.ts +61 -0
  42. package/dist/components/cv-copy-button.js +318 -0
  43. package/dist/components/cv-date-picker.d.ts +161 -0
  44. package/dist/components/cv-date-picker.js +803 -0
  45. package/dist/components/cv-dialog.d.ts +89 -0
  46. package/dist/components/cv-dialog.js +459 -0
  47. package/dist/components/cv-disclosure.d.ts +57 -0
  48. package/dist/components/cv-disclosure.js +241 -0
  49. package/dist/components/cv-drawer.d.ts +102 -0
  50. package/dist/components/cv-drawer.js +595 -0
  51. package/dist/components/cv-feed-article.d.ts +26 -0
  52. package/dist/components/cv-feed-article.js +52 -0
  53. package/dist/components/cv-feed.d.ts +62 -0
  54. package/dist/components/cv-feed.js +310 -0
  55. package/dist/components/cv-grid-cell.d.ts +30 -0
  56. package/dist/components/cv-grid-cell.js +57 -0
  57. package/dist/components/cv-grid-column.d.ts +30 -0
  58. package/dist/components/cv-grid-column.js +43 -0
  59. package/dist/components/cv-grid-row.d.ts +30 -0
  60. package/dist/components/cv-grid-row.js +42 -0
  61. package/dist/components/cv-grid.d.ts +119 -0
  62. package/dist/components/cv-grid.js +567 -0
  63. package/dist/components/cv-icon.d.ts +57 -0
  64. package/dist/components/cv-icon.js +352 -0
  65. package/dist/components/cv-input.d.ts +127 -0
  66. package/dist/components/cv-input.js +482 -0
  67. package/dist/components/cv-landmark.d.ts +32 -0
  68. package/dist/components/cv-landmark.js +62 -0
  69. package/dist/components/cv-link.d.ts +22 -0
  70. package/dist/components/cv-link.js +99 -0
  71. package/dist/components/cv-listbox-group.d.ts +15 -0
  72. package/dist/components/cv-listbox-group.js +42 -0
  73. package/dist/components/cv-listbox.d.ts +81 -0
  74. package/dist/components/cv-listbox.js +388 -0
  75. package/dist/components/cv-menu-button.d.ts +118 -0
  76. package/dist/components/cv-menu-button.js +822 -0
  77. package/dist/components/cv-menu-group.d.ts +20 -0
  78. package/dist/components/cv-menu-group.js +48 -0
  79. package/dist/components/cv-menu-item.d.ts +52 -0
  80. package/dist/components/cv-menu-item.js +105 -0
  81. package/dist/components/cv-menu.d.ts +62 -0
  82. package/dist/components/cv-menu.js +414 -0
  83. package/dist/components/cv-meter.d.ts +66 -0
  84. package/dist/components/cv-meter.js +154 -0
  85. package/dist/components/cv-number.d.ts +139 -0
  86. package/dist/components/cv-number.js +553 -0
  87. package/dist/components/cv-option.d.ts +30 -0
  88. package/dist/components/cv-option.js +84 -0
  89. package/dist/components/cv-popover.d.ts +87 -0
  90. package/dist/components/cv-popover.js +373 -0
  91. package/dist/components/cv-progress-ring.d.ts +45 -0
  92. package/dist/components/cv-progress-ring.js +169 -0
  93. package/dist/components/cv-progress.d.ts +45 -0
  94. package/dist/components/cv-progress.js +148 -0
  95. package/dist/components/cv-radio-group.d.ts +79 -0
  96. package/dist/components/cv-radio-group.js +398 -0
  97. package/dist/components/cv-radio.d.ts +36 -0
  98. package/dist/components/cv-radio.js +123 -0
  99. package/dist/components/cv-select-group.d.ts +15 -0
  100. package/dist/components/cv-select-group.js +44 -0
  101. package/dist/components/cv-select-option.d.ts +30 -0
  102. package/dist/components/cv-select-option.js +66 -0
  103. package/dist/components/cv-select.d.ts +128 -0
  104. package/dist/components/cv-select.js +666 -0
  105. package/dist/components/cv-sidebar-item.d.ts +26 -0
  106. package/dist/components/cv-sidebar-item.js +142 -0
  107. package/dist/components/cv-sidebar.d.ts +171 -0
  108. package/dist/components/cv-sidebar.js +767 -0
  109. package/dist/components/cv-slider-multi-thumb.d.ts +73 -0
  110. package/dist/components/cv-slider-multi-thumb.js +374 -0
  111. package/dist/components/cv-slider.d.ts +84 -0
  112. package/dist/components/cv-slider.js +328 -0
  113. package/dist/components/cv-spinbutton.d.ts +121 -0
  114. package/dist/components/cv-spinbutton.js +486 -0
  115. package/dist/components/cv-spinner.d.ts +18 -0
  116. package/dist/components/cv-spinner.js +95 -0
  117. package/dist/components/cv-switch.d.ts +81 -0
  118. package/dist/components/cv-switch.js +285 -0
  119. package/dist/components/cv-tab-panel.d.ts +20 -0
  120. package/dist/components/cv-tab-panel.js +37 -0
  121. package/dist/components/cv-tab.d.ts +40 -0
  122. package/dist/components/cv-tab.js +132 -0
  123. package/dist/components/cv-table-cell.d.ts +31 -0
  124. package/dist/components/cv-table-cell.js +49 -0
  125. package/dist/components/cv-table-column.d.ts +37 -0
  126. package/dist/components/cv-table-column.js +63 -0
  127. package/dist/components/cv-table-row.d.ts +30 -0
  128. package/dist/components/cv-table-row.js +45 -0
  129. package/dist/components/cv-table.d.ts +147 -0
  130. package/dist/components/cv-table.js +607 -0
  131. package/dist/components/cv-tabs.d.ts +70 -0
  132. package/dist/components/cv-tabs.js +524 -0
  133. package/dist/components/cv-textarea.d.ts +108 -0
  134. package/dist/components/cv-textarea.js +328 -0
  135. package/dist/components/cv-toast-region.d.ts +39 -0
  136. package/dist/components/cv-toast-region.js +162 -0
  137. package/dist/components/cv-toast.d.ts +67 -0
  138. package/dist/components/cv-toast.js +315 -0
  139. package/dist/components/cv-toolbar-item.d.ts +25 -0
  140. package/dist/components/cv-toolbar-item.js +72 -0
  141. package/dist/components/cv-toolbar-separator.d.ts +25 -0
  142. package/dist/components/cv-toolbar-separator.js +45 -0
  143. package/dist/components/cv-toolbar.d.ts +63 -0
  144. package/dist/components/cv-toolbar.js +295 -0
  145. package/dist/components/cv-tooltip.d.ts +83 -0
  146. package/dist/components/cv-tooltip.js +455 -0
  147. package/dist/components/cv-treegrid-cell.d.ts +30 -0
  148. package/dist/components/cv-treegrid-cell.js +57 -0
  149. package/dist/components/cv-treegrid-column.d.ts +37 -0
  150. package/dist/components/cv-treegrid-column.js +53 -0
  151. package/dist/components/cv-treegrid-row.d.ts +55 -0
  152. package/dist/components/cv-treegrid-row.js +90 -0
  153. package/dist/components/cv-treegrid.d.ts +96 -0
  154. package/dist/components/cv-treegrid.js +632 -0
  155. package/dist/components/cv-treeitem.d.ts +58 -0
  156. package/dist/components/cv-treeitem.js +144 -0
  157. package/dist/components/cv-treeview.d.ts +70 -0
  158. package/dist/components/cv-treeview.js +396 -0
  159. package/dist/components/cv-window-splitter.d.ts +79 -0
  160. package/dist/components/cv-window-splitter.js +316 -0
  161. package/dist/components/index.d.ts +94 -0
  162. package/dist/components/index.js +79 -0
  163. package/dist/dialog/create-dialog-controller.d.ts +31 -0
  164. package/dist/dialog/create-dialog-controller.js +320 -0
  165. package/dist/dialog/index.d.ts +2 -0
  166. package/dist/dialog/index.js +1 -0
  167. package/dist/form-associated/FormAssociatedReatomElement.d.ts +25 -0
  168. package/dist/form-associated/FormAssociatedReatomElement.js +70 -0
  169. package/dist/form-associated/withFormAssociated.d.ts +5 -0
  170. package/dist/form-associated/withFormAssociated.js +1 -0
  171. package/dist/index.d.ts +10 -0
  172. package/dist/index.js +9 -0
  173. package/dist/reatom-lit/ReatomLitElement.d.ts +27 -0
  174. package/dist/reatom-lit/ReatomLitElement.js +118 -0
  175. package/dist/reatom-lit/html.d.ts +4 -0
  176. package/dist/reatom-lit/html.js +10 -0
  177. package/dist/reatom-lit/index.d.ts +4 -0
  178. package/dist/reatom-lit/index.js +4 -0
  179. package/dist/reatom-lit/watch.d.ts +15 -0
  180. package/dist/reatom-lit/watch.js +40 -0
  181. package/dist/reatom-lit/withReatomElement.d.ts +4 -0
  182. package/dist/reatom-lit/withReatomElement.js +57 -0
  183. package/dist/register.d.ts +1 -0
  184. package/dist/register.js +84 -0
  185. package/dist/styles/component-styles.d.ts +4 -0
  186. package/dist/styles/component-styles.js +78 -0
  187. package/dist/theme/cv-theme-provider.d.ts +32 -0
  188. package/dist/theme/cv-theme-provider.js +110 -0
  189. package/dist/theme/index.d.ts +4 -0
  190. package/dist/theme/index.js +2 -0
  191. package/dist/theme/theme-engine.d.ts +4 -0
  192. package/dist/theme/theme-engine.js +67 -0
  193. package/dist/theme/tokens.css +265 -0
  194. package/dist/theme/types.d.ts +7 -0
  195. package/dist/theme/types.js +1 -0
  196. package/dist/toast/create-toast-controller.d.ts +12 -0
  197. package/dist/toast/create-toast-controller.js +12 -0
  198. package/dist/toast/index.d.ts +2 -0
  199. package/dist/toast/index.js +1 -0
  200. package/package.json +146 -0
  201. package/specs/_template.md +110 -0
  202. package/specs/components/accordion.md +207 -0
  203. package/specs/components/alert.md +83 -0
  204. package/specs/components/badge.md +183 -0
  205. package/specs/components/breadcrumb.md +152 -0
  206. package/specs/components/button.md +227 -0
  207. package/specs/components/callout.md +153 -0
  208. package/specs/components/card.md +192 -0
  209. package/specs/components/carousel.md +232 -0
  210. package/specs/components/checkbox.md +141 -0
  211. package/specs/components/combobox.md +427 -0
  212. package/specs/components/context-menu.md +375 -0
  213. package/specs/components/copy-button.md +236 -0
  214. package/specs/components/date-picker.md +290 -0
  215. package/specs/components/dialog.md +184 -0
  216. package/specs/components/disclosure.md +151 -0
  217. package/specs/components/drawer.md +216 -0
  218. package/specs/components/feed.md +266 -0
  219. package/specs/components/grid.md +423 -0
  220. package/specs/components/input.md +237 -0
  221. package/specs/components/landmark.md +92 -0
  222. package/specs/components/link.md +117 -0
  223. package/specs/components/listbox.md +327 -0
  224. package/specs/components/menu.md +508 -0
  225. package/specs/components/meter.md +148 -0
  226. package/specs/components/number.md +268 -0
  227. package/specs/components/option.md +167 -0
  228. package/specs/components/popover.md +207 -0
  229. package/specs/components/progress-ring.md +134 -0
  230. package/specs/components/progress.md +110 -0
  231. package/specs/components/radio.md +208 -0
  232. package/specs/components/select.md +305 -0
  233. package/specs/components/sidebar.md +204 -0
  234. package/specs/components/spinbutton.md +157 -0
  235. package/specs/components/spinner.md +83 -0
  236. package/specs/components/switch.md +145 -0
  237. package/specs/components/table.md +372 -0
  238. package/specs/components/tabs.md +242 -0
  239. package/specs/components/textarea.md +166 -0
  240. package/specs/components/theme.md +364 -0
  241. package/specs/components/toast.md +198 -0
  242. package/specs/components/toolbar.md +258 -0
  243. package/specs/components/tooltip.md +152 -0
  244. package/specs/components/treegrid.md +363 -0
  245. package/specs/components/treeview.md +263 -0
  246. package/specs/components/window-splitter.md +225 -0
@@ -0,0 +1,455 @@
1
+ import { createTooltip } from '@chromvoid/headless-ui/tooltip';
2
+ import { css, html, nothing } from 'lit';
3
+ import { ReatomLitElement } from '../reatom-lit/ReatomLitElement.js';
4
+ const supportsNativePopover = typeof HTMLElement !== 'undefined' &&
5
+ typeof HTMLElement.prototype.showPopover === 'function' &&
6
+ typeof HTMLElement.prototype.hidePopover === 'function';
7
+ const supportsAnchorPositioning = typeof CSS !== 'undefined' &&
8
+ typeof CSS.supports === 'function' &&
9
+ CSS.supports('anchor-name: --cv-tooltip-anchor') &&
10
+ CSS.supports('position-anchor: --cv-tooltip-anchor') &&
11
+ CSS.supports('position-area: top') &&
12
+ CSS.supports('top: anchor(bottom)');
13
+ const supportsAnchorTryFallbacks = typeof CSS !== 'undefined' &&
14
+ typeof CSS.supports === 'function' &&
15
+ CSS.supports('position-try-fallbacks: flip-block');
16
+ const supportsNativeAnchoredAutoplacement = supportsNativePopover && supportsAnchorPositioning && supportsAnchorTryFallbacks;
17
+ let cvTooltipNonce = 0;
18
+ export class CVTooltip extends ReatomLitElement {
19
+ static elementName = 'cv-tooltip';
20
+ static get properties() {
21
+ return {
22
+ open: { type: Boolean, reflect: true },
23
+ disabled: { type: Boolean, reflect: true },
24
+ showDelay: { type: Number, attribute: 'show-delay', reflect: true },
25
+ hideDelay: { type: Number, attribute: 'hide-delay', reflect: true },
26
+ trigger: { type: String, reflect: true },
27
+ arrow: { type: Boolean, reflect: true },
28
+ };
29
+ }
30
+ idBase = `cv-tooltip-${++cvTooltipNonce}`;
31
+ model;
32
+ triggerTargets = new Set();
33
+ lastEmittedOpen = false;
34
+ hasLayoutListeners = false;
35
+ layoutFrame = -1;
36
+ constructor() {
37
+ super();
38
+ this.open = false;
39
+ this.disabled = false;
40
+ this.showDelay = 120;
41
+ this.hideDelay = 80;
42
+ this.trigger = 'hover focus';
43
+ this.arrow = false;
44
+ this.model = this.createModel();
45
+ this.lastEmittedOpen = this.model.state.isOpen();
46
+ }
47
+ static styles = [
48
+ css `
49
+ :host {
50
+ display: inline-block;
51
+ }
52
+
53
+ [part='base'] {
54
+ position: relative;
55
+ display: inline-block;
56
+ }
57
+
58
+ [part='trigger'] {
59
+ display: inline-flex;
60
+ align-items: center;
61
+ justify-content: center;
62
+ anchor-name: --cv-tooltip-anchor;
63
+ }
64
+
65
+ [part='content'] {
66
+ position: absolute;
67
+ inset-inline-start: 50%;
68
+ inset-block-end: calc(100% + var(--cv-space-1, 4px));
69
+ transform: translateX(-50%);
70
+ z-index: 30;
71
+ max-inline-size: min(320px, calc(100vw - 32px));
72
+ padding: var(--cv-space-1, 4px) var(--cv-space-2, 8px);
73
+ border-radius: var(--cv-radius-sm, 6px);
74
+ border: 1px solid var(--cv-color-border, #2a3245);
75
+ background: var(--cv-color-surface-elevated, #1d2432);
76
+ color: var(--cv-color-text, #e8ecf6);
77
+ font-size: 0.85rem;
78
+ white-space: nowrap;
79
+ box-shadow: var(--cv-shadow-1, 0 2px 8px rgba(0, 0, 0, 0.24));
80
+ }
81
+
82
+ [part='content'][data-anchor-positioning='true'] {
83
+ position: fixed;
84
+ inset: auto;
85
+ margin: 0;
86
+ position-anchor: --cv-tooltip-anchor;
87
+ position-area: top;
88
+ position-try-fallbacks: flip-block, flip-inline, bottom, right, left;
89
+ position-visibility: anchors-visible;
90
+ transform: none;
91
+ translate: none;
92
+ }
93
+
94
+ [part='content'][hidden] {
95
+ display: none;
96
+ }
97
+
98
+ [part='arrow'] {
99
+ position: absolute;
100
+ inset-inline-start: 50%;
101
+ inset-block-start: 100%;
102
+ transform: translateX(-50%);
103
+ width: 0;
104
+ height: 0;
105
+ border-inline: 6px solid transparent;
106
+ border-block-start: 6px solid var(--cv-color-surface-elevated, #1d2432);
107
+ }
108
+
109
+ [part='content'][data-placement='bottom'] [part='arrow'] {
110
+ inset-block-start: auto;
111
+ inset-block-end: 100%;
112
+ border-block-start: none;
113
+ border-block-end: 6px solid var(--cv-color-surface-elevated, #1d2432);
114
+ }
115
+ `,
116
+ ];
117
+ static define() {
118
+ if (!customElements.get(this.elementName)) {
119
+ customElements.define(this.elementName, this);
120
+ }
121
+ }
122
+ connectedCallback() {
123
+ super.connectedCallback();
124
+ this.syncTriggerAria();
125
+ }
126
+ disconnectedCallback() {
127
+ super.disconnectedCallback();
128
+ this.toggleLayoutListeners(false);
129
+ this.cancelLayoutFrame();
130
+ if (supportsNativePopover) {
131
+ const content = this.getContentElement();
132
+ if (content?.matches(':popover-open')) {
133
+ content.hidePopover();
134
+ }
135
+ }
136
+ }
137
+ willUpdate(changedProperties) {
138
+ super.willUpdate(changedProperties);
139
+ if (changedProperties.has('showDelay') ||
140
+ changedProperties.has('hideDelay') ||
141
+ changedProperties.has('trigger')) {
142
+ // Preserve whichever is "more open": model state OR the declared property value.
143
+ // On first update all properties appear changed; use this.open so an initialOpen
144
+ // value set before connection is not discarded.
145
+ const wasOpen = this.model.state.isOpen() || this.open;
146
+ this.model = this.createModel(wasOpen);
147
+ return;
148
+ }
149
+ if (changedProperties.has('disabled')) {
150
+ this.model.actions.setDisabled(this.disabled);
151
+ }
152
+ if (changedProperties.has('open') && this.model.state.isOpen() !== this.open) {
153
+ const previousOpen = this.model.state.isOpen();
154
+ if (this.open) {
155
+ this.model.actions.open();
156
+ }
157
+ else {
158
+ this.model.actions.close();
159
+ }
160
+ this.applyInteractionResult(previousOpen);
161
+ }
162
+ }
163
+ updated(changedProperties) {
164
+ super.updated(changedProperties);
165
+ this.syncTriggerAria();
166
+ const modelOpen = this.model.state.isOpen();
167
+ if (this.open !== modelOpen) {
168
+ this.open = modelOpen;
169
+ }
170
+ if (this.lastEmittedOpen !== modelOpen) {
171
+ this.emitOpenChange(modelOpen);
172
+ }
173
+ this.syncNativePopover();
174
+ const shouldTrackLayout = modelOpen && !supportsNativeAnchoredAutoplacement;
175
+ this.toggleLayoutListeners(shouldTrackLayout);
176
+ if (modelOpen) {
177
+ this.scheduleLayout();
178
+ }
179
+ else {
180
+ this.cancelLayoutFrame();
181
+ const content = this.getContentElement();
182
+ if (content) {
183
+ this.clearInlineLayout(content);
184
+ content.dataset['placement'] = 'top';
185
+ }
186
+ }
187
+ }
188
+ getContentElement() {
189
+ return this.shadowRoot?.querySelector('[part="content"]');
190
+ }
191
+ getTriggerElement() {
192
+ return this.shadowRoot?.querySelector('[part="trigger"]');
193
+ }
194
+ clearInlineLayout(content) {
195
+ content.style.position = '';
196
+ content.style.top = '';
197
+ content.style.left = '';
198
+ content.style.bottom = '';
199
+ content.style.insetInlineStart = '';
200
+ content.style.insetBlockEnd = '';
201
+ content.style.transform = '';
202
+ content.style.translate = '';
203
+ }
204
+ syncNativePopover() {
205
+ if (!supportsNativePopover)
206
+ return;
207
+ const content = this.getContentElement();
208
+ if (!content)
209
+ return;
210
+ const isOpen = this.model.state.isOpen();
211
+ const isPopoverOpen = content.matches(':popover-open');
212
+ if (isOpen && !isPopoverOpen) {
213
+ content.showPopover();
214
+ return;
215
+ }
216
+ if (!isOpen && isPopoverOpen) {
217
+ content.hidePopover();
218
+ }
219
+ }
220
+ applyFallbackLayout(content, trigger) {
221
+ const triggerRect = trigger.getBoundingClientRect();
222
+ const contentRect = content.getBoundingClientRect();
223
+ const viewportWidth = window.innerWidth;
224
+ const viewportHeight = window.innerHeight;
225
+ const gap = 6;
226
+ const viewportPadding = 8;
227
+ const spaceAbove = triggerRect.top;
228
+ const spaceBelow = viewportHeight - triggerRect.bottom;
229
+ const placeAbove = spaceAbove >= contentRect.height + gap ||
230
+ (spaceAbove >= spaceBelow && spaceAbove >= contentRect.height / 2);
231
+ let top = placeAbove ? triggerRect.top - contentRect.height - gap : triggerRect.bottom + gap;
232
+ let left = triggerRect.left + triggerRect.width / 2 - contentRect.width / 2;
233
+ const maxLeft = Math.max(viewportPadding, viewportWidth - contentRect.width - viewportPadding);
234
+ const maxTop = Math.max(viewportPadding, viewportHeight - contentRect.height - viewportPadding);
235
+ left = Math.min(Math.max(left, viewportPadding), maxLeft);
236
+ top = Math.min(Math.max(top, viewportPadding), maxTop);
237
+ content.dataset['placement'] = placeAbove ? 'top' : 'bottom';
238
+ content.style.position = 'fixed';
239
+ content.style.top = `${top}px`;
240
+ content.style.left = `${left}px`;
241
+ content.style.bottom = 'auto';
242
+ content.style.insetInlineStart = 'auto';
243
+ content.style.insetBlockEnd = 'auto';
244
+ content.style.transform = 'none';
245
+ content.style.translate = 'none';
246
+ }
247
+ syncTooltipLayout() {
248
+ const content = this.getContentElement();
249
+ const trigger = this.getTriggerElement();
250
+ if (!content || !trigger)
251
+ return;
252
+ if (supportsNativeAnchoredAutoplacement) {
253
+ this.clearInlineLayout(content);
254
+ content.dataset['placement'] = 'top';
255
+ return;
256
+ }
257
+ this.applyFallbackLayout(content, trigger);
258
+ }
259
+ cancelLayoutFrame() {
260
+ if (this.layoutFrame === -1)
261
+ return;
262
+ cancelAnimationFrame(this.layoutFrame);
263
+ this.layoutFrame = -1;
264
+ }
265
+ scheduleLayout() {
266
+ this.cancelLayoutFrame();
267
+ this.layoutFrame = requestAnimationFrame(() => {
268
+ this.layoutFrame = -1;
269
+ this.syncTooltipLayout();
270
+ });
271
+ }
272
+ toggleLayoutListeners(nextState) {
273
+ if (this.hasLayoutListeners === nextState)
274
+ return;
275
+ this.hasLayoutListeners = nextState;
276
+ if (nextState) {
277
+ window.addEventListener('resize', this.handleViewportChange);
278
+ window.addEventListener('scroll', this.handleViewportChange, true);
279
+ return;
280
+ }
281
+ window.removeEventListener('resize', this.handleViewportChange);
282
+ window.removeEventListener('scroll', this.handleViewportChange, true);
283
+ }
284
+ handleViewportChange = () => {
285
+ if (!this.model.state.isOpen())
286
+ return;
287
+ this.scheduleLayout();
288
+ };
289
+ createModel(initialOpen = this.open) {
290
+ return createTooltip({
291
+ idBase: this.idBase,
292
+ initialOpen,
293
+ isDisabled: this.disabled,
294
+ showDelay: this.showDelay,
295
+ hideDelay: this.hideDelay,
296
+ trigger: this.trigger,
297
+ });
298
+ }
299
+ dispatchInput(detail) {
300
+ this.dispatchEvent(new CustomEvent('cv-input', {
301
+ detail,
302
+ bubbles: true,
303
+ composed: true,
304
+ }));
305
+ }
306
+ dispatchChange(detail) {
307
+ this.dispatchEvent(new CustomEvent('cv-change', {
308
+ detail,
309
+ bubbles: true,
310
+ composed: true,
311
+ }));
312
+ }
313
+ emitOpenChange(open) {
314
+ this.lastEmittedOpen = open;
315
+ const detail = { open };
316
+ this.dispatchInput(detail);
317
+ this.dispatchChange(detail);
318
+ }
319
+ applyInteractionResult(previousOpen) {
320
+ const nextOpen = this.model.state.isOpen();
321
+ this.open = nextOpen;
322
+ this.disabled = this.model.state.isDisabled();
323
+ this.syncTriggerAria();
324
+ if (previousOpen !== nextOpen) {
325
+ this.emitOpenChange(nextOpen);
326
+ }
327
+ }
328
+ syncTriggerAria() {
329
+ const triggerProps = this.model.contracts.getTriggerProps();
330
+ const describedBy = triggerProps['aria-describedby'];
331
+ const slot = this.shadowRoot?.querySelector('slot[name="trigger"]');
332
+ const assigned = (slot?.assignedElements({ flatten: true }) ?? []).filter((element) => element instanceof HTMLElement);
333
+ for (const element of this.triggerTargets) {
334
+ if (!assigned.includes(element)) {
335
+ element.removeAttribute('aria-describedby');
336
+ }
337
+ }
338
+ this.triggerTargets = new Set(assigned);
339
+ for (const element of assigned) {
340
+ if (describedBy) {
341
+ element.setAttribute('aria-describedby', describedBy);
342
+ }
343
+ else {
344
+ element.removeAttribute('aria-describedby');
345
+ }
346
+ }
347
+ const wrapper = this.shadowRoot?.querySelector('[part="trigger"]');
348
+ if (wrapper) {
349
+ if (describedBy) {
350
+ wrapper.setAttribute('aria-describedby', describedBy);
351
+ }
352
+ else {
353
+ wrapper.removeAttribute('aria-describedby');
354
+ }
355
+ }
356
+ }
357
+ handlePointerEnter() {
358
+ const triggerProps = this.model.contracts.getTriggerProps();
359
+ if (!triggerProps.onPointerEnter)
360
+ return;
361
+ const previousOpen = this.model.state.isOpen();
362
+ triggerProps.onPointerEnter();
363
+ this.applyInteractionResult(previousOpen);
364
+ }
365
+ handlePointerLeave() {
366
+ const triggerProps = this.model.contracts.getTriggerProps();
367
+ if (!triggerProps.onPointerLeave)
368
+ return;
369
+ const previousOpen = this.model.state.isOpen();
370
+ triggerProps.onPointerLeave();
371
+ this.applyInteractionResult(previousOpen);
372
+ }
373
+ handleFocusIn() {
374
+ const triggerProps = this.model.contracts.getTriggerProps();
375
+ if (!triggerProps.onFocus)
376
+ return;
377
+ const previousOpen = this.model.state.isOpen();
378
+ triggerProps.onFocus();
379
+ this.applyInteractionResult(previousOpen);
380
+ }
381
+ handleFocusOut() {
382
+ const triggerProps = this.model.contracts.getTriggerProps();
383
+ if (!triggerProps.onBlur)
384
+ return;
385
+ const previousOpen = this.model.state.isOpen();
386
+ triggerProps.onBlur();
387
+ this.applyInteractionResult(previousOpen);
388
+ }
389
+ handleClick() {
390
+ const triggerProps = this.model.contracts.getTriggerProps();
391
+ if (!triggerProps.onClick)
392
+ return;
393
+ const previousOpen = this.model.state.isOpen();
394
+ triggerProps.onClick();
395
+ this.applyInteractionResult(previousOpen);
396
+ }
397
+ handleKeyDown(event) {
398
+ const previousOpen = this.model.state.isOpen();
399
+ this.model.contracts.getTriggerProps().onKeyDown({ key: event.key });
400
+ this.applyInteractionResult(previousOpen);
401
+ }
402
+ handleTriggerSlotChange() {
403
+ this.syncTriggerAria();
404
+ }
405
+ /** Programmatically opens the tooltip (intended for manual trigger mode). */
406
+ show() {
407
+ const previousOpen = this.model.state.isOpen();
408
+ this.model.actions.show();
409
+ this.applyInteractionResult(previousOpen);
410
+ }
411
+ /** Programmatically closes the tooltip (intended for manual trigger mode). */
412
+ hide() {
413
+ const previousOpen = this.model.state.isOpen();
414
+ this.model.actions.hide();
415
+ this.applyInteractionResult(previousOpen);
416
+ }
417
+ render() {
418
+ const triggerProps = this.model.contracts.getTriggerProps();
419
+ const tooltipProps = this.model.contracts.getTooltipProps();
420
+ return html `
421
+ <span part="base">
422
+ <span
423
+ id=${triggerProps.id}
424
+ part="trigger"
425
+ @pointerenter=${this.handlePointerEnter}
426
+ @pointerleave=${this.handlePointerLeave}
427
+ @focusin=${this.handleFocusIn}
428
+ @focusout=${this.handleFocusOut}
429
+ @click=${this.handleClick}
430
+ @keydown=${this.handleKeyDown}
431
+ >
432
+ <slot name="trigger" @slotchange=${this.handleTriggerSlotChange}>?</slot>
433
+ </span>
434
+
435
+ <span
436
+ id=${tooltipProps.id}
437
+ role=${tooltipProps.role}
438
+ tabindex=${tooltipProps.tabindex}
439
+ popover=${supportsNativePopover ? 'manual' : nothing}
440
+ data-placement="top"
441
+ data-anchor-positioning=${supportsNativeAnchoredAutoplacement ? 'true' : 'false'}
442
+ ?hidden=${supportsNativePopover ? false : tooltipProps.hidden}
443
+ part="content"
444
+ >
445
+ <slot name="content"></slot>
446
+ ${this.arrow
447
+ ? html `
448
+ <span part="arrow"></span>
449
+ `
450
+ : ''}
451
+ </span>
452
+ </span>
453
+ `;
454
+ }
455
+ }
@@ -0,0 +1,30 @@
1
+ import { LitElement } from 'lit';
2
+ export declare class CVTreegridCell extends LitElement {
3
+ static elementName: string;
4
+ static get properties(): {
5
+ column: {
6
+ type: StringConstructor;
7
+ reflect: boolean;
8
+ };
9
+ disabled: {
10
+ type: BooleanConstructor;
11
+ reflect: boolean;
12
+ };
13
+ active: {
14
+ type: BooleanConstructor;
15
+ reflect: boolean;
16
+ };
17
+ selected: {
18
+ type: BooleanConstructor;
19
+ reflect: boolean;
20
+ };
21
+ };
22
+ column: string;
23
+ disabled: boolean;
24
+ active: boolean;
25
+ selected: boolean;
26
+ constructor();
27
+ static styles: import("lit").CSSResult[];
28
+ static define(): void;
29
+ protected render(): import("lit").TemplateResult<1>;
30
+ }
@@ -0,0 +1,57 @@
1
+ import { LitElement, css, html } from 'lit';
2
+ export class CVTreegridCell extends LitElement {
3
+ static elementName = 'cv-treegrid-cell';
4
+ static get properties() {
5
+ return {
6
+ column: { type: String, reflect: true },
7
+ disabled: { type: Boolean, reflect: true },
8
+ active: { type: Boolean, reflect: true },
9
+ selected: { type: Boolean, reflect: true },
10
+ };
11
+ }
12
+ constructor() {
13
+ super();
14
+ this.column = '';
15
+ this.disabled = false;
16
+ this.active = false;
17
+ this.selected = false;
18
+ }
19
+ static styles = [
20
+ css `
21
+ :host {
22
+ display: block;
23
+ padding-inline: var(--cv-space-2, 8px);
24
+ padding-block: var(--cv-space-1, 4px);
25
+ color: var(--cv-color-text, #e8ecf6);
26
+ outline: none;
27
+ }
28
+
29
+ :host([active]) {
30
+ background: color-mix(in oklab, var(--cv-color-primary, #65d7ff) 16%, transparent);
31
+ }
32
+
33
+ :host([selected]) {
34
+ font-weight: 600;
35
+ }
36
+
37
+ :host([disabled]) {
38
+ opacity: 0.55;
39
+ }
40
+
41
+ :host(:focus-visible) {
42
+ outline: 2px solid var(--cv-color-primary, #65d7ff);
43
+ outline-offset: -2px;
44
+ }
45
+ `,
46
+ ];
47
+ static define() {
48
+ if (!customElements.get(this.elementName)) {
49
+ customElements.define(this.elementName, this);
50
+ }
51
+ }
52
+ render() {
53
+ return html `
54
+ <slot></slot>
55
+ `;
56
+ }
57
+ }
@@ -0,0 +1,37 @@
1
+ import type { TreegridCellRole } from '@chromvoid/headless-ui/treegrid';
2
+ import { LitElement } from 'lit';
3
+ export declare class CVTreegridColumn extends LitElement {
4
+ static elementName: string;
5
+ static get properties(): {
6
+ value: {
7
+ type: StringConstructor;
8
+ reflect: boolean;
9
+ };
10
+ label: {
11
+ type: StringConstructor;
12
+ reflect: boolean;
13
+ };
14
+ index: {
15
+ type: NumberConstructor;
16
+ reflect: boolean;
17
+ };
18
+ disabled: {
19
+ type: BooleanConstructor;
20
+ reflect: boolean;
21
+ };
22
+ cellRole: {
23
+ type: StringConstructor;
24
+ attribute: string;
25
+ reflect: boolean;
26
+ };
27
+ };
28
+ value: string;
29
+ label: string;
30
+ index: number;
31
+ disabled: boolean;
32
+ cellRole: TreegridCellRole;
33
+ constructor();
34
+ static styles: import("lit").CSSResult[];
35
+ static define(): void;
36
+ protected render(): import("lit").TemplateResult<1>;
37
+ }
@@ -0,0 +1,53 @@
1
+ import { LitElement, css, html } from 'lit';
2
+ export class CVTreegridColumn extends LitElement {
3
+ static elementName = 'cv-treegrid-column';
4
+ static get properties() {
5
+ return {
6
+ value: { type: String, reflect: true },
7
+ label: { type: String, reflect: true },
8
+ index: { type: Number, reflect: true },
9
+ disabled: { type: Boolean, reflect: true },
10
+ cellRole: { type: String, attribute: 'cell-role', reflect: true },
11
+ };
12
+ }
13
+ constructor() {
14
+ super();
15
+ this.value = '';
16
+ this.label = '';
17
+ this.index = 0;
18
+ this.disabled = false;
19
+ this.cellRole = 'gridcell';
20
+ }
21
+ static styles = [
22
+ css `
23
+ :host {
24
+ display: flex;
25
+ align-items: center;
26
+ min-block-size: 36px;
27
+ padding-inline: var(--cv-space-2, 8px);
28
+ border-bottom: 1px solid var(--cv-color-border, #2a3245);
29
+ font-weight: 600;
30
+ color: var(--cv-color-text, #e8ecf6);
31
+ background: color-mix(in oklab, var(--cv-color-surface, #141923) 82%, transparent);
32
+ outline: none;
33
+ }
34
+
35
+ :host([disabled]) {
36
+ opacity: 0.55;
37
+ }
38
+
39
+ :host(:focus-visible) {
40
+ outline: 2px solid var(--cv-color-primary, #65d7ff);
41
+ outline-offset: -2px;
42
+ }
43
+ `,
44
+ ];
45
+ static define() {
46
+ if (!customElements.get(this.elementName)) {
47
+ customElements.define(this.elementName, this);
48
+ }
49
+ }
50
+ render() {
51
+ return html `<span><slot>${this.label}</slot></span>`;
52
+ }
53
+ }
@@ -0,0 +1,55 @@
1
+ import { LitElement } from 'lit';
2
+ export type CVTreegridRowSlotchangeEvent = CustomEvent<null>;
3
+ export interface CVTreegridRowEventMap {
4
+ 'cv-treegrid-row-slotchange': CVTreegridRowSlotchangeEvent;
5
+ }
6
+ export declare class CVTreegridRow extends LitElement {
7
+ static elementName: string;
8
+ static get properties(): {
9
+ value: {
10
+ type: StringConstructor;
11
+ reflect: boolean;
12
+ };
13
+ index: {
14
+ type: NumberConstructor;
15
+ reflect: boolean;
16
+ };
17
+ disabled: {
18
+ type: BooleanConstructor;
19
+ reflect: boolean;
20
+ };
21
+ active: {
22
+ type: BooleanConstructor;
23
+ reflect: boolean;
24
+ };
25
+ selected: {
26
+ type: BooleanConstructor;
27
+ reflect: boolean;
28
+ };
29
+ expanded: {
30
+ type: BooleanConstructor;
31
+ reflect: boolean;
32
+ };
33
+ branch: {
34
+ type: BooleanConstructor;
35
+ reflect: boolean;
36
+ };
37
+ level: {
38
+ type: NumberConstructor;
39
+ reflect: boolean;
40
+ };
41
+ };
42
+ value: string;
43
+ index: number;
44
+ disabled: boolean;
45
+ active: boolean;
46
+ selected: boolean;
47
+ expanded: boolean;
48
+ branch: boolean;
49
+ level: number;
50
+ constructor();
51
+ static styles: import("lit").CSSResult[];
52
+ static define(): void;
53
+ private handleSlotChange;
54
+ protected render(): import("lit").TemplateResult<1>;
55
+ }