@rettangoli/ui 0.1.31 → 1.0.0-rc1
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 +20 -85
- package/dist/rettangoli-iife-layout.min.js +113 -173
- package/dist/rettangoli-iife-ui.min.js +123 -183
- package/package.json +5 -4
- package/src/common/dimensions.js +72 -0
- package/src/common/link.js +111 -0
- package/src/common/responsive.js +8 -0
- package/src/common.js +43 -8
- package/src/components/accordionItem/accordionItem.handlers.js +1 -1
- package/src/components/accordionItem/accordionItem.schema.yaml +14 -0
- package/src/components/accordionItem/accordionItem.store.js +8 -8
- package/src/components/accordionItem/accordionItem.view.yaml +5 -35
- package/src/components/breadcrumb/breadcrumb.handlers.js +24 -3
- package/src/components/breadcrumb/breadcrumb.schema.yaml +51 -0
- package/src/components/breadcrumb/breadcrumb.store.js +66 -10
- package/src/components/breadcrumb/breadcrumb.view.yaml +18 -58
- package/src/components/dropdownMenu/dropdownMenu.handlers.js +17 -3
- package/src/components/dropdownMenu/dropdownMenu.schema.yaml +64 -0
- package/src/components/dropdownMenu/dropdownMenu.store.js +48 -6
- package/src/components/dropdownMenu/dropdownMenu.view.yaml +24 -46
- package/src/components/form/form.handlers.js +25 -108
- package/src/components/form/form.schema.yaml +283 -0
- package/src/components/form/form.store.js +19 -14
- package/src/components/form/form.view.yaml +28 -319
- package/src/components/globalUi/globalUi.handlers.js +2 -2
- package/src/components/globalUi/globalUi.schema.yaml +8 -0
- package/src/components/globalUi/globalUi.store.js +8 -8
- package/src/components/globalUi/globalUi.view.yaml +9 -46
- package/src/components/navbar/navbar.handlers.js +1 -1
- package/src/components/navbar/navbar.schema.yaml +25 -0
- package/src/components/navbar/navbar.store.js +28 -14
- package/src/components/navbar/navbar.view.yaml +21 -65
- package/src/components/pageOutline/pageOutline.handlers.js +17 -11
- package/src/components/pageOutline/pageOutline.schema.yaml +16 -0
- package/src/components/pageOutline/pageOutline.store.js +6 -7
- package/src/components/pageOutline/pageOutline.view.yaml +1 -29
- package/src/components/popoverInput/popoverInput.handlers.js +31 -31
- package/src/components/popoverInput/popoverInput.schema.yaml +18 -0
- package/src/components/popoverInput/popoverInput.store.js +9 -9
- package/src/components/popoverInput/popoverInput.view.yaml +5 -22
- package/src/components/select/select.handlers.js +31 -35
- package/src/components/select/select.schema.yaml +36 -0
- package/src/components/select/select.store.js +34 -35
- package/src/components/select/select.view.yaml +13 -56
- package/src/components/sidebar/sidebar.handlers.js +5 -5
- package/src/components/sidebar/sidebar.schema.yaml +57 -0
- package/src/components/sidebar/sidebar.store.js +45 -23
- package/src/components/sidebar/sidebar.view.yaml +79 -174
- package/src/components/sliderInput/sliderInput.handlers.js +28 -8
- package/src/components/sliderInput/sliderInput.schema.yaml +27 -0
- package/src/components/sliderInput/sliderInput.store.js +9 -9
- package/src/components/sliderInput/sliderInput.view.yaml +8 -33
- package/src/components/table/table.handlers.js +3 -3
- package/src/components/table/table.schema.yaml +27 -0
- package/src/components/table/table.store.js +8 -8
- package/src/components/table/table.view.yaml +16 -62
- package/src/components/tabs/tabs.schema.yaml +26 -0
- package/src/components/tabs/tabs.store.js +12 -9
- package/src/components/tabs/tabs.view.yaml +4 -60
- package/src/components/tooltip/tooltip.schema.yaml +18 -0
- package/src/components/tooltip/tooltip.store.js +7 -7
- package/src/components/tooltip/tooltip.view.yaml +4 -22
- package/src/components/waveform/waveform.handlers.js +6 -6
- package/src/components/waveform/waveform.schema.yaml +25 -0
- package/src/components/waveform/waveform.store.js +6 -6
- package/src/components/waveform/waveform.view.yaml +6 -34
- package/src/deps/createGlobalUI.js +2 -2
- package/src/primitives/button.js +200 -114
- package/src/primitives/colorPicker.js +56 -50
- package/src/primitives/dialog.js +2 -1
- package/src/primitives/image.js +73 -103
- package/src/primitives/input-number.js +139 -93
- package/src/primitives/input.js +87 -64
- package/src/primitives/popover.js +36 -28
- package/src/primitives/slider.js +6 -4
- package/src/primitives/svg.js +9 -10
- package/src/primitives/text.js +26 -47
- package/src/primitives/textarea.js +25 -9
- package/src/primitives/view.js +49 -90
- package/src/setup.js +1 -7
- package/src/styles/buttonMarginStyles.js +1 -13
- package/src/styles/cursorStyles.js +1 -5
- package/src/styles/flexDirectionStyles.js +4 -4
- package/src/styles/marginStylesForTarget.js +13 -0
- package/src/styles/textColorStyles.js +14 -6
- package/src/styles/textStyles.js +4 -4
- package/src/styles/viewStyles.js +6 -6
- package/src/styles/viewStylesForTarget.js +58 -0
- package/src/styles/flexChildStyles.js +0 -43
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rettangoli/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0-rc1",
|
|
4
4
|
"description": "A UI component library for building web interfaces.",
|
|
5
5
|
"main": "dist/rettangoli-esm.min.js",
|
|
6
6
|
"type": "module",
|
|
@@ -23,10 +23,11 @@
|
|
|
23
23
|
},
|
|
24
24
|
"license": "MIT",
|
|
25
25
|
"scripts": {
|
|
26
|
+
"check:contracts": "rtgl fe check",
|
|
26
27
|
"build:dev": "rtgl fe build -d && bun run esbuild-dev.js",
|
|
27
28
|
"build": "rtgl fe build && bun run esbuild.js",
|
|
28
|
-
"vt:generate": "bun run build:dev && rtgl vt generate",
|
|
29
|
-
"vt:docker": "bun run build:dev && docker run --rm --user $(id -u):$(id -g) -v \"$PWD:/app\" -w /app han4wluc/rtgl:playwright-v1.57.0-rtgl-v0.0.
|
|
29
|
+
"vt:generate": "bun run build:dev && rtgl vt generate --skip-screenshots",
|
|
30
|
+
"vt:docker": "bun run build:dev && docker run --rm --user $(id -u):$(id -g) -v \"$PWD:/app\" -w /app han4wluc/rtgl:playwright-v1.57.0-rtgl-v0.0.38 rtgl vt generate",
|
|
30
31
|
"vt:report": "bun run vt:docker && rtgl vt report",
|
|
31
32
|
"vt:accept": "rtgl vt accept",
|
|
32
33
|
"serve": "bunx serve .rettangoli/vt/_site"
|
|
@@ -50,7 +51,7 @@
|
|
|
50
51
|
"homepage": "https://github.com/yuusoft-org/rettangoli#readme",
|
|
51
52
|
"dependencies": {
|
|
52
53
|
"@floating-ui/dom": "^1.6.13",
|
|
53
|
-
"@rettangoli/fe": "0.0
|
|
54
|
+
"@rettangoli/fe": "1.0.0-rc1",
|
|
54
55
|
"commander": "^13.1.0",
|
|
55
56
|
"jempl": "1.0.0",
|
|
56
57
|
"js-yaml": "^4.1.0",
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
const FLEX_GROW_DIMENSION_REGEX = /^([1-9]|1[0-2])fg$/;
|
|
2
|
+
|
|
3
|
+
export const isFlexGrowDimension = (dimension) => {
|
|
4
|
+
return typeof dimension === "string" && FLEX_GROW_DIMENSION_REGEX.test(dimension);
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export const applyDimensionToStyleBucket = ({
|
|
8
|
+
styleBucket,
|
|
9
|
+
axis,
|
|
10
|
+
dimension,
|
|
11
|
+
fillValue,
|
|
12
|
+
allowFlexGrow = false,
|
|
13
|
+
lockBounds = true,
|
|
14
|
+
}) => {
|
|
15
|
+
if (dimension === undefined) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (dimension === "f") {
|
|
20
|
+
styleBucket[axis] = fillValue;
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (allowFlexGrow && isFlexGrowDimension(dimension)) {
|
|
25
|
+
styleBucket["flex-grow"] = dimension.slice(0, -2);
|
|
26
|
+
styleBucket["flex-basis"] = "0%";
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
styleBucket[axis] = dimension;
|
|
31
|
+
if (lockBounds) {
|
|
32
|
+
styleBucket[`min-${axis}`] = dimension;
|
|
33
|
+
styleBucket[`max-${axis}`] = dimension;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const applyInlineWidthDimension = ({
|
|
38
|
+
style,
|
|
39
|
+
width,
|
|
40
|
+
fillValue = "var(--width-stretch)",
|
|
41
|
+
allowFlexGrow = true,
|
|
42
|
+
flexMinWidth = "0",
|
|
43
|
+
}) => {
|
|
44
|
+
if (width === "f") {
|
|
45
|
+
style.width = fillValue;
|
|
46
|
+
style.flexGrow = "";
|
|
47
|
+
style.flexBasis = "";
|
|
48
|
+
style.minWidth = "";
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (allowFlexGrow && isFlexGrowDimension(width)) {
|
|
53
|
+
style.width = "";
|
|
54
|
+
style.flexGrow = width.slice(0, -2);
|
|
55
|
+
style.flexBasis = "0%";
|
|
56
|
+
style.minWidth = flexMinWidth;
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (width != null) {
|
|
61
|
+
style.width = width;
|
|
62
|
+
style.flexGrow = "";
|
|
63
|
+
style.flexBasis = "";
|
|
64
|
+
style.minWidth = "";
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
style.width = "";
|
|
69
|
+
style.flexGrow = "";
|
|
70
|
+
style.flexBasis = "";
|
|
71
|
+
style.minWidth = "";
|
|
72
|
+
};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
export const overlayLinkStyles = `
|
|
2
|
+
:host([href]) {
|
|
3
|
+
cursor: pointer;
|
|
4
|
+
position: relative;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
:host([href]) a {
|
|
8
|
+
position: absolute;
|
|
9
|
+
top: 0;
|
|
10
|
+
left: 0;
|
|
11
|
+
right: 0;
|
|
12
|
+
bottom: 0;
|
|
13
|
+
z-index: 1;
|
|
14
|
+
}
|
|
15
|
+
`;
|
|
16
|
+
|
|
17
|
+
export const applyLinkAttributes = ({ linkElement, href, newTab, rel }) => {
|
|
18
|
+
linkElement.href = href;
|
|
19
|
+
|
|
20
|
+
if (newTab) {
|
|
21
|
+
linkElement.target = "_blank";
|
|
22
|
+
} else {
|
|
23
|
+
linkElement.removeAttribute("target");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (rel != null) {
|
|
27
|
+
linkElement.rel = rel;
|
|
28
|
+
} else if (newTab) {
|
|
29
|
+
linkElement.rel = "noopener noreferrer";
|
|
30
|
+
} else {
|
|
31
|
+
linkElement.removeAttribute("rel");
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const syncLinkOverlay = ({
|
|
36
|
+
shadowRoot,
|
|
37
|
+
slotElement,
|
|
38
|
+
linkElement,
|
|
39
|
+
href,
|
|
40
|
+
newTab,
|
|
41
|
+
rel,
|
|
42
|
+
}) => {
|
|
43
|
+
if (slotElement.parentNode !== shadowRoot) {
|
|
44
|
+
shadowRoot.appendChild(slotElement);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!href) {
|
|
48
|
+
if (linkElement && linkElement.parentNode === shadowRoot) {
|
|
49
|
+
shadowRoot.removeChild(linkElement);
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const nextLinkElement = linkElement || document.createElement("a");
|
|
55
|
+
applyLinkAttributes({
|
|
56
|
+
linkElement: nextLinkElement,
|
|
57
|
+
href,
|
|
58
|
+
newTab,
|
|
59
|
+
rel,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
if (nextLinkElement.parentNode !== shadowRoot) {
|
|
63
|
+
shadowRoot.appendChild(nextLinkElement);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return nextLinkElement;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export const syncLinkWrapper = ({
|
|
70
|
+
shadowRoot,
|
|
71
|
+
childElement,
|
|
72
|
+
linkElement,
|
|
73
|
+
href,
|
|
74
|
+
newTab,
|
|
75
|
+
rel,
|
|
76
|
+
}) => {
|
|
77
|
+
if (!href) {
|
|
78
|
+
if (linkElement) {
|
|
79
|
+
if (childElement.parentNode === linkElement) {
|
|
80
|
+
shadowRoot.appendChild(childElement);
|
|
81
|
+
}
|
|
82
|
+
if (linkElement.parentNode === shadowRoot) {
|
|
83
|
+
shadowRoot.removeChild(linkElement);
|
|
84
|
+
}
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (childElement.parentNode !== shadowRoot) {
|
|
89
|
+
shadowRoot.appendChild(childElement);
|
|
90
|
+
}
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const nextLinkElement = linkElement || document.createElement("a");
|
|
95
|
+
applyLinkAttributes({
|
|
96
|
+
linkElement: nextLinkElement,
|
|
97
|
+
href,
|
|
98
|
+
newTab,
|
|
99
|
+
rel,
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
if (childElement.parentNode !== nextLinkElement) {
|
|
103
|
+
nextLinkElement.appendChild(childElement);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (nextLinkElement.parentNode !== shadowRoot) {
|
|
107
|
+
shadowRoot.appendChild(nextLinkElement);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return nextLinkElement;
|
|
111
|
+
};
|
package/src/common.js
CHANGED
|
@@ -7,7 +7,7 @@ function css(strings, ...values) {
|
|
|
7
7
|
return str;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
const breakpoints = ["
|
|
10
|
+
const breakpoints = ["sm", "md", "lg", "xl"];
|
|
11
11
|
|
|
12
12
|
const styleMap = {
|
|
13
13
|
mt: "margin-top",
|
|
@@ -36,8 +36,6 @@ const styleMap = {
|
|
|
36
36
|
br: "border-radius",
|
|
37
37
|
pos: "position",
|
|
38
38
|
shadow: "box-shadow",
|
|
39
|
-
ta: "text-align",
|
|
40
|
-
c: "color",
|
|
41
39
|
cur: "cursor",
|
|
42
40
|
};
|
|
43
41
|
|
|
@@ -59,7 +57,7 @@ const mediaQueries = {
|
|
|
59
57
|
sm: "@media only screen and (max-width: 640px)",
|
|
60
58
|
};
|
|
61
59
|
|
|
62
|
-
const generateCSS = (styles, descendants = {}) => {
|
|
60
|
+
const generateCSS = (styles, descendants = {}, targetSelector = null) => {
|
|
63
61
|
let css = "";
|
|
64
62
|
|
|
65
63
|
for (const [size, mediaQuery] of Object.entries(mediaQueries)) {
|
|
@@ -77,6 +75,16 @@ const generateCSS = (styles, descendants = {}) => {
|
|
|
77
75
|
const hoverAttributeWithBreakpoint =
|
|
78
76
|
size === "default" ? `h-${attr}` : `${size}-h-${attr}`;
|
|
79
77
|
|
|
78
|
+
// Build selector: either :host([...]) or :host([...]) targetSelector
|
|
79
|
+
const buildSelector = (attrStr) => {
|
|
80
|
+
const base = `:host([${attrStr}="${value}"])`;
|
|
81
|
+
if (targetSelector) {
|
|
82
|
+
// Generate: :host([...]) target1, :host([...]) target2
|
|
83
|
+
return targetSelector.split(',').map(t => `${base} ${t.trim()}`).join(', ');
|
|
84
|
+
}
|
|
85
|
+
return base + dscendant;
|
|
86
|
+
};
|
|
87
|
+
|
|
80
88
|
if (cssProperties) {
|
|
81
89
|
// Handle multiple properties if mapped in styleMap
|
|
82
90
|
const properties = cssProperties.split(" ");
|
|
@@ -85,20 +93,20 @@ const generateCSS = (styles, descendants = {}) => {
|
|
|
85
93
|
.join(" ");
|
|
86
94
|
|
|
87
95
|
css += `
|
|
88
|
-
|
|
96
|
+
${buildSelector(attributeWithBreakpoint)}{
|
|
89
97
|
${propertyRules}
|
|
90
98
|
}
|
|
91
|
-
|
|
99
|
+
${buildSelector(hoverAttributeWithBreakpoint)}:hover{
|
|
92
100
|
${propertyRules}
|
|
93
101
|
}
|
|
94
102
|
`;
|
|
95
103
|
} else {
|
|
96
104
|
// Attribute is not mapped, handle directly
|
|
97
105
|
css += `
|
|
98
|
-
|
|
106
|
+
${buildSelector(attributeWithBreakpoint)}{
|
|
99
107
|
${rule}
|
|
100
108
|
}
|
|
101
|
-
|
|
109
|
+
${buildSelector(hoverAttributeWithBreakpoint)}:hover{
|
|
102
110
|
${rule}
|
|
103
111
|
}
|
|
104
112
|
`;
|
|
@@ -129,11 +137,20 @@ const endsWithPercentage = (inputStr) => {
|
|
|
129
137
|
return /%$/.test(inputStr);
|
|
130
138
|
};
|
|
131
139
|
|
|
140
|
+
const endsWithFlexGrowUnit = (inputStr) => {
|
|
141
|
+
// Matches integers 1-12 followed by "fg"
|
|
142
|
+
return /^([1-9]|1[0-2])fg$/.test(inputStr);
|
|
143
|
+
};
|
|
144
|
+
|
|
132
145
|
const dimensionWithUnit = (dimension) => {
|
|
133
146
|
if (dimension === undefined) {
|
|
134
147
|
return;
|
|
135
148
|
}
|
|
136
149
|
|
|
150
|
+
if (endsWithFlexGrowUnit(dimension)) {
|
|
151
|
+
return dimension;
|
|
152
|
+
}
|
|
153
|
+
|
|
137
154
|
if (endsWithPercentage(dimension)) {
|
|
138
155
|
return dimension;
|
|
139
156
|
}
|
|
@@ -216,3 +233,21 @@ export {
|
|
|
216
233
|
convertObjectToCssString,
|
|
217
234
|
mediaQueries,
|
|
218
235
|
};
|
|
236
|
+
|
|
237
|
+
export {
|
|
238
|
+
overlayLinkStyles,
|
|
239
|
+
applyLinkAttributes,
|
|
240
|
+
syncLinkOverlay,
|
|
241
|
+
syncLinkWrapper,
|
|
242
|
+
} from "./common/link.js";
|
|
243
|
+
|
|
244
|
+
export {
|
|
245
|
+
responsiveStyleSizes,
|
|
246
|
+
createResponsiveStyleBuckets,
|
|
247
|
+
} from "./common/responsive.js";
|
|
248
|
+
|
|
249
|
+
export {
|
|
250
|
+
isFlexGrowDimension,
|
|
251
|
+
applyDimensionToStyleBucket,
|
|
252
|
+
applyInlineWidthDimension,
|
|
253
|
+
} from "./common/dimensions.js";
|
|
@@ -2,25 +2,25 @@ export const createInitialState = () => Object.freeze({
|
|
|
2
2
|
open: false
|
|
3
3
|
});
|
|
4
4
|
|
|
5
|
-
const blacklistedAttrs = ['id', 'class', 'style', 'slot', '
|
|
5
|
+
const blacklistedAttrs = ['id', 'class', 'style', 'slot', 'label', 'content'];
|
|
6
6
|
|
|
7
|
-
const stringifyAttrs = (
|
|
8
|
-
return Object.entries(
|
|
7
|
+
const stringifyAttrs = (props = {}) => {
|
|
8
|
+
return Object.entries(props)
|
|
9
9
|
.filter(([key]) => !blacklistedAttrs.includes(key))
|
|
10
10
|
.map(([key, value]) => `${key}=${value}`)
|
|
11
11
|
.join(' ');
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
-
export const selectViewData = ({ state, props
|
|
14
|
+
export const selectViewData = ({ state, props }) => {
|
|
15
15
|
return {
|
|
16
|
-
|
|
17
|
-
content:
|
|
16
|
+
label: props.label || '',
|
|
17
|
+
content: props.content || '',
|
|
18
18
|
openClass: state.open ? 'content-wrapper open' : 'content-wrapper',
|
|
19
19
|
chevronIcon: state.open ? 'chevronUp' : 'chevronDown',
|
|
20
|
-
containerAttrString: stringifyAttrs(
|
|
20
|
+
containerAttrString: stringifyAttrs(props),
|
|
21
21
|
};
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
-
export const toggleOpen = (state) => {
|
|
24
|
+
export const toggleOpen = ({ state }) => {
|
|
25
25
|
state.open = !state.open;
|
|
26
26
|
};
|
|
@@ -1,55 +1,25 @@
|
|
|
1
|
-
elementName: rtgl-accordion-item
|
|
2
|
-
|
|
3
|
-
viewDataSchema:
|
|
4
|
-
type: object
|
|
5
|
-
properties:
|
|
6
|
-
title:
|
|
7
|
-
type: string
|
|
8
|
-
content:
|
|
9
|
-
type: string
|
|
10
|
-
openClass:
|
|
11
|
-
type: string
|
|
12
|
-
chevronIcon:
|
|
13
|
-
type: string
|
|
14
|
-
containerAttrString:
|
|
15
|
-
type: string
|
|
16
|
-
|
|
17
|
-
attrsSchema:
|
|
18
|
-
type: object
|
|
19
|
-
properties:
|
|
20
|
-
title:
|
|
21
|
-
type: string
|
|
22
|
-
content:
|
|
23
|
-
type: string
|
|
24
|
-
w:
|
|
25
|
-
type: string
|
|
26
|
-
|
|
27
1
|
refs:
|
|
28
2
|
header:
|
|
29
3
|
eventListeners:
|
|
30
4
|
click:
|
|
31
5
|
handler: handleClickHeader
|
|
32
|
-
|
|
33
6
|
styles:
|
|
34
7
|
.content-wrapper:
|
|
35
8
|
display: grid
|
|
36
9
|
grid-template-rows: 0fr
|
|
37
10
|
transition: grid-template-rows 0.2s ease-out
|
|
38
|
-
|
|
39
11
|
.content-wrapper.open:
|
|
40
12
|
grid-template-rows: 1fr
|
|
41
|
-
|
|
42
13
|
.content-inner:
|
|
43
14
|
overflow: hidden
|
|
44
|
-
|
|
45
15
|
template:
|
|
46
16
|
- rtgl-view d=v ${containerAttrString}:
|
|
47
|
-
- rtgl-view#header d=h av=c w=f pv=md cur=
|
|
48
|
-
- rtgl-text: ${
|
|
49
|
-
- rtgl-view
|
|
50
|
-
- rtgl-svg svg=${chevronIcon} wh=16 c=mu-fg:
|
|
17
|
+
- rtgl-view#header d=h av=c w=f pv=md cur=pointer:
|
|
18
|
+
- rtgl-text: ${label}
|
|
19
|
+
- rtgl-view w=1fg: null
|
|
20
|
+
- rtgl-svg svg=${chevronIcon} wh=16 c=mu-fg: null
|
|
51
21
|
- div class="${openClass}":
|
|
52
22
|
- div class=content-inner:
|
|
53
23
|
- rtgl-view pb=md:
|
|
54
24
|
- rtgl-text c=mu-fg: ${content}
|
|
55
|
-
- slot name=content:
|
|
25
|
+
- slot name=content: null
|
|
@@ -1,10 +1,31 @@
|
|
|
1
1
|
export const handleClickItem = (deps, payload) => {
|
|
2
|
-
const { dispatchEvent } = deps;
|
|
2
|
+
const { dispatchEvent, props } = deps;
|
|
3
3
|
const event = payload._event;
|
|
4
|
-
const
|
|
4
|
+
const index = Number(event.currentTarget.dataset.index);
|
|
5
|
+
const item = Array.isArray(props.items) ? props.items[index] : undefined;
|
|
6
|
+
|
|
7
|
+
if (!item) {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if (item.disabled || item.current) {
|
|
12
|
+
event.preventDefault();
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const hasHref = typeof item.href === 'string' && item.href.length > 0;
|
|
17
|
+
if (!hasHref) {
|
|
18
|
+
event.preventDefault();
|
|
19
|
+
}
|
|
20
|
+
|
|
5
21
|
dispatchEvent(new CustomEvent('item-click', {
|
|
6
22
|
detail: {
|
|
7
|
-
id
|
|
23
|
+
id: item.id,
|
|
24
|
+
path: item.path,
|
|
25
|
+
href: item.href,
|
|
26
|
+
item,
|
|
27
|
+
index,
|
|
28
|
+
trigger: event.type,
|
|
8
29
|
}
|
|
9
30
|
}));
|
|
10
31
|
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
componentName: rtgl-breadcrumb
|
|
2
|
+
propsSchema:
|
|
3
|
+
type: object
|
|
4
|
+
properties:
|
|
5
|
+
items:
|
|
6
|
+
type: array
|
|
7
|
+
items:
|
|
8
|
+
type: object
|
|
9
|
+
properties:
|
|
10
|
+
label:
|
|
11
|
+
type: string
|
|
12
|
+
id:
|
|
13
|
+
type: string
|
|
14
|
+
href:
|
|
15
|
+
type: string
|
|
16
|
+
path:
|
|
17
|
+
type: string
|
|
18
|
+
current:
|
|
19
|
+
type: boolean
|
|
20
|
+
disabled:
|
|
21
|
+
type: boolean
|
|
22
|
+
click:
|
|
23
|
+
type: boolean
|
|
24
|
+
newTab:
|
|
25
|
+
type: boolean
|
|
26
|
+
rel:
|
|
27
|
+
type: string
|
|
28
|
+
sep:
|
|
29
|
+
type: string
|
|
30
|
+
default: breadcrumb-arrow
|
|
31
|
+
max:
|
|
32
|
+
type: number
|
|
33
|
+
events:
|
|
34
|
+
item-click:
|
|
35
|
+
type: object
|
|
36
|
+
properties:
|
|
37
|
+
id:
|
|
38
|
+
type: string
|
|
39
|
+
path:
|
|
40
|
+
type: string
|
|
41
|
+
href:
|
|
42
|
+
type: string
|
|
43
|
+
item:
|
|
44
|
+
type: object
|
|
45
|
+
index:
|
|
46
|
+
type: number
|
|
47
|
+
trigger:
|
|
48
|
+
type: string
|
|
49
|
+
methods:
|
|
50
|
+
type: object
|
|
51
|
+
properties: {}
|
|
@@ -1,22 +1,78 @@
|
|
|
1
1
|
export const createInitialState = () => Object.freeze({});
|
|
2
2
|
|
|
3
|
-
const blacklistedAttrs = ['id', 'class', 'style', 'slot'];
|
|
3
|
+
const blacklistedAttrs = ['id', 'class', 'style', 'slot', 'items', 'sep', 'max', 'separator'];
|
|
4
4
|
|
|
5
|
-
const stringifyAttrs = (
|
|
6
|
-
return Object.entries(
|
|
5
|
+
const stringifyAttrs = (props = {}) => {
|
|
6
|
+
return Object.entries(props).filter(([key]) => !blacklistedAttrs.includes(key)).map(([key, value]) => `${key}=${value}`).join(' ');
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
const toNumber = (value) => {
|
|
10
|
+
if (value === undefined || value === null || value === '') {
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
11
13
|
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
+
const parsed = Number(value);
|
|
15
|
+
return Number.isNaN(parsed) ? undefined : parsed;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const escapeAttrValue = (value) => `${value}`.replace(/"/g, '"');
|
|
19
|
+
|
|
20
|
+
const collapseItems = (items, max) => {
|
|
21
|
+
if (!max || max < 3 || items.length <= max) {
|
|
22
|
+
return items;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const tailCount = max - 2;
|
|
26
|
+
return [
|
|
27
|
+
items[0],
|
|
28
|
+
{ isEllipsis: true, label: '...' },
|
|
29
|
+
...items.slice(-tailCount),
|
|
30
|
+
];
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const normalizeItems = (items) => {
|
|
34
|
+
return items.map((item, index) => {
|
|
35
|
+
const hasHref = typeof item.href === 'string' && item.href.length > 0;
|
|
36
|
+
const hasPath = item.path !== undefined && item.path !== null && `${item.path}` !== '';
|
|
37
|
+
const isCurrent = !!item.current;
|
|
38
|
+
const isDisabled = !!item.disabled;
|
|
39
|
+
const isInteractive = !isCurrent && !isDisabled && (hasHref || hasPath || !!item.click);
|
|
40
|
+
const relValue = item.rel || (item.newTab ? 'noopener noreferrer' : '');
|
|
41
|
+
const linkExtraAttrs = [
|
|
42
|
+
item.newTab ? 'target="_blank"' : '',
|
|
43
|
+
relValue ? `rel="${escapeAttrValue(relValue)}"` : '',
|
|
44
|
+
].filter(Boolean).join(' ');
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
...item,
|
|
48
|
+
label: item.label || '',
|
|
49
|
+
index,
|
|
50
|
+
href: hasHref ? item.href : undefined,
|
|
51
|
+
path: hasPath ? item.path : undefined,
|
|
52
|
+
isCurrent,
|
|
53
|
+
isDisabled,
|
|
54
|
+
isInteractive,
|
|
55
|
+
linkExtraAttrs,
|
|
56
|
+
c: isCurrent ? 'fg' : 'mu-fg',
|
|
57
|
+
};
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export const selectViewData = ({ props }) => {
|
|
62
|
+
const containerAttrString = stringifyAttrs(props);
|
|
63
|
+
|
|
64
|
+
const items = Array.isArray(props.items) ? props.items : [];
|
|
65
|
+
const max = toNumber(props.max);
|
|
66
|
+
const sep = props.sep || 'breadcrumb-arrow';
|
|
67
|
+
|
|
68
|
+
const normalizedItems = normalizeItems(items);
|
|
69
|
+
const collapsedItems = collapseItems(normalizedItems, max);
|
|
14
70
|
|
|
15
71
|
// Add separators between items, but not after the last one
|
|
16
72
|
const itemsWithSeparators = [];
|
|
17
|
-
|
|
73
|
+
collapsedItems.forEach((item, index) => {
|
|
18
74
|
itemsWithSeparators.push(item);
|
|
19
|
-
if (index <
|
|
75
|
+
if (index < collapsedItems.length - 1) {
|
|
20
76
|
itemsWithSeparators.push({ isSeparator: true });
|
|
21
77
|
}
|
|
22
78
|
});
|
|
@@ -24,6 +80,6 @@ export const selectViewData = ({ props, attrs }) => {
|
|
|
24
80
|
return {
|
|
25
81
|
containerAttrString,
|
|
26
82
|
items: itemsWithSeparators,
|
|
27
|
-
|
|
83
|
+
sep
|
|
28
84
|
};
|
|
29
85
|
}
|