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.
@@ -1 +1 @@
1
- {"version":3,"file":"WInfiniteListWrapper.vue.d.ts","sourceRoot":"","sources":["../../../../src/components/InfiniteList/WInfiniteListWrapper.vue"],"names":[],"mappings":"AAsDA;AAmKA,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;AA8EF,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"}
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"}
@@ -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 sectionHeadOffset = computed(() => isPage.value ? sectionHeadHeight?.value ?? 0 : 0);
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":"AA4FA;AAgJA,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;AAqRF,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"}
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 = { class: "[overflow:inherit]" };
19
- var _hoisted_4 = { class: "flex items-center" };
20
- var _hoisted_5 = { class: "last-not:pr-1 min-w-0 font-normal" };
21
- var _hoisted_6 = { class: "relative inline-flex max-w-full items-center whitespace-nowrap tracking-wide" };
22
- var _hoisted_7 = {
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({ isActive });
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("div", _hoisted_3, [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", {
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", _hoisted_4, [iconLocal.value ? (openBlock(), createBlock(resolveDynamicComponent(iconLocal.value), {
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", _hoisted_5, [createElementVNode("span", _hoisted_6, [
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", _hoisted_7, toDisplayString(typeof __props.count === "number" ? `\u00A0(${unref(numberCompactFormatter).format(__props.count)})` : ""), 1)) : (openBlock(), createBlock(WSkeleton_default, {
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":"AAmGA;AAoMA,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,SAAS,CAAA;AAG/C,OAAO,EAAC,KAAK,KAAK,EAA4E,MAAM,KAAK,CAAA;AA+EzG,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;AAqVF,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"}
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, onBeforeUnmount, openBlock, ref, renderList, renderSlot, resolveDynamicComponent, unref, useSlots, useTemplateRef, watch, withCtx } from "vue";
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-hidden border border-solid border-line-raised text-start font-normal shadow" };
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 = ref(false);
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.value && !isActive.value,
56
+ "is-open": unref(isDropdownOpen) && !isActive.value,
78
57
  "horizontal-align": unref(HorizontalAlign).RIGHT_OUTER,
79
- "dropdown-class": "flex relative"
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.value && !hasActive.value
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((scope) => [createVNode(WClickOutside_default, {
117
- class: normalizeClass(["px-1", { "self-end": scope.atBottom }]),
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, ["class"])]),
110
+ }, 8, [
111
+ "onMouseenter",
112
+ "onMouseleave",
113
+ "onClick"
114
+ ])]),
131
115
  _: 3
132
- }, 8, ["is-open", "horizontal-align"]), createVNode(WExpansion_default, {
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,7 @@
1
+ export declare const useNavGroupDropdown: () => {
2
+ isOpen: import('vue').ComputedRef<boolean>;
3
+ show: () => void;
4
+ hide: () => void;
5
+ close: () => void;
6
+ };
7
+ //# sourceMappingURL=useNavGroupDropdown.d.ts.map
@@ -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.27, the one installed next to them. Start with Getting started and Conventions; each component page lists its props, events and slots with examples.
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
@@ -4,7 +4,7 @@
4
4
  "type": "git",
5
5
  "url": "https://github.com/rsmple/eco-vue-js.git"
6
6
  },
7
- "version": "0.26.27",
7
+ "version": "0.26.28",
8
8
  "homepage": "https://rsmple.github.io/eco-vue-js/",
9
9
  "dependencies": {
10
10
  "@stylistic/eslint-plugin": "5.10.0",
@@ -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 and ring: a theme sets a shadow list, `0 0 #0000` for none, never `none`. */
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. A floating header paints `--w-chrome-ring` over the gap above it and beside it, not
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: none;
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
- --w-page-backdrop:
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-line-subtle) var(--w-band-start) calc(var(--w-band-start) + var(--w-section-border)),
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-section-paint) var(--w-band-start) var(--w-band-end),
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-canvas-image);
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
- z-index: calc(21 - var(--w-chrome-float) * 15);
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
- z-index: calc(22 - var(--w-chrome-float) * 15);
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-backdrop);
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-backdrop);
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-backdrop);
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,