@rettangoli/ui 0.1.2-rc2 → 0.1.2-rc21
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/dist/rettangoli-iife-layout.min.js +102 -32
- package/dist/rettangoli-iife-ui.min.js +182 -69
- package/package.json +5 -3
- package/src/cli/buildSvg.js +86 -0
- package/src/cli/index.js +1 -0
- package/src/components/breadcrumb/breadcrumb.handlers.js +9 -0
- package/src/components/breadcrumb/breadcrumb.store.js +29 -0
- package/src/components/breadcrumb/breadcrumb.view.yaml +64 -0
- package/src/components/dropdownMenu/dropdownMenu.handlers.js +4 -4
- package/src/components/dropdownMenu/dropdownMenu.store.js +5 -17
- package/src/components/dropdownMenu/dropdownMenu.view.yaml +15 -13
- package/src/components/form/form.handlers.js +133 -24
- package/src/components/form/form.store.js +125 -23
- package/src/components/form/form.view.yaml +139 -29
- package/src/components/pageOutline/pageOutline.handlers.js +1 -1
- package/src/components/popoverInput/popoverInput.handlers.js +99 -0
- package/src/components/popoverInput/popoverInput.store.js +48 -0
- package/src/components/popoverInput/popoverInput.view.yaml +55 -0
- package/src/components/select/select.handlers.js +2 -5
- package/src/components/select/select.view.yaml +3 -3
- package/src/components/sidebar/sidebar.view.yaml +1 -1
- package/src/components/sliderInput/sliderInput.handlers.js +24 -0
- package/src/components/sliderInput/sliderInput.store.js +17 -0
- package/src/components/sliderInput/sliderInput.view.yaml +42 -0
- package/src/components/table/table.handlers.js +1 -1
- package/src/components/tabs/tabs.handlers.js +10 -0
- package/src/components/tabs/tabs.store.js +29 -0
- package/src/components/tabs/tabs.view.yaml +64 -0
- package/src/components/waveform/waveform.handlers.js +92 -0
- package/src/components/waveform/waveform.store.js +17 -0
- package/src/components/waveform/waveform.view.yaml +38 -0
- package/src/entry-iife-layout.js +3 -0
- package/src/entry-iife-ui.js +4 -0
- package/src/index.js +5 -1
- package/src/primitives/dialog.js +208 -0
- package/src/primitives/input.js +32 -11
- package/src/primitives/popover.js +275 -0
- package/src/primitives/slider.js +8 -9
- package/src/styles/viewStyles.js +1 -0
- package/src/components/dialog/dialog.handlers.js +0 -5
- package/src/components/dialog/dialog.store.js +0 -25
- package/src/components/dialog/dialog.view.yaml +0 -44
- package/src/components/popover/popover.handlers.js +0 -5
- package/src/components/popover/popover.store.js +0 -12
- package/src/components/popover/popover.view.yaml +0 -57
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import { css } from "../common.js";
|
|
2
|
+
|
|
3
|
+
class RettangoliPopoverElement extends HTMLElement {
|
|
4
|
+
static styleSheet = null;
|
|
5
|
+
|
|
6
|
+
static initializeStyleSheet() {
|
|
7
|
+
if (!RettangoliPopoverElement.styleSheet) {
|
|
8
|
+
RettangoliPopoverElement.styleSheet = new CSSStyleSheet();
|
|
9
|
+
RettangoliPopoverElement.styleSheet.replaceSync(css`
|
|
10
|
+
:host {
|
|
11
|
+
display: contents;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.popover-overlay {
|
|
15
|
+
position: fixed;
|
|
16
|
+
top: 0;
|
|
17
|
+
left: 0;
|
|
18
|
+
width: 100vw;
|
|
19
|
+
height: 100vh;
|
|
20
|
+
z-index: 999;
|
|
21
|
+
display: none;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.popover-container {
|
|
25
|
+
position: fixed;
|
|
26
|
+
z-index: 1000;
|
|
27
|
+
display: none;
|
|
28
|
+
outline: none;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
:host([open]) .popover-overlay {
|
|
32
|
+
display: block;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
:host([open]) .popover-container {
|
|
36
|
+
display: block;
|
|
37
|
+
visibility: hidden;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
:host([open][positioned]) .popover-container {
|
|
41
|
+
visibility: visible;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
slot[name="content"] {
|
|
45
|
+
display: block;
|
|
46
|
+
background-color: var(--muted);
|
|
47
|
+
border: 1px solid var(--border);
|
|
48
|
+
border-radius: var(--border-radius-md);
|
|
49
|
+
padding: var(--spacing-md);
|
|
50
|
+
min-width: 200px;
|
|
51
|
+
max-width: 400px;
|
|
52
|
+
}
|
|
53
|
+
`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
constructor() {
|
|
58
|
+
super();
|
|
59
|
+
RettangoliPopoverElement.initializeStyleSheet();
|
|
60
|
+
this.shadow = this.attachShadow({ mode: "open" });
|
|
61
|
+
this.shadow.adoptedStyleSheets = [RettangoliPopoverElement.styleSheet];
|
|
62
|
+
|
|
63
|
+
// Create overlay
|
|
64
|
+
this._popoverOverlay = document.createElement('div');
|
|
65
|
+
this._popoverOverlay.className = 'popover-overlay';
|
|
66
|
+
this.shadow.appendChild(this._popoverOverlay);
|
|
67
|
+
|
|
68
|
+
// Handle overlay clicks to close popover
|
|
69
|
+
this._popoverOverlay.addEventListener('click', () => {
|
|
70
|
+
this.dispatchEvent(new CustomEvent('close', {
|
|
71
|
+
detail: {}
|
|
72
|
+
}));
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Handle right-click on overlay to close popover
|
|
76
|
+
this._popoverOverlay.addEventListener('contextmenu', (e) => {
|
|
77
|
+
e.preventDefault();
|
|
78
|
+
this.dispatchEvent(new CustomEvent('close', {
|
|
79
|
+
detail: {}
|
|
80
|
+
}));
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Create popover container
|
|
84
|
+
this._popoverContainer = document.createElement('div');
|
|
85
|
+
this._popoverContainer.className = 'popover-container';
|
|
86
|
+
this.shadow.appendChild(this._popoverContainer);
|
|
87
|
+
|
|
88
|
+
// Store reference for content slot
|
|
89
|
+
this._slotElement = null;
|
|
90
|
+
|
|
91
|
+
// Track if we're open
|
|
92
|
+
this._isOpen = false;
|
|
93
|
+
|
|
94
|
+
// Bind event handlers
|
|
95
|
+
this._handleEscKey = this._handleEscKey.bind(this);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
static get observedAttributes() {
|
|
99
|
+
return ["open", "x", "y", "placement"];
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
connectedCallback() {
|
|
103
|
+
// Check initial open attribute
|
|
104
|
+
if (this.hasAttribute('open')) {
|
|
105
|
+
this._show();
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
disconnectedCallback() {
|
|
110
|
+
// Clean up event listeners
|
|
111
|
+
this._removeGlobalListeners();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
115
|
+
if (name === 'open') {
|
|
116
|
+
if (newValue !== null && !this._isOpen) {
|
|
117
|
+
this._show();
|
|
118
|
+
} else if (newValue === null && this._isOpen) {
|
|
119
|
+
this._hide();
|
|
120
|
+
}
|
|
121
|
+
} else if ((name === 'x' || name === 'y' || name === 'placement') && this._isOpen) {
|
|
122
|
+
this._updatePosition();
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
_show() {
|
|
127
|
+
if (!this._isOpen) {
|
|
128
|
+
// Create and append slot for content only if it doesn't exist
|
|
129
|
+
if (!this._slotElement) {
|
|
130
|
+
this._slotElement = document.createElement('slot');
|
|
131
|
+
this._slotElement.setAttribute('name', 'content');
|
|
132
|
+
this._popoverContainer.appendChild(this._slotElement);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
this._isOpen = true;
|
|
136
|
+
this._updatePosition();
|
|
137
|
+
this._addGlobalListeners();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
_hide() {
|
|
142
|
+
if (this._isOpen) {
|
|
143
|
+
this._isOpen = false;
|
|
144
|
+
|
|
145
|
+
// Remove slot to unmount content
|
|
146
|
+
if (this._slotElement) {
|
|
147
|
+
this._popoverContainer.removeChild(this._slotElement);
|
|
148
|
+
this._slotElement = null;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
this._removeGlobalListeners();
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
_updatePosition() {
|
|
156
|
+
const x = parseFloat(this.getAttribute('x') || '0');
|
|
157
|
+
const y = parseFloat(this.getAttribute('y') || '0');
|
|
158
|
+
const placement = this.getAttribute('placement') || 'bottom-start';
|
|
159
|
+
|
|
160
|
+
// Remove positioned attribute to hide during repositioning
|
|
161
|
+
this.removeAttribute('positioned');
|
|
162
|
+
|
|
163
|
+
// Calculate position based on placement
|
|
164
|
+
// We'll position after the popover is rendered to get its dimensions
|
|
165
|
+
requestAnimationFrame(() => {
|
|
166
|
+
const rect = this._popoverContainer.getBoundingClientRect();
|
|
167
|
+
const { left, top } = this._calculatePosition(x, y, rect.width, rect.height, placement);
|
|
168
|
+
|
|
169
|
+
// Set position first
|
|
170
|
+
this._popoverContainer.style.left = `${left}px`;
|
|
171
|
+
this._popoverContainer.style.top = `${top}px`;
|
|
172
|
+
|
|
173
|
+
// Then make visible in next frame to prevent flicker
|
|
174
|
+
requestAnimationFrame(() => {
|
|
175
|
+
this.setAttribute('positioned', '');
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
_calculatePosition(x, y, width, height, placement) {
|
|
181
|
+
const offset = 8; // Small offset from the cursor
|
|
182
|
+
let left = x;
|
|
183
|
+
let top = y;
|
|
184
|
+
|
|
185
|
+
switch (placement) {
|
|
186
|
+
case 'top':
|
|
187
|
+
left = x - width / 2;
|
|
188
|
+
top = y - height - offset;
|
|
189
|
+
break;
|
|
190
|
+
case 'top-start':
|
|
191
|
+
left = x;
|
|
192
|
+
top = y - height - offset;
|
|
193
|
+
break;
|
|
194
|
+
case 'top-end':
|
|
195
|
+
left = x - width;
|
|
196
|
+
top = y - height - offset;
|
|
197
|
+
break;
|
|
198
|
+
case 'right':
|
|
199
|
+
left = x + offset;
|
|
200
|
+
top = y - height / 2;
|
|
201
|
+
break;
|
|
202
|
+
case 'right-start':
|
|
203
|
+
left = x + offset;
|
|
204
|
+
top = y;
|
|
205
|
+
break;
|
|
206
|
+
case 'right-end':
|
|
207
|
+
left = x + offset;
|
|
208
|
+
top = y - height;
|
|
209
|
+
break;
|
|
210
|
+
case 'bottom':
|
|
211
|
+
left = x - width / 2;
|
|
212
|
+
top = y + offset;
|
|
213
|
+
break;
|
|
214
|
+
case 'bottom-start':
|
|
215
|
+
left = x;
|
|
216
|
+
top = y + offset;
|
|
217
|
+
break;
|
|
218
|
+
case 'bottom-end':
|
|
219
|
+
left = x - width;
|
|
220
|
+
top = y + offset;
|
|
221
|
+
break;
|
|
222
|
+
case 'left':
|
|
223
|
+
left = x - width - offset;
|
|
224
|
+
top = y - height / 2;
|
|
225
|
+
break;
|
|
226
|
+
case 'left-start':
|
|
227
|
+
left = x - width - offset;
|
|
228
|
+
top = y;
|
|
229
|
+
break;
|
|
230
|
+
case 'left-end':
|
|
231
|
+
left = x - width - offset;
|
|
232
|
+
top = y - height;
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Ensure popover stays within viewport
|
|
237
|
+
const padding = 8;
|
|
238
|
+
left = Math.max(padding, Math.min(left, window.innerWidth - width - padding));
|
|
239
|
+
top = Math.max(padding, Math.min(top, window.innerHeight - height - padding));
|
|
240
|
+
|
|
241
|
+
return { left, top };
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
_addGlobalListeners() {
|
|
245
|
+
// Use setTimeout to avoid immediate triggering
|
|
246
|
+
setTimeout(() => {
|
|
247
|
+
document.addEventListener('keydown', this._handleEscKey);
|
|
248
|
+
}, 0);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
_removeGlobalListeners() {
|
|
252
|
+
document.removeEventListener('keydown', this._handleEscKey);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
_handleEscKey(e) {
|
|
257
|
+
if (e.key === 'Escape') {
|
|
258
|
+
this.dispatchEvent(new CustomEvent('close', {
|
|
259
|
+
detail: {}
|
|
260
|
+
}));
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Expose popover container for advanced usage
|
|
265
|
+
get popover() {
|
|
266
|
+
return this._popoverContainer;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Export factory function to maintain API compatibility
|
|
271
|
+
export default ({ render, html }) => {
|
|
272
|
+
// Note: render and html parameters are accepted but not used
|
|
273
|
+
// This maintains backward compatibility with existing code
|
|
274
|
+
return RettangoliPopoverElement;
|
|
275
|
+
};
|
package/src/primitives/slider.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
css,
|
|
1
|
+
import {
|
|
2
|
+
css,
|
|
3
3
|
dimensionWithUnit,
|
|
4
4
|
convertObjectToCssString,
|
|
5
5
|
styleMapKeys,
|
|
@@ -22,7 +22,6 @@ class RettangoliSliderElement extends HTMLElement {
|
|
|
22
22
|
input[type="range"] {
|
|
23
23
|
-webkit-appearance: none;
|
|
24
24
|
appearance: none;
|
|
25
|
-
width: 200px;
|
|
26
25
|
height: 8px;
|
|
27
26
|
background: var(--muted);
|
|
28
27
|
border-radius: var(--border-radius-full);
|
|
@@ -79,7 +78,7 @@ class RettangoliSliderElement extends HTMLElement {
|
|
|
79
78
|
RettangoliSliderElement.initializeStyleSheet();
|
|
80
79
|
this.shadow = this.attachShadow({ mode: "closed" });
|
|
81
80
|
this.shadow.adoptedStyleSheets = [RettangoliSliderElement.styleSheet];
|
|
82
|
-
|
|
81
|
+
|
|
83
82
|
// Initialize style tracking properties
|
|
84
83
|
this._styles = {
|
|
85
84
|
default: {},
|
|
@@ -89,12 +88,12 @@ class RettangoliSliderElement extends HTMLElement {
|
|
|
89
88
|
xl: {},
|
|
90
89
|
};
|
|
91
90
|
this._lastStyleString = "";
|
|
92
|
-
|
|
91
|
+
|
|
93
92
|
// Create initial DOM structure
|
|
94
93
|
this._inputElement = document.createElement('input');
|
|
95
94
|
this._inputElement.type = 'range';
|
|
96
95
|
this._styleElement = document.createElement('style');
|
|
97
|
-
|
|
96
|
+
|
|
98
97
|
this.shadow.appendChild(this._styleElement);
|
|
99
98
|
this.shadow.appendChild(this._inputElement);
|
|
100
99
|
|
|
@@ -105,7 +104,7 @@ class RettangoliSliderElement extends HTMLElement {
|
|
|
105
104
|
|
|
106
105
|
static get observedAttributes() {
|
|
107
106
|
return [
|
|
108
|
-
"key",
|
|
107
|
+
"key",
|
|
109
108
|
"value",
|
|
110
109
|
"min",
|
|
111
110
|
"max",
|
|
@@ -248,7 +247,7 @@ class RettangoliSliderElement extends HTMLElement {
|
|
|
248
247
|
} else {
|
|
249
248
|
this._inputElement.step = "1";
|
|
250
249
|
}
|
|
251
|
-
|
|
250
|
+
|
|
252
251
|
if (isDisabled) {
|
|
253
252
|
this._inputElement.setAttribute("disabled", "");
|
|
254
253
|
} else {
|
|
@@ -266,4 +265,4 @@ export default ({ render, html }) => {
|
|
|
266
265
|
// Note: render and html parameters are accepted but not used
|
|
267
266
|
// This maintains backward compatibility with existing code
|
|
268
267
|
return RettangoliSliderElement;
|
|
269
|
-
};
|
|
268
|
+
};
|
package/src/styles/viewStyles.js
CHANGED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
export const INITIAL_STATE = Object.freeze({
|
|
2
|
-
//
|
|
3
|
-
});
|
|
4
|
-
|
|
5
|
-
export const toViewData = ({ state, props }) => {
|
|
6
|
-
return {
|
|
7
|
-
isOpen: props.isOpen,
|
|
8
|
-
w: props.w || 600,
|
|
9
|
-
position: {
|
|
10
|
-
x: 0,
|
|
11
|
-
y: 0
|
|
12
|
-
}
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export const selectState = ({ state }) => {
|
|
17
|
-
return state;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export const setState = (state) => {
|
|
21
|
-
// do doSomething
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
elementName: rtgl-dialog
|
|
2
|
-
|
|
3
|
-
viewDataSchema:
|
|
4
|
-
type: object
|
|
5
|
-
|
|
6
|
-
propsSchema:
|
|
7
|
-
type: object
|
|
8
|
-
properties:
|
|
9
|
-
isOpen:
|
|
10
|
-
type: boolean
|
|
11
|
-
w:
|
|
12
|
-
type: string
|
|
13
|
-
|
|
14
|
-
refs:
|
|
15
|
-
dialog-overlay:
|
|
16
|
-
eventListeners:
|
|
17
|
-
click:
|
|
18
|
-
handler: handleClickDialogueOverlay
|
|
19
|
-
|
|
20
|
-
events:
|
|
21
|
-
close-dialogue:
|
|
22
|
-
type: object
|
|
23
|
-
properties: {}
|
|
24
|
-
|
|
25
|
-
styles:
|
|
26
|
-
# '@keyframes dialog-in':
|
|
27
|
-
# from:
|
|
28
|
-
# opacity: 0
|
|
29
|
-
# transform: scale(0.95)
|
|
30
|
-
# to:
|
|
31
|
-
# opacity: 1
|
|
32
|
-
# transform: scale(1)
|
|
33
|
-
|
|
34
|
-
# '#dialog-container':
|
|
35
|
-
# animation: dialog-in 150ms cubic-bezier(0.16, 1, 0.3, 1)
|
|
36
|
-
# transform-origin: top
|
|
37
|
-
|
|
38
|
-
template:
|
|
39
|
-
- $if isOpen:
|
|
40
|
-
- rtgl-view pos=fix cor=full ah=c:
|
|
41
|
-
- 'rtgl-view#dialog-overlay pos=fix cor=full ah=c av=c bgc=bg op=0.5':
|
|
42
|
-
- rtgl-view h=10vh:
|
|
43
|
-
- rtgl-view#dialog-container z=100 bw=xs p=lg bgc=bg w=${w} br=sm:
|
|
44
|
-
- slot name=content:
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
elementName: rtgl-popover
|
|
2
|
-
|
|
3
|
-
viewDataSchema:
|
|
4
|
-
type: object
|
|
5
|
-
properties:
|
|
6
|
-
isOpen:
|
|
7
|
-
type: boolean
|
|
8
|
-
position:
|
|
9
|
-
type: object
|
|
10
|
-
properties:
|
|
11
|
-
x:
|
|
12
|
-
type: number
|
|
13
|
-
y:
|
|
14
|
-
type: number
|
|
15
|
-
placement:
|
|
16
|
-
type: string
|
|
17
|
-
|
|
18
|
-
propsSchema:
|
|
19
|
-
type: object
|
|
20
|
-
properties:
|
|
21
|
-
placement:
|
|
22
|
-
type: string
|
|
23
|
-
default: bottom
|
|
24
|
-
isOpen:
|
|
25
|
-
type: boolean
|
|
26
|
-
position:
|
|
27
|
-
type: object
|
|
28
|
-
properties:
|
|
29
|
-
x:
|
|
30
|
-
type: number
|
|
31
|
-
y:
|
|
32
|
-
type: number
|
|
33
|
-
|
|
34
|
-
refs:
|
|
35
|
-
popoverOverlay:
|
|
36
|
-
eventListeners:
|
|
37
|
-
click:
|
|
38
|
-
handler: handleClickOverlay
|
|
39
|
-
|
|
40
|
-
styles:
|
|
41
|
-
'@keyframes popover-in':
|
|
42
|
-
from:
|
|
43
|
-
opacity: 0
|
|
44
|
-
transform: scale(0.95)
|
|
45
|
-
to:
|
|
46
|
-
opacity: 1
|
|
47
|
-
transform: scale(1)
|
|
48
|
-
|
|
49
|
-
'#popoverContainer':
|
|
50
|
-
animation: popover-in 150ms cubic-bezier(0.16, 1, 0.3, 1)
|
|
51
|
-
transform-origin: top
|
|
52
|
-
|
|
53
|
-
template:
|
|
54
|
-
- $if isOpen:
|
|
55
|
-
- rtgl-view#popoverOverlay pos=fix cor=full:
|
|
56
|
-
- 'rtgl-view#popoverContainer pos=fix style="left: ${position.x}px; top: ${position.y}px;" id=floatingElement bw=xs p=md bgc=mu':
|
|
57
|
-
- slot name=content:
|