@v1nt1248/3nclient-lib 0.3.21 → 0.3.23

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.
@@ -29,6 +29,8 @@ import { default as Ui3nEditable } from './components/ui3n-editable/ui3n-editabl
29
29
  import { default as Ui3nAutocomplete } from './components/ui3n-autocomplete/ui3n-autocomplete.vue';
30
30
  import { default as Ui3nSlider } from './components/ui3n-slider/ui3n-slider.vue';
31
31
  import { default as Ui3nSelector } from './components/ui3n-selector/ui3n-selector.vue';
32
+ import { default as Ui3nMobileMenu } from './components/ui3n-mobile-menu/ui3n-mobile-menu.vue';
33
+ import { default as Ui3nMobileMenuItem } from './components/ui3n-mobile-menu-item/ui3n-mobile-menu-item.vue';
32
34
  import { default as Ui3nHtml } from './directives/ui3n-html';
33
35
  import { default as Ui3nClickOutside } from './directives/ui3n-click-outside';
34
36
  import { default as Ui3nResize } from './directives/ui3n-resize';
@@ -72,6 +74,8 @@ declare module 'vue' {
72
74
  Ui3nText: typeof Ui3nText;
73
75
  Ui3nVirtualScroll: typeof Ui3nVirtualScroll;
74
76
  Ui3nTooltip: typeof Ui3nTooltip;
77
+ Ui3nMobileMenu: typeof Ui3nMobileMenu;
78
+ Ui3nMobileMenuItem: typeof Ui3nMobileMenuItem;
75
79
  }
76
80
  interface GlobalDirectives {
77
81
  Ui3nHtml: typeof Ui3nHtml;
@@ -20596,10 +20596,96 @@ var Qu = /* @__PURE__ */ Q(/* @__PURE__ */ d({
20596
20596
  item: "_item_11ric_91",
20597
20597
  itemSelected: "_itemSelected_11ric_105",
20598
20598
  itemDisabled: "_itemDisabled_11ric_109"
20599
+ } }]]), Rd = /* @__PURE__ */ Q(/* @__PURE__ */ d({
20600
+ __name: "ui3n-mobile-menu",
20601
+ props: {
20602
+ modelValue: { type: Boolean },
20603
+ width: {},
20604
+ withBlur: { type: Boolean }
20605
+ },
20606
+ emits: ["update:modelValue"],
20607
+ setup(e, { emit: n }) {
20608
+ M((e) => ({
20609
+ v5ec41730: f.value,
20610
+ v06b55ad7: p.value
20611
+ }));
20612
+ let l = e, d = n, f = i(() => l.width || "240px"), p = i(() => l.withBlur ? "2px" : "0");
20613
+ function m() {
20614
+ d("update:modelValue", !l.modelValue);
20615
+ }
20616
+ return (n, i) => (x(), s(t, null, [c("div", { class: g(n.$style.ui3nMobileMenu) }, [e.modelValue ? o("", !0) : (x(), a(Gl, {
20617
+ key: 0,
20618
+ type: "icon",
20619
+ class: g(n.$style.menuButton),
20620
+ color: "var(--color-bg-block-primary-default)",
20621
+ icon: "round-menu",
20622
+ "icon-color": "var(--color-icon-block-primary-default)",
20623
+ "icon-size": "32",
20624
+ onClick: B(m, ["stop", "prevent"])
20625
+ }, null, 8, ["class"])), u(r, { name: "slide-fade" }, {
20626
+ default: L(() => [e.modelValue ? (x(), s("div", {
20627
+ key: 0,
20628
+ class: g(n.$style.appMenu)
20629
+ }, [
20630
+ c("div", { class: g(n.$style.appMenuHeader) }, [T(n.$slots, "header")], 2),
20631
+ c("div", { class: g(n.$style.appMenuBody) }, [T(n.$slots, "menuBody")], 2),
20632
+ c("div", { class: g(n.$style.appMenuFooter) }, [T(n.$slots, "footer")], 2),
20633
+ u(Gl, {
20634
+ type: "icon",
20635
+ icon: "round-close",
20636
+ color: "transparent",
20637
+ "icon-color": "var(--color-icon-block-secondary-default)",
20638
+ "icon-size": "32",
20639
+ class: g(n.$style.closeBtn),
20640
+ onClick: B(m, ["stop", "prevent"])
20641
+ }, null, 8, ["class"])
20642
+ ], 2)) : o("", !0)]),
20643
+ _: 3
20644
+ })], 2), e.modelValue ? (x(), s("div", {
20645
+ key: 0,
20646
+ class: g(n.$style.overlay)
20647
+ }, null, 2)) : o("", !0)], 64));
20648
+ }
20649
+ }), [["__cssModules", { $style: {
20650
+ ui3nMobileMenu: "_ui3nMobileMenu_b61ep_1",
20651
+ appMenu: "_appMenu_b61ep_6",
20652
+ appMenuHeader: "_appMenuHeader_b61ep_25",
20653
+ appMenuBody: "_appMenuBody_b61ep_30",
20654
+ appMenuFooter: "_appMenuFooter_b61ep_38",
20655
+ menuButton: "_menuButton_b61ep_43",
20656
+ closeBtn: "_closeBtn_b61ep_48",
20657
+ overlay: "_overlay_b61ep_57"
20658
+ } }]]), zd = /* @__PURE__ */ Q(/* @__PURE__ */ d({
20659
+ __name: "ui3n-mobile-menu-item",
20660
+ props: {
20661
+ item: {},
20662
+ isActive: { type: Boolean }
20663
+ },
20664
+ emits: ["selectItem"],
20665
+ setup(e, { emit: t }) {
20666
+ let n = e, r = t;
20667
+ async function i() {
20668
+ r("selectItem", n.item);
20669
+ }
20670
+ return (t, n) => (x(), s("div", {
20671
+ class: g([t.$style.menuItem, e.isActive && t.$style.menuItemSelected]),
20672
+ onClick: i
20673
+ }, [e.item.icon ? (x(), a(Hl, {
20674
+ key: 0,
20675
+ icon: e.item.icon,
20676
+ size: "20",
20677
+ color: "var(--color-icon-control-secondary-default)"
20678
+ }, null, 8, ["icon"])) : o("", !0), c("span", { class: g(t.$style.menuItemName) }, D(e.item.name), 3)], 2));
20679
+ }
20680
+ }), [["__cssModules", { $style: {
20681
+ menuItem: "_menuItem_1a8ao_2",
20682
+ menuItemName: "_menuItemName_1a8ao_13",
20683
+ menuItemSelected: "_menuItemSelected_1a8ao_19",
20684
+ bounceOnce: "_bounceOnce_1a8ao_1"
20599
20685
  } }]]);
20600
20686
  //#endregion
20601
20687
  //#region src/composables/useDblClickHandler.ts
20602
- function Rd(e, t, n = 250) {
20688
+ function Bd(e, t, n = 250) {
20603
20689
  let r = 0, i = null;
20604
20690
  function a(a) {
20605
20691
  r++, i && clearTimeout(i), i = setTimeout(() => {
@@ -20609,4 +20695,4 @@ function Rd(e, t, n = 250) {
20609
20695
  return { handleDblClick: a };
20610
20696
  }
20611
20697
  //#endregion
20612
- export { Pd as Ui3nAutocomplete, ad as Ui3nBadge, od as Ui3nBreadcrumb, sd as Ui3nBreadcrumbs, Gl as Ui3nButton, Ou as Ui3nCheckbox, Kl as Ui3nChip, Ho as Ui3nClickOutside, Bu as Ui3nDialog, Lu as Ui3nDialogProvider, Jl as Ui3nDropFiles, Ad as Ui3nEditable, Xl as Ui3nEmoji, Bo as Ui3nHtml, Hl as Ui3nIcon, Ql as Ui3nInput, Su as Ui3nInputFile, ed as Ui3nList, Rl as Ui3nLongPress, Qu as Ui3nMenu, Au as Ui3nNotification, yd as Ui3nProgressCircular, md as Ui3nProgressLinear, Td as Ui3nRadio, Ed as Ui3nRadioGroup, Yo as Ui3nResize, es as Ui3nRipple, Ld as Ui3nSelector, Fd as Ui3nSlider, ud as Ui3nStepLineBar, ld as Ui3nSwitch, Pu as Ui3nTable, ju as Ui3nTableSortIcon, rd as Ui3nTabs, wu as Ui3nText, jl as Ui3nTitle, xd as Ui3nTooltip, nd as Ui3nVirtualScroll, Rd as useDblClickHandler };
20698
+ export { Pd as Ui3nAutocomplete, ad as Ui3nBadge, od as Ui3nBreadcrumb, sd as Ui3nBreadcrumbs, Gl as Ui3nButton, Ou as Ui3nCheckbox, Kl as Ui3nChip, Ho as Ui3nClickOutside, Bu as Ui3nDialog, Lu as Ui3nDialogProvider, Jl as Ui3nDropFiles, Ad as Ui3nEditable, Xl as Ui3nEmoji, Bo as Ui3nHtml, Hl as Ui3nIcon, Ql as Ui3nInput, Su as Ui3nInputFile, ed as Ui3nList, Rl as Ui3nLongPress, Qu as Ui3nMenu, Rd as Ui3nMobileMenu, zd as Ui3nMobileMenuItem, Au as Ui3nNotification, yd as Ui3nProgressCircular, md as Ui3nProgressLinear, Td as Ui3nRadio, Ed as Ui3nRadioGroup, Yo as Ui3nResize, es as Ui3nRipple, Ld as Ui3nSelector, Fd as Ui3nSlider, ud as Ui3nStepLineBar, ld as Ui3nSwitch, Pu as Ui3nTable, ju as Ui3nTableSortIcon, rd as Ui3nTabs, wu as Ui3nText, jl as Ui3nTitle, xd as Ui3nTooltip, nd as Ui3nVirtualScroll, Bd as useDblClickHandler };
@@ -6,6 +6,7 @@
6
6
  --spacing-l: 32px;
7
7
  --spacing-xl: 40px;
8
8
  --spacing-xxl: 48px;
9
+ --spacing-xxxl: 64px;
9
10
  --white-inf: oklch(100% 0.000 0.0deg / 0.000);
10
11
  --white-100: oklch(100% 0.000 0.0deg);
11
12
  --white-4: oklch(98.5% 0.000 0.0deg / 0.040);
@@ -119,6 +120,7 @@
119
120
  --font-20: 20px;
120
121
  --font-24: 24px;
121
122
  --font-32: 32px;
123
+
122
124
  }
123
125
 
124
126
  .default-theme {
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@v1nt1248/3nclient-lib",
3
3
  "license": "AGPL-3.0-or-later",
4
4
  "author": "v1nt1248",
5
- "version": "0.3.21",
5
+ "version": "0.3.23",
6
6
  "description": "Library for 3NWeb clients",
7
7
  "type": "module",
8
8
  "files": [
@@ -112,6 +112,14 @@ import type {
112
112
  Ui3nSelectorSlots,
113
113
  Ui3nSelectorItemDisplayingFunction,
114
114
  } from './ui3n-selector/types';
115
+ import Ui3nMobileMenu from './ui3n-mobile-menu/ui3n-mobile-menu.vue';
116
+ import type { Ui3nMobileMenuProps, Ui3nMobileMenuEmits, Ui3nMobileMenuSlots } from './ui3n-mobile-menu/types';
117
+ import Ui3nMobileMenuItem from './ui3n-mobile-menu-item/ui3n-mobile-menu-item.vue';
118
+ import type {
119
+ Ui3nMobileMenuItemBase,
120
+ Ui3nMobileMenuItemProps,
121
+ Ui3nMobileMenuItemEmits,
122
+ } from './ui3n-mobile-menu-item/types';
115
123
 
116
124
  export {
117
125
  Ui3nIcon,
@@ -233,4 +241,12 @@ export {
233
241
  Ui3nSelectorSlots,
234
242
  Ui3nSelectorOptionBase,
235
243
  Ui3nSelectorItemDisplayingFunction,
244
+ Ui3nMobileMenu,
245
+ Ui3nMobileMenuProps,
246
+ Ui3nMobileMenuEmits,
247
+ Ui3nMobileMenuSlots,
248
+ Ui3nMobileMenuItem,
249
+ Ui3nMobileMenuItemBase,
250
+ Ui3nMobileMenuItemProps,
251
+ Ui3nMobileMenuItemEmits,
236
252
  };
@@ -134,12 +134,12 @@
134
134
  v-on="
135
135
  draggable
136
136
  ? {
137
- dragstart: onDragstart,
138
- mousedown: onMousedown,
139
- mouseup: onMouseup,
140
- mousemove: onMousemove,
141
- keydown: onKeydown,
142
- }
137
+ dragstart: onDragstart,
138
+ mousedown: onMousedown,
139
+ mouseup: onMouseup,
140
+ mousemove: onMousemove,
141
+ keydown: onKeydown,
142
+ }
143
143
  : { keydown: onKeydown }
144
144
  "
145
145
  >
@@ -0,0 +1,38 @@
1
+ import type { VNode } from 'vue';
2
+
3
+ /**
4
+ * Menu component properties
5
+ */
6
+ export interface Ui3nMobileMenuProps {
7
+ modelValue: boolean;
8
+ width?: string;
9
+ withBlur?: boolean;
10
+ }
11
+
12
+ /**
13
+ * Menu component emits
14
+ */
15
+ export interface Ui3nMobileMenuEmits {
16
+ /**
17
+ * Emitted when model value updates
18
+ */
19
+ (event: 'update:modelValue', value: boolean): void;
20
+ }
21
+
22
+ /**
23
+ * Menu component slots
24
+ */
25
+ export interface Ui3nMobileMenuSlots {
26
+ /**
27
+ * Menu Header slot - section to add custom data on top of the menu
28
+ */
29
+ header: () => VNode;
30
+ /**
31
+ * Menu body slot - The section is where your menu items are placed
32
+ */
33
+ menuBody: () => VNode;
34
+ /**
35
+ * Menu footer slot - section to add custm data on the bottom of menu
36
+ */
37
+ footer: () => VNode;
38
+ }
@@ -0,0 +1,151 @@
1
+ <script lang="ts" setup>
2
+ import { computed } from 'vue';
3
+ import type { Ui3nMobileMenuProps, Ui3nMobileMenuEmits, Ui3nMobileMenuSlots } from './types';
4
+ import Ui3nButton from '../ui3n-button/ui3n-button.vue';
5
+
6
+ const props = defineProps<Ui3nMobileMenuProps>();
7
+ const emits = defineEmits<Ui3nMobileMenuEmits>();
8
+ defineSlots<Ui3nMobileMenuSlots>();
9
+
10
+ const widthCss = computed(() => props.width || '240px');
11
+ const blurValue = computed(() => (props.withBlur ? '2px' : '0'));
12
+
13
+ function toggleMenu() {
14
+ emits('update:modelValue', !props.modelValue);
15
+ }
16
+ </script>
17
+
18
+ <template>
19
+ <div :class="$style.ui3nMobileMenu">
20
+ <ui3n-button
21
+ v-if="!modelValue"
22
+ type="icon"
23
+ :class="$style.menuButton"
24
+ color="var(--color-bg-block-primary-default)"
25
+ icon="round-menu"
26
+ icon-color="var(--color-icon-block-primary-default)"
27
+ icon-size="32"
28
+ @click.stop.prevent="toggleMenu"
29
+ />
30
+
31
+ <transition name="slide-fade">
32
+ <div
33
+ v-if="modelValue"
34
+ :class="$style.appMenu"
35
+ >
36
+ <div :class="$style.appMenuHeader">
37
+ <slot name="header" />
38
+ </div>
39
+ <div :class="$style.appMenuBody">
40
+ <slot name="menuBody" />
41
+ </div>
42
+ <div :class="$style.appMenuFooter">
43
+ <slot name="footer" />
44
+ </div>
45
+
46
+ <ui3n-button
47
+ type="icon"
48
+ icon="round-close"
49
+ color="transparent"
50
+ icon-color="var(--color-icon-block-secondary-default)"
51
+ icon-size="32"
52
+ :class="$style.closeBtn"
53
+ @click.stop.prevent="toggleMenu"
54
+ />
55
+ </div>
56
+ </transition>
57
+ </div>
58
+ <div
59
+ v-if="modelValue"
60
+ :class="$style.overlay"
61
+ />
62
+ </template>
63
+
64
+ <style lang="scss" module>
65
+ @use '../../assets/styles/mixins' as mixins;
66
+ .ui3nMobileMenu {
67
+ --ui3n-menu-width-custom: v-bind(widthCss);
68
+
69
+ width: max-content;
70
+ }
71
+
72
+ .appMenu {
73
+ position: fixed;
74
+ top: 0;
75
+ left: 0;
76
+ width: var(--ui3n-menu-width-custom);
77
+ max-width: 80vw;
78
+ display: flex;
79
+ flex-direction: column;
80
+ justify-content: flex-start;
81
+ align-items: stretch;
82
+ min-height: 100dvh;
83
+ max-height: 100dvh;
84
+ color: var(--color-text-block-primary-default);
85
+ background-color: var(--color-bg-block-primary-default);
86
+ overflow-x: hidden;
87
+ overflow-y: auto;
88
+ z-index: 1050;
89
+ }
90
+
91
+ .appMenuHeader {
92
+ position: relative;
93
+ width: 100%;
94
+ }
95
+
96
+ .appMenuBody {
97
+ position: relative;
98
+ width: 100%;
99
+ flex-grow: 1;
100
+ overflow-x: hidden;
101
+ overflow-y: auto;
102
+ }
103
+
104
+ .appMenuFooter {
105
+ position: relative;
106
+ width: 100%;
107
+ }
108
+
109
+ .menuButton {
110
+ min-width: 48px !important;
111
+ height: 48px;
112
+ }
113
+
114
+ .closeBtn {
115
+ position: fixed;
116
+ min-width: 48px !important;
117
+ height: 48px;
118
+ top: 8px;
119
+ left: calc(var(--ui3n-menu-width-custom) + 8px);
120
+ z-index: 1005;
121
+ }
122
+
123
+ .overlay {
124
+ position: fixed;
125
+ inset: 0;
126
+ background-color: oklch(from var(--color-bg-block-primary-default) calc(l * 0.1) c h / 0.5);
127
+ backdrop-filter: blur(v-bind(blurValue));
128
+ z-index: 1000;
129
+ }
130
+ </style>
131
+
132
+ <style lang="scss">
133
+ .slide-fade-enter-active,
134
+ .slide-fade-leave-active {
135
+ transition:
136
+ transform 0.2s ease-in-out,
137
+ opacity 0.2s ease-in-out;
138
+ }
139
+
140
+ .slide-fade-enter-from,
141
+ .slide-fade-leave-to {
142
+ transform: translateX(calc(var(--ui3n-menu-width-custom) * -1));
143
+ opacity: 0;
144
+ }
145
+
146
+ .slide-fade-enter-to,
147
+ .slide-fade-leave-from {
148
+ transform: translateX(0);
149
+ opacity: 1;
150
+ }
151
+ </style>
@@ -0,0 +1,23 @@
1
+ export interface Ui3nMobileMenuItemBase {
2
+ id: string | number;
3
+ name: string;
4
+ icon?: string;
5
+ }
6
+
7
+ /**
8
+ * Menu Item component properties
9
+ */
10
+ export interface Ui3nMobileMenuItemProps<T extends Ui3nMobileMenuItemBase> {
11
+ item: T;
12
+ isActive?: boolean;
13
+ }
14
+
15
+ /**
16
+ * Menu Item component emits
17
+ */
18
+ export interface Ui3nMobileMenuItemEmits<T extends Ui3nMobileMenuItemBase> {
19
+ /**
20
+ * Emitted when an item is selected on the menu
21
+ */
22
+ (event: 'selectItem', item: T): void;
23
+ }
@@ -0,0 +1,73 @@
1
+ <script lang="ts" setup generic="T extends Ui3nMobileMenuItemBase">
2
+ import type { Ui3nMobileMenuItemBase, Ui3nMobileMenuItemProps, Ui3nMobileMenuItemEmits } from './types';
3
+ import Ui3nIcon from '../ui3n-icon/ui3n-icon.vue';
4
+
5
+ const props = defineProps<Ui3nMobileMenuItemProps<T>>();
6
+ const emits = defineEmits<Ui3nMobileMenuItemEmits<T>>();
7
+
8
+ async function selectMenuItem() {
9
+ emits('selectItem', props.item);
10
+ }
11
+ </script>
12
+
13
+ <template>
14
+ <div
15
+ :class="[$style.menuItem, isActive && $style.menuItemSelected]"
16
+ @click="selectMenuItem"
17
+ >
18
+ <ui3n-icon
19
+ v-if="item.icon"
20
+ :icon="item.icon"
21
+ size="20"
22
+ color="var(--color-icon-control-secondary-default)"
23
+ />
24
+ <span :class="$style.menuItemName">
25
+ {{ item.name }}
26
+ </span>
27
+ </div>
28
+ </template>
29
+
30
+ <style lang="scss" module>
31
+ @use '../../assets/styles/mixins' as mixins;
32
+
33
+ .menuItem {
34
+ display: flex;
35
+ width: 100%;
36
+ height: var(--spacing-xxl);
37
+ border-radius: var(--spacing-s);
38
+ justify-content: flex-start;
39
+ align-items: center;
40
+ column-gap: var(--spacing-s);
41
+ padding: 0 var(--spacing-s);
42
+ cursor: pointer;
43
+
44
+ .menuItemName {
45
+ font-size: var(--font-14);
46
+ font-weight: 600;
47
+ line-height: var(--font-20);
48
+ color: var(--color-text-control-primary-default);
49
+ }
50
+
51
+ &:hover,
52
+ &.menuItemSelected {
53
+ background-color: var(--color-bg-control-primary-hover);
54
+
55
+ & > div {
56
+ color: var(--color-icon-control-accent-default);
57
+ animation: bounceOnce 0.4s ease-in-out forwards;
58
+ }
59
+ }
60
+ }
61
+
62
+ @keyframes bounceOnce {
63
+ 0% {
64
+ transform: scale(1);
65
+ }
66
+ 50% {
67
+ transform: scale(1.25); /* Пик увеличения */
68
+ }
69
+ 100% {
70
+ transform: scale(1); /* Финал анимации */
71
+ }
72
+ }
73
+ </style>