eco-vue-js 0.26.27 → 0.26.28
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/components/InfiniteList/WInfiniteListWrapper.vue.d.ts.map +1 -1
- package/dist/components/InfiniteList/WInfiniteListWrapper.vue_vue_type_script_setup_true_lang.js +3 -1
- package/dist/components/Nav/WNavItem.vue.d.ts +1 -0
- package/dist/components/Nav/WNavItem.vue.d.ts.map +1 -1
- package/dist/components/Nav/WNavItem.vue_vue_type_script_setup_true_lang.js +20 -11
- package/dist/components/Nav/WNavItemExpand.vue.d.ts.map +1 -1
- package/dist/components/Nav/WNavItemExpand.vue_vue_type_script_setup_true_lang.js +27 -39
- package/dist/components/Nav/use/useNavGroupDropdown.d.ts +7 -0
- package/dist/components/Nav/use/useNavGroupDropdown.d.ts.map +1 -0
- package/dist/components/Nav/use/useNavGroupDropdown.js +38 -0
- package/docs/components/nav-bar.md +1 -1
- package/docs/llms.txt +1 -1
- package/package.json +1 -1
- package/tailwind-base/css/surfaces.css +102 -23
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WInfiniteListWrapper.vue.d.ts","sourceRoot":"","sources":["../../../../src/components/InfiniteList/WInfiniteListWrapper.vue"],"names":[],"mappings":"AAsDA;
|
|
1
|
+
{"version":3,"file":"WInfiniteListWrapper.vue.d.ts","sourceRoot":"","sources":["../../../../src/components/InfiniteList/WInfiniteListWrapper.vue"],"names":[],"mappings":"AAsDA;AAqKA,OAAO,KAAK,EAAC,uBAAuB,EAAC,MAAM,SAAS,CAAA;AAEpD,OAAO,EAAC,KAAK,KAAK,EAA2E,MAAM,KAAK,CAAA;AAcxG,KAAK,WAAW,GAAG;IACjB,gIAAgI;IAChI,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,kFAAkF;IAClF,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB,CAAC;AAgFF,KAAK,WAAW,GAAG;IACjB,uGAAuG;IACvG,MAAM,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,KAAK,EAAE,CAAA;IACnD,+EAA+E;IAC/E,OAAO,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,KAAK,EAAE,CAAA;CACrD,CAAC;AA6HF,QAAA,MAAM,UAAU,kSAEd,CAAC;AACH,QAAA,MAAM,YAAY,EAAS,eAAe,CAAC,OAAO,UAAU,EAAE,WAAW,CAAC,CAAC;wBACtD,OAAO,YAAY;AAAxC,wBAAyC;AACzC,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}
|
package/dist/components/InfiniteList/WInfiniteListWrapper.vue_vue_type_script_setup_true_lang.js
CHANGED
|
@@ -39,11 +39,13 @@ var WInfiniteListWrapper_vue_vue_type_script_setup_true_lang_default = /*@__PURE
|
|
|
39
39
|
};
|
|
40
40
|
const sectionHeadHeight = isContained ? null : inject(wSectionHeadHeight, null);
|
|
41
41
|
const isPage = ref(false);
|
|
42
|
-
const
|
|
42
|
+
const stickyGap = ref(0);
|
|
43
|
+
const sectionHeadOffset = computed(() => isPage.value ? sectionHeadHeight?.value ?? 0 : stickyGap.value);
|
|
43
44
|
const observe = () => {
|
|
44
45
|
if (!indicatorRef.value) return;
|
|
45
46
|
isPage.value = indicatorRef.value.closest(".w-list-page") !== null;
|
|
46
47
|
const top = getStickyTop();
|
|
48
|
+
stickyGap.value = isContained ? 0 : Math.max(0, top - headerHeight.value);
|
|
47
49
|
if (observer && top === observerTop) return;
|
|
48
50
|
observer?.disconnect();
|
|
49
51
|
observerTop = top;
|
|
@@ -7,6 +7,7 @@ type __VLS_Slots = {
|
|
|
7
7
|
};
|
|
8
8
|
declare const __VLS_base: import('vue').DefineComponent<NavItemProps, {
|
|
9
9
|
isActive: import('vue').ComputedRef<boolean>;
|
|
10
|
+
anchorRef: Readonly<import('vue').ShallowRef<HTMLSpanElement | null>>;
|
|
10
11
|
}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<NavItemProps> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
11
12
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
12
13
|
declare const _default: typeof __VLS_export;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WNavItem.vue.d.ts","sourceRoot":"","sources":["../../../../src/components/Nav/WNavItem.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"WNavItem.vue.d.ts","sourceRoot":"","sources":["../../../../src/components/Nav/WNavItem.vue"],"names":[],"mappings":"AAkGA;AA0JA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,SAAS,CAAA;AAkBzC,KAAK,WAAW,GAAG;IACjB,qFAAqF;IACrF,IAAI,CAAC,EAAE,MAAM,IAAI,CAAA;IACjB,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,IAAI,CAAA;CACnB,CAAC;AAmSF,QAAA,MAAM,UAAU;;;qPAGd,CAAC;AACH,QAAA,MAAM,YAAY,EAAS,eAAe,CAAC,OAAO,UAAU,EAAE,WAAW,CAAC,CAAC;wBACtD,OAAO,YAAY;AAAxC,wBAAyC;AACzC,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}
|
|
@@ -5,7 +5,7 @@ import WTextOverflow_default from "../TextOverflow/WTextOverflow.vue.js";
|
|
|
5
5
|
import { useOptionalRoute, useOptionalRouter } from "../../composables/useOptionalRouter.js";
|
|
6
6
|
import { getRouteTitle, getRouteTitleShort } from "../../utils/useRouteTitle.js";
|
|
7
7
|
import { isEqualObj, numberCompactFormatter } from "../../utils/utils.js";
|
|
8
|
-
import { Transition, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, normalizeClass, openBlock, renderSlot, resolveDynamicComponent, toDisplayString, unref, withCtx } from "vue";
|
|
8
|
+
import { Transition, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, normalizeClass, openBlock, renderSlot, resolveDynamicComponent, toDisplayString, unref, useTemplateRef, withCtx } from "vue";
|
|
9
9
|
// src/components/Nav/WNavItem.vue?vue&type=script&setup=true&lang.ts
|
|
10
10
|
var _hoisted_1 = {
|
|
11
11
|
key: 0,
|
|
@@ -15,11 +15,16 @@ var _hoisted_2 = {
|
|
|
15
15
|
key: 0,
|
|
16
16
|
class: "absolute left-3 top-0 flex h-full items-center"
|
|
17
17
|
};
|
|
18
|
-
var _hoisted_3 = {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
var _hoisted_3 = {
|
|
19
|
+
ref: "anchor",
|
|
20
|
+
"aria-hidden": "true",
|
|
21
|
+
class: "w-nav-item-anchor pointer-events-none absolute inset-x-0"
|
|
22
|
+
};
|
|
23
|
+
var _hoisted_4 = { class: "[overflow:inherit]" };
|
|
24
|
+
var _hoisted_5 = { class: "flex items-center" };
|
|
25
|
+
var _hoisted_6 = { class: "last-not:pr-1 min-w-0 font-normal" };
|
|
26
|
+
var _hoisted_7 = { class: "relative inline-flex max-w-full items-center whitespace-nowrap tracking-wide" };
|
|
27
|
+
var _hoisted_8 = {
|
|
23
28
|
key: 0,
|
|
24
29
|
class: "shrink-0"
|
|
25
30
|
};
|
|
@@ -54,7 +59,10 @@ var WNavItem_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineC
|
|
|
54
59
|
const iconLocal = computed(() => props.icon ?? routeTo.value?.meta?.icon);
|
|
55
60
|
const titleLocal = computed(() => props.title ?? (routeTitle.value ? getRouteTitleShort(routeTitle.value) : void 0) ?? (typeof routeTo.value?.meta?.titleShort === "string" ? routeTo.value.meta.titleShort : typeof routeTo.value?.meta?.title === "string" ? routeTo.value.meta.title : ""));
|
|
56
61
|
const isTextColor = computed(() => props.hasActive ? !props.indent : isActive.value);
|
|
57
|
-
__expose({
|
|
62
|
+
__expose({
|
|
63
|
+
isActive,
|
|
64
|
+
anchorRef: useTemplateRef("anchor")
|
|
65
|
+
});
|
|
58
66
|
return (_ctx, _cache) => {
|
|
59
67
|
return openBlock(), createBlock(WRouterLink_default, {
|
|
60
68
|
to: __props.to,
|
|
@@ -84,21 +92,22 @@ var WNavItem_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineC
|
|
|
84
92
|
default: withCtx(() => [__props.indent && !__props.expand && isActive.value ? (openBlock(), createElementBlock("div", _hoisted_2, [..._cache[0] || (_cache[0] = [createElementVNode("div", { class: "square-1.5 rounded-full bg-(--w-nav-item-dot-color)" }, null, -1)])])) : createCommentVNode("", true)]),
|
|
85
93
|
_: 1
|
|
86
94
|
}),
|
|
87
|
-
createElementVNode("
|
|
95
|
+
createElementVNode("span", _hoisted_3, null, 512),
|
|
96
|
+
createElementVNode("div", _hoisted_4, [createElementVNode("div", { class: normalizeClass(["w-ripple w-ripple-hover relative grid grid-cols-[1.5rem_1fr_auto] items-center rounded-(--w-nav-item-rounded,var(--radius-lg)) pr-2", {
|
|
88
97
|
"before:opacity-10": __props.hovered,
|
|
89
98
|
"pl-4": __props.indent,
|
|
90
99
|
"pl-2": !__props.indent
|
|
91
100
|
}]) }, [
|
|
92
|
-
createElementVNode("div",
|
|
101
|
+
createElementVNode("div", _hoisted_5, [iconLocal.value ? (openBlock(), createBlock(resolveDynamicComponent(iconLocal.value), {
|
|
93
102
|
key: 0,
|
|
94
103
|
class: "square-[1.25em]"
|
|
95
104
|
})) : renderSlot(_ctx.$slots, "icon", {}, void 0, void 0, 1)]),
|
|
96
|
-
createElementVNode("div",
|
|
105
|
+
createElementVNode("div", _hoisted_6, [createElementVNode("span", _hoisted_7, [
|
|
97
106
|
createVNode(WTextOverflow_default, { class: "min-w-0 leading-loose" }, {
|
|
98
107
|
default: withCtx(() => [createTextVNode(toDisplayString(titleLocal.value), 1)]),
|
|
99
108
|
_: 1
|
|
100
109
|
}),
|
|
101
|
-
!__props.skeleton ? (openBlock(), createElementBlock("span",
|
|
110
|
+
!__props.skeleton ? (openBlock(), createElementBlock("span", _hoisted_8, toDisplayString(typeof __props.count === "number" ? `\u00A0(${unref(numberCompactFormatter).format(__props.count)})` : ""), 1)) : (openBlock(), createBlock(WSkeleton_default, {
|
|
102
111
|
key: 1,
|
|
103
112
|
class: "w-skeleton-w-10 ml-1 inline-flex shrink-0"
|
|
104
113
|
})),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WNavItemExpand.vue.d.ts","sourceRoot":"","sources":["../../../../src/components/Nav/WNavItemExpand.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"WNavItemExpand.vue.d.ts","sourceRoot":"","sources":["../../../../src/components/Nav/WNavItemExpand.vue"],"names":[],"mappings":"AAiGA;AAuKA,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,SAAS,CAAA;AAG/C,OAAO,EAAC,KAAK,KAAK,EAA2D,MAAM,KAAK,CAAA;AAoDxF,KAAK,WAAW,GAAG;IACjB,4HAA4H;IAC5H,OAAO,CAAC,EAAE,MAAM,KAAK,EAAE,CAAA;IACvB,oDAAoD;IACpD,IAAI,CAAC,EAAE,MAAM,KAAK,EAAE,CAAA;CACrB,CAAC;AAkVF,QAAA,MAAM,UAAU;;;2PAGd,CAAC;AACH,QAAA,MAAM,YAAY,EAAS,eAAe,CAAC,OAAO,UAAU,EAAE,WAAW,CAAC,CAAC;wBACtD,OAAO,YAAY;AAAxC,wBAAyC;AACzC,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}
|
|
@@ -6,11 +6,12 @@ import { useIsMobile } from "../../utils/mobile.js";
|
|
|
6
6
|
import { unwrapSlots } from "../../utils/utils.js";
|
|
7
7
|
import WNavItem_default from "./WNavItem.vue.js";
|
|
8
8
|
import WNavItemTransition_default from "./WNavItemTransition.vue.js";
|
|
9
|
+
import { useNavGroupDropdown } from "./use/useNavGroupDropdown.js";
|
|
9
10
|
import WClickOutside_default from "../ClickOutside/WClickOutside.vue.js";
|
|
10
|
-
import { Fragment, computed, createBlock, createElementBlock, createElementVNode, createVNode, defineComponent, mergeProps, nextTick, normalizeClass, normalizeProps,
|
|
11
|
+
import { Fragment, computed, createBlock, createElementBlock, createElementVNode, createVNode, defineComponent, mergeProps, nextTick, normalizeClass, normalizeProps, openBlock, ref, renderList, renderSlot, resolveDynamicComponent, unref, useSlots, useTemplateRef, watch, withCtx } from "vue";
|
|
11
12
|
// src/components/Nav/WNavItemExpand.vue?vue&type=script&setup=true&lang.ts
|
|
12
13
|
var _hoisted_1 = { key: 1 };
|
|
13
|
-
var _hoisted_2 = { class: "w-nav-bar w-nav-bar-dropdown w-nav-bar-width overflow-
|
|
14
|
+
var _hoisted_2 = { class: "w-nav-bar w-nav-bar-dropdown w-nav-bar-width overflow-y-auto overscroll-contain border border-solid border-line-raised text-start font-normal shadow" };
|
|
14
15
|
var WNavItemExpand_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
|
|
15
16
|
__name: "WNavItemExpand",
|
|
16
17
|
props: {
|
|
@@ -30,7 +31,7 @@ var WNavItemExpand_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
|
|
|
30
31
|
const slotsDefault = computed(() => unwrapSlots(slots.default?.() ?? []));
|
|
31
32
|
const componentRef = useTemplateRef("component");
|
|
32
33
|
const innerRef = useTemplateRef("inner");
|
|
33
|
-
const isDropdownOpen =
|
|
34
|
+
const { isOpen: isDropdownOpen, show: showDropdown, hide: hideDropdown, close: closeDropdown } = useNavGroupDropdown();
|
|
34
35
|
const hasActive = ref(false);
|
|
35
36
|
const isActive = computed(() => hasActive.value || (componentRef.value?.isActive ?? false));
|
|
36
37
|
const hasInnerActive = computed(() => innerRef.value?.some((item) => item.isActive) ?? false);
|
|
@@ -39,32 +40,10 @@ var WNavItemExpand_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
|
|
|
39
40
|
await nextTick();
|
|
40
41
|
hasActive.value = innerRef.value?.some((item) => item.isActive) ?? false;
|
|
41
42
|
};
|
|
42
|
-
let timeout = null;
|
|
43
|
-
const showDropdown = () => {
|
|
44
|
-
if (timeout) {
|
|
45
|
-
clearTimeout(timeout);
|
|
46
|
-
timeout = null;
|
|
47
|
-
}
|
|
48
|
-
isDropdownOpen.value = true;
|
|
49
|
-
};
|
|
50
|
-
const hideDropdown = () => {
|
|
51
|
-
if (timeout) {
|
|
52
|
-
clearTimeout(timeout);
|
|
53
|
-
timeout = null;
|
|
54
|
-
}
|
|
55
|
-
timeout = setTimeout(() => {
|
|
56
|
-
isDropdownOpen.value = false;
|
|
57
|
-
}, 20);
|
|
58
|
-
};
|
|
59
43
|
watch(hasInnerActive, updateHasActive, { immediate: true });
|
|
60
44
|
watch(isActive, updateHasActive, { immediate: true });
|
|
61
45
|
watch(slotsDefault, updateHasActive, { immediate: true });
|
|
62
|
-
watch(hasActive,
|
|
63
|
-
isDropdownOpen.value = false;
|
|
64
|
-
}, { immediate: true });
|
|
65
|
-
onBeforeUnmount(() => {
|
|
66
|
-
isDropdownOpen.value = false;
|
|
67
|
-
});
|
|
46
|
+
watch(hasActive, closeDropdown, { immediate: true });
|
|
68
47
|
__expose({
|
|
69
48
|
isActive,
|
|
70
49
|
isVisible
|
|
@@ -74,13 +53,14 @@ var WNavItemExpand_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
|
|
|
74
53
|
icon: withCtx(() => [renderSlot(_ctx.$slots, "icon")]),
|
|
75
54
|
_: 3
|
|
76
55
|
}, 16)) : (openBlock(), createElementBlock("div", _hoisted_1, [createVNode(WDropdownMenu_default, {
|
|
77
|
-
"is-open": isDropdownOpen
|
|
56
|
+
"is-open": unref(isDropdownOpen) && !isActive.value,
|
|
78
57
|
"horizontal-align": unref(HorizontalAlign).RIGHT_OUTER,
|
|
79
|
-
"
|
|
58
|
+
"parent-element": componentRef.value?.anchorRef ?? void 0,
|
|
59
|
+
"dropdown-class": "w-nav-group-dropdown relative w-max"
|
|
80
60
|
}, {
|
|
81
61
|
toggle: withCtx(() => [createVNode(WNavItem_default, mergeProps(unref(isMobile) || hasActive.value || __props.even ? void 0 : {
|
|
82
|
-
onMouseenter: showDropdown,
|
|
83
|
-
onMouseleave: hideDropdown
|
|
62
|
+
onMouseenter: unref(showDropdown),
|
|
63
|
+
onMouseleave: unref(hideDropdown)
|
|
84
64
|
}, {
|
|
85
65
|
ref: "component",
|
|
86
66
|
to: __props.to ?? slotsDefault.value?.[0]?.props?.to,
|
|
@@ -94,7 +74,7 @@ var WNavItemExpand_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
|
|
|
94
74
|
even: __props.even,
|
|
95
75
|
expand: !__props.to,
|
|
96
76
|
"query-fields": __props.queryFields,
|
|
97
|
-
hovered: isDropdownOpen
|
|
77
|
+
hovered: unref(isDropdownOpen) && !hasActive.value
|
|
98
78
|
}), {
|
|
99
79
|
icon: withCtx(() => [renderSlot(_ctx.$slots, "icon")]),
|
|
100
80
|
right: withCtx(() => [createVNode(unref(IconArrow_default), { class: normalizeClass(["square-3 transition-transform", { "-rotate-90": !hasActive.value && !__props.even }]) }, null, 8, ["class"])]),
|
|
@@ -113,23 +93,31 @@ var WNavItemExpand_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
|
|
|
113
93
|
"query-fields",
|
|
114
94
|
"hovered"
|
|
115
95
|
])]),
|
|
116
|
-
content: withCtx((
|
|
117
|
-
class:
|
|
118
|
-
onMouseenter: showDropdown,
|
|
119
|
-
onMouseleave: hideDropdown,
|
|
120
|
-
onClick: hideDropdown
|
|
96
|
+
content: withCtx(() => [createVNode(WClickOutside_default, {
|
|
97
|
+
class: "w-nav-group-dropdown-content px-1",
|
|
98
|
+
onMouseenter: unref(showDropdown),
|
|
99
|
+
onMouseleave: unref(hideDropdown),
|
|
100
|
+
onClick: unref(hideDropdown)
|
|
121
101
|
}, {
|
|
122
102
|
default: withCtx(() => [createElementVNode("div", _hoisted_2, [(openBlock(true), createElementBlock(Fragment, null, renderList(slotsDefault.value, (slot, index) => {
|
|
123
103
|
return openBlock(), createBlock(resolveDynamicComponent(slot), {
|
|
124
104
|
key: index,
|
|
125
105
|
even: "",
|
|
126
|
-
"onUpdate:isActive": _cache[0] || (_cache[0] = ($event) => $event[1] && hideDropdown())
|
|
106
|
+
"onUpdate:isActive": _cache[0] || (_cache[0] = ($event) => $event[1] && unref(hideDropdown)())
|
|
127
107
|
}, null, 32);
|
|
128
108
|
}), 128))])]),
|
|
129
109
|
_: 1
|
|
130
|
-
}, 8, [
|
|
110
|
+
}, 8, [
|
|
111
|
+
"onMouseenter",
|
|
112
|
+
"onMouseleave",
|
|
113
|
+
"onClick"
|
|
114
|
+
])]),
|
|
131
115
|
_: 3
|
|
132
|
-
}, 8, [
|
|
116
|
+
}, 8, [
|
|
117
|
+
"is-open",
|
|
118
|
+
"horizontal-align",
|
|
119
|
+
"parent-element"
|
|
120
|
+
]), createVNode(WExpansion_default, {
|
|
133
121
|
"is-shown": isActive.value || __props.even,
|
|
134
122
|
class: normalizeClass({ "w-nav-group-collapsed": !isActive.value && !__props.even })
|
|
135
123
|
}, {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useNavGroupDropdown.d.ts","sourceRoot":"","sources":["../../../../../src/components/Nav/use/useNavGroupDropdown.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,mBAAmB;;;;;CAwC/B,CAAA"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { computed, onBeforeUnmount, ref } from "vue";
|
|
2
|
+
// src/components/Nav/use/useNavGroupDropdown.ts
|
|
3
|
+
var openKey = ref(null);
|
|
4
|
+
var timeout = null;
|
|
5
|
+
var clearHide = () => {
|
|
6
|
+
if (timeout === null) return;
|
|
7
|
+
clearTimeout(timeout);
|
|
8
|
+
timeout = null;
|
|
9
|
+
};
|
|
10
|
+
var useNavGroupDropdown = () => {
|
|
11
|
+
const key = Symbol("nav-group");
|
|
12
|
+
const isOpen = computed(() => openKey.value === key);
|
|
13
|
+
const show = () => {
|
|
14
|
+
clearHide();
|
|
15
|
+
openKey.value = key;
|
|
16
|
+
};
|
|
17
|
+
const hide = () => {
|
|
18
|
+
if (!isOpen.value) return;
|
|
19
|
+
clearHide();
|
|
20
|
+
timeout = setTimeout(() => {
|
|
21
|
+
timeout = null;
|
|
22
|
+
if (openKey.value === key) openKey.value = null;
|
|
23
|
+
}, 20);
|
|
24
|
+
};
|
|
25
|
+
const close = () => {
|
|
26
|
+
if (!isOpen.value) return;
|
|
27
|
+
clearHide();
|
|
28
|
+
openKey.value = null;
|
|
29
|
+
};
|
|
30
|
+
onBeforeUnmount(close);
|
|
31
|
+
return {
|
|
32
|
+
isOpen,
|
|
33
|
+
show,
|
|
34
|
+
hide,
|
|
35
|
+
close
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
export { useNavGroupDropdown };
|
|
@@ -24,7 +24,7 @@ The `footer` slot is the nav's bottom, such as a back button or the app's versio
|
|
|
24
24
|
|
|
25
25
|
`WNavItem` is a router link with an icon and a title. Both default to the route's `meta.icon` and `meta.titleShort` (or `meta.title`), so an item is often just `<WNavItem :to="{name: RouteName.PROJECTS}" />`. It is active while the current route has the same name; `queryFields` lists the query params that must match too, for items that open the same route with different filters. `count` shows a number in brackets after the title and `counter` a badge, with `skeleton` while they load.
|
|
26
26
|
|
|
27
|
-
`WNavItemExpand` groups items under a title. The items show under it while one of them is active; otherwise hovering the group opens them in a menu to the right. With `to`, the group is a link of its own. `even` keeps the items always shown and not indented, for a nav inside a page.
|
|
27
|
+
`WNavItemExpand` groups items under a title. The items show under it while one of them is active; otherwise hovering the group opens them in a menu to the right. One group's menu is open at a time, so moving down the nav switches it. The menu lines up with the group by its top, or by its bottom low on the screen, and shifts to stay on screen when it is taller than the room there — it scrolls once taller than the screen. With `to`, the group is a link of its own. `even` keeps the items always shown and not indented, for a nav inside a page.
|
|
28
28
|
|
|
29
29
|
`WNavItemTransition` wraps a list of items so that the ones added or removed with `v-if` — such as an item for the current record — expand and collapse.
|
|
30
30
|
|
package/docs/llms.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# eco-vue-js
|
|
2
2
|
|
|
3
|
-
> Vue 3 UI kit with Tailwind v4 — components, utilities, icons and recipes. These are the docs of version 0.26.
|
|
3
|
+
> Vue 3 UI kit with Tailwind v4 — components, utilities, icons and recipes. These are the docs of version 0.26.28, the one installed next to them. Start with Getting started and Conventions; each component page lists its props, events and slots with examples.
|
|
4
4
|
|
|
5
5
|
Release notes, for what changed between versions: https://github.com/rsmple/eco-vue-js/releases. The docs site, with live demos: https://rsmple.github.io/eco-vue-js/
|
|
6
6
|
|
package/package.json
CHANGED
|
@@ -65,12 +65,10 @@
|
|
|
65
65
|
--w-chrome-gap: 0px;
|
|
66
66
|
--w-chrome-rounded: 0px;
|
|
67
67
|
--w-chrome-border: 0px;
|
|
68
|
-
/* Shadows the bars combine with their edge
|
|
68
|
+
/* Shadows the bars combine with their edge: a theme sets a shadow list, `0 0 #0000` for none, never `none`. */
|
|
69
69
|
--w-chrome-shadow: 0 0 #0000;
|
|
70
70
|
--w-chrome-opacity: 1;
|
|
71
71
|
/* What blurs behind the bars, such as a glass theme's blur. Unset, the header keeps its own and the others none. */
|
|
72
|
-
/* What fills the gap around a floating bar, so content scrolling under the header doesn't show above it. */
|
|
73
|
-
--w-chrome-ring: transparent;
|
|
74
72
|
|
|
75
73
|
/* A picture on the canvas, such as a glass theme's gradient: fixed to the viewport, so what paints it again matches. */
|
|
76
74
|
--w-canvas-image: none;
|
|
@@ -533,8 +531,7 @@
|
|
|
533
531
|
* App chrome. The nav and the actions bar run the screen's full height, so the nav's top, the brand's place, is the
|
|
534
532
|
* frame's top-left corner in every style. Docked (flat), the header spans the screen under them. Floating, each bar
|
|
535
533
|
* is a card `--w-chrome-gap` off the screen edges and the frame's margins, and the header only spans the page between
|
|
536
|
-
* the nav and the actions bar.
|
|
537
|
-
* below: there the page shows, such as a stuck list's section above its toolbar.
|
|
534
|
+
* the nav and the actions bar. The header casts no shadow, so none spreads onto the bars beside it.
|
|
538
535
|
*/
|
|
539
536
|
@layer utilities {
|
|
540
537
|
/* Its content lines up with the page's: the header's own row adds `--inner-margin`, as the page does. */
|
|
@@ -566,9 +563,6 @@
|
|
|
566
563
|
color-mix(in oklab, var(--w-chrome-base) calc(var(--w-chrome-opacity) * 100%), transparent) calc(var(--w-chrome-float) * 100%),
|
|
567
564
|
var(--w-overlay)
|
|
568
565
|
);
|
|
569
|
-
box-shadow:
|
|
570
|
-
var(--w-chrome-shadow),
|
|
571
|
-
0 calc(var(--w-chrome-gap) * -1) 0 var(--w-chrome-gap) var(--w-chrome-ring);
|
|
572
566
|
|
|
573
567
|
/* On phones it spans the screen, like a section: only the edge toward the page is left. */
|
|
574
568
|
@variant sm-not {
|
|
@@ -646,6 +640,30 @@
|
|
|
646
640
|
background-color: color-mix(in oklab, var(--w-surface) calc(var(--w-chrome-float) * 100%), transparent);
|
|
647
641
|
}
|
|
648
642
|
|
|
643
|
+
/*
|
|
644
|
+
* A list header on the page outside any section, such as a page's own toolbar in WInfiniteListWrapper, is a section
|
|
645
|
+
* of its own: the section's paint, edges and padding, reaching into the page gutter, stuck under the header bar as
|
|
646
|
+
* the bars float. Flat, the section tokens are 0: it stays a clear bar the header bar grows behind.
|
|
647
|
+
*/
|
|
648
|
+
.w-infinite-list-header:not(:is(.w-list-page, .surface-section, .surface-card) *) {
|
|
649
|
+
--w-surface: color-mix(in oklab, var(--w-section-base) calc(var(--w-section-opacity) * 100%), var(--w-canvas));
|
|
650
|
+
|
|
651
|
+
margin-inline: calc(var(--w-page-bleed, 0px) * -1);
|
|
652
|
+
padding: var(--w-section-padding);
|
|
653
|
+
background-color: color-mix(in oklab, var(--w-section-base) calc(var(--w-section-opacity) * 100%), transparent);
|
|
654
|
+
border: var(--w-section-border) solid var(--w-line-subtle);
|
|
655
|
+
border-radius: var(--w-section-rounded);
|
|
656
|
+
box-shadow: var(--w-section-shadow);
|
|
657
|
+
backdrop-filter: var(--w-section-backdrop);
|
|
658
|
+
|
|
659
|
+
@variant sm-not {
|
|
660
|
+
margin-inline: calc(var(--w-page-inset, 0px) * -1);
|
|
661
|
+
padding-inline: var(--inner-margin);
|
|
662
|
+
border-inline-width: 0;
|
|
663
|
+
border-radius: 0;
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
|
|
649
667
|
/*
|
|
650
668
|
* Floating, the items keep off the nav's edges, and their hover pill and the active marker follow its rounding: the
|
|
651
669
|
* pill's radius is the nav's less the inset, so the two curves run parallel. Docked, the pill and the marker meet
|
|
@@ -761,6 +779,12 @@
|
|
|
761
779
|
border-radius: calc(var(--w-chrome-float) * 9999px);
|
|
762
780
|
}
|
|
763
781
|
|
|
782
|
+
/* A group's dropdown opens at the item without the first and last items' extra room, so it lines up with the pill. */
|
|
783
|
+
.w-nav-item-anchor {
|
|
784
|
+
top: calc(var(--w-nav-item-pad-top, 0.25rem) - 0.25rem);
|
|
785
|
+
bottom: calc(var(--w-nav-item-pad-bottom, 0.25rem) - 0.25rem);
|
|
786
|
+
}
|
|
787
|
+
|
|
764
788
|
/*
|
|
765
789
|
* A group's dropdown shares the nav's paint (`.w-nav-bar`) but not its place: it sizes to its items. Its corners
|
|
766
790
|
* are the nav's when floating; docked they stay rounded, as before.
|
|
@@ -774,10 +798,39 @@
|
|
|
774
798
|
top: auto;
|
|
775
799
|
left: auto;
|
|
776
800
|
height: auto;
|
|
777
|
-
max-height:
|
|
801
|
+
max-height: calc(100vh - 1.5rem);
|
|
778
802
|
border-radius: var(--w-nav-dropdown-rounded);
|
|
779
803
|
}
|
|
780
804
|
|
|
805
|
+
/*
|
|
806
|
+
* A group's dropdown lines up with the item by its top, or by its bottom when it opens upward. Where that runs past
|
|
807
|
+
* the screen, it shifts to stay on it and sticks to the edge, and scrolls once taller than the screen. The space the
|
|
808
|
+
* dropdown would size it to is not kept, so the shift has room.
|
|
809
|
+
*/
|
|
810
|
+
.w-nav-group-dropdown {
|
|
811
|
+
max-height: none !important;
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
.w-nav-group-dropdown-content {
|
|
815
|
+
--w-nav-group-edge: 0.75rem;
|
|
816
|
+
|
|
817
|
+
transform: translateY(
|
|
818
|
+
max(
|
|
819
|
+
var(--w-nav-group-edge) - var(--dropdown-y, 0px),
|
|
820
|
+
min(0px, 100vh - var(--w-nav-group-edge) - var(--dropdown-y, 0px) - 100%)
|
|
821
|
+
)
|
|
822
|
+
);
|
|
823
|
+
|
|
824
|
+
.dropdown-top & {
|
|
825
|
+
transform: translateY(
|
|
826
|
+
min(
|
|
827
|
+
100vh - var(--w-nav-group-edge) - var(--dropdown-y, 0px),
|
|
828
|
+
max(0px, var(--w-nav-group-edge) - var(--dropdown-y, 0px) + 100%)
|
|
829
|
+
)
|
|
830
|
+
);
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
|
|
781
834
|
/* The icon starts where the items' do: past their inset and the item's own padding. */
|
|
782
835
|
.w-nav-bar-toggle {
|
|
783
836
|
top: var(--w-chrome-gap);
|
|
@@ -803,22 +856,26 @@
|
|
|
803
856
|
--w-section-paint: color-mix(in oklab, var(--w-section-base) calc(var(--w-section-opacity) * 100%), transparent);
|
|
804
857
|
--w-band-start: calc(var(--w-left-inner) - var(--w-section-padding));
|
|
805
858
|
--w-band-end: calc(100vw - var(--vw-scroll-bar-width, 0px) - var(--w-right-inner) + var(--w-section-padding));
|
|
806
|
-
|
|
859
|
+
/* The section's fill: for what draws the section's edges as its own border, which the bands would double. */
|
|
860
|
+
--w-page-fill:
|
|
807
861
|
linear-gradient(
|
|
808
862
|
to right,
|
|
809
863
|
transparent var(--w-band-start),
|
|
810
|
-
var(--w-
|
|
811
|
-
transparent calc(var(--w-band-start) + var(--w-section-border)) calc(var(--w-band-end) - var(--w-section-border)),
|
|
812
|
-
var(--w-line-subtle) calc(var(--w-band-end) - var(--w-section-border)) var(--w-band-end),
|
|
864
|
+
var(--w-section-paint) var(--w-band-start) var(--w-band-end),
|
|
813
865
|
transparent var(--w-band-end)
|
|
814
866
|
),
|
|
867
|
+
var(--w-canvas-image);
|
|
868
|
+
/* The fill with the section's side edges, for what has no border of its own. */
|
|
869
|
+
--w-page-backdrop:
|
|
815
870
|
linear-gradient(
|
|
816
871
|
to right,
|
|
817
872
|
transparent var(--w-band-start),
|
|
818
|
-
var(--w-
|
|
873
|
+
var(--w-line-subtle) var(--w-band-start) calc(var(--w-band-start) + var(--w-section-border)),
|
|
874
|
+
transparent calc(var(--w-band-start) + var(--w-section-border)) calc(var(--w-band-end) - var(--w-section-border)),
|
|
875
|
+
var(--w-line-subtle) calc(var(--w-band-end) - var(--w-section-border)) var(--w-band-end),
|
|
819
876
|
transparent var(--w-band-end)
|
|
820
877
|
),
|
|
821
|
-
var(--w-
|
|
878
|
+
var(--w-page-fill);
|
|
822
879
|
}
|
|
823
880
|
|
|
824
881
|
.w-list-page {
|
|
@@ -919,6 +976,22 @@
|
|
|
919
976
|
}
|
|
920
977
|
}
|
|
921
978
|
|
|
979
|
+
.w-list-page-frame {
|
|
980
|
+
/*
|
|
981
|
+
* Joined to a section head above it, the frame runs on up over the head with its top corners: one shadow and one
|
|
982
|
+
* top highlight for the whole section, instead of the head's ending at its bottom and the frame's starting there.
|
|
983
|
+
*/
|
|
984
|
+
--w-frame-head: calc(var(--w-section-head-height, 0px) * var(--w-joined, 0));
|
|
985
|
+
|
|
986
|
+
margin-top: calc(var(--w-section-padding) * -1 - var(--w-frame-head));
|
|
987
|
+
border-start-start-radius: var(--w-section-rounded);
|
|
988
|
+
border-start-end-radius: var(--w-section-rounded);
|
|
989
|
+
|
|
990
|
+
@variant sm-not {
|
|
991
|
+
border-radius: 0;
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
|
|
922
995
|
.w-list-page-surface {
|
|
923
996
|
background-color: var(--w-section-paint);
|
|
924
997
|
border: var(--w-section-border) solid var(--w-line-subtle);
|
|
@@ -932,9 +1005,12 @@
|
|
|
932
1005
|
* header bar.
|
|
933
1006
|
*/
|
|
934
1007
|
.w-list-page-frame {
|
|
935
|
-
|
|
1008
|
+
/* Over the head it runs up over (`--w-frame-head`), whose shadow it draws. */
|
|
1009
|
+
z-index: calc(21 - var(--w-chrome-float) * 15 + var(--w-joined, 0) * 2);
|
|
936
1010
|
pointer-events: none;
|
|
937
1011
|
box-shadow: var(--w-section-shadow);
|
|
1012
|
+
/* As wide as the section's edge, so a highlight inside the shadow lies inside the edge, as on a section, not over it. */
|
|
1013
|
+
border: var(--w-section-border) solid transparent;
|
|
938
1014
|
|
|
939
1015
|
/*
|
|
940
1016
|
* Only the part of the section in view, from the header bar's gap to the screen's bottom gap: its shadow wraps the
|
|
@@ -942,10 +1018,10 @@
|
|
|
942
1018
|
*/
|
|
943
1019
|
@variant sm {
|
|
944
1020
|
align-self: start;
|
|
945
|
-
top: calc(var(--w-header-inner) + var(--w-section-head-height, 0px));
|
|
1021
|
+
top: calc(var(--w-header-inner) + var(--w-section-head-height, 0px) - var(--w-frame-head, 0px));
|
|
946
1022
|
height: min(
|
|
947
|
-
calc(100% + var(--w-section-padding) * 2),
|
|
948
|
-
calc(100vh - var(--w-header-inner) - var(--w-section-head-height, 0px) - var(--w-chrome-gap))
|
|
1023
|
+
calc(100% + var(--w-section-padding) * 2 + var(--w-frame-head, 0px)),
|
|
1024
|
+
calc(100vh - var(--w-header-inner) - var(--w-section-head-height, 0px) + var(--w-frame-head, 0px) - var(--w-chrome-gap))
|
|
949
1025
|
);
|
|
950
1026
|
}
|
|
951
1027
|
}
|
|
@@ -968,7 +1044,8 @@
|
|
|
968
1044
|
|
|
969
1045
|
position: sticky;
|
|
970
1046
|
bottom: 0;
|
|
971
|
-
|
|
1047
|
+
/* Over the frame also where it is raised over a joined head. */
|
|
1048
|
+
z-index: calc(22 - var(--w-chrome-float) * 15 + var(--w-joined, 0) * 2);
|
|
972
1049
|
height: var(--w-list-end-height);
|
|
973
1050
|
margin-bottom: calc(var(--w-list-end-height) * -1);
|
|
974
1051
|
pointer-events: none;
|
|
@@ -1033,7 +1110,7 @@
|
|
|
1033
1110
|
border-end-start-radius: var(--w-section-rounded);
|
|
1034
1111
|
border-end-end-radius: var(--w-section-rounded);
|
|
1035
1112
|
background-color: var(--w-canvas);
|
|
1036
|
-
background-image: var(--w-page-
|
|
1113
|
+
background-image: var(--w-page-fill);
|
|
1037
1114
|
background-attachment: fixed;
|
|
1038
1115
|
}
|
|
1039
1116
|
|
|
@@ -1304,7 +1381,7 @@
|
|
|
1304
1381
|
border-start-start-radius: calc(var(--w-section-rounded) * (1 - var(--w-joined, 0)));
|
|
1305
1382
|
border-start-end-radius: calc(var(--w-section-rounded) * (1 - var(--w-joined, 0)));
|
|
1306
1383
|
background-color: var(--w-canvas);
|
|
1307
|
-
background-image: var(--w-page-
|
|
1384
|
+
background-image: var(--w-page-fill);
|
|
1308
1385
|
background-attachment: fixed;
|
|
1309
1386
|
|
|
1310
1387
|
@variant sm-not {
|
|
@@ -1322,9 +1399,11 @@
|
|
|
1322
1399
|
top: var(--w-header-inner);
|
|
1323
1400
|
z-index: calc(22 - var(--w-chrome-float) * 15);
|
|
1324
1401
|
background-color: var(--w-canvas);
|
|
1325
|
-
background-image: var(--w-page-
|
|
1402
|
+
background-image: var(--w-page-fill);
|
|
1326
1403
|
background-attachment: fixed;
|
|
1327
1404
|
backdrop-filter: none;
|
|
1405
|
+
/* The list's frame runs on up over it and casts the section's shadow. */
|
|
1406
|
+
box-shadow: none;
|
|
1328
1407
|
}
|
|
1329
1408
|
|
|
1330
1409
|
.w-list-page-repaint .w-infinite-list-header-stuck .w-infinite-list-header-edge::before,
|