@rettangoli/ui 0.1.8 → 0.1.9
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.
package/package.json
CHANGED
|
@@ -12,7 +12,7 @@ function flattenItems(items, selectedItemId = null) {
|
|
|
12
12
|
for (const item of items) {
|
|
13
13
|
const itemId = item.id || item.href || item.path;
|
|
14
14
|
const isSelected = selectedItemId === itemId;
|
|
15
|
-
|
|
15
|
+
|
|
16
16
|
// Add the parent item if it's not just a group label
|
|
17
17
|
result.push({
|
|
18
18
|
id: itemId,
|
|
@@ -31,7 +31,7 @@ function flattenItems(items, selectedItemId = null) {
|
|
|
31
31
|
for (const subItem of item.items) {
|
|
32
32
|
const subItemId = subItem.id || subItem.href || subItem.path;
|
|
33
33
|
const isSubSelected = selectedItemId === subItemId;
|
|
34
|
-
|
|
34
|
+
|
|
35
35
|
result.push({
|
|
36
36
|
id: subItemId,
|
|
37
37
|
title: subItem.title,
|
|
@@ -139,4 +139,4 @@ export const selectItem = ({ state, props, attrs }, id) => {
|
|
|
139
139
|
|
|
140
140
|
export const setState = (state) => {
|
|
141
141
|
// State management if needed
|
|
142
|
-
}
|
|
142
|
+
}
|
|
@@ -11,36 +11,41 @@ class RettangoliPopoverElement extends HTMLElement {
|
|
|
11
11
|
display: contents;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
dialog {
|
|
15
|
+
padding: 0;
|
|
16
|
+
border: none;
|
|
17
|
+
background: transparent;
|
|
18
|
+
margin: 0;
|
|
19
|
+
overflow: visible;
|
|
20
|
+
color: inherit;
|
|
21
|
+
scrollbar-width: none;
|
|
22
|
+
outline: none;
|
|
15
23
|
position: fixed;
|
|
16
24
|
top: 0;
|
|
17
25
|
left: 0;
|
|
18
26
|
width: 100vw;
|
|
19
27
|
height: 100vh;
|
|
20
|
-
|
|
21
|
-
|
|
28
|
+
/* Prevent dialog from being focused */
|
|
29
|
+
pointer-events: none;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
dialog::backdrop {
|
|
33
|
+
background-color: transparent;
|
|
34
|
+
/* Allow backdrop to receive clicks */
|
|
35
|
+
pointer-events: auto;
|
|
22
36
|
}
|
|
23
37
|
|
|
24
38
|
.popover-container {
|
|
25
39
|
position: fixed;
|
|
26
40
|
z-index: 1000;
|
|
27
|
-
display: none;
|
|
28
41
|
outline: none;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
:host([open]:not([no-overlay])) .popover-overlay {
|
|
32
|
-
display: block;
|
|
42
|
+
pointer-events: auto;
|
|
33
43
|
}
|
|
34
44
|
|
|
35
45
|
:host([open]) .popover-container {
|
|
36
46
|
display: block;
|
|
37
47
|
visibility: hidden;
|
|
38
48
|
}
|
|
39
|
-
|
|
40
|
-
/* For no-overlay mode, make the container non-interactive */
|
|
41
|
-
:host([no-overlay]) .popover-container {
|
|
42
|
-
pointer-events: none;
|
|
43
|
-
}
|
|
44
49
|
|
|
45
50
|
:host([open][positioned]) .popover-container {
|
|
46
51
|
visibility: visible;
|
|
@@ -65,20 +70,41 @@ class RettangoliPopoverElement extends HTMLElement {
|
|
|
65
70
|
this.shadow = this.attachShadow({ mode: "open" });
|
|
66
71
|
this.shadow.adoptedStyleSheets = [RettangoliPopoverElement.styleSheet];
|
|
67
72
|
|
|
68
|
-
// Create
|
|
69
|
-
this.
|
|
70
|
-
this.
|
|
71
|
-
|
|
73
|
+
// Create dialog element
|
|
74
|
+
this._dialogElement = document.createElement('dialog');
|
|
75
|
+
this.shadow.appendChild(this._dialogElement);
|
|
76
|
+
|
|
77
|
+
// Handle dialog backdrop clicks to close popover
|
|
78
|
+
this._dialogElement.addEventListener('click', (e) => {
|
|
79
|
+
// Close on backdrop clicks (when clicking outside the popover content)
|
|
80
|
+
const path = e.composedPath();
|
|
81
|
+
const clickedOnBackdrop = path[0] === this._dialogElement ||
|
|
82
|
+
(path[0].nodeName === 'DIALOG' && path[0] === this._dialogElement);
|
|
83
|
+
|
|
84
|
+
if (clickedOnBackdrop) {
|
|
85
|
+
this.dispatchEvent(new CustomEvent('close', {
|
|
86
|
+
detail: {}
|
|
87
|
+
}));
|
|
88
|
+
}
|
|
89
|
+
});
|
|
72
90
|
|
|
73
|
-
// Handle
|
|
74
|
-
this.
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
91
|
+
// Handle right-click on backdrop to close popover
|
|
92
|
+
this._dialogElement.addEventListener('contextmenu', (e) => {
|
|
93
|
+
// Close on backdrop right-clicks
|
|
94
|
+
const path = e.composedPath();
|
|
95
|
+
const clickedOnBackdrop = path[0] === this._dialogElement ||
|
|
96
|
+
(path[0].nodeName === 'DIALOG' && path[0] === this._dialogElement);
|
|
97
|
+
|
|
98
|
+
if (clickedOnBackdrop) {
|
|
99
|
+
e.preventDefault();
|
|
100
|
+
this.dispatchEvent(new CustomEvent('close', {
|
|
101
|
+
detail: {}
|
|
102
|
+
}));
|
|
103
|
+
}
|
|
78
104
|
});
|
|
79
105
|
|
|
80
|
-
// Handle
|
|
81
|
-
this.
|
|
106
|
+
// Handle ESC key - prevent native close and emit custom event
|
|
107
|
+
this._dialogElement.addEventListener('cancel', (e) => {
|
|
82
108
|
e.preventDefault();
|
|
83
109
|
this.dispatchEvent(new CustomEvent('close', {
|
|
84
110
|
detail: {}
|
|
@@ -88,20 +114,17 @@ class RettangoliPopoverElement extends HTMLElement {
|
|
|
88
114
|
// Create popover container
|
|
89
115
|
this._popoverContainer = document.createElement('div');
|
|
90
116
|
this._popoverContainer.className = 'popover-container';
|
|
91
|
-
this.
|
|
117
|
+
this._dialogElement.appendChild(this._popoverContainer);
|
|
92
118
|
|
|
93
119
|
// Store reference for content slot
|
|
94
120
|
this._slotElement = null;
|
|
95
121
|
|
|
96
122
|
// Track if we're open
|
|
97
123
|
this._isOpen = false;
|
|
98
|
-
|
|
99
|
-
// Bind event handlers
|
|
100
|
-
this._handleEscKey = this._handleEscKey.bind(this);
|
|
101
124
|
}
|
|
102
125
|
|
|
103
126
|
static get observedAttributes() {
|
|
104
|
-
return ["open", "x", "y", "placement"
|
|
127
|
+
return ["open", "x", "y", "placement"];
|
|
105
128
|
}
|
|
106
129
|
|
|
107
130
|
connectedCallback() {
|
|
@@ -112,14 +135,19 @@ class RettangoliPopoverElement extends HTMLElement {
|
|
|
112
135
|
}
|
|
113
136
|
|
|
114
137
|
disconnectedCallback() {
|
|
115
|
-
// Clean up
|
|
116
|
-
this.
|
|
138
|
+
// Clean up dialog if it's open
|
|
139
|
+
if (this._isOpen && this._dialogElement.open) {
|
|
140
|
+
this._dialogElement.close();
|
|
141
|
+
}
|
|
117
142
|
}
|
|
118
143
|
|
|
119
144
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
120
145
|
if (name === 'open') {
|
|
121
146
|
if (newValue !== null && !this._isOpen) {
|
|
122
|
-
|
|
147
|
+
// Only show if element is connected to DOM
|
|
148
|
+
if (this.isConnected) {
|
|
149
|
+
this._show();
|
|
150
|
+
}
|
|
123
151
|
} else if (newValue === null && this._isOpen) {
|
|
124
152
|
this._hide();
|
|
125
153
|
}
|
|
@@ -138,8 +166,20 @@ class RettangoliPopoverElement extends HTMLElement {
|
|
|
138
166
|
}
|
|
139
167
|
|
|
140
168
|
this._isOpen = true;
|
|
141
|
-
|
|
142
|
-
|
|
169
|
+
|
|
170
|
+
// Show the dialog using setTimeout to ensure it's in the DOM
|
|
171
|
+
if (!this._dialogElement.open) {
|
|
172
|
+
setTimeout(() => {
|
|
173
|
+
if (this._dialogElement && !this._dialogElement.open) {
|
|
174
|
+
this._dialogElement.showModal();
|
|
175
|
+
}
|
|
176
|
+
}, 0);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Update position after dialog is shown
|
|
180
|
+
requestAnimationFrame(() => {
|
|
181
|
+
this._updatePosition();
|
|
182
|
+
});
|
|
143
183
|
}
|
|
144
184
|
}
|
|
145
185
|
|
|
@@ -147,13 +187,16 @@ class RettangoliPopoverElement extends HTMLElement {
|
|
|
147
187
|
if (this._isOpen) {
|
|
148
188
|
this._isOpen = false;
|
|
149
189
|
|
|
190
|
+
// Close the dialog
|
|
191
|
+
if (this._dialogElement.open) {
|
|
192
|
+
this._dialogElement.close();
|
|
193
|
+
}
|
|
194
|
+
|
|
150
195
|
// Remove slot to unmount content
|
|
151
196
|
if (this._slotElement) {
|
|
152
197
|
this._popoverContainer.removeChild(this._slotElement);
|
|
153
198
|
this._slotElement = null;
|
|
154
199
|
}
|
|
155
|
-
|
|
156
|
-
this._removeGlobalListeners();
|
|
157
200
|
}
|
|
158
201
|
}
|
|
159
202
|
|
|
@@ -246,26 +289,7 @@ class RettangoliPopoverElement extends HTMLElement {
|
|
|
246
289
|
return { left, top };
|
|
247
290
|
}
|
|
248
291
|
|
|
249
|
-
|
|
250
|
-
// Use setTimeout to avoid immediate triggering
|
|
251
|
-
setTimeout(() => {
|
|
252
|
-
document.addEventListener('keydown', this._handleEscKey);
|
|
253
|
-
}, 0);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
_removeGlobalListeners() {
|
|
257
|
-
document.removeEventListener('keydown', this._handleEscKey);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
_handleEscKey(e) {
|
|
262
|
-
if (e.key === 'Escape') {
|
|
263
|
-
this.dispatchEvent(new CustomEvent('close', {
|
|
264
|
-
detail: {}
|
|
265
|
-
}));
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
|
|
292
|
+
|
|
269
293
|
// Expose popover container for advanced usage
|
|
270
294
|
get popover() {
|
|
271
295
|
return this._popoverContainer;
|