rettangoli-ui 0.1.0-rc2 → 0.1.0-rc3
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/README.md +16 -27
- package/dist/rettangoli-iife-layout.min.js +98 -47
- package/dist/rettangoli-iife-ui.min.js +63 -64
- package/package.json +11 -4
- package/src/common/BaseElement.js +182 -0
- package/src/common.js +190 -0
- package/src/components/dialog/dialog.handlers.js +5 -0
- package/src/components/dialog/dialog.store.js +24 -0
- package/src/components/dialog/dialog.view.yaml +40 -0
- package/src/components/form/form.handlers.js +30 -0
- package/src/components/form/form.store.js +45 -0
- package/src/components/form/form.view.yaml +47 -0
- package/src/components/navbar/navbar.examples.yaml +86 -0
- package/src/components/navbar/navbar.handlers.js +10 -0
- package/src/components/navbar/navbar.store.js +46 -0
- package/src/components/navbar/navbar.view.yaml +74 -0
- package/src/components/pageOutline/pageOutline.handlers.js +69 -0
- package/src/components/pageOutline/pageOutline.store.js +40 -0
- package/src/components/pageOutline/pageOutline.view.yaml +34 -0
- package/src/components/popover/popover.handlers.js +17 -0
- package/src/components/popover/popover.store.js +37 -0
- package/src/components/popover/popover.view.yaml +50 -0
- package/src/components/select/select.handlers.js +15 -0
- package/src/components/select/select.store.js +25 -0
- package/src/components/select/select.view.yaml +38 -0
- package/src/components/sidebar/sidebar.handlers.js +36 -0
- package/src/components/sidebar/sidebar.store.js +125 -0
- package/src/components/sidebar/sidebar.view.yaml +186 -0
- package/src/entry-iife-layout.js +15 -0
- package/src/entry-iife-ui.js +18 -0
- package/src/index.js +17 -0
- package/src/lib/uhtml.js +9 -0
- package/src/primitives/button.js +263 -0
- package/src/primitives/image.js +234 -0
- package/src/primitives/input.js +208 -0
- package/src/primitives/svg.js +95 -0
- package/src/primitives/text.js +141 -0
- package/src/primitives/textarea.js +103 -0
- package/src/primitives/view.js +215 -0
- package/src/setup.js +16 -0
- package/src/styles/anchorStyles.js +13 -0
- package/src/styles/buttonMarginStyles.js +84 -0
- package/src/styles/cursorStyles.js +12 -0
- package/src/styles/flexChildStyles.js +43 -0
- package/src/styles/flexDirectionStyles.js +74 -0
- package/src/styles/marginStyles.js +13 -0
- package/src/styles/paddingSvgStyles.js +120 -0
- package/src/styles/scrollStyles.js +22 -0
- package/src/styles/textColorStyles.js +14 -0
- package/src/styles/textStyles.js +62 -0
- package/src/styles/viewStyles.js +119 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
export const INITIAL_STATE = 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 toViewData = ({ state, props, attrs }) => {
|
10
|
+
console.log('attrs', {
|
11
|
+
attrs,
|
12
|
+
entries: Object.entries(attrs)
|
13
|
+
})
|
14
|
+
|
15
|
+
const attrsStart = attrs.start ? JSON.parse(decodeURIComponent(attrs.start)) : props.start;
|
16
|
+
|
17
|
+
const containerAttrString = stringifyAttrs(attrs);
|
18
|
+
const start = attrsStart || {
|
19
|
+
label: '',
|
20
|
+
// href: undefined,
|
21
|
+
// path: undefined,
|
22
|
+
image: {
|
23
|
+
src: '',
|
24
|
+
width: 32,
|
25
|
+
height: 32,
|
26
|
+
alt: ''
|
27
|
+
}
|
28
|
+
}
|
29
|
+
// start.hasImage = start.image && start.image.src;
|
30
|
+
// start.hasHref = !!start.href;
|
31
|
+
return {
|
32
|
+
containerAttrString,
|
33
|
+
start
|
34
|
+
};
|
35
|
+
}
|
36
|
+
|
37
|
+
export const selectPath = ({ props }) => {
|
38
|
+
return props.start.path;
|
39
|
+
}
|
40
|
+
|
41
|
+
export const setState = (state) => {
|
42
|
+
// do doSomething
|
43
|
+
}
|
44
|
+
|
45
|
+
|
46
|
+
|
@@ -0,0 +1,74 @@
|
|
1
|
+
elementName: rtgl-navbar
|
2
|
+
|
3
|
+
viewDataSchema:
|
4
|
+
type: object
|
5
|
+
properties:
|
6
|
+
containerAttrString:
|
7
|
+
type: string
|
8
|
+
start:
|
9
|
+
type: object
|
10
|
+
properties:
|
11
|
+
label:
|
12
|
+
type: string
|
13
|
+
href:
|
14
|
+
type: string
|
15
|
+
image:
|
16
|
+
type: object
|
17
|
+
properties:
|
18
|
+
src:
|
19
|
+
type: string
|
20
|
+
hasImage:
|
21
|
+
type: boolean
|
22
|
+
hasHref:
|
23
|
+
type: boolean
|
24
|
+
|
25
|
+
propsSchema:
|
26
|
+
type: object
|
27
|
+
properties:
|
28
|
+
start:
|
29
|
+
type: object
|
30
|
+
properties:
|
31
|
+
label:
|
32
|
+
type: string
|
33
|
+
href:
|
34
|
+
type: string
|
35
|
+
image:
|
36
|
+
type: object
|
37
|
+
properties:
|
38
|
+
src:
|
39
|
+
type: string
|
40
|
+
|
41
|
+
refs:
|
42
|
+
start:
|
43
|
+
eventListeners:
|
44
|
+
click:
|
45
|
+
handler: handleClickStart
|
46
|
+
|
47
|
+
events:
|
48
|
+
clickStart:
|
49
|
+
type: object
|
50
|
+
properties:
|
51
|
+
path:
|
52
|
+
type: string
|
53
|
+
|
54
|
+
anchors:
|
55
|
+
- &image
|
56
|
+
- rtgl-text s=lg: "${start.label}"
|
57
|
+
- $if start.image && start.image.src:
|
58
|
+
- rtgl-image w=${start.image.width} h=${start.image.height} src=${start.image.src} alt=${start.image.alt}:
|
59
|
+
|
60
|
+
template:
|
61
|
+
- rtgl-view bgc=bg d=h h=48 av=c w=f ${containerAttrString}:
|
62
|
+
- $if start.href:
|
63
|
+
- a href=${start.href}:
|
64
|
+
- rtgl-view d=h av=c g=lg g=md:
|
65
|
+
- *image
|
66
|
+
$elif start.path:
|
67
|
+
- rtgl-view#start d=h av=c g=lg g=md cur=p:
|
68
|
+
- *image
|
69
|
+
$else:
|
70
|
+
- rtgl-view d=h av=c g=lg g=md:
|
71
|
+
- *image
|
72
|
+
- rtgl-view flex=1:
|
73
|
+
- rtgl-view d=h av=c g=lg:
|
74
|
+
- slot name=right:
|
@@ -0,0 +1,69 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
/**
|
4
|
+
*
|
5
|
+
* @param {*} headingElements
|
6
|
+
* @param {*} deps
|
7
|
+
*/
|
8
|
+
const updateToLatestCurrentId = (headingElements, deps) => {
|
9
|
+
const { store, render } = deps;
|
10
|
+
|
11
|
+
let currentHeadingId;
|
12
|
+
let closestTopPosition = -Infinity;
|
13
|
+
|
14
|
+
headingElements.forEach((heading) => {
|
15
|
+
const rect = heading.getBoundingClientRect();
|
16
|
+
|
17
|
+
if (rect.top <= 20) {
|
18
|
+
if (rect.top > closestTopPosition) {
|
19
|
+
closestTopPosition = rect.top;
|
20
|
+
currentHeadingId = heading.id;
|
21
|
+
}
|
22
|
+
}
|
23
|
+
});
|
24
|
+
|
25
|
+
if (currentHeadingId && currentHeadingId !== store.selectCurrentId()) {
|
26
|
+
store.setCurrentId(currentHeadingId);
|
27
|
+
render();
|
28
|
+
}
|
29
|
+
};
|
30
|
+
|
31
|
+
const startListening = (contentContainer, deps) => {
|
32
|
+
const { store, render } = deps;
|
33
|
+
|
34
|
+
// Extract headings
|
35
|
+
const headings = contentContainer.querySelectorAll("rtgl-text[id]");
|
36
|
+
const headingElements = Array.from(headings);
|
37
|
+
|
38
|
+
const items = headingElements.map((heading) => ({
|
39
|
+
id: heading.id,
|
40
|
+
href: `#${heading.id}`,
|
41
|
+
title: heading.textContent
|
42
|
+
}));
|
43
|
+
|
44
|
+
store.setItems(items);
|
45
|
+
updateToLatestCurrentId(headingElements, deps);
|
46
|
+
render();
|
47
|
+
|
48
|
+
const boundCheckCurrentHeading = updateToLatestCurrentId.bind(this, headingElements, deps);
|
49
|
+
|
50
|
+
// Add scroll listener to the content container
|
51
|
+
contentContainer.addEventListener("scroll", boundCheckCurrentHeading, {
|
52
|
+
passive: true,
|
53
|
+
});
|
54
|
+
|
55
|
+
return () => {
|
56
|
+
contentContainer.removeEventListener("scroll", boundCheckCurrentHeading);
|
57
|
+
}
|
58
|
+
};
|
59
|
+
|
60
|
+
export const handleOnMount = (deps) => {
|
61
|
+
const { attrs } = deps;
|
62
|
+
requestAnimationFrame(() => {
|
63
|
+
const targetElement = document.getElementById(attrs['target-id'])
|
64
|
+
const stopListening = startListening(targetElement, deps)
|
65
|
+
return () => {
|
66
|
+
stopListening();
|
67
|
+
}
|
68
|
+
})
|
69
|
+
}
|
@@ -0,0 +1,40 @@
|
|
1
|
+
export const INITIAL_STATE = Object.freeze({
|
2
|
+
items: [],
|
3
|
+
currentId: null,
|
4
|
+
contentContainer: null
|
5
|
+
});
|
6
|
+
|
7
|
+
export const toViewData = ({ state }) => {
|
8
|
+
return {
|
9
|
+
items: state.items.map((item) => {
|
10
|
+
return {
|
11
|
+
...item,
|
12
|
+
c: item.id === state.currentId ? 'fg' : 'mu-fg'
|
13
|
+
}
|
14
|
+
}),
|
15
|
+
currentId: state.currentId
|
16
|
+
};
|
17
|
+
}
|
18
|
+
|
19
|
+
export const selectState = ({ state }) => {
|
20
|
+
return state;
|
21
|
+
}
|
22
|
+
|
23
|
+
export const selectCurrentId = ({ state }) => {
|
24
|
+
return state.currentId;
|
25
|
+
}
|
26
|
+
|
27
|
+
export const setItems = (state, items) => {
|
28
|
+
state.items = items;
|
29
|
+
}
|
30
|
+
|
31
|
+
export const setCurrentId = (state, id) => {
|
32
|
+
state.currentId = id;
|
33
|
+
}
|
34
|
+
|
35
|
+
export const setContentContainer = (state, container) => {
|
36
|
+
state.contentContainer = container;
|
37
|
+
}
|
38
|
+
|
39
|
+
|
40
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
elementName: rtgl-page-outline
|
2
|
+
|
3
|
+
viewDataSchema:
|
4
|
+
type: object
|
5
|
+
properties:
|
6
|
+
items:
|
7
|
+
type: array
|
8
|
+
items:
|
9
|
+
type: object
|
10
|
+
properties:
|
11
|
+
slug:
|
12
|
+
type: string
|
13
|
+
title:
|
14
|
+
type: string
|
15
|
+
selectedSlug:
|
16
|
+
type: string
|
17
|
+
nullable: true
|
18
|
+
|
19
|
+
propsSchema:
|
20
|
+
type: object
|
21
|
+
properties: {}
|
22
|
+
|
23
|
+
refs: {}
|
24
|
+
|
25
|
+
events:
|
26
|
+
onItemClick:
|
27
|
+
type: object
|
28
|
+
|
29
|
+
template:
|
30
|
+
- rtgl-view h=f w=272:
|
31
|
+
- rtgl-view w=f g=sm mt=xl:
|
32
|
+
- $for item, i in items:
|
33
|
+
- rtgl-view pv=xs av=c href=${item.href}:
|
34
|
+
- rtgl-text s=sm c=${item.c} h-c=fg: ${item.title}
|
@@ -0,0 +1,17 @@
|
|
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
|
+
|
11
|
+
export const open = (payload, deps) => {
|
12
|
+
const { position } = payload;
|
13
|
+
const { store, render } = deps;
|
14
|
+
store.setOpen(position);
|
15
|
+
render();
|
16
|
+
}
|
17
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
export const INITIAL_STATE = Object.freeze({
|
2
|
+
isOpen: false,
|
3
|
+
position: {
|
4
|
+
x: 0,
|
5
|
+
y: 0
|
6
|
+
},
|
7
|
+
});
|
8
|
+
|
9
|
+
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
|
+
return {
|
20
|
+
isOpen: state.isOpen,
|
21
|
+
position: state.position,
|
22
|
+
};
|
23
|
+
}
|
24
|
+
|
25
|
+
export const selectState = ({ state }) => {
|
26
|
+
return state;
|
27
|
+
}
|
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
|
+
}
|
@@ -0,0 +1,50 @@
|
|
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
|
+
|
27
|
+
refs:
|
28
|
+
popoverOverlay:
|
29
|
+
eventListeners:
|
30
|
+
click:
|
31
|
+
handler: handleClickOverlay
|
32
|
+
|
33
|
+
styles:
|
34
|
+
'@keyframes popover-in':
|
35
|
+
from:
|
36
|
+
opacity: 0
|
37
|
+
transform: scale(0.95)
|
38
|
+
to:
|
39
|
+
opacity: 1
|
40
|
+
transform: scale(1)
|
41
|
+
|
42
|
+
'#popoverContainer':
|
43
|
+
animation: popover-in 150ms cubic-bezier(0.16, 1, 0.3, 1)
|
44
|
+
transform-origin: top
|
45
|
+
|
46
|
+
template:
|
47
|
+
- $if isOpen:
|
48
|
+
- 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=bg':
|
50
|
+
- slot name=content:
|
@@ -0,0 +1,15 @@
|
|
1
|
+
|
2
|
+
export const handleOnMount = (deps) => {
|
3
|
+
}
|
4
|
+
|
5
|
+
export const handleButtonClick = (e, deps) => {
|
6
|
+
const { store, render, getRefIds } = deps;
|
7
|
+
const refIds = getRefIds();
|
8
|
+
refIds.popover.elm.transformedHandlers.open({
|
9
|
+
position: {
|
10
|
+
x: e.clientX,
|
11
|
+
y: e.clientY
|
12
|
+
}
|
13
|
+
});
|
14
|
+
|
15
|
+
}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
export const INITIAL_STATE = Object.freeze({
|
2
|
+
isOpen: false,
|
3
|
+
});
|
4
|
+
|
5
|
+
export const toViewData = ({ state, props }) => {
|
6
|
+
return {
|
7
|
+
isOpen: state.isOpen,
|
8
|
+
options: props.options || []
|
9
|
+
};
|
10
|
+
}
|
11
|
+
|
12
|
+
export const selectState = ({ state }) => {
|
13
|
+
return state;
|
14
|
+
}
|
15
|
+
|
16
|
+
export const setOpen = (state) => {
|
17
|
+
state.open = true;
|
18
|
+
}
|
19
|
+
|
20
|
+
export const setState = (state) => {
|
21
|
+
// do doSomething
|
22
|
+
}
|
23
|
+
|
24
|
+
|
25
|
+
|
@@ -0,0 +1,38 @@
|
|
1
|
+
elementName: rtgl-select
|
2
|
+
|
3
|
+
viewDataSchema:
|
4
|
+
type: object
|
5
|
+
|
6
|
+
propsSchema:
|
7
|
+
type: object
|
8
|
+
properties:
|
9
|
+
options:
|
10
|
+
items:
|
11
|
+
type: array
|
12
|
+
items:
|
13
|
+
type: object
|
14
|
+
properties:
|
15
|
+
id:
|
16
|
+
type: string
|
17
|
+
lalbel:
|
18
|
+
type: string
|
19
|
+
value:
|
20
|
+
type: any
|
21
|
+
|
22
|
+
refs:
|
23
|
+
select-button:
|
24
|
+
eventListeners:
|
25
|
+
click:
|
26
|
+
handler: handleButtonClick
|
27
|
+
popover: {}
|
28
|
+
|
29
|
+
|
30
|
+
events: {}
|
31
|
+
|
32
|
+
template:
|
33
|
+
- rtgl-button#select-button v=ol: Placeholder
|
34
|
+
- rtgl-popover#popover:
|
35
|
+
- rtgl-view wh=300 g=xs slot=content:
|
36
|
+
- $for option, i in options:
|
37
|
+
- rtgl-view w=f h-bgc=mu ph=lg pv=md cur=p br=md:
|
38
|
+
- rtgl-text: ${option.label}
|
@@ -0,0 +1,36 @@
|
|
1
|
+
export const handleHeaderClick = (e, deps) => {
|
2
|
+
const { store, dispatchEvent } = deps;
|
3
|
+
|
4
|
+
let path;
|
5
|
+
|
6
|
+
const header = store.selectHeader();
|
7
|
+
|
8
|
+
if (e.currentTarget.id === 'header-label') {
|
9
|
+
path = header.labelPath;
|
10
|
+
} else if (e.currentTarget.id === 'header-image') {
|
11
|
+
path = header.image.path;
|
12
|
+
} else if (e.currentTarget.id === 'header') {
|
13
|
+
path = header.path;
|
14
|
+
}
|
15
|
+
|
16
|
+
dispatchEvent(new CustomEvent('headerClick', {
|
17
|
+
detail: {
|
18
|
+
path
|
19
|
+
},
|
20
|
+
bubbles: true,
|
21
|
+
composed: true
|
22
|
+
}));
|
23
|
+
}
|
24
|
+
|
25
|
+
export const handleItemClick = (e, deps) => {
|
26
|
+
const { store, dispatchEvent } = deps;
|
27
|
+
const id = e.currentTarget.id.replace('item-', '');
|
28
|
+
const item = store.selectItem(id);
|
29
|
+
dispatchEvent(new CustomEvent('itemClick', {
|
30
|
+
detail: {
|
31
|
+
item,
|
32
|
+
},
|
33
|
+
bubbles: true,
|
34
|
+
composed: true
|
35
|
+
}));
|
36
|
+
}
|
@@ -0,0 +1,125 @@
|
|
1
|
+
export const INITIAL_STATE = 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
|
+
function flattenItems(items) {
|
10
|
+
let result = [];
|
11
|
+
|
12
|
+
for (const item of items) {
|
13
|
+
// Add the parent item if it's not just a group label
|
14
|
+
result.push({
|
15
|
+
id: item.id || item.href || item.path,
|
16
|
+
title: item.title,
|
17
|
+
href: item.href,
|
18
|
+
type: item.type || 'item',
|
19
|
+
icon: item.icon,
|
20
|
+
hrefAttr: item.href ? `href=${item.href}` : '',
|
21
|
+
});
|
22
|
+
|
23
|
+
// Add child items if they exist
|
24
|
+
if (item.items && Array.isArray(item.items)) {
|
25
|
+
for (const subItem of item.items) {
|
26
|
+
result.push({
|
27
|
+
id: subItem.id || subItem.href || subItem.path,
|
28
|
+
title: subItem.title,
|
29
|
+
href: subItem.href,
|
30
|
+
type: subItem.type || 'item',
|
31
|
+
icon: subItem.icon,
|
32
|
+
hrefAttr: subItem.href ? `href=${subItem.href}` : '',
|
33
|
+
});
|
34
|
+
}
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
return result;
|
39
|
+
}
|
40
|
+
|
41
|
+
export const toViewData = ({ state, props, attrs }) => {
|
42
|
+
const attrsHeader = attrs.header ? JSON.parse(decodeURIComponent(attrs.header)) : props.header;
|
43
|
+
const attrsItems = attrs.items ? JSON.parse(decodeURIComponent(attrs.items)) : props.items;
|
44
|
+
|
45
|
+
const containerAttrString = stringifyAttrs(attrs);
|
46
|
+
const mode = attrs.mode || 'full';
|
47
|
+
const header = attrsHeader || {
|
48
|
+
label: '',
|
49
|
+
path: '',
|
50
|
+
image: {
|
51
|
+
src: '',
|
52
|
+
alt: '',
|
53
|
+
width: 0,
|
54
|
+
height: 0,
|
55
|
+
},
|
56
|
+
};
|
57
|
+
|
58
|
+
const items = attrsItems ? flattenItems(attrsItems) : [];
|
59
|
+
|
60
|
+
// Computed values based on mode
|
61
|
+
const sidebarWidth = mode === 'full' ? 272 : 64;
|
62
|
+
const headerAlign = mode === 'full' ? 'fs' : 'c';
|
63
|
+
const itemAlign = mode === 'full' ? 'fs' : 'c';
|
64
|
+
const headerPadding = mode === 'full' ? 'lg' : 'sm';
|
65
|
+
const itemPadding = mode === 'full' ? 'md' : 'sm';
|
66
|
+
const itemHeight = mode === 'shrunk-lg' ? 48 : 40;
|
67
|
+
const iconSize = mode === 'shrunk-lg' ? 28 : 20;
|
68
|
+
const firstLetterSize = mode === 'shrunk-lg' ? 'md' : 'sm';
|
69
|
+
const showLabels = mode === 'full';
|
70
|
+
const showGroupLabels = mode === 'full';
|
71
|
+
|
72
|
+
// For items with icons in full mode, we need left alignment within the container
|
73
|
+
// but the container itself should use flex-start alignment
|
74
|
+
const itemContentAlign = mode === 'full' ? 'fs' : 'c';
|
75
|
+
|
76
|
+
// Item container alignment - only set for shrunk modes, leave default for full mode
|
77
|
+
const itemAlignAttr = mode === 'full' ? '' : `ah=${itemAlign}`;
|
78
|
+
|
79
|
+
// Item width - for shrunk modes, make it square to constrain the highlight
|
80
|
+
const itemWidth = mode === 'full' ? 'f' : itemHeight;
|
81
|
+
|
82
|
+
// Header width - should match item width for alignment
|
83
|
+
const headerWidth = itemWidth;
|
84
|
+
|
85
|
+
return {
|
86
|
+
containerAttrString,
|
87
|
+
mode,
|
88
|
+
header,
|
89
|
+
items,
|
90
|
+
sidebarWidth,
|
91
|
+
headerAlign,
|
92
|
+
itemAlign,
|
93
|
+
headerPadding,
|
94
|
+
itemPadding,
|
95
|
+
itemHeight,
|
96
|
+
iconSize,
|
97
|
+
firstLetterSize,
|
98
|
+
showLabels,
|
99
|
+
showGroupLabels,
|
100
|
+
itemContentAlign,
|
101
|
+
itemAlignAttr,
|
102
|
+
itemWidth,
|
103
|
+
headerWidth
|
104
|
+
};
|
105
|
+
}
|
106
|
+
|
107
|
+
export const selectHeader = ({ state, props, attrs }) => {
|
108
|
+
const attrsHeader = attrs.header ? JSON.parse(decodeURIComponent(attrs.header)) : props.header;
|
109
|
+
return attrsHeader;
|
110
|
+
}
|
111
|
+
|
112
|
+
export const selectActiveItem = ({ state, props }) => {
|
113
|
+
const items = props.items ? flattenItems(props.items) : [];
|
114
|
+
return items.find(item => item.active);
|
115
|
+
}
|
116
|
+
|
117
|
+
export const selectItem = ({ state, props, attrs }, id) => {
|
118
|
+
const attrsItems = attrs.items ? JSON.parse(decodeURIComponent(attrs.items)) : props.items;
|
119
|
+
const items = attrsItems ? flattenItems(attrsItems) : [];
|
120
|
+
return items.find(item => item.id === id);
|
121
|
+
}
|
122
|
+
|
123
|
+
export const setState = (state) => {
|
124
|
+
// State management if needed
|
125
|
+
}
|