@kubex/zinc 1.0.25 → 1.0.98

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 (198) hide show
  1. package/.claude/project.md +556 -0
  2. package/.github/workflows/js_build_and_deploy.yaml +9 -10
  3. package/dist/custom-elements.json +13431 -8728
  4. package/dist/vscode.html-custom-data.json +571 -37
  5. package/dist/web-types.json +1439 -181
  6. package/dist/zn.d.ts +1642 -661
  7. package/dist/zn.min.css +1 -1
  8. package/dist/zn.min.js +1406 -891
  9. package/docs/_utilities/code-previews.cjs +10 -1
  10. package/docs/assets/scripts/docs.js +42 -18
  11. package/docs/data/data-table.json +229 -66
  12. package/docs/data/empty.json +6 -0
  13. package/docs/data/products-table.json +41 -193
  14. package/docs/pages/components/action-bar.md +121 -6
  15. package/docs/pages/components/alert.md +118 -15
  16. package/docs/pages/components/animated-button.md +299 -0
  17. package/docs/pages/components/audio-select.md +534 -0
  18. package/docs/pages/components/bulk-actions.md +79 -5
  19. package/docs/pages/components/button-group.md +235 -27
  20. package/docs/pages/components/button.md +139 -1
  21. package/docs/pages/components/chart.md +365 -9
  22. package/docs/pages/components/checkbox.md +387 -58
  23. package/docs/pages/components/chip.md +253 -33
  24. package/docs/pages/components/collapsible.md +393 -46
  25. package/docs/pages/components/cols.md +152 -30
  26. package/docs/pages/components/confirm.md +182 -16
  27. package/docs/pages/components/copy-button.md +169 -6
  28. package/docs/pages/components/data-select.md +194 -15
  29. package/docs/pages/components/data-table-filter.md +96 -5
  30. package/docs/pages/components/data-table-search.md +451 -0
  31. package/docs/pages/components/data-table-sort.md +66 -5
  32. package/docs/pages/components/data-table.md +727 -66
  33. package/docs/pages/components/datepicker.md +402 -7
  34. package/docs/pages/components/defined-label.md +120 -5
  35. package/docs/pages/components/dialog.md +339 -59
  36. package/docs/pages/components/dropdown.md +366 -11
  37. package/docs/pages/components/editor.md +604 -7
  38. package/docs/pages/components/empty-state.md +315 -16
  39. package/docs/pages/components/expanding-action.md +212 -28
  40. package/docs/pages/components/file.md +421 -12
  41. package/docs/pages/components/filter-container.md +158 -5
  42. package/docs/pages/components/filter-wrapper.md +167 -6
  43. package/docs/pages/components/form-group.md +383 -6
  44. package/docs/pages/components/hover-container.md +237 -6
  45. package/docs/pages/components/icon-picker.md +121 -0
  46. package/docs/pages/components/icon.md +454 -48
  47. package/docs/pages/components/inline-edit.md +787 -19
  48. package/docs/pages/components/input-group.md +207 -13
  49. package/docs/pages/components/input.md +194 -0
  50. package/docs/pages/components/key-container.md +115 -0
  51. package/docs/pages/components/key.md +101 -0
  52. package/docs/pages/components/menu.md +512 -6
  53. package/docs/pages/components/note.md +239 -36
  54. package/docs/pages/components/opt-group.md +107 -0
  55. package/docs/pages/components/pagination.md +332 -6
  56. package/docs/pages/components/pane.md +222 -6
  57. package/docs/pages/components/panel.md +213 -26
  58. package/docs/pages/components/popup.md +1354 -6
  59. package/docs/pages/components/priority-list.md +233 -0
  60. package/docs/pages/components/progress-bar.md +387 -6
  61. package/docs/pages/components/radio-group.md +242 -5
  62. package/docs/pages/components/radio.md +474 -6
  63. package/docs/pages/components/rating.md +331 -7
  64. package/docs/pages/components/reveal.md +524 -6
  65. package/docs/pages/components/scroll-container.md +552 -6
  66. package/docs/pages/components/select.md +762 -160
  67. package/docs/pages/components/skeleton.md +473 -30
  68. package/docs/pages/components/slideout.md +261 -5
  69. package/docs/pages/components/sp.md +99 -41
  70. package/docs/pages/components/split-button.md +347 -9
  71. package/docs/pages/components/split-pane.md +445 -6
  72. package/docs/pages/components/stat.md +549 -9
  73. package/docs/pages/components/status-indicator.md +230 -1
  74. package/docs/pages/components/stepper.md +563 -6
  75. package/docs/pages/components/tabs.md +439 -13
  76. package/docs/pages/components/textarea.md +415 -17
  77. package/docs/pages/components/tile.md +385 -26
  78. package/docs/pages/components/toggle.md +424 -6
  79. package/docs/pages/components/tooltip.md +367 -0
  80. package/docs/pages/components/translation-group.md +210 -0
  81. package/docs/pages/components/translations.md +319 -19
  82. package/docs/pages/components/vertical-stepper.md +401 -8
  83. package/docs/pages/components/well.md +300 -3
  84. package/docs/pages/getting-started/form-controls.md +162 -0
  85. package/docs/pages/index.md +116 -15
  86. package/package.json +5 -6
  87. package/scss/_global-spacing.scss +4 -0
  88. package/scss/_root.scss +2 -2
  89. package/scss/boot.scss +19 -0
  90. package/scss/shared/layout.scss +5 -0
  91. package/scss/themes/_light.scss +3 -3
  92. package/src/components/alert/alert.scss +1 -0
  93. package/src/components/animated-button/README.md +306 -0
  94. package/src/components/animated-button/animated-button.component.ts +229 -0
  95. package/src/components/animated-button/animated-button.scss +228 -0
  96. package/src/components/animated-button/animated-button.test.ts +143 -0
  97. package/src/components/animated-button/index.ts +12 -0
  98. package/src/components/button/button.component.ts +5 -0
  99. package/src/components/button-group/button-group.component.ts +25 -13
  100. package/src/components/button-group/button-group.scss +6 -0
  101. package/src/components/checkbox/checkbox.component.ts +4 -0
  102. package/src/components/checkbox/checkbox.scss +7 -4
  103. package/src/components/checkbox-group/checkbox-group.scss +7 -0
  104. package/src/components/chip/chip.component.ts +7 -2
  105. package/src/components/chip/chip.scss +16 -2
  106. package/src/components/collapsible/collapsible.component.ts +27 -20
  107. package/src/components/cols/cols.component.ts +14 -2
  108. package/src/components/cols/cols.scss +6 -12
  109. package/src/components/confirm/confirm.component.ts +7 -0
  110. package/src/components/copy-button/copy-button.component.ts +12 -11
  111. package/src/components/data-select/data-select.component.ts +215 -44
  112. package/src/components/data-select/data-select.scss +66 -6
  113. package/src/components/data-select/providers/currency-data-provider.ts +20 -6
  114. package/src/components/data-select/providers/provider.ts +1 -0
  115. package/src/components/data-select/providers/us-state-data-provider.ts +68 -0
  116. package/src/components/data-table/data-table.component.ts +81 -22
  117. package/src/components/data-table-search/data-table-search.component.ts +184 -0
  118. package/src/components/data-table-search/data-table-search.scss +17 -0
  119. package/src/components/data-table-search/data-table-search.test.ts +11 -0
  120. package/src/components/data-table-search/index.ts +12 -0
  121. package/src/components/datepicker/datepicker.component.ts +347 -13
  122. package/src/components/dialog/dialog.component.ts +1 -1
  123. package/src/components/empty-state/empty-state.scss +6 -1
  124. package/src/components/header/header.scss +3 -3
  125. package/src/components/icon/icon.component.ts +23 -1
  126. package/src/components/icon/icon.scss +23 -0
  127. package/src/components/icon-picker/brand-icons.ts +24 -0
  128. package/src/components/icon-picker/icon-picker.component.ts +407 -0
  129. package/src/components/icon-picker/icon-picker.scss +205 -0
  130. package/src/components/icon-picker/index.ts +12 -0
  131. package/src/components/icon-picker/line-icons.ts +612 -0
  132. package/src/components/icon-picker/material-icons.ts +14543 -0
  133. package/src/components/inline-edit/inline-edit.component.ts +190 -46
  134. package/src/components/inline-edit/inline-edit.scss +29 -0
  135. package/src/components/inline-edit/inline-edit.test.ts +314 -1
  136. package/src/components/input/input.component.ts +324 -5
  137. package/src/components/input/input.scss +87 -0
  138. package/src/components/input-group/input-group.component.ts +28 -7
  139. package/src/components/input-group/input-group.scss +48 -10
  140. package/src/components/item/item.component.ts +11 -2
  141. package/src/components/item/item.scss +7 -0
  142. package/src/components/key/index.ts +12 -0
  143. package/src/components/key/key.component.ts +47 -0
  144. package/src/components/key/key.scss +38 -0
  145. package/src/components/key-container/index.ts +12 -0
  146. package/src/components/key-container/key-container.component.ts +142 -0
  147. package/src/components/key-container/key-container.scss +33 -0
  148. package/src/components/menu-item/menu-item.component.ts +20 -0
  149. package/src/components/menu-item/menu-item.scss +69 -2
  150. package/src/components/navbar/navbar.component.ts +103 -11
  151. package/src/components/navbar/navbar.scss +6 -1
  152. package/src/components/opt-group/index.ts +12 -0
  153. package/src/components/opt-group/opt-group.component.ts +74 -0
  154. package/src/components/opt-group/opt-group.scss +37 -0
  155. package/src/components/opt-group/opt-group.test.ts +27 -0
  156. package/src/components/option/option.component.ts +1 -16
  157. package/src/components/option/option.scss +4 -0
  158. package/src/components/panel/panel.component.ts +10 -8
  159. package/src/components/panel/panel.scss +20 -0
  160. package/src/components/priority-list/index.ts +12 -0
  161. package/src/components/priority-list/priority-list.component.ts +611 -0
  162. package/src/components/priority-list/priority-list.scss +185 -0
  163. package/src/components/priority-list/priority-list.test.ts +139 -0
  164. package/src/components/progress-bar/progress-bar.component.ts +22 -16
  165. package/src/components/radio/radio.scss +10 -3
  166. package/src/components/select/select.component.ts +812 -72
  167. package/src/components/select/select.scss +108 -2
  168. package/src/components/select/select.test.ts +147 -2
  169. package/src/components/settings-container/settings-container.component.ts +44 -19
  170. package/src/components/settings-container/settings-container.scss +1 -1
  171. package/src/components/skeleton/skeleton.component.ts +6 -1
  172. package/src/components/slideout/slideout.scss +8 -3
  173. package/src/components/sp/sp.component.ts +3 -1
  174. package/src/components/sp/sp.scss +19 -0
  175. package/src/components/stepper/stepper.component.ts +16 -10
  176. package/src/components/textarea/textarea.scss +0 -4
  177. package/src/components/tile/tile.component.ts +12 -3
  178. package/src/components/tile/tile.scss +1 -1
  179. package/src/components/timer/timer.component.ts +15 -2
  180. package/src/components/toggle/toggle.component.ts +29 -26
  181. package/src/components/toggle/toggle.scss +13 -1
  182. package/src/components/translation-group/index.ts +12 -0
  183. package/src/components/translation-group/translation-group.component.ts +207 -0
  184. package/src/components/translation-group/translation-group.scss +8 -0
  185. package/src/components/translations/translations.component.ts +90 -44
  186. package/src/components/translations/translations.scss +4 -0
  187. package/src/components/vertical-stepper/vertical-stepper.component.ts +14 -9
  188. package/src/events/events.ts +12 -7
  189. package/src/events/zn-language-change.ts +7 -0
  190. package/src/events/zn-purchase.ts +11 -0
  191. package/src/events/zn-redirect.ts +7 -0
  192. package/src/events/zn-reorder.ts +7 -0
  193. package/src/events/zn-search-change.ts +11 -0
  194. package/src/events/zn-submit.ts +1 -1
  195. package/src/form-control.scss +4 -0
  196. package/src/internal/form-navigation.ts +510 -0
  197. package/src/internal/form.ts +6 -0
  198. package/src/zinc.ts +91 -83
@@ -1,22 +1,1370 @@
1
1
  ---
2
2
  meta:
3
3
  title: Popup
4
- description:
4
+ description: Popups are low-level positioning primitives used by components like dropdown and tooltip to anchor floating elements to other elements.
5
5
  layout: component
6
6
  ---
7
7
 
8
+ Popups use [Floating UI](https://floating-ui.com/) under the hood to provide robust positioning for floating elements. The popup component exposes all of the underlying positioning features and allows you to anchor any element to any other element.
9
+
10
+ Popups are designed to work with `anchor` elements and popup content. The anchor can be provided through the `anchor` attribute (by ID or element reference) or by slotting an element into the `anchor` slot.
11
+
12
+ :::warning
13
+ **Important:** Popup is a low-level utility component. For most use cases, you should use higher-level components like [Dropdown](/components/dropdown) or [Tooltip](/components/tooltip) instead.
14
+ :::
15
+
8
16
  ```html:preview
9
- <zn-popup></zn-popup>
17
+ <div class="popup-overview">
18
+ <zn-popup placement="top" active>
19
+ <span slot="anchor" style="
20
+ display: inline-block;
21
+ width: 150px;
22
+ height: 150px;
23
+ background: var(--zn-color-primary-600);
24
+ border-radius: 4px;
25
+ "></span>
26
+
27
+ <div style="
28
+ background: var(--zn-color-neutral-900);
29
+ color: white;
30
+ padding: 0.5rem 1rem;
31
+ border-radius: 4px;
32
+ ">
33
+ I'm a popup!
34
+ </div>
35
+ </zn-popup>
36
+ </div>
37
+
38
+ <style>
39
+ .popup-overview {
40
+ display: flex;
41
+ justify-content: center;
42
+ padding: 3rem;
43
+ }
44
+ </style>
10
45
  ```
11
46
 
12
47
  ## Examples
13
48
 
14
- ### First Example
49
+ ### Activating the Popup
50
+
51
+ Popups are inactive by default. They won't be positioned until you add the `active` attribute. The popup logic can be computationally expensive, so only activate popups when needed.
52
+
53
+ ```html:preview
54
+ <div class="popup-active">
55
+ <zn-popup placement="top" active>
56
+ <span slot="anchor" style="
57
+ display: inline-block;
58
+ width: 100px;
59
+ height: 100px;
60
+ background: var(--zn-color-success-600);
61
+ border-radius: 4px;
62
+ "></span>
63
+
64
+ <div style="
65
+ background: var(--zn-color-neutral-900);
66
+ color: white;
67
+ padding: 0.5rem 1rem;
68
+ border-radius: 4px;
69
+ ">
70
+ Active
71
+ </div>
72
+ </zn-popup>
73
+
74
+ <zn-popup placement="top">
75
+ <span slot="anchor" style="
76
+ display: inline-block;
77
+ width: 100px;
78
+ height: 100px;
79
+ background: var(--zn-color-neutral-300);
80
+ border-radius: 4px;
81
+ margin-left: 2rem;
82
+ "></span>
83
+
84
+ <div style="
85
+ background: var(--zn-color-neutral-900);
86
+ color: white;
87
+ padding: 0.5rem 1rem;
88
+ border-radius: 4px;
89
+ ">
90
+ Inactive
91
+ </div>
92
+ </zn-popup>
93
+ </div>
94
+
95
+ <style>
96
+ .popup-active {
97
+ display: flex;
98
+ justify-content: center;
99
+ padding: 3rem;
100
+ }
101
+ </style>
102
+ ```
103
+
104
+ ### External Anchors
105
+
106
+ By default, anchors are slotted into the popup using the `anchor` slot. If your anchor needs to live outside of the popup, you can pass its `id`, a DOM reference, or a `VirtualElement` to the `anchor` property.
107
+
108
+ ```html:preview
109
+ <div class="popup-external">
110
+ <div
111
+ id="external-anchor"
112
+ style="
113
+ display: inline-block;
114
+ width: 100px;
115
+ height: 100px;
116
+ background: var(--zn-color-primary-600);
117
+ border-radius: 4px;
118
+ "
119
+ ></div>
120
+
121
+ <zn-popup anchor="external-anchor" placement="top" active>
122
+ <div style="
123
+ background: var(--zn-color-neutral-900);
124
+ color: white;
125
+ padding: 0.5rem 1rem;
126
+ border-radius: 4px;
127
+ ">
128
+ Anchored externally
129
+ </div>
130
+ </zn-popup>
131
+ </div>
132
+
133
+ <style>
134
+ .popup-external {
135
+ padding: 3rem;
136
+ }
137
+ </style>
138
+ ```
139
+
140
+ ### Placement
141
+
142
+ Use the `placement` attribute to set the preferred placement of the popup. Note that the actual placement may vary to keep the popup inside the viewport when using positioning features like `flip` and `shift`.
143
+
144
+ Since placement is preferred when the popup is active, the popup will use the `data-current-placement` attribute on the host element to reflect the actual placement at any given time. This allows you to style the popup based on its current placement if needed.
145
+
146
+ ```html:preview
147
+ <div class="popup-placement">
148
+ <zn-popup placement="top-start" active>
149
+ <span slot="anchor"></span>
150
+ <span class="popup-placement-label">top-start</span>
151
+ </zn-popup>
152
+
153
+ <zn-popup placement="top" active>
154
+ <span slot="anchor"></span>
155
+ <span class="popup-placement-label">top</span>
156
+ </zn-popup>
157
+
158
+ <zn-popup placement="top-end" active>
159
+ <span slot="anchor"></span>
160
+ <span class="popup-placement-label">top-end</span>
161
+ </zn-popup>
162
+
163
+ <br><br>
164
+
165
+ <zn-popup placement="left-start" active>
166
+ <span slot="anchor"></span>
167
+ <span class="popup-placement-label">left-start</span>
168
+ </zn-popup>
169
+
170
+ <zn-popup placement="right-start" active>
171
+ <span slot="anchor"></span>
172
+ <span class="popup-placement-label">right-start</span>
173
+ </zn-popup>
174
+
175
+ <br><br>
176
+
177
+ <zn-popup placement="left" active>
178
+ <span slot="anchor"></span>
179
+ <span class="popup-placement-label">left</span>
180
+ </zn-popup>
181
+
182
+ <zn-popup placement="right" active>
183
+ <span slot="anchor"></span>
184
+ <span class="popup-placement-label">right</span>
185
+ </zn-popup>
186
+
187
+ <br><br>
188
+
189
+ <zn-popup placement="left-end" active>
190
+ <span slot="anchor"></span>
191
+ <span class="popup-placement-label">left-end</span>
192
+ </zn-popup>
193
+
194
+ <zn-popup placement="right-end" active>
195
+ <span slot="anchor"></span>
196
+ <span class="popup-placement-label">right-end</span>
197
+ </zn-popup>
198
+
199
+ <br><br>
200
+
201
+ <zn-popup placement="bottom-start" active>
202
+ <span slot="anchor"></span>
203
+ <span class="popup-placement-label">bottom-start</span>
204
+ </zn-popup>
205
+
206
+ <zn-popup placement="bottom" active>
207
+ <span slot="anchor"></span>
208
+ <span class="popup-placement-label">bottom</span>
209
+ </zn-popup>
210
+
211
+ <zn-popup placement="bottom-end" active>
212
+ <span slot="anchor"></span>
213
+ <span class="popup-placement-label">bottom-end</span>
214
+ </zn-popup>
215
+ </div>
216
+
217
+ <style>
218
+ .popup-placement {
219
+ padding: 3rem;
220
+ }
221
+
222
+ .popup-placement zn-popup span[slot="anchor"] {
223
+ display: inline-block;
224
+ width: 75px;
225
+ height: 50px;
226
+ background: var(--zn-color-primary-600);
227
+ border-radius: 4px;
228
+ margin: 0.5rem;
229
+ }
230
+
231
+ .popup-placement-label {
232
+ display: inline-block;
233
+ padding: 0.5rem 1rem;
234
+ background: var(--zn-color-neutral-900);
235
+ color: white;
236
+ border-radius: 4px;
237
+ white-space: nowrap;
238
+ font-size: 0.875rem;
239
+ }
240
+ </style>
241
+ ```
242
+
243
+ ### Distance
244
+
245
+ Use the `distance` attribute to change the distance between the popup and its anchor. A positive value moves the popup farther away, while a negative value moves it closer.
246
+
247
+ ```html:preview
248
+ <div class="popup-distance">
249
+ <zn-popup placement="top" distance="0" active>
250
+ <span slot="anchor"></span>
251
+ <span class="popup-distance-label">Distance: 0</span>
252
+ </zn-popup>
253
+
254
+ <zn-popup placement="top" distance="10" active>
255
+ <span slot="anchor"></span>
256
+ <span class="popup-distance-label">Distance: 10</span>
257
+ </zn-popup>
258
+
259
+ <zn-popup placement="top" distance="20" active>
260
+ <span slot="anchor"></span>
261
+ <span class="popup-distance-label">Distance: 20</span>
262
+ </zn-popup>
263
+ </div>
264
+
265
+ <style>
266
+ .popup-distance {
267
+ display: flex;
268
+ gap: 4rem;
269
+ padding: 3rem;
270
+ }
271
+
272
+ .popup-distance zn-popup span[slot="anchor"] {
273
+ display: inline-block;
274
+ width: 100px;
275
+ height: 100px;
276
+ background: var(--zn-color-primary-600);
277
+ border-radius: 4px;
278
+ }
279
+
280
+ .popup-distance-label {
281
+ display: inline-block;
282
+ padding: 0.5rem 1rem;
283
+ background: var(--zn-color-neutral-900);
284
+ color: white;
285
+ border-radius: 4px;
286
+ white-space: nowrap;
287
+ font-size: 0.875rem;
288
+ }
289
+ </style>
290
+ ```
291
+
292
+ ### Skidding
293
+
294
+ Use the `skidding` attribute to move the popup along the anchor. This is useful for fine-tuning the popup's position.
295
+
296
+ ```html:preview
297
+ <div class="popup-skidding">
298
+ <zn-popup placement="top" skidding="-50" active>
299
+ <span slot="anchor"></span>
300
+ <span class="popup-skidding-label">Skidding: -50</span>
301
+ </zn-popup>
302
+
303
+ <zn-popup placement="top" skidding="0" active>
304
+ <span slot="anchor"></span>
305
+ <span class="popup-skidding-label">Skidding: 0</span>
306
+ </zn-popup>
307
+
308
+ <zn-popup placement="top" skidding="50" active>
309
+ <span slot="anchor"></span>
310
+ <span class="popup-skidding-label">Skidding: 50</span>
311
+ </zn-popup>
312
+ </div>
313
+
314
+ <style>
315
+ .popup-skidding {
316
+ display: flex;
317
+ gap: 4rem;
318
+ padding: 3rem;
319
+ }
320
+
321
+ .popup-skidding zn-popup span[slot="anchor"] {
322
+ display: inline-block;
323
+ width: 100px;
324
+ height: 100px;
325
+ background: var(--zn-color-primary-600);
326
+ border-radius: 4px;
327
+ }
328
+
329
+ .popup-skidding-label {
330
+ display: inline-block;
331
+ padding: 0.5rem 1rem;
332
+ background: var(--zn-color-neutral-900);
333
+ color: white;
334
+ border-radius: 4px;
335
+ white-space: nowrap;
336
+ font-size: 0.875rem;
337
+ }
338
+ </style>
339
+ ```
340
+
341
+ ### Arrows
342
+
343
+ Add an arrow to the popup with the `arrow` attribute. The arrow can be styled using the `--arrow-size` and `--arrow-color` custom properties. You can also target `::part(arrow)` in your stylesheet for additional customizations.
344
+
345
+ ```html:preview
346
+ <div class="popup-arrow">
347
+ <zn-popup placement="top" arrow active>
348
+ <span slot="anchor"></span>
349
+ <span class="popup-arrow-label">Top</span>
350
+ </zn-popup>
351
+
352
+ <zn-popup placement="bottom" arrow active>
353
+ <span slot="anchor"></span>
354
+ <span class="popup-arrow-label">Bottom</span>
355
+ </zn-popup>
356
+
357
+ <zn-popup placement="left" arrow active>
358
+ <span slot="anchor"></span>
359
+ <span class="popup-arrow-label">Left</span>
360
+ </zn-popup>
361
+
362
+ <zn-popup placement="right" arrow active>
363
+ <span slot="anchor"></span>
364
+ <span class="popup-arrow-label">Right</span>
365
+ </zn-popup>
366
+ </div>
367
+
368
+ <style>
369
+ .popup-arrow {
370
+ display: flex;
371
+ gap: 3rem;
372
+ padding: 3rem;
373
+ }
374
+
375
+ .popup-arrow zn-popup span[slot="anchor"] {
376
+ display: inline-block;
377
+ width: 80px;
378
+ height: 80px;
379
+ background: var(--zn-color-primary-600);
380
+ border-radius: 4px;
381
+ }
382
+
383
+ .popup-arrow-label {
384
+ display: inline-block;
385
+ padding: 0.5rem 1rem;
386
+ background: var(--zn-color-neutral-900);
387
+ color: white;
388
+ border-radius: 4px;
389
+ white-space: nowrap;
390
+ font-size: 0.875rem;
391
+ }
392
+ </style>
393
+ ```
394
+
395
+ ### Arrow Placement
396
+
397
+ Use the `arrow-placement` attribute to control how the arrow is positioned. The default is `anchor`, which aligns the arrow as close to the center of the anchor as possible. You can also use `start`, `end`, or `center` to align the arrow to the start, end, or center of the popup instead.
398
+
399
+ ```html:preview
400
+ <div class="popup-arrow-placement">
401
+ <zn-popup placement="top" arrow arrow-placement="start" active>
402
+ <span slot="anchor"></span>
403
+ <span class="popup-arrow-placement-label">start</span>
404
+ </zn-popup>
405
+
406
+ <zn-popup placement="top" arrow arrow-placement="anchor" active>
407
+ <span slot="anchor"></span>
408
+ <span class="popup-arrow-placement-label">anchor (default)</span>
409
+ </zn-popup>
410
+
411
+ <zn-popup placement="top" arrow arrow-placement="center" active>
412
+ <span slot="anchor"></span>
413
+ <span class="popup-arrow-placement-label">center</span>
414
+ </zn-popup>
415
+
416
+ <zn-popup placement="top" arrow arrow-placement="end" active>
417
+ <span slot="anchor"></span>
418
+ <span class="popup-arrow-placement-label">end</span>
419
+ </zn-popup>
420
+ </div>
421
+
422
+ <style>
423
+ .popup-arrow-placement {
424
+ display: flex;
425
+ gap: 3rem;
426
+ padding: 3rem;
427
+ }
428
+
429
+ .popup-arrow-placement zn-popup span[slot="anchor"] {
430
+ display: inline-block;
431
+ width: 60px;
432
+ height: 60px;
433
+ background: var(--zn-color-primary-600);
434
+ border-radius: 4px;
435
+ }
436
+
437
+ .popup-arrow-placement-label {
438
+ display: inline-block;
439
+ padding: 0.5rem 1rem;
440
+ background: var(--zn-color-neutral-900);
441
+ color: white;
442
+ border-radius: 4px;
443
+ white-space: nowrap;
444
+ font-size: 0.875rem;
445
+ }
446
+ </style>
447
+ ```
448
+
449
+ ### Arrow Padding
450
+
451
+ Use the `arrow-padding` attribute to add padding between the arrow and the edges of the popup. This prevents the arrow from overflowing corners when the popup has a border radius.
452
+
453
+ ```html:preview
454
+ <div class="popup-arrow-padding">
455
+ <zn-popup placement="top" arrow arrow-padding="0" active>
456
+ <span slot="anchor"></span>
457
+ <span class="popup-arrow-padding-label">Padding: 0</span>
458
+ </zn-popup>
459
+
460
+ <zn-popup placement="top" arrow arrow-padding="10" active>
461
+ <span slot="anchor"></span>
462
+ <span class="popup-arrow-padding-label">Padding: 10</span>
463
+ </zn-popup>
464
+
465
+ <zn-popup placement="top" arrow arrow-padding="20" active>
466
+ <span slot="anchor"></span>
467
+ <span class="popup-arrow-padding-label">Padding: 20</span>
468
+ </zn-popup>
469
+ </div>
470
+
471
+ <style>
472
+ .popup-arrow-padding {
473
+ display: flex;
474
+ gap: 3rem;
475
+ padding: 3rem;
476
+ }
477
+
478
+ .popup-arrow-padding zn-popup span[slot="anchor"] {
479
+ display: inline-block;
480
+ width: 100px;
481
+ height: 100px;
482
+ background: var(--zn-color-primary-600);
483
+ border-radius: 4px;
484
+ }
485
+
486
+ .popup-arrow-padding-label {
487
+ display: inline-block;
488
+ padding: 0.5rem 1rem;
489
+ background: var(--zn-color-neutral-900);
490
+ color: white;
491
+ border-radius: 12px;
492
+ white-space: nowrap;
493
+ font-size: 0.875rem;
494
+ }
495
+ </style>
496
+ ```
497
+
498
+ ### Flip
499
+
500
+ When the popup doesn't have enough room in its preferred placement, it can automatically flip to keep it in view. Use the `flip` attribute to enable this behavior.
501
+
502
+ ```html:preview
503
+ <div class="popup-flip">
504
+ <div class="popup-flip-scroll">
505
+ <zn-popup placement="top" flip active>
506
+ <span slot="anchor"></span>
507
+ <span class="popup-flip-label">Scroll down to see me flip</span>
508
+ </zn-popup>
509
+ </div>
510
+ </div>
511
+
512
+ <style>
513
+ .popup-flip {
514
+ height: 200px;
515
+ }
516
+
517
+ .popup-flip-scroll {
518
+ height: 150px;
519
+ overflow: auto;
520
+ padding: 3rem;
521
+ padding-bottom: 200px;
522
+ }
523
+
524
+ .popup-flip zn-popup span[slot="anchor"] {
525
+ display: inline-block;
526
+ width: 100px;
527
+ height: 100px;
528
+ background: var(--zn-color-primary-600);
529
+ border-radius: 4px;
530
+ }
531
+
532
+ .popup-flip-label {
533
+ display: inline-block;
534
+ padding: 0.5rem 1rem;
535
+ background: var(--zn-color-neutral-900);
536
+ color: white;
537
+ border-radius: 4px;
538
+ white-space: nowrap;
539
+ font-size: 0.875rem;
540
+ }
541
+ </style>
542
+ ```
543
+
544
+ ### Flip Fallback Placements
545
+
546
+ When using the `flip` attribute, you can specify fallback placements using `flip-fallback-placements`. The popup will try each placement in order until it finds one that fits.
547
+
548
+ ```html:preview
549
+ <div class="popup-flip-fallback">
550
+ <zn-popup placement="top" flip flip-fallback-placements="right bottom left" active>
551
+ <span slot="anchor"></span>
552
+ <span class="popup-flip-fallback-label">Try: top, right, bottom, left</span>
553
+ </zn-popup>
554
+ </div>
555
+
556
+ <style>
557
+ .popup-flip-fallback {
558
+ padding: 3rem;
559
+ }
560
+
561
+ .popup-flip-fallback zn-popup span[slot="anchor"] {
562
+ display: inline-block;
563
+ width: 100px;
564
+ height: 100px;
565
+ background: var(--zn-color-primary-600);
566
+ border-radius: 4px;
567
+ }
568
+
569
+ .popup-flip-fallback-label {
570
+ display: inline-block;
571
+ padding: 0.5rem 1rem;
572
+ background: var(--zn-color-neutral-900);
573
+ color: white;
574
+ border-radius: 4px;
575
+ white-space: nowrap;
576
+ font-size: 0.875rem;
577
+ }
578
+ </style>
579
+ ```
580
+
581
+ ### Flip Fallback Strategy
582
+
583
+ When neither the preferred placement nor the fallback placements fit, the `flip-fallback-strategy` determines the final placement. Use `best-fit` (default) to position using the best available space, or `initial` to use the preferred placement.
584
+
585
+ ```html:preview
586
+ <div class="popup-flip-strategy">
587
+ <zn-popup placement="top" flip flip-fallback-strategy="best-fit" active>
588
+ <span slot="anchor"></span>
589
+ <span class="popup-flip-strategy-label">best-fit</span>
590
+ </zn-popup>
591
+
592
+ <zn-popup placement="top" flip flip-fallback-strategy="initial" active>
593
+ <span slot="anchor"></span>
594
+ <span class="popup-flip-strategy-label">initial</span>
595
+ </zn-popup>
596
+ </div>
597
+
598
+ <style>
599
+ .popup-flip-strategy {
600
+ display: flex;
601
+ gap: 3rem;
602
+ padding: 3rem;
603
+ }
604
+
605
+ .popup-flip-strategy zn-popup span[slot="anchor"] {
606
+ display: inline-block;
607
+ width: 100px;
608
+ height: 100px;
609
+ background: var(--zn-color-primary-600);
610
+ border-radius: 4px;
611
+ }
612
+
613
+ .popup-flip-strategy-label {
614
+ display: inline-block;
615
+ padding: 0.5rem 1rem;
616
+ background: var(--zn-color-neutral-900);
617
+ color: white;
618
+ border-radius: 4px;
619
+ white-space: nowrap;
620
+ font-size: 0.875rem;
621
+ }
622
+ </style>
623
+ ```
624
+
625
+ ### Shift
626
+
627
+ When a popup is near the edge of the viewport, part of it may be clipped. Use the `shift` attribute to move it along the axis and keep it in view.
628
+
629
+ ```html:preview
630
+ <div class="popup-shift">
631
+ <div class="popup-shift-scroll">
632
+ <zn-popup placement="top" shift active>
633
+ <span slot="anchor"></span>
634
+ <span class="popup-shift-label">Scroll horizontally to see me shift</span>
635
+ </zn-popup>
636
+ </div>
637
+ </div>
638
+
639
+ <style>
640
+ .popup-shift {
641
+ width: 300px;
642
+ }
643
+
644
+ .popup-shift-scroll {
645
+ width: 100%;
646
+ overflow: auto;
647
+ padding: 3rem;
648
+ padding-right: 400px;
649
+ }
650
+
651
+ .popup-shift zn-popup span[slot="anchor"] {
652
+ display: inline-block;
653
+ width: 100px;
654
+ height: 100px;
655
+ background: var(--zn-color-primary-600);
656
+ border-radius: 4px;
657
+ }
658
+
659
+ .popup-shift-label {
660
+ display: inline-block;
661
+ padding: 0.5rem 1rem;
662
+ background: var(--zn-color-neutral-900);
663
+ color: white;
664
+ border-radius: 4px;
665
+ white-space: nowrap;
666
+ font-size: 0.875rem;
667
+ }
668
+ </style>
669
+ ```
670
+
671
+ ### Auto-size
672
+
673
+ Use the `auto-size` attribute to prevent the popup from overflowing when clipped. The available width and/or height will be applied to the popup as CSS custom properties (`--auto-size-available-width` and `--auto-size-available-height`). Use these properties to set a `max-width` and/or `max-height` on the popup.
674
+
675
+ ```html:preview
676
+ <div class="popup-auto-size">
677
+ <div class="popup-auto-size-scroll">
678
+ <zn-popup placement="top" auto-size="both" active>
679
+ <span slot="anchor"></span>
680
+ <div class="popup-auto-size-content">
681
+ <p>This popup will resize to fit the available space.</p>
682
+ <p>Scroll around the container to see how it adapts.</p>
683
+ <p>The content will adjust its size automatically.</p>
684
+ </div>
685
+ </zn-popup>
686
+ </div>
687
+ </div>
688
+
689
+ <style>
690
+ .popup-auto-size {
691
+ height: 250px;
692
+ }
15
693
 
16
- TODO
694
+ .popup-auto-size-scroll {
695
+ width: 300px;
696
+ height: 200px;
697
+ overflow: auto;
698
+ padding: 3rem;
699
+ padding-bottom: 300px;
700
+ padding-right: 400px;
701
+ }
702
+
703
+ .popup-auto-size zn-popup span[slot="anchor"] {
704
+ display: inline-block;
705
+ width: 100px;
706
+ height: 100px;
707
+ background: var(--zn-color-primary-600);
708
+ border-radius: 4px;
709
+ }
710
+
711
+ .popup-auto-size-content {
712
+ max-width: var(--auto-size-available-width);
713
+ max-height: var(--auto-size-available-height);
714
+ overflow: auto;
715
+ padding: 1rem;
716
+ background: var(--zn-color-neutral-900);
717
+ color: white;
718
+ border-radius: 4px;
719
+ }
720
+
721
+ .popup-auto-size-content p {
722
+ margin: 0;
723
+ padding: 0.25rem 0;
724
+ }
725
+ </style>
726
+ ```
727
+
728
+ ### Sync Width and Height
729
+
730
+ Use the `sync` attribute to make the popup the same width and/or height as the anchor element. This is useful for dropdowns and select controls where the popup should match the trigger's dimensions.
731
+
732
+ ```html:preview
733
+ <div class="popup-sync">
734
+ <zn-popup placement="bottom" sync="width" active>
735
+ <span slot="anchor" style="width: 200px;"></span>
736
+ <span class="popup-sync-label">sync="width"</span>
737
+ </zn-popup>
738
+
739
+ <zn-popup placement="bottom" sync="height" active>
740
+ <span slot="anchor" style="height: 80px;"></span>
741
+ <span class="popup-sync-label">sync="height"</span>
742
+ </zn-popup>
743
+
744
+ <zn-popup placement="bottom" sync="both" active>
745
+ <span slot="anchor" style="width: 180px; height: 80px;"></span>
746
+ <span class="popup-sync-label">sync="both"</span>
747
+ </zn-popup>
748
+ </div>
749
+
750
+ <style>
751
+ .popup-sync {
752
+ display: flex;
753
+ gap: 3rem;
754
+ padding: 3rem;
755
+ }
756
+
757
+ .popup-sync zn-popup span[slot="anchor"] {
758
+ display: inline-block;
759
+ width: 150px;
760
+ height: 60px;
761
+ background: var(--zn-color-primary-600);
762
+ border-radius: 4px;
763
+ }
764
+
765
+ .popup-sync-label {
766
+ display: inline-block;
767
+ padding: 0.5rem 1rem;
768
+ background: var(--zn-color-neutral-900);
769
+ color: white;
770
+ border-radius: 4px;
771
+ white-space: nowrap;
772
+ font-size: 0.875rem;
773
+ }
774
+ </style>
775
+ ```
776
+
777
+ ### Positioning Strategy
778
+
779
+ By default, popups use a `fixed` positioning strategy. This works well in most situations, but if the popup's anchor is inside a container with `overflow: auto|hidden|scroll`, the popup may be clipped. You can change the strategy to `absolute` to position the popup relative to its containing block.
780
+
781
+ ```html:preview
782
+ <div class="popup-strategy">
783
+ <div class="popup-strategy-container">
784
+ <h4>Fixed (Default)</h4>
785
+ <zn-popup placement="bottom" strategy="fixed" active>
786
+ <span slot="anchor"></span>
787
+ <span class="popup-strategy-label">Fixed positioning</span>
788
+ </zn-popup>
789
+ </div>
790
+
791
+ <div class="popup-strategy-container">
792
+ <h4>Absolute</h4>
793
+ <zn-popup placement="bottom" strategy="absolute" active>
794
+ <span slot="anchor"></span>
795
+ <span class="popup-strategy-label">Absolute positioning</span>
796
+ </zn-popup>
797
+ </div>
798
+ </div>
799
+
800
+ <style>
801
+ .popup-strategy {
802
+ display: flex;
803
+ gap: 3rem;
804
+ padding: 3rem;
805
+ }
806
+
807
+ .popup-strategy-container {
808
+ position: relative;
809
+ overflow: hidden;
810
+ border: solid 2px var(--zn-color-neutral-300);
811
+ padding: 2rem;
812
+ }
813
+
814
+ .popup-strategy-container h4 {
815
+ margin: 0 0 1rem 0;
816
+ }
817
+
818
+ .popup-strategy zn-popup span[slot="anchor"] {
819
+ display: inline-block;
820
+ width: 100px;
821
+ height: 100px;
822
+ background: var(--zn-color-primary-600);
823
+ border-radius: 4px;
824
+ }
825
+
826
+ .popup-strategy-label {
827
+ display: inline-block;
828
+ padding: 0.5rem 1rem;
829
+ background: var(--zn-color-neutral-900);
830
+ color: white;
831
+ border-radius: 4px;
832
+ white-space: nowrap;
833
+ font-size: 0.875rem;
834
+ }
835
+ </style>
836
+ ```
837
+
838
+ ### Hover Bridge
839
+
840
+ When a gap exists between the anchor and the popup, it can be difficult to interact with tooltips that show on hover. The `hover-bridge` attribute fills the gap with an invisible element, making it easier for the pointer to move from the anchor to the popup without dismissing it.
841
+
842
+ ```html:preview
843
+ <div class="popup-hover-bridge">
844
+ <zn-popup placement="top" distance="20" hover-bridge active>
845
+ <span slot="anchor"></span>
846
+ <span class="popup-hover-bridge-label">With hover bridge</span>
847
+ </zn-popup>
848
+
849
+ <zn-popup placement="top" distance="20" active>
850
+ <span slot="anchor"></span>
851
+ <span class="popup-hover-bridge-label">Without hover bridge</span>
852
+ </zn-popup>
853
+ </div>
854
+
855
+ <style>
856
+ .popup-hover-bridge {
857
+ display: flex;
858
+ gap: 3rem;
859
+ padding: 3rem;
860
+ }
861
+
862
+ .popup-hover-bridge zn-popup span[slot="anchor"] {
863
+ display: inline-block;
864
+ width: 100px;
865
+ height: 100px;
866
+ background: var(--zn-color-primary-600);
867
+ border-radius: 4px;
868
+ }
869
+
870
+ .popup-hover-bridge-label {
871
+ display: inline-block;
872
+ padding: 0.5rem 1rem;
873
+ background: var(--zn-color-neutral-900);
874
+ color: white;
875
+ border-radius: 4px;
876
+ white-space: nowrap;
877
+ font-size: 0.875rem;
878
+ }
879
+ </style>
880
+ ```
881
+
882
+ ### Virtual Elements
883
+
884
+ In some cases, you may want to position the popup relative to a non-element coordinate. Virtual elements can be used for this purpose. A virtual element must contain a function called `getBoundingClientRect()` that returns a `DOMRect` object as shown below.
885
+
886
+ ```html:preview
887
+ <div class="popup-virtual-element">
888
+ <div id="virtual-element-container">
889
+ <zn-popup id="virtual-element-popup" placement="top" active>
890
+ <div style="
891
+ background: var(--zn-color-neutral-900);
892
+ color: white;
893
+ padding: 0.5rem 1rem;
894
+ border-radius: 4px;
895
+ ">
896
+ Click anywhere
897
+ </div>
898
+ </zn-popup>
899
+ </div>
900
+ </div>
901
+
902
+ <script>
903
+ const container = document.getElementById('virtual-element-container');
904
+ const popup = document.getElementById('virtual-element-popup');
905
+
906
+ let x = 150;
907
+ let y = 50;
908
+
909
+ // Create a virtual element
910
+ const virtualElement = {
911
+ getBoundingClientRect: () => ({
912
+ x: x,
913
+ y: y,
914
+ width: 0,
915
+ height: 0,
916
+ top: y,
917
+ left: x,
918
+ right: x,
919
+ bottom: y,
920
+ })
921
+ };
922
+
923
+ // Set the anchor to the virtual element
924
+ popup.anchor = virtualElement;
925
+
926
+ // Update the virtual element on click
927
+ container.addEventListener('click', (event) => {
928
+ const rect = container.getBoundingClientRect();
929
+ x = event.clientX - rect.left;
930
+ y = event.clientY - rect.top;
931
+
932
+ // Force the popup to reposition
933
+ popup.reposition();
934
+ });
935
+ </script>
936
+
937
+ <style>
938
+ .popup-virtual-element #virtual-element-container {
939
+ position: relative;
940
+ height: 300px;
941
+ background: var(--zn-color-neutral-100);
942
+ border: dashed 2px var(--zn-color-neutral-400);
943
+ border-radius: 4px;
944
+ cursor: crosshair;
945
+ }
946
+ </style>
947
+ ```
948
+
949
+ ## Methods
950
+
951
+ ### reposition()
952
+
953
+ Forces the popup to recalculate and reposition itself. This is useful when the popup's anchor or content changes dynamically.
954
+
955
+ ```html:preview
956
+ <div class="popup-reposition">
957
+ <zn-popup id="reposition-popup" placement="top" active>
958
+ <span id="reposition-anchor" slot="anchor"></span>
959
+ <span class="popup-reposition-label">I'll reposition!</span>
960
+ </zn-popup>
961
+
962
+ <br><br>
963
+
964
+ <zn-button id="reposition-btn">Change Anchor Size</zn-button>
965
+ </div>
966
+
967
+ <script>
968
+ const popup = document.getElementById('reposition-popup');
969
+ const anchor = document.getElementById('reposition-anchor');
970
+ const button = document.getElementById('reposition-btn');
971
+
972
+ let size = 100;
973
+
974
+ button.addEventListener('click', () => {
975
+ size = size === 100 ? 150 : 100;
976
+ anchor.style.width = size + 'px';
977
+ anchor.style.height = size + 'px';
978
+
979
+ // Force reposition after size change
980
+ popup.reposition();
981
+ });
982
+ </script>
983
+
984
+ <style>
985
+ .popup-reposition {
986
+ padding: 3rem;
987
+ }
988
+
989
+ .popup-reposition zn-popup span[slot="anchor"] {
990
+ display: inline-block;
991
+ width: 100px;
992
+ height: 100px;
993
+ background: var(--zn-color-primary-600);
994
+ border-radius: 4px;
995
+ transition: all 0.3s ease;
996
+ }
997
+
998
+ .popup-reposition-label {
999
+ display: inline-block;
1000
+ padding: 0.5rem 1rem;
1001
+ background: var(--zn-color-neutral-900);
1002
+ color: white;
1003
+ border-radius: 4px;
1004
+ white-space: nowrap;
1005
+ font-size: 0.875rem;
1006
+ }
1007
+ </style>
1008
+ ```
1009
+
1010
+ ## Slots
1011
+
1012
+ ### Default Slot
1013
+
1014
+ The popup's content is placed in the default slot.
1015
+
1016
+ ```html:preview
1017
+ <div class="popup-slot-default">
1018
+ <zn-popup placement="top" active>
1019
+ <span slot="anchor"></span>
1020
+ <div style="
1021
+ background: var(--zn-color-neutral-900);
1022
+ color: white;
1023
+ padding: 1rem;
1024
+ border-radius: 4px;
1025
+ ">
1026
+ <h4 style="margin: 0 0 0.5rem 0;">Custom Content</h4>
1027
+ <p style="margin: 0;">Any HTML can go in here!</p>
1028
+ </div>
1029
+ </zn-popup>
1030
+ </div>
1031
+
1032
+ <style>
1033
+ .popup-slot-default {
1034
+ padding: 3rem;
1035
+ }
1036
+
1037
+ .popup-slot-default zn-popup span[slot="anchor"] {
1038
+ display: inline-block;
1039
+ width: 100px;
1040
+ height: 100px;
1041
+ background: var(--zn-color-primary-600);
1042
+ border-radius: 4px;
1043
+ }
1044
+ </style>
1045
+ ```
1046
+
1047
+ ### Anchor Slot
1048
+
1049
+ The anchor element is placed in the `anchor` slot.
1050
+
1051
+ ```html:preview
1052
+ <div class="popup-slot-anchor">
1053
+ <zn-popup placement="top" active>
1054
+ <zn-button slot="anchor">Anchor Button</zn-button>
1055
+ <div style="
1056
+ background: var(--zn-color-neutral-900);
1057
+ color: white;
1058
+ padding: 0.5rem 1rem;
1059
+ border-radius: 4px;
1060
+ ">
1061
+ I'm anchored to the button!
1062
+ </div>
1063
+ </zn-popup>
1064
+ </div>
1065
+
1066
+ <style>
1067
+ .popup-slot-anchor {
1068
+ padding: 3rem;
1069
+ }
1070
+ </style>
1071
+ ```
1072
+
1073
+ ## CSS Parts
1074
+
1075
+ ### popup
1076
+
1077
+ The popup container. Useful for styling or applying animations.
1078
+
1079
+ ```html:preview
1080
+ <div class="popup-part">
1081
+ <zn-popup placement="top" active class="popup-custom">
1082
+ <span slot="anchor"></span>
1083
+ <span class="popup-part-label">Styled with ::part(popup)</span>
1084
+ </zn-popup>
1085
+ </div>
1086
+
1087
+ <style>
1088
+ .popup-custom::part(popup) {
1089
+ background: var(--zn-color-primary-100);
1090
+ padding: 0.5rem;
1091
+ border-radius: 8px;
1092
+ }
1093
+
1094
+ .popup-part {
1095
+ padding: 3rem;
1096
+ }
1097
+
1098
+ .popup-part zn-popup span[slot="anchor"] {
1099
+ display: inline-block;
1100
+ width: 100px;
1101
+ height: 100px;
1102
+ background: var(--zn-color-primary-600);
1103
+ border-radius: 4px;
1104
+ }
1105
+
1106
+ .popup-part-label {
1107
+ display: inline-block;
1108
+ padding: 0.5rem 1rem;
1109
+ background: var(--zn-color-neutral-900);
1110
+ color: white;
1111
+ border-radius: 4px;
1112
+ white-space: nowrap;
1113
+ font-size: 0.875rem;
1114
+ }
1115
+ </style>
1116
+ ```
1117
+
1118
+ ### arrow
1119
+
1120
+ The arrow element. Use this to style the arrow with custom colors or shapes.
1121
+
1122
+ ```html:preview
1123
+ <div class="popup-part-arrow">
1124
+ <zn-popup placement="top" arrow active class="popup-custom-arrow">
1125
+ <span slot="anchor"></span>
1126
+ <span class="popup-part-arrow-label">Styled with ::part(arrow)</span>
1127
+ </zn-popup>
1128
+ </div>
1129
+
1130
+ <style>
1131
+ .popup-custom-arrow::part(arrow) {
1132
+ background: var(--zn-color-success-600);
1133
+ }
1134
+
1135
+ .popup-part-arrow {
1136
+ padding: 3rem;
1137
+ }
1138
+
1139
+ .popup-part-arrow zn-popup span[slot="anchor"] {
1140
+ display: inline-block;
1141
+ width: 100px;
1142
+ height: 100px;
1143
+ background: var(--zn-color-primary-600);
1144
+ border-radius: 4px;
1145
+ }
1146
+
1147
+ .popup-part-arrow-label {
1148
+ display: inline-block;
1149
+ padding: 0.5rem 1rem;
1150
+ background: var(--zn-color-neutral-900);
1151
+ color: white;
1152
+ border-radius: 4px;
1153
+ white-space: nowrap;
1154
+ font-size: 0.875rem;
1155
+ }
1156
+ </style>
1157
+ ```
1158
+
1159
+ ### hover-bridge
1160
+
1161
+ The hover bridge element. Use this to debug or style the invisible hover bridge.
1162
+
1163
+ ```html:preview
1164
+ <div class="popup-part-bridge">
1165
+ <zn-popup placement="top" distance="20" hover-bridge active class="popup-bridge-visible">
1166
+ <span slot="anchor"></span>
1167
+ <span class="popup-part-bridge-label">Hover bridge visible</span>
1168
+ </zn-popup>
1169
+ </div>
1170
+
1171
+ <style>
1172
+ .popup-bridge-visible::part(hover-bridge) {
1173
+ background: rgba(255, 0, 0, 0.1);
1174
+ }
1175
+
1176
+ .popup-part-bridge {
1177
+ padding: 3rem;
1178
+ }
1179
+
1180
+ .popup-part-bridge zn-popup span[slot="anchor"] {
1181
+ display: inline-block;
1182
+ width: 100px;
1183
+ height: 100px;
1184
+ background: var(--zn-color-primary-600);
1185
+ border-radius: 4px;
1186
+ }
1187
+
1188
+ .popup-part-bridge-label {
1189
+ display: inline-block;
1190
+ padding: 0.5rem 1rem;
1191
+ background: var(--zn-color-neutral-900);
1192
+ color: white;
1193
+ border-radius: 4px;
1194
+ white-space: nowrap;
1195
+ font-size: 0.875rem;
1196
+ }
1197
+ </style>
1198
+ ```
1199
+
1200
+ ## CSS Custom Properties
1201
+
1202
+ ### --arrow-size
1203
+
1204
+ Controls the size of the arrow. The default is `6px`.
1205
+
1206
+ ```html:preview
1207
+ <div class="popup-css-arrow-size">
1208
+ <zn-popup placement="top" arrow active style="--arrow-size: 4px;">
1209
+ <span slot="anchor"></span>
1210
+ <span class="popup-css-label">4px</span>
1211
+ </zn-popup>
1212
+
1213
+ <zn-popup placement="top" arrow active style="--arrow-size: 8px;">
1214
+ <span slot="anchor"></span>
1215
+ <span class="popup-css-label">8px</span>
1216
+ </zn-popup>
1217
+
1218
+ <zn-popup placement="top" arrow active style="--arrow-size: 12px;">
1219
+ <span slot="anchor"></span>
1220
+ <span class="popup-css-label">12px</span>
1221
+ </zn-popup>
1222
+ </div>
1223
+
1224
+ <style>
1225
+ .popup-css-arrow-size {
1226
+ display: flex;
1227
+ gap: 3rem;
1228
+ padding: 3rem;
1229
+ }
1230
+
1231
+ .popup-css-arrow-size zn-popup span[slot="anchor"] {
1232
+ display: inline-block;
1233
+ width: 80px;
1234
+ height: 80px;
1235
+ background: var(--zn-color-primary-600);
1236
+ border-radius: 4px;
1237
+ }
1238
+
1239
+ .popup-css-label {
1240
+ display: inline-block;
1241
+ padding: 0.5rem 1rem;
1242
+ background: var(--zn-color-neutral-900);
1243
+ color: white;
1244
+ border-radius: 4px;
1245
+ white-space: nowrap;
1246
+ font-size: 0.875rem;
1247
+ }
1248
+ </style>
1249
+ ```
1250
+
1251
+ ### --arrow-color
1252
+
1253
+ Controls the color of the arrow. The default is `rgb(0, 0, 0, 0.9)`.
1254
+
1255
+ ```html:preview
1256
+ <div class="popup-css-arrow-color">
1257
+ <zn-popup placement="top" arrow active style="--arrow-color: var(--zn-color-success-600);">
1258
+ <span slot="anchor"></span>
1259
+ <span class="popup-css-arrow-color-label popup-css-arrow-color-label--success">Green arrow</span>
1260
+ </zn-popup>
1261
+
1262
+ <zn-popup placement="top" arrow active style="--arrow-color: var(--zn-color-error-600);">
1263
+ <span slot="anchor"></span>
1264
+ <span class="popup-css-arrow-color-label popup-css-arrow-color-label--error">Red arrow</span>
1265
+ </zn-popup>
1266
+
1267
+ <zn-popup placement="top" arrow active style="--arrow-color: var(--zn-color-warning-600);">
1268
+ <span slot="anchor"></span>
1269
+ <span class="popup-css-arrow-color-label popup-css-arrow-color-label--warning">Orange arrow</span>
1270
+ </zn-popup>
1271
+ </div>
1272
+
1273
+ <style>
1274
+ .popup-css-arrow-color {
1275
+ display: flex;
1276
+ gap: 3rem;
1277
+ padding: 3rem;
1278
+ }
1279
+
1280
+ .popup-css-arrow-color zn-popup span[slot="anchor"] {
1281
+ display: inline-block;
1282
+ width: 80px;
1283
+ height: 80px;
1284
+ background: var(--zn-color-primary-600);
1285
+ border-radius: 4px;
1286
+ }
1287
+
1288
+ .popup-css-arrow-color-label {
1289
+ display: inline-block;
1290
+ padding: 0.5rem 1rem;
1291
+ color: white;
1292
+ border-radius: 4px;
1293
+ white-space: nowrap;
1294
+ font-size: 0.875rem;
1295
+ }
1296
+
1297
+ .popup-css-arrow-color-label--success {
1298
+ background: var(--zn-color-success-600);
1299
+ }
1300
+
1301
+ .popup-css-arrow-color-label--error {
1302
+ background: var(--zn-color-error-600);
1303
+ }
1304
+
1305
+ .popup-css-arrow-color-label--warning {
1306
+ background: var(--zn-color-warning-600);
1307
+ }
1308
+ </style>
1309
+ ```
1310
+
1311
+ ### --auto-size-available-width and --auto-size-available-height
1312
+
1313
+ When using the `auto-size` attribute, these properties are set automatically with the available width and/or height. Use them to constrain your popup content.
1314
+
1315
+ ```html:preview
1316
+ <div class="popup-css-auto-size">
1317
+ <div class="popup-css-auto-size-scroll">
1318
+ <zn-popup placement="top" auto-size="both" active>
1319
+ <span slot="anchor"></span>
1320
+ <div class="popup-css-auto-size-content">
1321
+ This content will resize based on available space. The max-width and max-height are set using the CSS custom properties.
1322
+ </div>
1323
+ </zn-popup>
1324
+ </div>
1325
+ </div>
1326
+
1327
+ <style>
1328
+ .popup-css-auto-size {
1329
+ height: 200px;
1330
+ }
1331
+
1332
+ .popup-css-auto-size-scroll {
1333
+ width: 250px;
1334
+ height: 150px;
1335
+ overflow: auto;
1336
+ padding: 3rem;
1337
+ padding-bottom: 250px;
1338
+ padding-right: 350px;
1339
+ }
1340
+
1341
+ .popup-css-auto-size zn-popup span[slot="anchor"] {
1342
+ display: inline-block;
1343
+ width: 100px;
1344
+ height: 100px;
1345
+ background: var(--zn-color-primary-600);
1346
+ border-radius: 4px;
1347
+ }
1348
+
1349
+ .popup-css-auto-size-content {
1350
+ max-width: var(--auto-size-available-width);
1351
+ max-height: var(--auto-size-available-height);
1352
+ overflow: auto;
1353
+ padding: 1rem;
1354
+ background: var(--zn-color-neutral-900);
1355
+ color: white;
1356
+ border-radius: 4px;
1357
+ }
1358
+ </style>
1359
+ ```
17
1360
 
18
- ### Second Example
1361
+ ## Accessibility
19
1362
 
20
- TODO
1363
+ Popups are low-level primitives and do not include built-in accessibility features. It's your responsibility to ensure proper accessibility when using popups:
21
1364
 
1365
+ - Add appropriate ARIA attributes to popup content
1366
+ - Ensure keyboard navigation works correctly
1367
+ - Manage focus as needed
1368
+ - Use semantic HTML inside the popup
22
1369
 
1370
+ For accessible overlays, consider using higher-level components like [Dropdown](/components/dropdown) or [Tooltip](/components/tooltip), which include built-in accessibility features.