rettangoli-ui 0.1.0-rc3 → 0.1.0-rc5
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 +48 -26
- package/dist/rettangoli-iife-ui.min.js +58 -36
- package/package.json +1 -1
- package/src/components/dialog/dialog.view.yaml +12 -11
- package/src/components/dropdownMenu/dropdownMenu.handlers.js +18 -0
- package/src/components/dropdownMenu/dropdownMenu.store.js +25 -0
- package/src/components/dropdownMenu/dropdownMenu.view.yaml +54 -0
- package/src/components/popover/popover.handlers.js +3 -15
- package/src/components/popover/popover.store.js +3 -28
- package/src/components/popover/popover.view.yaml +8 -1
- package/src/components/select/select.handlers.js +35 -4
- package/src/components/select/select.store.js +45 -5
- package/src/components/select/select.view.yaml +20 -8
- package/src/components/sidebar/sidebar.store.js +19 -5
- package/src/components/sidebar/sidebar.view.yaml +5 -1
- package/src/primitives/button.js +50 -7
- package/src/primitives/view.js +2 -0
package/package.json
CHANGED
@@ -21,20 +21,21 @@ events:
|
|
21
21
|
properties: {}
|
22
22
|
|
23
23
|
styles:
|
24
|
-
'@keyframes dialog-in':
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
24
|
+
# '@keyframes dialog-in':
|
25
|
+
# from:
|
26
|
+
# opacity: 0
|
27
|
+
# transform: scale(0.95)
|
28
|
+
# to:
|
29
|
+
# opacity: 1
|
30
|
+
# transform: scale(1)
|
31
31
|
|
32
|
-
'#dialog-container':
|
33
|
-
|
34
|
-
|
32
|
+
# '#dialog-container':
|
33
|
+
# animation: dialog-in 150ms cubic-bezier(0.16, 1, 0.3, 1)
|
34
|
+
# transform-origin: top
|
35
35
|
|
36
36
|
template:
|
37
37
|
- $if isOpen:
|
38
|
-
- rtgl-view
|
38
|
+
- rtgl-view pos=fix cor=full ah=c av=c:
|
39
|
+
- 'rtgl-view#dialog-overlay pos=fix cor=full ah=c av=c bgc=bg op=0.5':
|
39
40
|
- rtgl-view#dialog-container pos=fix bw=xs p=lg bgc=bg w=600 br=sm:
|
40
41
|
- slot name=content:
|
@@ -0,0 +1,18 @@
|
|
1
|
+
|
2
|
+
export const handleClickPopoverOverlay = (e, deps) => {
|
3
|
+
const { dispatchEvent } = deps;
|
4
|
+
dispatchEvent(new CustomEvent('click-overlay'));
|
5
|
+
}
|
6
|
+
|
7
|
+
export const handleClickMenuItem = (e, deps) => {
|
8
|
+
const { dispatchEvent } = deps;
|
9
|
+
const index = parseInt(e.currentTarget.id.replace('option-', ''));
|
10
|
+
const item = deps.props.items[index];
|
11
|
+
|
12
|
+
dispatchEvent(new CustomEvent('click-item', {
|
13
|
+
detail: {
|
14
|
+
index,
|
15
|
+
item
|
16
|
+
}
|
17
|
+
}));
|
18
|
+
}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
|
2
|
+
export const INITIAL_STATE = Object.freeze({
|
3
|
+
});
|
4
|
+
|
5
|
+
export const toViewData = ({ state, props }) => {
|
6
|
+
return {
|
7
|
+
items: props.items || [],
|
8
|
+
isOpen: props.isOpen || false,
|
9
|
+
position: props.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
|
+
|
@@ -0,0 +1,54 @@
|
|
1
|
+
elementName: rtgl-dropdown-menu
|
2
|
+
|
3
|
+
viewDataSchema:
|
4
|
+
type: object
|
5
|
+
|
6
|
+
propsSchema:
|
7
|
+
type: object
|
8
|
+
properties:
|
9
|
+
items:
|
10
|
+
type: array
|
11
|
+
items:
|
12
|
+
type: object
|
13
|
+
properties:
|
14
|
+
label:
|
15
|
+
type: string
|
16
|
+
type:
|
17
|
+
type: string
|
18
|
+
enum:
|
19
|
+
- label
|
20
|
+
- item
|
21
|
+
- separator
|
22
|
+
isOpen:
|
23
|
+
type: boolean
|
24
|
+
position:
|
25
|
+
type: object
|
26
|
+
properties:
|
27
|
+
x:
|
28
|
+
type: number
|
29
|
+
y:
|
30
|
+
type: number
|
31
|
+
|
32
|
+
refs:
|
33
|
+
popover:
|
34
|
+
eventListeners:
|
35
|
+
click-overlay:
|
36
|
+
handler: handleClickPopoverOverlay
|
37
|
+
option-*:
|
38
|
+
eventListeners:
|
39
|
+
click:
|
40
|
+
handler: handleClickMenuItem
|
41
|
+
|
42
|
+
template:
|
43
|
+
- rtgl-popover#popover .isOpen=isOpen .position=position:
|
44
|
+
- rtgl-view wh=300 g=xs slot=content bgc=background br=md:
|
45
|
+
- $for item, i in items:
|
46
|
+
- $if item.type == 'label':
|
47
|
+
- rtgl-view w=f ph=lg pv=md:
|
48
|
+
- rtgl-text s=sm c=mu-fg: ${item.label}
|
49
|
+
$elif item.type == 'item':
|
50
|
+
- rtgl-view#option-${i} w=f h-bgc=ac ph=lg pv=md cur=p br=md bgc=mu:
|
51
|
+
- rtgl-text: ${item.label}
|
52
|
+
$elif item.type == 'separator':
|
53
|
+
- rtgl-view w=f h=1 ph=lg mv=md bgc=bo:
|
54
|
+
|
@@ -1,17 +1,5 @@
|
|
1
|
-
export const handleClickOverlay = (e, deps) => {
|
2
|
-
const { props, dispatchEvent, store, render } = deps;
|
3
|
-
if (props.isOpen !== undefined) {
|
4
|
-
dispatchEvent(new CustomEvent('closePopover'));
|
5
|
-
return;
|
6
|
-
}
|
7
|
-
store.setClose();
|
8
|
-
render();
|
9
|
-
}
|
10
1
|
|
11
|
-
export const
|
12
|
-
const {
|
13
|
-
|
14
|
-
store.setOpen(position);
|
15
|
-
render();
|
2
|
+
export const handleClickOverlay = (e, deps) => {
|
3
|
+
const { dispatchEvent } = deps;
|
4
|
+
dispatchEvent(new CustomEvent('click-overlay'));
|
16
5
|
}
|
17
|
-
|
@@ -1,37 +1,12 @@
|
|
1
|
-
export const INITIAL_STATE = Object.freeze({
|
2
|
-
isOpen: false,
|
3
|
-
position: {
|
4
|
-
x: 0,
|
5
|
-
y: 0
|
6
|
-
},
|
7
|
-
});
|
1
|
+
export const INITIAL_STATE = Object.freeze({});
|
8
2
|
|
9
3
|
export const toViewData = ({ state, props }) => {
|
10
|
-
if (props.isOpen !== undefined) {
|
11
|
-
return {
|
12
|
-
isOpen: props.isOpen,
|
13
|
-
position: {
|
14
|
-
x: 0,
|
15
|
-
y: 0
|
16
|
-
}
|
17
|
-
}
|
18
|
-
}
|
19
4
|
return {
|
20
|
-
isOpen:
|
21
|
-
position:
|
5
|
+
isOpen: props.isOpen,
|
6
|
+
position: props.position,
|
22
7
|
};
|
23
8
|
}
|
24
9
|
|
25
10
|
export const selectState = ({ state }) => {
|
26
11
|
return state;
|
27
12
|
}
|
28
|
-
|
29
|
-
export const setOpen = (state, position) => {
|
30
|
-
state.isOpen = true;
|
31
|
-
state.position = position;
|
32
|
-
}
|
33
|
-
|
34
|
-
export const setClose = (state) => {
|
35
|
-
state.isOpen = false;
|
36
|
-
state.position = { x: 0, y: 0 };
|
37
|
-
}
|
@@ -23,6 +23,13 @@ propsSchema:
|
|
23
23
|
default: bottom
|
24
24
|
isOpen:
|
25
25
|
type: boolean
|
26
|
+
position:
|
27
|
+
type: object
|
28
|
+
properties:
|
29
|
+
x:
|
30
|
+
type: number
|
31
|
+
y:
|
32
|
+
type: number
|
26
33
|
|
27
34
|
refs:
|
28
35
|
popoverOverlay:
|
@@ -46,5 +53,5 @@ styles:
|
|
46
53
|
template:
|
47
54
|
- $if isOpen:
|
48
55
|
- rtgl-view#popoverOverlay pos=fix cor=full:
|
49
|
-
- 'rtgl-view#popoverContainer pos=fix style="left: ${position.x}px; top: ${position.y}px;" id=floatingElement bw=xs p=md bgc=
|
56
|
+
- 'rtgl-view#popoverContainer pos=fix style="left: ${position.x}px; top: ${position.y}px;" id=floatingElement bw=xs p=md bgc=mu':
|
50
57
|
- slot name=content:
|
@@ -1,15 +1,46 @@
|
|
1
1
|
|
2
2
|
export const handleOnMount = (deps) => {
|
3
|
+
const { store, props, render } = deps;
|
4
|
+
|
5
|
+
if (props.selectedValue !== null && props.selectedValue !== undefined && props.options) {
|
6
|
+
const selectedOption = props.options.find(opt => opt.value === props.selectedValue);
|
7
|
+
if (selectedOption) {
|
8
|
+
store.update((state) => {
|
9
|
+
state.selectedValue = selectedOption.value;
|
10
|
+
state.selectedLabel = selectedOption.label;
|
11
|
+
});
|
12
|
+
render();
|
13
|
+
}
|
14
|
+
}
|
3
15
|
}
|
4
16
|
|
5
17
|
export const handleButtonClick = (e, deps) => {
|
6
18
|
const { store, render, getRefIds } = deps;
|
7
|
-
|
8
|
-
refIds.popover.elm.transformedHandlers.open({
|
19
|
+
store.openOptionsPopover({
|
9
20
|
position: {
|
21
|
+
y: e.clientY,
|
10
22
|
x: e.clientX,
|
11
|
-
y: e.clientY
|
12
23
|
}
|
13
|
-
})
|
24
|
+
})
|
25
|
+
render();
|
26
|
+
}
|
27
|
+
|
28
|
+
export const handleClickOptionsPopoverOverlay = (e, deps) => {
|
29
|
+
const { store, render } = deps;
|
30
|
+
store.closeOptionsPopover();
|
31
|
+
render();
|
32
|
+
}
|
33
|
+
|
34
|
+
export const handleOptionClick = (e, deps) => {
|
35
|
+
const { render, dispatchEvent, props } = deps;
|
36
|
+
const id = e.currentTarget.id.replace('option-', '');
|
37
|
+
|
38
|
+
const option = props.options[id];
|
14
39
|
|
40
|
+
dispatchEvent(new CustomEvent('option-selected', {
|
41
|
+
detail: { value: option.value, label: option.label },
|
42
|
+
bubbles: true
|
43
|
+
}));
|
44
|
+
|
45
|
+
render();
|
15
46
|
}
|
@@ -1,11 +1,43 @@
|
|
1
1
|
export const INITIAL_STATE = Object.freeze({
|
2
2
|
isOpen: false,
|
3
|
+
position: {
|
4
|
+
x: 0,
|
5
|
+
y: 0,
|
6
|
+
},
|
7
|
+
selectedValue: null,
|
8
|
+
selectedLabel: null,
|
3
9
|
});
|
4
10
|
|
5
11
|
export const toViewData = ({ state, props }) => {
|
12
|
+
// Calculate display label
|
13
|
+
let displayLabel = props.placeholder || 'Select an option';
|
14
|
+
|
15
|
+
// Use state's selected value if available, otherwise use props.selectedValue
|
16
|
+
const currentValue = state.selectedValue !== null ? state.selectedValue : props.selectedValue;
|
17
|
+
|
18
|
+
if (currentValue !== null && currentValue !== undefined && props.options) {
|
19
|
+
const selectedOption = props.options.find(opt => opt.value === currentValue);
|
20
|
+
if (selectedOption) {
|
21
|
+
displayLabel = selectedOption.label;
|
22
|
+
}
|
23
|
+
} else if (state.selectedLabel) {
|
24
|
+
displayLabel = state.selectedLabel;
|
25
|
+
}
|
26
|
+
|
27
|
+
// Map options to include isSelected flag and computed background color
|
28
|
+
const optionsWithSelection = (props.options || []).map(option => ({
|
29
|
+
...option,
|
30
|
+
isSelected: option.value === currentValue,
|
31
|
+
bgc: option.value === currentValue ? 'mu' : ''
|
32
|
+
}));
|
33
|
+
|
6
34
|
return {
|
7
35
|
isOpen: state.isOpen,
|
8
|
-
|
36
|
+
position: state.position,
|
37
|
+
options: optionsWithSelection,
|
38
|
+
selectedValue: currentValue,
|
39
|
+
selectedLabel: displayLabel,
|
40
|
+
placeholder: props.placeholder || 'Select an option'
|
9
41
|
};
|
10
42
|
}
|
11
43
|
|
@@ -13,12 +45,20 @@ export const selectState = ({ state }) => {
|
|
13
45
|
return state;
|
14
46
|
}
|
15
47
|
|
16
|
-
export const
|
17
|
-
|
48
|
+
export const openOptionsPopover = (state, payload) => {
|
49
|
+
const { position } = payload;
|
50
|
+
state.position = position;
|
51
|
+
state.isOpen = true;
|
18
52
|
}
|
19
53
|
|
20
|
-
export const
|
21
|
-
|
54
|
+
export const closeOptionsPopover = (state) => {
|
55
|
+
state.isOpen = false;
|
56
|
+
}
|
57
|
+
|
58
|
+
export const selectOption = (state, option) => {
|
59
|
+
state.selectedValue = option.value;
|
60
|
+
state.selectedLabel = option.label;
|
61
|
+
state.isOpen = false;
|
22
62
|
}
|
23
63
|
|
24
64
|
|
@@ -7,32 +7,44 @@ propsSchema:
|
|
7
7
|
type: object
|
8
8
|
properties:
|
9
9
|
options:
|
10
|
-
items:
|
11
10
|
type: array
|
12
11
|
items:
|
13
12
|
type: object
|
14
13
|
properties:
|
15
14
|
id:
|
16
15
|
type: string
|
17
|
-
|
16
|
+
label:
|
18
17
|
type: string
|
19
18
|
value:
|
20
19
|
type: any
|
20
|
+
selectedValue:
|
21
|
+
type: any
|
22
|
+
placeholder:
|
23
|
+
type: string
|
24
|
+
onChange:
|
25
|
+
type: function
|
21
26
|
|
22
27
|
refs:
|
23
28
|
select-button:
|
24
29
|
eventListeners:
|
25
30
|
click:
|
26
31
|
handler: handleButtonClick
|
27
|
-
popover:
|
28
|
-
|
32
|
+
popover:
|
33
|
+
eventListeners:
|
34
|
+
click-overlay:
|
35
|
+
handler: handleClickOptionsPopoverOverlay
|
36
|
+
option-*:
|
37
|
+
eventListeners:
|
38
|
+
click:
|
39
|
+
handler: handleOptionClick
|
29
40
|
|
30
41
|
events: {}
|
31
42
|
|
32
43
|
template:
|
33
|
-
- rtgl-button#select-button v=ol:
|
34
|
-
|
35
|
-
|
44
|
+
- rtgl-button#select-button v=ol:
|
45
|
+
- ${selectedLabel}
|
46
|
+
- rtgl-popover#popover .isOpen=isOpen .position=position:
|
47
|
+
- rtgl-view wh=300 g=xs slot=content bgc=background br=md:
|
36
48
|
- $for option, i in options:
|
37
|
-
- rtgl-view w=f h-bgc=
|
49
|
+
- rtgl-view#option-${i} w=f h-bgc=ac ph=lg pv=md cur=p br=md bgc=${option.bgc}:
|
38
50
|
- rtgl-text: ${option.label}
|
@@ -6,30 +6,42 @@ const stringifyAttrs = (attrs) => {
|
|
6
6
|
return Object.entries(attrs).filter(([key]) => !blacklistedAttrs.includes(key)).map(([key, value]) => `${key}=${value}`).join(' ');
|
7
7
|
}
|
8
8
|
|
9
|
-
function flattenItems(items) {
|
9
|
+
function flattenItems(items, selectedItemId = null) {
|
10
10
|
let result = [];
|
11
11
|
|
12
12
|
for (const item of items) {
|
13
|
+
const itemId = item.id || item.href || item.path;
|
14
|
+
const isSelected = selectedItemId === itemId;
|
15
|
+
|
13
16
|
// Add the parent item if it's not just a group label
|
14
17
|
result.push({
|
15
|
-
id:
|
18
|
+
id: itemId,
|
16
19
|
title: item.title,
|
17
20
|
href: item.href,
|
18
21
|
type: item.type || 'item',
|
19
22
|
icon: item.icon,
|
20
23
|
hrefAttr: item.href ? `href=${item.href}` : '',
|
24
|
+
isSelected,
|
25
|
+
itemBgc: isSelected ? 'ac' : 'bg',
|
26
|
+
itemHoverBgc: isSelected ? 'ac' : 'mu',
|
21
27
|
});
|
22
28
|
|
23
29
|
// Add child items if they exist
|
24
30
|
if (item.items && Array.isArray(item.items)) {
|
25
31
|
for (const subItem of item.items) {
|
32
|
+
const subItemId = subItem.id || subItem.href || subItem.path;
|
33
|
+
const isSubSelected = selectedItemId === subItemId;
|
34
|
+
|
26
35
|
result.push({
|
27
|
-
id:
|
36
|
+
id: subItemId,
|
28
37
|
title: subItem.title,
|
29
38
|
href: subItem.href,
|
30
39
|
type: subItem.type || 'item',
|
31
40
|
icon: subItem.icon,
|
32
41
|
hrefAttr: subItem.href ? `href=${subItem.href}` : '',
|
42
|
+
isSelected: isSubSelected,
|
43
|
+
itemBgc: isSubSelected ? 'ac' : 'bg',
|
44
|
+
itemHoverBgc: isSubSelected ? 'ac' : 'mu',
|
33
45
|
});
|
34
46
|
}
|
35
47
|
}
|
@@ -41,6 +53,7 @@ function flattenItems(items) {
|
|
41
53
|
export const toViewData = ({ state, props, attrs }) => {
|
42
54
|
const attrsHeader = attrs.header ? JSON.parse(decodeURIComponent(attrs.header)) : props.header;
|
43
55
|
const attrsItems = attrs.items ? JSON.parse(decodeURIComponent(attrs.items)) : props.items;
|
56
|
+
const selectedItemId = attrs.selectedItemId || props.selectedItemId;
|
44
57
|
|
45
58
|
const containerAttrString = stringifyAttrs(attrs);
|
46
59
|
const mode = attrs.mode || 'full';
|
@@ -55,7 +68,7 @@ export const toViewData = ({ state, props, attrs }) => {
|
|
55
68
|
},
|
56
69
|
};
|
57
70
|
|
58
|
-
const items = attrsItems ? flattenItems(attrsItems) : [];
|
71
|
+
const items = attrsItems ? flattenItems(attrsItems, selectedItemId) : [];
|
59
72
|
|
60
73
|
// Computed values based on mode
|
61
74
|
const sidebarWidth = mode === 'full' ? 272 : 64;
|
@@ -100,7 +113,8 @@ export const toViewData = ({ state, props, attrs }) => {
|
|
100
113
|
itemContentAlign,
|
101
114
|
itemAlignAttr,
|
102
115
|
itemWidth,
|
103
|
-
headerWidth
|
116
|
+
headerWidth,
|
117
|
+
selectedItemId
|
104
118
|
};
|
105
119
|
}
|
106
120
|
|
@@ -37,6 +37,8 @@ viewDataSchema:
|
|
37
37
|
type: string
|
38
38
|
headerWidth:
|
39
39
|
type: string
|
40
|
+
selectedItemId:
|
41
|
+
type: string
|
40
42
|
header:
|
41
43
|
type: object
|
42
44
|
properties:
|
@@ -74,6 +76,8 @@ viewDataSchema:
|
|
74
76
|
propsSchema:
|
75
77
|
type: object
|
76
78
|
properties:
|
79
|
+
selectedItemId:
|
80
|
+
type: string
|
77
81
|
header:
|
78
82
|
type: object
|
79
83
|
properties:
|
@@ -170,7 +174,7 @@ template:
|
|
170
174
|
$else:
|
171
175
|
- rtgl-view mt=md h=1 bgc=mu-bg:
|
172
176
|
$else:
|
173
|
-
- rtgl-view#item-${item.id} ${item.hrefAttr} h=${itemHeight} av=c ${itemAlignAttr} ph=${itemPadding} w=${itemWidth} h-bgc
|
177
|
+
- rtgl-view#item-${item.id} ${item.hrefAttr} h=${itemHeight} av=c ${itemAlignAttr} ph=${itemPadding} w=${itemWidth} h-bgc=${item.itemHoverBgc} br=lg bgc=${item.itemBgc} cur=p title="${item.title}":
|
174
178
|
- $if item.icon:
|
175
179
|
- $if showLabels:
|
176
180
|
- rtgl-view d=h ah=${itemContentAlign} g=sm:
|
package/src/primitives/button.js
CHANGED
@@ -23,7 +23,7 @@ class RettangoliButtonElement extends HTMLElement {
|
|
23
23
|
flex-direction: row;
|
24
24
|
align-items: center;
|
25
25
|
justify-content: center;
|
26
|
-
gap: var(--spacing-
|
26
|
+
gap: var(--spacing-lg);
|
27
27
|
border-width: 0px;
|
28
28
|
border-style: solid;
|
29
29
|
border-color: var(--border);
|
@@ -124,6 +124,28 @@ class RettangoliButtonElement extends HTMLElement {
|
|
124
124
|
text-decoration: underline;
|
125
125
|
}
|
126
126
|
|
127
|
+
/* Square button styles */
|
128
|
+
:host([sq]) button {
|
129
|
+
width: 32px;
|
130
|
+
height: 32px;
|
131
|
+
padding: 0;
|
132
|
+
gap: 0;
|
133
|
+
}
|
134
|
+
|
135
|
+
:host([sq][s="sm"]) button {
|
136
|
+
width: 24px;
|
137
|
+
height: 24px;
|
138
|
+
padding: 0;
|
139
|
+
gap: 0;
|
140
|
+
}
|
141
|
+
|
142
|
+
:host([sq][s="lg"]) button {
|
143
|
+
width: 40px;
|
144
|
+
height: 40px;
|
145
|
+
padding: 0;
|
146
|
+
gap: 0;
|
147
|
+
}
|
148
|
+
|
127
149
|
${anchorStyles}
|
128
150
|
|
129
151
|
a {
|
@@ -152,7 +174,7 @@ class RettangoliButtonElement extends HTMLElement {
|
|
152
174
|
}
|
153
175
|
|
154
176
|
static get observedAttributes() {
|
155
|
-
return ["key", "href", "target", "w", "t", "icon", "disabled", "v", "s"];
|
177
|
+
return ["key", "href", "target", "w", "t", "icon", "disabled", "v", "s", "sq", "ip"];
|
156
178
|
}
|
157
179
|
|
158
180
|
connectedCallback() {
|
@@ -170,8 +192,10 @@ class RettangoliButtonElement extends HTMLElement {
|
|
170
192
|
// Update icon
|
171
193
|
this._updateIcon();
|
172
194
|
|
173
|
-
// Update width styling
|
174
|
-
this.
|
195
|
+
// Update width styling (skip for square buttons)
|
196
|
+
if (!this.hasAttribute('sq')) {
|
197
|
+
this._updateWidth();
|
198
|
+
}
|
175
199
|
|
176
200
|
// Update disabled state
|
177
201
|
const isDisabled = this.hasAttribute('disabled');
|
@@ -226,15 +250,34 @@ class RettangoliButtonElement extends HTMLElement {
|
|
226
250
|
lg: 22
|
227
251
|
};
|
228
252
|
const color = colorMap[this.getAttribute("v")] || 'pr-fg';
|
229
|
-
|
253
|
+
|
254
|
+
// For square buttons, use button size (s attribute), otherwise use icon size (t attribute)
|
255
|
+
let size = 18; // default
|
256
|
+
if (this.hasAttribute('sq')) {
|
257
|
+
const buttonSizeMap = {
|
258
|
+
sm: 14,
|
259
|
+
lg: 22
|
260
|
+
};
|
261
|
+
const buttonSize = this.getAttribute("s");
|
262
|
+
size = buttonSizeMap[buttonSize] || 18;
|
263
|
+
} else {
|
264
|
+
size = sizeMap[this.getAttribute("t")] || 18;
|
265
|
+
}
|
230
266
|
|
231
267
|
this._iconElement = document.createElement('rtgl-svg');
|
232
268
|
this._iconElement.setAttribute('svg', icon);
|
233
269
|
this._iconElement.setAttribute('c', color);
|
234
270
|
this._iconElement.setAttribute('wh', size.toString());
|
235
271
|
|
236
|
-
// Insert icon
|
237
|
-
this.
|
272
|
+
// Insert icon based on position (default is right, 's' means start/left)
|
273
|
+
const iconPosition = this.getAttribute("ip");
|
274
|
+
if (iconPosition === 's') {
|
275
|
+
// Insert icon before slot (left position)
|
276
|
+
this._buttonElement.insertBefore(this._iconElement, this._slotElement);
|
277
|
+
} else {
|
278
|
+
// Insert icon after slot (right position - default)
|
279
|
+
this._buttonElement.appendChild(this._iconElement);
|
280
|
+
}
|
238
281
|
}
|
239
282
|
}
|
240
283
|
|
package/src/primitives/view.js
CHANGED
@@ -83,6 +83,7 @@ class RettangoliViewElement extends HTMLElement {
|
|
83
83
|
return [
|
84
84
|
"href",
|
85
85
|
"target",
|
86
|
+
"op",
|
86
87
|
...permutateBreakpoints([
|
87
88
|
...styleMapKeys,
|
88
89
|
"wh",
|
@@ -141,6 +142,7 @@ class RettangoliViewElement extends HTMLElement {
|
|
141
142
|
this._updateDOM();
|
142
143
|
return;
|
143
144
|
}
|
145
|
+
|
144
146
|
// Reset styles for fresh calculation
|
145
147
|
this._styles = {
|
146
148
|
default: {},
|