@rettangoli/ui 0.1.2-rc8 → 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 +5 -3
- package/src/cli/buildSvg.js +86 -0
- package/src/cli/index.js +1 -0
- 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
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
/**
|
|
4
4
|
*
|
|
5
5
|
* @param {*} headingElements
|
|
6
|
+
* @param {*} offsetTop
|
|
6
7
|
* @param {*} deps
|
|
7
8
|
*/
|
|
8
|
-
const updateToLatestCurrentId = (headingElements, deps) => {
|
|
9
|
+
const updateToLatestCurrentId = (headingElements, offsetTop, deps) => {
|
|
9
10
|
const { store, render } = deps;
|
|
10
11
|
|
|
11
12
|
let currentHeadingId;
|
|
@@ -14,7 +15,9 @@ const updateToLatestCurrentId = (headingElements, deps) => {
|
|
|
14
15
|
headingElements.forEach((heading) => {
|
|
15
16
|
const rect = heading.getBoundingClientRect();
|
|
16
17
|
|
|
17
|
-
if
|
|
18
|
+
// A heading is "current" if it's at or above the offset line
|
|
19
|
+
// We want the heading that's closest to the offset but still above it
|
|
20
|
+
if (rect.top <= offsetTop) {
|
|
18
21
|
if (rect.top > closestTopPosition) {
|
|
19
22
|
closestTopPosition = rect.top;
|
|
20
23
|
currentHeadingId = heading.id;
|
|
@@ -22,46 +25,83 @@ const updateToLatestCurrentId = (headingElements, deps) => {
|
|
|
22
25
|
}
|
|
23
26
|
});
|
|
24
27
|
|
|
28
|
+
// If no heading is above the threshold, select the first visible heading below it
|
|
29
|
+
if (!currentHeadingId) {
|
|
30
|
+
let lowestTop = Infinity;
|
|
31
|
+
headingElements.forEach((heading) => {
|
|
32
|
+
const rect = heading.getBoundingClientRect();
|
|
33
|
+
if (rect.top > offsetTop && rect.top < lowestTop) {
|
|
34
|
+
lowestTop = rect.top;
|
|
35
|
+
currentHeadingId = heading.id;
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
25
40
|
if (currentHeadingId && currentHeadingId !== store.selectCurrentId()) {
|
|
26
41
|
store.setCurrentId(currentHeadingId);
|
|
27
42
|
render();
|
|
28
43
|
}
|
|
29
44
|
};
|
|
30
45
|
|
|
31
|
-
const startListening = (contentContainer, deps) => {
|
|
46
|
+
const startListening = (contentContainer, scrollContainer, offsetTop, deps) => {
|
|
32
47
|
const { store, render } = deps;
|
|
33
48
|
|
|
34
49
|
// Extract headings
|
|
35
|
-
const headings = contentContainer.querySelectorAll("rtgl-text[id]");
|
|
50
|
+
const headings = contentContainer.querySelectorAll("h1[id], h2[id], h3[id], h4[id], rtgl-text[id]");
|
|
36
51
|
const headingElements = Array.from(headings);
|
|
37
52
|
|
|
38
|
-
const items = headingElements.map((heading) =>
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
53
|
+
const items = headingElements.map((heading) => {
|
|
54
|
+
let level = 1;
|
|
55
|
+
const tagName = heading.tagName.toLowerCase();
|
|
56
|
+
|
|
57
|
+
if (tagName === 'h1') level = 1;
|
|
58
|
+
else if (tagName === 'h2') level = 2;
|
|
59
|
+
else if (tagName === 'h3') level = 3;
|
|
60
|
+
else if (tagName === 'h4') level = 4;
|
|
61
|
+
else if (tagName === 'rtgl-text') {
|
|
62
|
+
// For rtgl-text, check if it has a data-level attribute or default to 1
|
|
63
|
+
level = parseInt(heading.getAttribute('data-level') || '1', 10);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
id: heading.id,
|
|
68
|
+
href: `#${heading.id}`,
|
|
69
|
+
title: heading.textContent,
|
|
70
|
+
level: level
|
|
71
|
+
};
|
|
72
|
+
});
|
|
43
73
|
|
|
44
74
|
store.setItems(items);
|
|
45
|
-
updateToLatestCurrentId(headingElements, deps);
|
|
75
|
+
updateToLatestCurrentId(headingElements, offsetTop, deps);
|
|
46
76
|
render();
|
|
47
77
|
|
|
48
|
-
const boundCheckCurrentHeading = updateToLatestCurrentId.bind(this, headingElements, deps);
|
|
78
|
+
const boundCheckCurrentHeading = updateToLatestCurrentId.bind(this, headingElements, offsetTop, deps);
|
|
49
79
|
|
|
50
|
-
// Add scroll listener to the
|
|
51
|
-
|
|
80
|
+
// Add scroll listener to the scroll container
|
|
81
|
+
scrollContainer.addEventListener("scroll", boundCheckCurrentHeading, {
|
|
52
82
|
passive: true,
|
|
53
83
|
});
|
|
54
84
|
|
|
55
85
|
return () => {
|
|
56
|
-
|
|
86
|
+
scrollContainer.removeEventListener("scroll", boundCheckCurrentHeading);
|
|
57
87
|
}
|
|
58
88
|
};
|
|
59
89
|
|
|
60
|
-
export const
|
|
90
|
+
export const handleBeforeMount = (deps) => {
|
|
61
91
|
const { attrs } = deps;
|
|
62
92
|
requestAnimationFrame(() => {
|
|
63
|
-
const targetElement = document.getElementById(attrs['target-id'])
|
|
64
|
-
|
|
93
|
+
const targetElement = document.getElementById(attrs['target-id']);
|
|
94
|
+
|
|
95
|
+
// Get scroll container - default to window for page scroll if not specified
|
|
96
|
+
let scrollContainer = window;
|
|
97
|
+
if (attrs['scroll-container-id']) {
|
|
98
|
+
scrollContainer = document.getElementById(attrs['scroll-container-id']) || window;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Get offset top - default to 100px if not specified
|
|
102
|
+
const offsetTop = parseInt(attrs['offset-top'] || '100', 10);
|
|
103
|
+
|
|
104
|
+
const stopListening = startListening(targetElement, scrollContainer, offsetTop, deps);
|
|
65
105
|
return () => {
|
|
66
106
|
stopListening();
|
|
67
107
|
}
|
|
@@ -1,15 +1,60 @@
|
|
|
1
|
-
export const
|
|
1
|
+
export const createInitialState = () => Object.freeze({
|
|
2
2
|
items: [],
|
|
3
3
|
currentId: null,
|
|
4
4
|
contentContainer: null
|
|
5
5
|
});
|
|
6
6
|
|
|
7
|
-
export const
|
|
7
|
+
export const selectViewData = ({ state }) => {
|
|
8
|
+
// Find all parent IDs for the current active item
|
|
9
|
+
const getActiveParentIds = (items, currentId) => {
|
|
10
|
+
const activeParentIds = new Set();
|
|
11
|
+
const currentIndex = items.findIndex(item => item.id === currentId);
|
|
12
|
+
|
|
13
|
+
if (currentIndex === -1) return activeParentIds;
|
|
14
|
+
|
|
15
|
+
const currentLevel = items[currentIndex].level;
|
|
16
|
+
|
|
17
|
+
// Look backwards for all parents (items with lower level)
|
|
18
|
+
for (let i = currentIndex - 1; i >= 0; i--) {
|
|
19
|
+
if (items[i].level < currentLevel) {
|
|
20
|
+
// This is a parent - mark all ancestors
|
|
21
|
+
let ancestorLevel = items[i].level;
|
|
22
|
+
activeParentIds.add(items[i].id);
|
|
23
|
+
|
|
24
|
+
// Continue looking for grandparents
|
|
25
|
+
for (let j = i - 1; j >= 0; j--) {
|
|
26
|
+
if (items[j].level < ancestorLevel) {
|
|
27
|
+
activeParentIds.add(items[j].id);
|
|
28
|
+
ancestorLevel = items[j].level;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
break; // Found the immediate parent chain
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return activeParentIds;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const activeParentIds = getActiveParentIds(state.items, state.currentId);
|
|
39
|
+
|
|
8
40
|
return {
|
|
9
41
|
items: state.items.map((item) => {
|
|
42
|
+
const mlValues = {
|
|
43
|
+
1: '0',
|
|
44
|
+
2: '12px',
|
|
45
|
+
3: '24px',
|
|
46
|
+
4: '32px'
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const isDirectlyActive = item.id === state.currentId;
|
|
50
|
+
const isParentActive = activeParentIds.has(item.id);
|
|
51
|
+
const active = isDirectlyActive || isParentActive;
|
|
52
|
+
|
|
10
53
|
return {
|
|
11
54
|
...item,
|
|
12
|
-
c:
|
|
55
|
+
c: active ? 'fg' : 'mu-fg',
|
|
56
|
+
ml: mlValues[item.level] || '',
|
|
57
|
+
bc: active ? "fg" : "mu-fg"
|
|
13
58
|
}
|
|
14
59
|
}),
|
|
15
60
|
currentId: state.currentId
|
|
@@ -27,8 +27,10 @@ events:
|
|
|
27
27
|
type: object
|
|
28
28
|
|
|
29
29
|
template:
|
|
30
|
-
- rtgl-view h=f w=272:
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
- rtgl-view h=f w=272 pr=md:
|
|
31
|
+
- rtgl-view w=f mt=xl:
|
|
32
|
+
- $for item, i in items:
|
|
33
|
+
- rtgl-view d=h bwl=xs bc="${item.bc}" pv=sm av=c href=${item.href} pl=md:
|
|
34
|
+
- rtgl-view w=${item.ml}:
|
|
35
|
+
- rtgl-text s=sm c=${item.c} h-c=fg: ${item.title}
|
|
36
|
+
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
export const handleBeforeMount = (deps) => {
|
|
2
|
+
const { store, props } = deps;
|
|
3
|
+
|
|
4
|
+
if (props.value !== undefined || props.defaultValue !== undefined) {
|
|
5
|
+
store.setValue(props.value || props.defaultValue || '');
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const handleOnUpdate = (changes, deps) => {
|
|
10
|
+
const { oldProps, newProps} = changes
|
|
11
|
+
const { store, props, render } = deps;
|
|
12
|
+
|
|
13
|
+
if (oldProps.defaultValue !== newProps.defaultValue) {
|
|
14
|
+
store.setValue(props.defaultValue || '');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
render();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const handleTextClick = (deps, event) => {
|
|
21
|
+
const { store, render, getRefIds, attrs } = deps;
|
|
22
|
+
|
|
23
|
+
const value = store.selectValue();
|
|
24
|
+
store.setTempValue(value)
|
|
25
|
+
|
|
26
|
+
store.openPopover({
|
|
27
|
+
position: {
|
|
28
|
+
x: event.currentTarget.getBoundingClientRect().left,
|
|
29
|
+
y: event.currentTarget.getBoundingClientRect().bottom,
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const { input } = getRefIds();
|
|
34
|
+
input.elm.value = value;
|
|
35
|
+
render();
|
|
36
|
+
|
|
37
|
+
if (attrs['auto-focus']) {
|
|
38
|
+
setTimeout(() => {
|
|
39
|
+
input.elm.focus();
|
|
40
|
+
}, 50)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const handlePopoverClose = (deps, event) => {
|
|
45
|
+
const { store, render } = deps;
|
|
46
|
+
store.closePopover();
|
|
47
|
+
render();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export const handleInputChange = (deps, event) => {
|
|
51
|
+
const { store, render, dispatchEvent } = deps;
|
|
52
|
+
const value = event.detail.value;
|
|
53
|
+
|
|
54
|
+
store.setTempValue(value);
|
|
55
|
+
|
|
56
|
+
dispatchEvent(new CustomEvent('temp-input-change', {
|
|
57
|
+
detail: { value },
|
|
58
|
+
bubbles: true
|
|
59
|
+
}));
|
|
60
|
+
|
|
61
|
+
render();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export const handleSubmitClick = (deps, event) => {
|
|
65
|
+
const { store, render, dispatchEvent, getRefIds } = deps;
|
|
66
|
+
const { input } = getRefIds()
|
|
67
|
+
const value = input.elm.value;
|
|
68
|
+
|
|
69
|
+
store.setValue(value)
|
|
70
|
+
store.closePopover();
|
|
71
|
+
|
|
72
|
+
dispatchEvent(new CustomEvent('input-change', {
|
|
73
|
+
detail: { value },
|
|
74
|
+
bubbles: true
|
|
75
|
+
}));
|
|
76
|
+
|
|
77
|
+
render();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export const handleInputKeydown = (deps, event) => {
|
|
81
|
+
const { store, render, dispatchEvent, getRefIds } = deps;
|
|
82
|
+
|
|
83
|
+
if (event.key === 'Enter') {
|
|
84
|
+
const { input } = getRefIds()
|
|
85
|
+
const value = input.elm.value;
|
|
86
|
+
|
|
87
|
+
store.closePopover();
|
|
88
|
+
// Dispatch custom event
|
|
89
|
+
dispatchEvent(new CustomEvent('input-change', {
|
|
90
|
+
detail: { value },
|
|
91
|
+
bubbles: true
|
|
92
|
+
}));
|
|
93
|
+
|
|
94
|
+
render();
|
|
95
|
+
} else if (event.key === 'Escape') {
|
|
96
|
+
store.closePopover();
|
|
97
|
+
render();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export const createInitialState = () => Object.freeze({
|
|
2
|
+
isOpen: false,
|
|
3
|
+
position: {
|
|
4
|
+
x: 0,
|
|
5
|
+
y: 0,
|
|
6
|
+
},
|
|
7
|
+
value: '',
|
|
8
|
+
tempValue: '',
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
export const selectViewData = ({ attrs, state, props }) => {
|
|
12
|
+
// Use state's current value if it has been modified, otherwise use props
|
|
13
|
+
const value = state.value || '-';
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
isOpen: state.isOpen,
|
|
17
|
+
position: state.position,
|
|
18
|
+
value: value ?? '-',
|
|
19
|
+
tempValue: state.tempValue,
|
|
20
|
+
placeholder: props.placeholder ?? '',
|
|
21
|
+
label: attrs.label,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const setTempValue = (state, value) => {
|
|
26
|
+
state.tempValue = value;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const openPopover = (state, payload) => {
|
|
30
|
+
const { position } = payload;
|
|
31
|
+
state.position = position;
|
|
32
|
+
state.isOpen = true;
|
|
33
|
+
// Reset the current value to match the display value when opening
|
|
34
|
+
state.hasUnsavedChanges = false;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const closePopover = (state) => {
|
|
38
|
+
state.isOpen = false;
|
|
39
|
+
state.tempValue = '';
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const setValue = (state, value) => {
|
|
43
|
+
state.value = value;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const selectValue = ({ state }) => {
|
|
47
|
+
return state.value;
|
|
48
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
elementName: rtgl-popover-input
|
|
2
|
+
|
|
3
|
+
viewDataSchema:
|
|
4
|
+
type: object
|
|
5
|
+
|
|
6
|
+
attrsSchema:
|
|
7
|
+
type: object
|
|
8
|
+
properties:
|
|
9
|
+
auto-focus:
|
|
10
|
+
type: boolean
|
|
11
|
+
|
|
12
|
+
propsSchema:
|
|
13
|
+
type: object
|
|
14
|
+
properties:
|
|
15
|
+
value:
|
|
16
|
+
type: string
|
|
17
|
+
defaultValue:
|
|
18
|
+
type: string
|
|
19
|
+
placeholder:
|
|
20
|
+
type: string
|
|
21
|
+
onChange:
|
|
22
|
+
type: function
|
|
23
|
+
|
|
24
|
+
refs:
|
|
25
|
+
text-display:
|
|
26
|
+
eventListeners:
|
|
27
|
+
click:
|
|
28
|
+
handler: handleTextClick
|
|
29
|
+
popover:
|
|
30
|
+
eventListeners:
|
|
31
|
+
close:
|
|
32
|
+
handler: handlePopoverClose
|
|
33
|
+
input:
|
|
34
|
+
eventListeners:
|
|
35
|
+
input-change:
|
|
36
|
+
handler: handleInputChange
|
|
37
|
+
keydown:
|
|
38
|
+
handler: handleInputKeydown
|
|
39
|
+
submit:
|
|
40
|
+
eventListeners:
|
|
41
|
+
click:
|
|
42
|
+
handler: handleSubmitClick
|
|
43
|
+
|
|
44
|
+
events:
|
|
45
|
+
input-change: {}
|
|
46
|
+
|
|
47
|
+
template:
|
|
48
|
+
- rtgl-view#text-display w=f cur=p:
|
|
49
|
+
- rtgl-text: ${value}
|
|
50
|
+
- rtgl-popover#popover ?open=${isOpen} x=${position.x} y=${position.y}:
|
|
51
|
+
- rtgl-view g=md w=240 slot=content bgc=background br=md:
|
|
52
|
+
- rtgl-text: ${label}
|
|
53
|
+
- rtgl-input#input w=f placeholder=${placeholder}:
|
|
54
|
+
- rtgl-view w=f ah=e:
|
|
55
|
+
- rtgl-button#submit: Submit
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { deepEqual } from '../../common.js';
|
|
1
2
|
|
|
2
|
-
export const
|
|
3
|
+
export const handleBeforeMount = (deps) => {
|
|
3
4
|
const { store, props, render } = deps;
|
|
4
|
-
|
|
5
|
+
|
|
5
6
|
if (props.selectedValue !== null && props.selectedValue !== undefined && props.options) {
|
|
6
|
-
const selectedOption = props.options.find(opt => opt.value
|
|
7
|
+
const selectedOption = props.options.find(opt => deepEqual(opt.value, props.selectedValue));
|
|
7
8
|
if (selectedOption) {
|
|
8
9
|
store.updateSelectOption(selectedOption);
|
|
9
10
|
render();
|
|
@@ -11,26 +12,66 @@ export const handleOnMount = (deps) => {
|
|
|
11
12
|
}
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
export const
|
|
15
|
-
const {
|
|
15
|
+
export const handleOnUpdate = (changes, deps) => {
|
|
16
|
+
const { oldAttrs, newAttrs, oldProps, newProps } = changes;
|
|
17
|
+
const { store, props, render } = deps;
|
|
18
|
+
|
|
19
|
+
// Check if key changed
|
|
20
|
+
if (oldAttrs?.key !== newAttrs?.key && newAttrs?.key) {
|
|
21
|
+
// Clear current state using store action
|
|
22
|
+
store.resetSelection();
|
|
23
|
+
|
|
24
|
+
// Re-apply the prop value if available
|
|
25
|
+
const selectedValue = newProps?.selectedValue || props?.selectedValue;
|
|
26
|
+
const options = newProps?.options || props?.options;
|
|
27
|
+
|
|
28
|
+
if (selectedValue !== null && selectedValue !== undefined && options) {
|
|
29
|
+
const selectedOption = options.find(opt => deepEqual(opt.value, selectedValue));
|
|
30
|
+
if (selectedOption) {
|
|
31
|
+
store.updateSelectOption(selectedOption);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
render();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const handleButtonClick = (deps, event) => {
|
|
39
|
+
const { store, render, getRefIds, props } = deps;
|
|
40
|
+
|
|
41
|
+
const button = getRefIds()['select-button'].elm;
|
|
42
|
+
|
|
43
|
+
// Get first child's bounding rectangle (since button has display: contents)
|
|
44
|
+
const firstChild = button.firstElementChild;
|
|
45
|
+
const rect = firstChild ? firstChild.getBoundingClientRect() : button.getBoundingClientRect();
|
|
46
|
+
|
|
47
|
+
// Find the index of the currently selected option
|
|
48
|
+
const storeSelectedValue = store.selectSelectedValue();
|
|
49
|
+
const currentValue = storeSelectedValue !== null ? storeSelectedValue : props.selectedValue;
|
|
50
|
+
let selectedIndex = null;
|
|
51
|
+
if (currentValue !== null && currentValue !== undefined && props.options) {
|
|
52
|
+
selectedIndex = props.options.findIndex(opt => deepEqual(opt.value, currentValue));
|
|
53
|
+
if (selectedIndex === -1) selectedIndex = null;
|
|
54
|
+
}
|
|
55
|
+
|
|
16
56
|
store.openOptionsPopover({
|
|
17
57
|
position: {
|
|
18
|
-
y:
|
|
19
|
-
x:
|
|
20
|
-
}
|
|
58
|
+
y: rect.bottom + 12, // Bottom edge of button
|
|
59
|
+
x: rect.left - 24, // Left edge of button
|
|
60
|
+
},
|
|
61
|
+
selectedIndex
|
|
21
62
|
})
|
|
22
63
|
render();
|
|
23
64
|
}
|
|
24
65
|
|
|
25
|
-
export const handleClickOptionsPopoverOverlay = (
|
|
66
|
+
export const handleClickOptionsPopoverOverlay = (deps, event) => {
|
|
26
67
|
const { store, render } = deps;
|
|
27
68
|
store.closeOptionsPopover();
|
|
28
69
|
render();
|
|
29
70
|
}
|
|
30
71
|
|
|
31
|
-
export const handleOptionClick = (
|
|
72
|
+
export const handleOptionClick = (deps, event) => {
|
|
32
73
|
const { render, dispatchEvent, props, store } = deps;
|
|
33
|
-
const id =
|
|
74
|
+
const id = event.currentTarget.id.replace('option-', '');
|
|
34
75
|
|
|
35
76
|
const option = props.options[id];
|
|
36
77
|
|
|
@@ -53,6 +94,73 @@ export const handleOptionClick = (e, deps) => {
|
|
|
53
94
|
detail: { selectedValue: option.value },
|
|
54
95
|
bubbles: true
|
|
55
96
|
}));
|
|
56
|
-
|
|
97
|
+
|
|
98
|
+
render();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export const handleOptionMouseEnter = (deps, event) => {
|
|
102
|
+
const { store, render } = deps;
|
|
103
|
+
const id = parseInt(event.currentTarget.id.replace('option-', ''));
|
|
104
|
+
store.setHoveredOption(id);
|
|
105
|
+
render();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export const handleOptionMouseLeave = (deps, event) => {
|
|
109
|
+
const { store, render } = deps;
|
|
110
|
+
store.clearHoveredOption();
|
|
111
|
+
render();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export const handleClearClick = (deps, event) => {
|
|
115
|
+
const { store, render, dispatchEvent, props } = deps;
|
|
116
|
+
|
|
117
|
+
event.stopPropagation();
|
|
118
|
+
|
|
119
|
+
// Clear the internal state
|
|
120
|
+
store.clearSelectedValue();
|
|
121
|
+
|
|
122
|
+
// Call onChange if provided
|
|
123
|
+
if (props.onChange && typeof props.onChange === 'function') {
|
|
124
|
+
props.onChange(undefined);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Dispatch custom event for backward compatibility
|
|
128
|
+
dispatchEvent(new CustomEvent('option-selected', {
|
|
129
|
+
detail: { value: undefined, label: undefined },
|
|
130
|
+
bubbles: true
|
|
131
|
+
}));
|
|
132
|
+
|
|
133
|
+
// Also dispatch select-change event to match form's event listener pattern
|
|
134
|
+
dispatchEvent(new CustomEvent('select-change', {
|
|
135
|
+
detail: { selectedValue: undefined },
|
|
136
|
+
bubbles: true
|
|
137
|
+
}));
|
|
138
|
+
|
|
139
|
+
render();
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export const handleAddOptionClick = (deps, event) => {
|
|
143
|
+
const { store, render, dispatchEvent } = deps;
|
|
144
|
+
|
|
145
|
+
// Close the popover
|
|
146
|
+
store.closeOptionsPopover();
|
|
147
|
+
|
|
148
|
+
// Dispatch custom event for add option (no detail)
|
|
149
|
+
dispatchEvent(new CustomEvent('add-option-selected', {
|
|
150
|
+
bubbles: true
|
|
151
|
+
}));
|
|
152
|
+
|
|
153
|
+
render();
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export const handleAddOptionMouseEnter = (deps, event) => {
|
|
157
|
+
const { store, render } = deps;
|
|
158
|
+
store.setHoveredAddOption(true);
|
|
159
|
+
render();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export const handleAddOptionMouseLeave = (deps, event) => {
|
|
163
|
+
const { store, render } = deps;
|
|
164
|
+
store.setHoveredAddOption(false);
|
|
57
165
|
render();
|
|
58
166
|
}
|