@rettangoli/ui 0.1.2-rc9 → 0.1.3
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 +128 -56
- package/dist/rettangoli-iife-ui.min.js +187 -66
- package/package.json +3 -2
- package/src/common.js +30 -2
- 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 +6 -6
- package/src/components/dropdownMenu/dropdownMenu.store.js +6 -18
- package/src/components/dropdownMenu/dropdownMenu.view.yaml +15 -13
- package/src/components/form/form.handlers.js +170 -33
- package/src/components/form/form.store.js +175 -21
- package/src/components/form/form.view.yaml +182 -27
- package/src/components/globalUi/globalUi.handlers.js +51 -0
- package/src/components/globalUi/globalUi.store.js +57 -0
- package/src/components/globalUi/globalUi.view.yaml +50 -0
- package/src/components/navbar/navbar.handlers.js +1 -1
- package/src/components/navbar/navbar.store.js +2 -2
- package/src/components/pageOutline/pageOutline.handlers.js +57 -17
- package/src/components/pageOutline/pageOutline.store.js +48 -3
- package/src/components/pageOutline/pageOutline.view.yaml +7 -5
- 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 +120 -12
- package/src/components/select/select.store.js +86 -20
- package/src/components/select/select.view.yaml +40 -10
- package/src/components/sidebar/sidebar.handlers.js +6 -6
- package/src/components/sidebar/sidebar.store.js +6 -6
- package/src/components/sidebar/sidebar.view.yaml +1 -1
- package/src/components/sliderInput/sliderInput.handlers.js +23 -6
- package/src/components/sliderInput/sliderInput.store.js +3 -2
- package/src/components/sliderInput/sliderInput.view.yaml +3 -2
- package/src/components/table/table.handlers.js +10 -10
- package/src/components/table/table.store.js +4 -4
- 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/tooltip/tooltip.handlers.js +0 -0
- package/src/components/tooltip/tooltip.store.js +12 -0
- package/src/components/tooltip/tooltip.view.yaml +27 -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/deps/createGlobalUI.js +39 -0
- package/src/entry-iife-layout.js +3 -0
- package/src/entry-iife-ui.js +4 -0
- package/src/index.js +7 -1
- package/src/primitives/button.js +10 -0
- package/src/primitives/colorPicker.js +13 -4
- package/src/primitives/dialog.js +254 -0
- package/src/primitives/image.js +4 -3
- package/src/primitives/input.js +17 -4
- package/src/primitives/popover.js +280 -0
- package/src/primitives/slider.js +14 -4
- package/src/primitives/svg.js +2 -0
- package/src/primitives/textarea.js +25 -1
- package/src/primitives/view.js +132 -13
- package/src/setup.js +7 -2
- package/src/styles/cursorStyles.js +38 -2
- 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 -48
- 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
|
@@ -1,43 +1,82 @@
|
|
|
1
|
-
|
|
1
|
+
import { deepEqual } from '../../common.js';
|
|
2
|
+
|
|
3
|
+
// Attributes that should not be passed through to the container
|
|
4
|
+
// These are either handled internally or have special meaning
|
|
5
|
+
const blacklistedAttrs = [
|
|
6
|
+
"id",
|
|
7
|
+
"class",
|
|
8
|
+
"style",
|
|
9
|
+
"slot",
|
|
10
|
+
// Select-specific props that are handled separately
|
|
11
|
+
"placeholder",
|
|
12
|
+
"selectedValue",
|
|
13
|
+
"selected-value",
|
|
14
|
+
"onChange",
|
|
15
|
+
"on-change",
|
|
16
|
+
"options"
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
const stringifyAttrs = (attrs) => {
|
|
20
|
+
return Object.entries(attrs || {})
|
|
21
|
+
.filter(([key]) => !blacklistedAttrs.includes(key))
|
|
22
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
23
|
+
.join(" ");
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const createInitialState = () => Object.freeze({
|
|
2
27
|
isOpen: false,
|
|
3
28
|
position: {
|
|
4
29
|
x: 0,
|
|
5
30
|
y: 0,
|
|
6
31
|
},
|
|
7
32
|
selectedValue: null,
|
|
8
|
-
|
|
33
|
+
hoveredOptionId: null,
|
|
34
|
+
hoveredAddOption: false,
|
|
9
35
|
});
|
|
10
36
|
|
|
11
|
-
export const
|
|
12
|
-
//
|
|
13
|
-
|
|
14
|
-
|
|
37
|
+
export const selectViewData = ({ state, props, attrs }) => {
|
|
38
|
+
// Generate container attribute string
|
|
39
|
+
const containerAttrString = stringifyAttrs(attrs);
|
|
40
|
+
|
|
15
41
|
// Use state's selected value if available, otherwise use props.selectedValue
|
|
16
42
|
const currentValue = state.selectedValue !== null ? state.selectedValue : props.selectedValue;
|
|
17
|
-
|
|
43
|
+
|
|
44
|
+
// Calculate display label from value
|
|
45
|
+
let displayLabel = props.placeholder || 'Select an option';
|
|
46
|
+
let isPlaceholderLabel = true;
|
|
18
47
|
if (currentValue !== null && currentValue !== undefined && props.options) {
|
|
19
|
-
const selectedOption = props.options.find(opt => opt.value
|
|
48
|
+
const selectedOption = props.options.find(opt => deepEqual(opt.value, currentValue));
|
|
20
49
|
if (selectedOption) {
|
|
21
50
|
displayLabel = selectedOption.label;
|
|
51
|
+
isPlaceholderLabel = false;
|
|
22
52
|
}
|
|
23
|
-
} else if (state.selectedLabel) {
|
|
24
|
-
displayLabel = state.selectedLabel;
|
|
25
53
|
}
|
|
26
|
-
|
|
54
|
+
|
|
27
55
|
// Map options to include isSelected flag and computed background color
|
|
28
|
-
const optionsWithSelection = (props.options || []).map(option =>
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
56
|
+
const optionsWithSelection = (props.options || []).map((option, index) => {
|
|
57
|
+
const isSelected = deepEqual(option.value, currentValue);
|
|
58
|
+
const isHovered = state.hoveredOptionId === index;
|
|
59
|
+
return {
|
|
60
|
+
...option,
|
|
61
|
+
isSelected,
|
|
62
|
+
bgc: isHovered ? 'ac' : (isSelected ? 'mu' : '')
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
|
|
34
66
|
return {
|
|
67
|
+
containerAttrString,
|
|
35
68
|
isOpen: state.isOpen,
|
|
36
69
|
position: state.position,
|
|
37
70
|
options: optionsWithSelection,
|
|
38
71
|
selectedValue: currentValue,
|
|
39
72
|
selectedLabel: displayLabel,
|
|
40
|
-
|
|
73
|
+
selectedLabelColor: isPlaceholderLabel ? "mu-fg" : "fg",
|
|
74
|
+
placeholder: props.placeholder || 'Select an option',
|
|
75
|
+
hasValue: currentValue !== null && currentValue !== undefined,
|
|
76
|
+
showClear: !attrs['no-clear'] && !props['no-clear'] && (currentValue !== null && currentValue !== undefined),
|
|
77
|
+
showAddOption: !!props.addOption,
|
|
78
|
+
addOptionLabel: props.addOption?.label ? `+ ${props.addOption.label}` : '+ Add',
|
|
79
|
+
addOptionBgc: state.hoveredAddOption ? 'ac' : ''
|
|
41
80
|
};
|
|
42
81
|
}
|
|
43
82
|
|
|
@@ -45,10 +84,18 @@ export const selectState = ({ state }) => {
|
|
|
45
84
|
return state;
|
|
46
85
|
}
|
|
47
86
|
|
|
87
|
+
export const selectSelectedValue = ({ state }) => {
|
|
88
|
+
return state.selectedValue;
|
|
89
|
+
}
|
|
90
|
+
|
|
48
91
|
export const openOptionsPopover = (state, payload) => {
|
|
49
|
-
const { position } = payload;
|
|
92
|
+
const { position, selectedIndex } = payload;
|
|
50
93
|
state.position = position;
|
|
51
94
|
state.isOpen = true;
|
|
95
|
+
// Set hoveredOptionId to the selected option's index if available
|
|
96
|
+
if (selectedIndex !== undefined && selectedIndex !== null) {
|
|
97
|
+
state.hoveredOptionId = selectedIndex;
|
|
98
|
+
}
|
|
52
99
|
}
|
|
53
100
|
|
|
54
101
|
export const closeOptionsPopover = (state) => {
|
|
@@ -57,9 +104,28 @@ export const closeOptionsPopover = (state) => {
|
|
|
57
104
|
|
|
58
105
|
export const updateSelectOption = (state, option) => {
|
|
59
106
|
state.selectedValue = option.value;
|
|
60
|
-
state.selectedLabel = option.label;
|
|
61
107
|
state.isOpen = false;
|
|
62
108
|
}
|
|
63
109
|
|
|
110
|
+
export const resetSelection = (state) => {
|
|
111
|
+
state.selectedValue = undefined;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export const setHoveredOption = (state, optionId) => {
|
|
115
|
+
state.hoveredOptionId = optionId;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export const clearHoveredOption = (state) => {
|
|
119
|
+
state.hoveredOptionId = null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export const clearSelectedValue = (state) => {
|
|
123
|
+
state.selectedValue = undefined;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export const setHoveredAddOption = (state, isHovered) => {
|
|
127
|
+
state.hoveredAddOption = isHovered;
|
|
128
|
+
}
|
|
129
|
+
|
|
64
130
|
|
|
65
131
|
|
|
@@ -11,8 +11,6 @@ propsSchema:
|
|
|
11
11
|
items:
|
|
12
12
|
type: object
|
|
13
13
|
properties:
|
|
14
|
-
id:
|
|
15
|
-
type: string
|
|
16
14
|
label:
|
|
17
15
|
type: string
|
|
18
16
|
value:
|
|
@@ -23,28 +21,60 @@ propsSchema:
|
|
|
23
21
|
type: string
|
|
24
22
|
onChange:
|
|
25
23
|
type: function
|
|
24
|
+
no-clear:
|
|
25
|
+
type: boolean
|
|
26
|
+
addOption:
|
|
27
|
+
type: object
|
|
28
|
+
properties:
|
|
29
|
+
label:
|
|
30
|
+
type: string
|
|
26
31
|
|
|
27
32
|
refs:
|
|
28
33
|
select-button:
|
|
29
34
|
eventListeners:
|
|
30
35
|
click:
|
|
31
36
|
handler: handleButtonClick
|
|
37
|
+
clear-button:
|
|
38
|
+
eventListeners:
|
|
39
|
+
click:
|
|
40
|
+
handler: handleClearClick
|
|
32
41
|
popover:
|
|
33
42
|
eventListeners:
|
|
34
|
-
|
|
43
|
+
close:
|
|
35
44
|
handler: handleClickOptionsPopoverOverlay
|
|
36
45
|
option-*:
|
|
37
46
|
eventListeners:
|
|
38
47
|
click:
|
|
39
48
|
handler: handleOptionClick
|
|
49
|
+
mouseenter:
|
|
50
|
+
handler: handleOptionMouseEnter
|
|
51
|
+
mouseleave:
|
|
52
|
+
handler: handleOptionMouseLeave
|
|
53
|
+
option-add:
|
|
54
|
+
eventListeners:
|
|
55
|
+
click:
|
|
56
|
+
handler: handleAddOptionClick
|
|
57
|
+
mouseenter:
|
|
58
|
+
handler: handleAddOptionMouseEnter
|
|
59
|
+
mouseleave:
|
|
60
|
+
handler: handleAddOptionMouseLeave
|
|
40
61
|
|
|
41
62
|
events: {}
|
|
42
63
|
|
|
43
64
|
template:
|
|
44
|
-
- rtgl-button#select-button v=ol:
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
- rtgl-
|
|
65
|
+
- rtgl-button#select-button v=ol ${containerAttrString}:
|
|
66
|
+
- rtgl-view d=h av=c w=f:
|
|
67
|
+
- rtgl-text c=${selectedLabelColor}: ${selectedLabel}
|
|
68
|
+
- rtgl-view mh=md flex=1:
|
|
69
|
+
- $if showClear:
|
|
70
|
+
- rtgl-svg#clear-button mr=md svg=x wh=16 c=mu-fg cur=p:
|
|
71
|
+
- rtgl-svg svg=chevronDown wh=16 c=mu-fg:
|
|
72
|
+
- rtgl-popover#popover ?open=${isOpen} x=${position.x} y=${position.y} placement=right-start:
|
|
73
|
+
- rtgl-view wh=300 g=xs slot=content bgc=background br=md sv=true:
|
|
74
|
+
- $for option, i in options:
|
|
75
|
+
- rtgl-view#option-${i} w=f ph=lg pv=md cur=p br=md bgc=${option.bgc}:
|
|
76
|
+
- rtgl-text: ${option.label}
|
|
77
|
+
- $if showAddOption:
|
|
78
|
+
- rtgl-view w=f bw=xs bc=mu-bg bt=sm:
|
|
79
|
+
- rtgl-view#option-add w=f ph=lg pv=md cur=p br=md bgc=${addOptionBgc}:
|
|
80
|
+
- rtgl-text c=ac: ${addOptionLabel}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
export const handleHeaderClick = (
|
|
1
|
+
export const handleHeaderClick = (deps, event) => {
|
|
2
2
|
const { store, dispatchEvent } = deps;
|
|
3
3
|
|
|
4
4
|
let path;
|
|
5
5
|
|
|
6
6
|
const header = store.selectHeader();
|
|
7
7
|
|
|
8
|
-
if (
|
|
8
|
+
if (event.currentTarget.id === 'header-label') {
|
|
9
9
|
path = header.labelPath;
|
|
10
|
-
} else if (
|
|
10
|
+
} else if (event.currentTarget.id === 'header-image') {
|
|
11
11
|
path = header.image.path;
|
|
12
|
-
} else if (
|
|
12
|
+
} else if (event.currentTarget.id === 'header') {
|
|
13
13
|
path = header.path;
|
|
14
14
|
}
|
|
15
15
|
|
|
@@ -22,9 +22,9 @@ export const handleHeaderClick = (e, deps) => {
|
|
|
22
22
|
}));
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
export const handleItemClick = (
|
|
25
|
+
export const handleItemClick = (deps, event) => {
|
|
26
26
|
const { store, dispatchEvent } = deps;
|
|
27
|
-
const id =
|
|
27
|
+
const id = event.currentTarget.id.replace('item-', '');
|
|
28
28
|
const item = store.selectItem(id);
|
|
29
29
|
dispatchEvent(new CustomEvent('itemClick', {
|
|
30
30
|
detail: {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const
|
|
1
|
+
export const createInitialState = () => Object.freeze({});
|
|
2
2
|
|
|
3
3
|
const blacklistedAttrs = ['id', 'class', 'style', 'slot'];
|
|
4
4
|
|
|
@@ -50,7 +50,7 @@ function flattenItems(items, selectedItemId = null) {
|
|
|
50
50
|
return result;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
export const
|
|
53
|
+
export const selectViewData = ({ state, props, attrs }) => {
|
|
54
54
|
const attrsHeader = attrs.header ? JSON.parse(decodeURIComponent(attrs.header)) : props.header;
|
|
55
55
|
const attrsItems = attrs.items ? JSON.parse(decodeURIComponent(attrs.items)) : props.items;
|
|
56
56
|
const selectedItemId = attrs.selectedItemId || props.selectedItemId;
|
|
@@ -81,17 +81,17 @@ export const toViewData = ({ state, props, attrs }) => {
|
|
|
81
81
|
const firstLetterSize = mode === 'shrunk-lg' ? 'md' : 'sm';
|
|
82
82
|
const showLabels = mode === 'full';
|
|
83
83
|
const showGroupLabels = mode === 'full';
|
|
84
|
-
|
|
84
|
+
|
|
85
85
|
// For items with icons in full mode, we need left alignment within the container
|
|
86
86
|
// but the container itself should use flex-start alignment
|
|
87
87
|
const itemContentAlign = mode === 'full' ? 'fs' : 'c';
|
|
88
|
-
|
|
88
|
+
|
|
89
89
|
// Item container alignment - only set for shrunk modes, leave default for full mode
|
|
90
90
|
const itemAlignAttr = mode === 'full' ? '' : `ah=${itemAlign}`;
|
|
91
|
-
|
|
91
|
+
|
|
92
92
|
// Item width - for shrunk modes, make it square to constrain the highlight
|
|
93
93
|
const itemWidth = mode === 'full' ? 'f' : itemHeight;
|
|
94
|
-
|
|
94
|
+
|
|
95
95
|
// Header width - should match item width for alignment
|
|
96
96
|
const headerWidth = itemWidth;
|
|
97
97
|
|
|
@@ -174,7 +174,7 @@ template:
|
|
|
174
174
|
$else:
|
|
175
175
|
- rtgl-view mt=md h=1 bgc=mu-bg:
|
|
176
176
|
$else:
|
|
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
|
|
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:
|
|
178
178
|
- $if item.icon:
|
|
179
179
|
- $if showLabels:
|
|
180
180
|
- rtgl-view d=h ah=${itemContentAlign} g=sm:
|
|
@@ -1,17 +1,34 @@
|
|
|
1
|
-
export const
|
|
1
|
+
export const handleBeforeMount = (deps) => {
|
|
2
2
|
const { store, attrs } = deps;
|
|
3
3
|
store.setValue(attrs.defaultValue || 0);
|
|
4
|
-
}
|
|
4
|
+
}
|
|
5
5
|
|
|
6
|
-
export const
|
|
6
|
+
export const handleOnUpdate = (changes, deps) => {
|
|
7
|
+
const { oldAttrs, newAttrs } = changes;
|
|
8
|
+
const { store, render, attrs } = deps;
|
|
9
|
+
|
|
10
|
+
// Reset when key changes
|
|
11
|
+
if (oldAttrs?.key !== newAttrs?.key && newAttrs?.key) {
|
|
12
|
+
const defaultValue = newAttrs?.defaultValue || attrs?.defaultValue || 0;
|
|
13
|
+
store.setValue(defaultValue);
|
|
14
|
+
render();
|
|
15
|
+
} else if (oldAttrs?.defaultValue !== newAttrs?.defaultValue) {
|
|
16
|
+
// Also reset when defaultValue changes
|
|
17
|
+
const defaultValue = newAttrs?.defaultValue || 0;
|
|
18
|
+
store.setValue(defaultValue);
|
|
19
|
+
render();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const handleValueChange = (deps, event) => {
|
|
7
24
|
const { store, render, dispatchEvent } = deps;
|
|
8
|
-
const newValue = Number(
|
|
25
|
+
const newValue = Number(event.detail.value);
|
|
9
26
|
|
|
10
27
|
store.setValue(newValue);
|
|
11
|
-
|
|
28
|
+
|
|
12
29
|
// Re-render to sync slider and input
|
|
13
30
|
render();
|
|
14
|
-
|
|
31
|
+
|
|
15
32
|
// Dispatch event for external listeners
|
|
16
33
|
dispatchEvent(
|
|
17
34
|
new CustomEvent("slider-input-value-change", {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
export const
|
|
1
|
+
export const createInitialState = () => Object.freeze({
|
|
2
2
|
value: 0
|
|
3
3
|
});
|
|
4
4
|
|
|
5
|
-
export const
|
|
5
|
+
export const selectViewData = ({ state, attrs }) => {
|
|
6
6
|
return {
|
|
7
|
+
key: attrs.key,
|
|
7
8
|
value: state.value,
|
|
8
9
|
w: attrs.w || '',
|
|
9
10
|
min: attrs.min || 0,
|
|
@@ -37,5 +37,6 @@ events:
|
|
|
37
37
|
|
|
38
38
|
template:
|
|
39
39
|
- rtgl-view d=h av=c g=md w=${w}:
|
|
40
|
-
- rtgl-slider#slider w=
|
|
41
|
-
- rtgl-
|
|
40
|
+
- rtgl-slider#slider key=${key} w=f type=range min=${min} max=${max} step=${step} value=${value}:
|
|
41
|
+
- rtgl-view w=84:
|
|
42
|
+
- rtgl-input#input key=${key} w=f type=number min=${min} max=${max} step=${step} value=${value}:
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
export const
|
|
1
|
+
export const handleBeforeMount = (deps) => {
|
|
2
2
|
// No special initialization needed for basic table
|
|
3
3
|
};
|
|
4
4
|
|
|
5
|
-
export const handleRowClick = (
|
|
5
|
+
export const handleRowClick = (deps, event) => {
|
|
6
6
|
const { dispatchEvent, props } = deps;
|
|
7
|
-
const rowIndex = parseInt(
|
|
7
|
+
const rowIndex = parseInt(event.currentTarget.id.replace("row-", ""));
|
|
8
8
|
const rowData = props.data?.rows?.[rowIndex];
|
|
9
|
-
|
|
9
|
+
|
|
10
10
|
if (rowData) {
|
|
11
11
|
dispatchEvent(
|
|
12
12
|
new CustomEvent("row-click", {
|
|
@@ -19,11 +19,11 @@ export const handleRowClick = (e, deps) => {
|
|
|
19
19
|
}
|
|
20
20
|
};
|
|
21
21
|
|
|
22
|
-
export const handleHeaderClick = (
|
|
22
|
+
export const handleHeaderClick = (deps, event) => {
|
|
23
23
|
const { store, render, dispatchEvent } = deps;
|
|
24
|
-
const columnKey =
|
|
24
|
+
const columnKey = event.currentTarget.id.replace("header-", "");
|
|
25
25
|
const currentSort = store.selectSortInfo();
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
// Determine new sort direction
|
|
28
28
|
let newDirection = 'asc';
|
|
29
29
|
if (currentSort.column === columnKey) {
|
|
@@ -33,15 +33,15 @@ export const handleHeaderClick = (e, deps) => {
|
|
|
33
33
|
newDirection = null; // Clear sort
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
|
-
|
|
36
|
+
|
|
37
37
|
if (newDirection) {
|
|
38
38
|
store.setSortColumn({ column: columnKey, direction: newDirection });
|
|
39
39
|
} else {
|
|
40
40
|
store.clearSort();
|
|
41
41
|
}
|
|
42
|
-
|
|
42
|
+
|
|
43
43
|
render();
|
|
44
|
-
|
|
44
|
+
|
|
45
45
|
// Dispatch custom event for external handling
|
|
46
46
|
dispatchEvent(
|
|
47
47
|
new CustomEvent("header-click", {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const
|
|
1
|
+
export const createInitialState = () => Object.freeze({
|
|
2
2
|
sortColumn: null,
|
|
3
3
|
sortDirection: null,
|
|
4
4
|
});
|
|
@@ -23,10 +23,10 @@ const getNestedValue = (obj, path) => {
|
|
|
23
23
|
return result;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
export const
|
|
26
|
+
export const selectViewData = ({ state, props, attrs }) => {
|
|
27
27
|
const containerAttrString = stringifyAttrs(attrs);
|
|
28
28
|
const data = props.data || { columns: [], rows: [] };
|
|
29
|
-
|
|
29
|
+
|
|
30
30
|
// Transform rows to create cells array for easier template access
|
|
31
31
|
const transformedRows = data.rows.map((row, rowIndex) => {
|
|
32
32
|
const cells = data.columns.map(column => {
|
|
@@ -36,7 +36,7 @@ export const toViewData = ({ state, props, attrs }) => {
|
|
|
36
36
|
value: value !== null && value !== undefined ? String(value) : ''
|
|
37
37
|
};
|
|
38
38
|
});
|
|
39
|
-
|
|
39
|
+
|
|
40
40
|
return {
|
|
41
41
|
index: rowIndex,
|
|
42
42
|
cells: cells
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export const createInitialState = () => Object.freeze({});
|
|
2
|
+
|
|
3
|
+
const blacklistedAttrs = ['id', 'class', 'style', 'slot'];
|
|
4
|
+
|
|
5
|
+
const stringifyAttrs = (attrs) => {
|
|
6
|
+
return Object.entries(attrs).filter(([key]) => !blacklistedAttrs.includes(key)).map(([key, value]) => `${key}=${value}`).join(' ');
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const selectViewData = ({ state, props, attrs }) => {
|
|
10
|
+
const containerAttrString = stringifyAttrs(attrs);
|
|
11
|
+
|
|
12
|
+
const items = props.items || [];
|
|
13
|
+
const selectedTab = attrs['selected-tab'];
|
|
14
|
+
|
|
15
|
+
// Mark selected tab with styling
|
|
16
|
+
const itemsWithSelection = items.map(item => ({
|
|
17
|
+
...item,
|
|
18
|
+
isSelected: item.id === selectedTab,
|
|
19
|
+
bgColor: item.id === selectedTab ? 'ac' : '',
|
|
20
|
+
borderColor: item.id === selectedTab ? '' : 'tr',
|
|
21
|
+
textColor: item.id === selectedTab ? '' : 'mu-fg'
|
|
22
|
+
}));
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
containerAttrString,
|
|
26
|
+
items: itemsWithSelection,
|
|
27
|
+
selectedTab
|
|
28
|
+
};
|
|
29
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
elementName: rtgl-tabs
|
|
2
|
+
|
|
3
|
+
viewDataSchema:
|
|
4
|
+
type: object
|
|
5
|
+
properties:
|
|
6
|
+
containerAttrString:
|
|
7
|
+
type: string
|
|
8
|
+
items:
|
|
9
|
+
type: array
|
|
10
|
+
items:
|
|
11
|
+
type: object
|
|
12
|
+
properties:
|
|
13
|
+
label:
|
|
14
|
+
type: string
|
|
15
|
+
id:
|
|
16
|
+
type: string
|
|
17
|
+
isSelected:
|
|
18
|
+
type: boolean
|
|
19
|
+
bgColor:
|
|
20
|
+
type: string
|
|
21
|
+
textColor:
|
|
22
|
+
type: string
|
|
23
|
+
borderColor:
|
|
24
|
+
type: string
|
|
25
|
+
selectedTab:
|
|
26
|
+
type: string
|
|
27
|
+
|
|
28
|
+
propsSchema:
|
|
29
|
+
type: object
|
|
30
|
+
properties:
|
|
31
|
+
items:
|
|
32
|
+
type: array
|
|
33
|
+
items:
|
|
34
|
+
type: object
|
|
35
|
+
properties:
|
|
36
|
+
label:
|
|
37
|
+
type: string
|
|
38
|
+
id:
|
|
39
|
+
type: string
|
|
40
|
+
|
|
41
|
+
attrsSchema:
|
|
42
|
+
type: object
|
|
43
|
+
properties:
|
|
44
|
+
selected-tab:
|
|
45
|
+
type: string
|
|
46
|
+
|
|
47
|
+
refs:
|
|
48
|
+
tab-*:
|
|
49
|
+
eventListeners:
|
|
50
|
+
click:
|
|
51
|
+
handler: handleClickItem
|
|
52
|
+
|
|
53
|
+
events:
|
|
54
|
+
item-click:
|
|
55
|
+
type: object
|
|
56
|
+
properties:
|
|
57
|
+
id:
|
|
58
|
+
type: string
|
|
59
|
+
|
|
60
|
+
template:
|
|
61
|
+
- rtgl-view d=h g=sm bgc=mu p=sm br=lg ${containerAttrString}:
|
|
62
|
+
- $for item in items:
|
|
63
|
+
- rtgl-view#tab-${item.id} data-id=${item.id} cur=p bgc=${item.bgColor} bw=xs bc=${item.borderColor} pv=md ph=lg br=lg:
|
|
64
|
+
- rtgl-text s=sm c=${item.textColor}: "${item.label}"
|
|
File without changes
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export const createInitialState = () => Object.freeze({
|
|
2
|
+
});
|
|
3
|
+
|
|
4
|
+
export const selectViewData = ({ attrs }) => {
|
|
5
|
+
return {
|
|
6
|
+
open: !!attrs.open,
|
|
7
|
+
x: attrs.x || 0,
|
|
8
|
+
y: attrs.y || 0,
|
|
9
|
+
placement: attrs.placement || 'top',
|
|
10
|
+
content: attrs.content || ''
|
|
11
|
+
};
|
|
12
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
elementName: rtgl-tooltip
|
|
2
|
+
|
|
3
|
+
viewDataSchema:
|
|
4
|
+
type: object
|
|
5
|
+
|
|
6
|
+
attrsSchema:
|
|
7
|
+
type: object
|
|
8
|
+
properties:
|
|
9
|
+
open:
|
|
10
|
+
type: string
|
|
11
|
+
x:
|
|
12
|
+
type: string
|
|
13
|
+
y:
|
|
14
|
+
type: string
|
|
15
|
+
placement:
|
|
16
|
+
type: string
|
|
17
|
+
content:
|
|
18
|
+
type: string
|
|
19
|
+
|
|
20
|
+
refs:
|
|
21
|
+
popover:
|
|
22
|
+
|
|
23
|
+
template:
|
|
24
|
+
- rtgl-popover#popover ?open=${open} x=${x} y=${y} placement=${placement} no-overlay:
|
|
25
|
+
- rtgl-view slot=content bgc=background bc=border br=md p=sm ah=c av=c:
|
|
26
|
+
- rtgl-text ta=c s=sm c=foreground: ${content}
|
|
27
|
+
|