lkt-menu 1.4.1 → 2.0.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lkt-menu",
3
- "version": "1.4.1",
3
+ "version": "2.0.0",
4
4
  "description": "",
5
5
  "keywords": [
6
6
  "lkt",
@@ -54,7 +54,7 @@
54
54
  "lkt-data-state": "^1.0.11",
55
55
  "lkt-http-client": "^1.0.34",
56
56
  "lkt-i18n": "^1.0.6",
57
- "lkt-vue-kernel": "1.0.44",
57
+ "lkt-vue-kernel": "^1.0.46",
58
58
  "vue": "^3.3.0",
59
59
  "vue-router": "^4.3.3"
60
60
  }
@@ -1,21 +1,21 @@
1
1
  <script setup lang="ts">
2
- import { extractI18nValue, LktObject, MenuEntry } from 'lkt-vue-kernel';
3
- import { computed, onMounted, ref, useSlots, watch } from 'vue';
4
- import { fetchKeys } from '../functions/helpers';
5
- import { useRouter } from 'vue-router';
6
- import { Settings } from '../settings/Settings';
2
+ import { MenuEntryConfig, MenuEntryType } from 'lkt-vue-kernel';
3
+ import { computed, onMounted, ref, useSlots, watch } from 'vue';
4
+ import { fetchKeys } from '../functions/helpers';
5
+ import { useRouter } from 'vue-router';
6
+ import { Settings } from '../settings/Settings';
7
7
 
8
- const emit = defineEmits([
8
+ const emit = defineEmits([
9
9
  'update:modelValue'
10
10
  ]);
11
11
 
12
12
  const props = withDefaults(defineProps<{
13
- modelValue?: MenuEntry
13
+ modelValue?: MenuEntryConfig
14
14
  }>(), {
15
- modelValue: () => (new MenuEntry())
15
+ modelValue: () => ({})
16
16
  });
17
17
 
18
- const entry = ref(props.modelValue),
18
+ const entry = ref(<MenuEntryConfig>props.modelValue),
19
19
  slots = useSlots(),
20
20
  router = useRouter(),
21
21
  isActive = ref(false);
@@ -24,7 +24,7 @@ const onClickToggle = () => {
24
24
  entry.value.isOpened = !entry.value.isOpened;
25
25
  },
26
26
  onClick = () => {
27
- if (entry.value.children?.length > 0) onClickToggle();
27
+ if (typeof entry.value.children !== 'undefined' && entry.value.children?.length > 0) onClickToggle();
28
28
 
29
29
  if (typeof entry.value.events?.click === 'function') {
30
30
  entry.value.events.click({
@@ -49,14 +49,15 @@ const canRenderIcon = computed(() => {
49
49
  let r = [];
50
50
  if (canRenderIcon.value) r.push('has-icon');
51
51
  if (isActive.value) r.push('is-active');
52
+ if (entry.value.type) r.push(`is-${entry.value.type}`);
52
53
  return r.join(' ');
53
54
  });
54
55
 
55
56
  const availableKeys = computed(() => {
56
57
  let r: string[] = [];
57
- return fetchKeys(r, entry.value.children);
58
+ return fetchKeys(r, entry.value?.children ?? []);
58
59
  }),
59
- entryIconSlots = computed((): LktObject => {
60
+ entryIconSlots = computed((): Array<string> => {
60
61
  let r = [];
61
62
  for (let k in slots) {
62
63
  if (k.startsWith('icon-')) {
@@ -67,9 +68,6 @@ const availableKeys = computed(() => {
67
68
  }
68
69
  return r;
69
70
  }),
70
- computedLabel = computed(() => {
71
- return extractI18nValue(entry.value.label);
72
- }),
73
71
  computedIsActive = computed(() => {
74
72
  if (entry.value.isActive) return true;
75
73
 
@@ -100,13 +98,13 @@ watch(entry, (v) => {
100
98
  onMounted(() => {
101
99
  let currentRoute = router?.currentRoute;
102
100
  if (currentRoute) {
103
- if (currentRoute.value.path === entry.value.href) {
101
+ if (currentRoute.value.path === entry.value.anchor?.to) {
104
102
  entry.value.isOpened = true;
105
103
 
106
- } else if (entry.value.children?.length > 0) {
104
+ } else if (typeof entry.value.children !== 'undefined' && entry.value.children?.length > 0) {
107
105
  let opened = false;
108
106
  entry.value.children?.forEach((child) => {
109
- if (currentRoute.value.path === child.href) opened = true;
107
+ if (currentRoute.value.path === child.anchor?.to) opened = true;
110
108
  });
111
109
 
112
110
  if (opened) entry.value.isOpened = true;
@@ -118,34 +116,55 @@ onMounted(() => {
118
116
  <template>
119
117
  <div class="lkt-menu-entry" :class="classes">
120
118
  <div class="lkt-menu-entry-main">
119
+ <lkt-button
120
+ v-if="entry.type === MenuEntryType.Button"
121
+ v-bind="entry.button"
122
+ >
123
+ <template v-if="slots.tooltip" #tooltip>
124
+ <slot name="tooltip"/>
125
+ </template>
126
+ <template v-if="slots.split" #split>
127
+ <slot name="split"/>
128
+ </template>
129
+ </lkt-button>
130
+
121
131
  <lkt-anchor
122
- :to="entry.href"
132
+ v-else-if="entry.type === MenuEntryType.Anchor"
133
+ v-bind="entry.anchor"
134
+ />
135
+ <lkt-anchor
136
+ v-else
137
+ v-bind="entry.anchor"
123
138
  :on-click="onClick"
124
139
  :is-active="computedIsActive"
125
140
  @active="($e: any) => isActive = $e"
126
141
  >
127
- <div class="lkt-entry-content">
128
- <div class="lkt-menu-entry-icon" v-if="canRenderIcon">
129
- <template v-if="slots['icon-'+entry.key]">
130
- <slot :name="'icon-'+entry.key"
131
- :key="entry.key"
132
- :entry="entry"/>
133
- </template>
134
- <template v-else-if="entry.icon !== ''">
135
- <i :class="entry.icon"/>
136
- </template>
137
- </div>
138
- <div class="lkt-menu-entry-text" v-if="entry.label !== ''">
139
- {{ computedLabel }}
142
+ <template #text="{text}">
143
+ <div class="lkt-entry-content">
144
+ <div class="lkt-menu-entry-icon" v-if="canRenderIcon">
145
+ <template v-if="slots['icon-'+entry.key]">
146
+ <slot :name="'icon-'+entry.key"
147
+ :key="entry.key"
148
+ :entry="entry"/>
149
+ </template>
150
+ <template v-else-if="entry.icon !== ''">
151
+ <i :class="entry.icon"/>
152
+ </template>
153
+ </div>
154
+ <div class="lkt-menu-entry-text" v-if="text !== ''">
155
+ {{ text }}
156
+ </div>
140
157
  </div>
141
- </div>
158
+ </template>
142
159
  </lkt-anchor>
143
160
 
144
- <div class="lkt-menu-entry-toggle" v-if="entry.children?.length > 0" @click="onClickToggle">
161
+ <div class="lkt-menu-entry-toggle" v-if="entry.type !== MenuEntryType.Button && entry.children && entry.children?.length > 0" @click="onClickToggle">
145
162
  <template v-if="hasToggleSlot">
146
163
  <component :is="toggleSlot" class="lkt-menu-entry-toggle-inner" :class="entry.isOpened ? 'is-opened' : '' "/>
147
164
  </template>
148
- <div v-else class="lkt-menu-entry-toggle-inner lkt-menu-entry-toggle-triangle" :class="entry.isOpened ? 'is-opened' : '' "/>
165
+ <div v-else class="lkt-menu-entry-toggle-inner" :class="entry.isOpened ? 'is-opened' : '' ">
166
+ <i class="lkt-icn-angle-bottom"/>
167
+ </div>
149
168
  </div>
150
169
  </div>
151
170
  <div class="lkt-menu-entry-children" v-if="entry.isOpened">
@@ -1,87 +1,87 @@
1
1
  <script setup lang="ts">
2
- import MenuItem from '../components/MenuItem.vue';
3
- import { computed, ref, useSlots, watch } from 'vue';
4
- import { getDefaultValues, LktObject, Menu, MenuConfig } from 'lkt-vue-kernel';
5
- import { fetchKeys } from '../functions/helpers';
6
- import { DataState } from 'lkt-data-state';
7
- import { httpCall, HTTPResponse } from 'lkt-http-client';
8
-
9
- const props = withDefaults(defineProps<MenuConfig>(), getDefaultValues(Menu));
10
-
11
- const emit = defineEmits([
12
- 'update:modelValue',
13
- 'click-outside',
14
- 'loading',
15
- 'results',
16
- 'response',
17
- 'error'
18
- ]);
19
-
20
- const slots = useSlots();
21
-
22
- const entries = ref(props.modelValue);
23
-
24
- const parseFilters = (filters: LktObject) => {
25
- let d: LktObject = {};
26
- if (typeof filters === 'object' && Object.keys(filters).length > 0) {
27
- d = JSON.parse(JSON.stringify(filters));
28
- }
29
- for (let k in d) {
30
- if (Array.isArray(d[k]) || typeof d[k] === 'object') {
31
- d[k] = JSON.stringify(d[k]);
2
+ import MenuItem from '../components/MenuItem.vue';
3
+ import { computed, ref, useSlots, watch } from 'vue';
4
+ import { getDefaultValues, LktObject, Menu, MenuConfig } from 'lkt-vue-kernel';
5
+ import { fetchKeys } from '../functions/helpers';
6
+ import { DataState } from 'lkt-data-state';
7
+ import { httpCall, HTTPResponse } from 'lkt-http-client';
8
+
9
+ const props = withDefaults(defineProps<MenuConfig>(), getDefaultValues(Menu));
10
+
11
+ const emit = defineEmits([
12
+ 'update:modelValue',
13
+ 'click-outside',
14
+ 'loading',
15
+ 'results',
16
+ 'response',
17
+ 'error',
18
+ ]);
19
+
20
+ const slots = useSlots();
21
+
22
+ const entries = ref(props.modelValue);
23
+
24
+ const parseFilters = (filters: LktObject) => {
25
+ let d: LktObject = {};
26
+ if (typeof filters === 'object' && Object.keys(filters).length > 0) {
27
+ d = JSON.parse(JSON.stringify(filters));
32
28
  }
33
- }
34
- return d;
35
- }
36
- let resourceDataState = new DataState({});
37
- resourceDataState.increment(parseFilters(props.resourceData))
38
-
39
- const availableKeys = computed(() => {
40
- let r:string[] = [];
41
- return fetchKeys(r, entries.value);
42
- }),
43
- entryIconSlots = computed((): LktObject => {
44
- let r = [];
45
- for (let k in slots) {
46
- if (k.startsWith('icon-')) {
47
- if (availableKeys.value.includes(k.substring(5))) {
48
- r.push(k);
49
- }
29
+ for (let k in d) {
30
+ if (Array.isArray(d[k]) || typeof d[k] === 'object') {
31
+ d[k] = JSON.stringify(d[k]);
50
32
  }
51
33
  }
52
- return r;
53
- }),
54
- loadResource = () => {
55
- if (!props.resource) return;
56
-
57
- let d = resourceDataState.getData();
58
- emit('loading');
59
-
60
- httpCall(props.resource, d).then((r: HTTPResponse) => {
61
- resourceDataState.turnStoredIntoOriginal();
62
- //@ts-ignore
63
- entries.value = r.data;
64
- emit('results', r.data);
65
- emit('response', r);
66
-
67
- }).catch((r: any) => {
68
- emit('error', r);
69
- });
34
+ return d;
70
35
  };
36
+ let resourceDataState = new DataState({});
37
+ resourceDataState.increment(parseFilters(props.http?.data ?? {}));
38
+
39
+ const availableKeys = computed(() => {
40
+ let r: string[] = [];
41
+ return fetchKeys(r, entries.value);
42
+ }),
43
+ entryIconSlots = computed((): LktObject => {
44
+ let r = [];
45
+ for (let k in slots) {
46
+ if (k.startsWith('icon-')) {
47
+ if (availableKeys.value.includes(k.substring(5))) {
48
+ r.push(k);
49
+ }
50
+ }
51
+ }
52
+ return r;
53
+ }),
54
+ loadResource = () => {
55
+ if (!props.http?.resource) return;
71
56
 
72
- const onClickOutside = () => {
73
- emit('click-outside');
74
- }
57
+ let d = resourceDataState.getData();
58
+ emit('loading');
75
59
 
76
- watch(() => props.modelValue, (v) => {
77
- entries.value = v;
78
- }, {deep: true})
60
+ httpCall(props.http?.resource, d).then((r: HTTPResponse) => {
61
+ resourceDataState.turnStoredIntoOriginal();
62
+ //@ts-ignore
63
+ entries.value = r.data;
64
+ emit('results', r.data);
65
+ emit('response', r);
79
66
 
80
- watch(entries, (v) => {
81
- emit('update:modelValue', v);
82
- }, {deep: true})
67
+ }).catch((r: any) => {
68
+ emit('error', r);
69
+ });
70
+ };
83
71
 
84
- loadResource();
72
+ const onClickOutside = () => {
73
+ emit('click-outside');
74
+ };
75
+
76
+ watch(() => props.modelValue, (v) => {
77
+ entries.value = v;
78
+ }, { deep: true });
79
+
80
+ watch(entries, (v) => {
81
+ emit('update:modelValue', v);
82
+ }, { deep: true });
83
+
84
+ loadResource();
85
85
  </script>
86
86
 
87
87
  <template>
@@ -89,10 +89,18 @@ loadResource();
89
89
  <div class="lkt-menu">
90
90
  <menu-item v-for="(entry, i) in entries" v-model="entries[i]" :key="entry.key">
91
91
  <template v-for="slot in entryIconSlots" v-slot:[slot]>
92
- <slot :name="slot"/>
92
+ <slot :name="slot" />
93
+ </template>
94
+
95
+ <template v-if="slots[`tooltip-${entry.key}`]" #tooltip>
96
+ <slot :name="`tooltip-${entry.key}`"/>
97
+ </template>
98
+
99
+ <template v-if="slots[`split-${entry.key}`]" #split>
100
+ <slot :name="`split-${entry.key}`"/>
93
101
  </template>
94
102
  </menu-item>
95
103
  </div>
96
- <div class="lkt-menu-outside" v-on:click="onClickOutside"/>
104
+ <div class="lkt-menu-outside" v-on:click="onClickOutside" />
97
105
  </div>
98
106
  </template>
package/theme/default.css CHANGED
@@ -1,35 +1,35 @@
1
1
  :root {
2
2
  /** Font */
3
- --lkt-menu-font-family: system-ui, Helvetica;
4
- --lkt-menu-font-size: 16px;
5
- --lkt-menu-font-weight: 400;
6
- --lkt-menu-line-height: 1;
7
- --lkt-menu-text-align: left;
8
- --lkt-menu-text-decoration: none;
9
- --lkt-menu-text-decoration-hover: none;
3
+ --lkt-menu--font-family: system-ui, Helvetica;
4
+ --lkt-menu--font-size: 16px;
5
+ --lkt-menu--font-weight: 400;
6
+ --lkt-menu--line-height: 1;
7
+ --lkt-menu--text-align: left;
8
+ --lkt-menu--text-decoration: none;
9
+ --lkt-menu--text-decoration--hover: none;
10
10
 
11
11
  /** Sizing */
12
- --lkt-menu-width: 100%;
13
- --lkt-menu-min-width: 0;
14
- --lkt-menu-max-width: initial;
15
- --lkt-menu-min-height: 0;
16
- --lkt-menu-padding: 15px;
17
- --lkt-menu-gap: 15px;
18
- --lkt-menu-gap-entries: 0;
12
+ --lkt-menu--width: 100%;
13
+ --lkt-menu--min-width: 0;
14
+ --lkt-menu--max-width: initial;
15
+ --lkt-menu--min-height: 0;
16
+ --lkt-menu--padding: 15px;
17
+ --lkt-menu--gap: 15px;
18
+ --lkt-menu--entry--gap: 0;
19
19
 
20
20
  /** Colors */
21
- --lkt-menu-bg: #ffffff;
22
- --lkt-menu-color-toggle: #444444;
21
+ --lkt-menu--bg: #ffffff;
22
+ --lkt-menu--toggle--color: #444444;
23
23
 
24
24
  /** Sizing: Entries */
25
- --lkt-menu-padding-entry: 15px;
26
- --lkt-menu-padding-text: 0 0 0 30px;
27
- --lkt-menu-padding-text-with-icon: 0;
28
- --lkt-menu-padding-text-without-icon: 0;
25
+ --lkt-menu--entry--padding: 15px;
26
+ --lkt-menu--text--padding: 0 0 0 30px;
27
+ --lkt-menu--text-with-icon--padding: 0;
28
+ --lkt-menu--text-without-icon--padding: 0;
29
29
 
30
30
  /** Sizing: Children */
31
- --lkt-menu-padding-children: 0 0 0 10px;
31
+ --lkt-menu--children--padding: 0 0 0 10px;
32
32
 
33
33
  /** Colors: Outside */
34
- --lkt-menu-bg-outside: rgba(255, 255, 255, 0.75);
34
+ --lkt-menu--outside--bg: rgba(255, 255, 255, 0.75);
35
35
  }