@apptegy/nuxt-navigation 0.1.5 → 0.1.7

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/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@apptegy/nuxt-navigation",
3
3
  "configKey": "@apptegy/nuxt-navigation",
4
- "version": "0.1.5",
4
+ "version": "0.1.7",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "0.8.3",
7
7
  "unbuild": "unknown"
@@ -4,18 +4,17 @@
4
4
  :class="{ sticky }"
5
5
  role="banner"
6
6
  >
7
- <NavSidebarToggle @toggle-sidebar="$emit('toggle-sidebar')"/>
7
+ <NavSidebarToggle />
8
8
  <div class="header__breadcrumbs">
9
9
  <slot name="breadcrumbs" />
10
10
  </div>
11
11
  <slot name="org-select" />
12
12
  <slot name="user-controls" />
13
- <NavUserDropdown :user="user" :user-dropdown-options="userDropdownOptions" :selected-option="selectedOptions" @select-option="$emit('selectedOption')"/>
13
+ <NavUserDropdown :user="user" :user-dropdown-options="userDropdownOptions" @select-option="(index) => $emit('selected-option', index)"/>
14
14
  </header>
15
15
  </template>
16
16
 
17
17
  <script setup lang="ts">
18
-
19
18
  interface IHeaderProps {
20
19
  sticky?: boolean;
21
20
  }
@@ -26,13 +25,10 @@ interface IUserDropdown {
26
25
  avatar?: string;
27
26
  };
28
27
  userDropdownOptions: Array<unknown>;
29
- selectedOption?: unknown
30
28
  }
31
29
 
32
-
33
30
  defineProps<IHeaderProps & IUserDropdown>();
34
- defineEmits(['toggle-sidebar', 'selectedOption']);
35
-
31
+ defineEmits(['selected-option']);
36
32
  </script>
37
33
 
38
34
  <style scoped>
@@ -1,69 +1,11 @@
1
- <template>
2
- <div class="org-selection">
3
- <label id="org-dropdown-label" class="sr-only">
4
- {{ $t("navigation.orgDropdown") }}
5
- </label>
6
- <div
7
- ref="dropdownTriggerRef"
8
- aria-labelledby="org-dropdown-label"
9
- aria-controls="organizations-options-list"
10
- :aria-expanded="active"
11
- aria-haspopup="listbox"
12
- role="combobox"
13
- class="dropdown-trigger"
14
- >
15
- <input
16
- ref="inputRef"
17
- type="text"
18
- class="org-title"
19
- :placeholder="$t('navigation.orgPlaceholder')"
20
- :value="active ? searchQuery : selectedOrg?.name"
21
- @keydown="keydownActionsOnTrigger"
22
- @click.prevent="toggleDropdown"
23
- @input="handleDropdownSearch"
24
- >
25
- <span v-if="selectedOrg?.intranet" class="badge selected">
26
- <a-icon icon="16:lock-locked" />
27
- {{ $t("navigation.orgBadge") }}
28
- </span>
29
- </div>
30
- <div
31
- v-show="active"
32
- id="organizations-options-list"
33
- class="dropdown"
34
- role="listbox"
35
- >
36
- <div
37
- v-for="(option) in sortedOrgs"
38
- :key="option.id"
39
- ref="optionRef"
40
- v-on-click-outside="onClickOutsideHandler"
41
- role="option"
42
- class="org-option"
43
- :class="{ selected: option.id === modelValue }"
44
- :aria-selected="option.id === modelValue"
45
- tabindex="-1"
46
- @keydown="handleSelectedOrg($event, option.id)"
47
- @click="handleSelectedOrg($event, option.id)"
48
- >
49
- <span :class="{ pinned: option.pinned, 'item-flex': true }"
50
- >{{ option.name }}
51
- <span v-if="option.intranet" class="badge selected">
52
- <a-icon icon="16:lock-locked" />
53
- {{ $t("navigation.orgBadge") }}
54
- </span>
55
- </span>
56
- </div>
57
- </div>
58
- </div>
59
- </template>
60
-
61
1
  <script setup lang="ts">
62
- import { useDropdown, useNuxtApp } from "#imports";
2
+ import { useDropdown, useNuxtApp, useAppConfig } from "#imports";
63
3
  import { vOnClickOutside } from "@vueuse/components";
64
4
  import { ref, computed } from "vue";
65
5
 
66
6
  const { $t } = useNuxtApp();
7
+ const appConfig = useAppConfig();
8
+ const zIndex = computed(() => appConfig?.navigation?.zIndex || 100)
67
9
 
68
10
  interface IOrg {
69
11
  name: string;
@@ -74,17 +16,17 @@ interface IOrg {
74
16
 
75
17
  interface IOrgSelectProps {
76
18
  orgs: Array<IOrg>;
77
- modelValue: number
19
+ modelValue: number;
78
20
  }
79
21
 
80
22
  const emit = defineEmits<{
81
- 'update:model-value': [index: number]
82
- }>();
23
+ "update:model-value": [index: number];
24
+ }>();
83
25
 
84
26
  const dropdownTriggerRef = ref();
85
27
  const optionRef = ref();
86
28
  const selectedOrg = computed(() => {
87
- return props.orgs.find(({id}) => id == props.modelValue);
29
+ return props.orgs.find(({ id }) => id == props.modelValue);
88
30
  });
89
31
 
90
32
  const props = defineProps<IOrgSelectProps>();
@@ -116,16 +58,76 @@ const sortedOrgs = computed(() => {
116
58
  });
117
59
 
118
60
  function handleSelectedOrg($event: KeyboardEvent | MouseEvent, orgId: number) {
119
- if($event.type == 'click') {
61
+ if ($event.type == "click") {
120
62
  emit("update:model-value", orgId);
121
63
  closeDropdown();
122
- } else if ($event.type == 'keydown') {
64
+ } else if ($event.type == "keydown") {
123
65
  emit("update:model-value", orgId);
124
66
  handleKeydown($event as KeyboardEvent, orgId);
125
67
  }
126
68
  }
127
69
  </script>
128
70
 
71
+ <template>
72
+ <div class="org-selection">
73
+ <label id="org-dropdown-label" class="sr-only">
74
+ {{ $t("navigation.orgDropdown") }}
75
+ </label>
76
+ <div
77
+ ref="dropdownTriggerRef"
78
+ aria-labelledby="org-dropdown-label"
79
+ aria-controls="organizations-options-list"
80
+ :aria-expanded="active"
81
+ aria-haspopup="listbox"
82
+ role="combobox"
83
+ class="dropdown-trigger"
84
+ >
85
+ <input
86
+ ref="inputRef"
87
+ type="text"
88
+ class="org-title"
89
+ :placeholder="$t('navigation.orgPlaceholder')"
90
+ :value="active ? searchQuery : selectedOrg?.name"
91
+ @keydown="keydownActionsOnTrigger"
92
+ @click.prevent="toggleDropdown"
93
+ @input="handleDropdownSearch"
94
+ >
95
+ <span v-if="selectedOrg?.intranet" class="badge selected">
96
+ <a-icon icon="16:lock-locked" />
97
+ {{ $t("navigation.orgBadge") }}
98
+ </span>
99
+ </div>
100
+ <div
101
+ v-show="active"
102
+ id="organizations-options-list"
103
+ class="dropdown"
104
+ role="listbox"
105
+ >
106
+ <div
107
+ v-for="option in sortedOrgs"
108
+ :key="option.id"
109
+ ref="optionRef"
110
+ v-on-click-outside="onClickOutsideHandler"
111
+ role="option"
112
+ class="org-option"
113
+ :class="{ selected: option.id === modelValue }"
114
+ :aria-selected="option.id === modelValue"
115
+ tabindex="-1"
116
+ @keydown="handleSelectedOrg($event, option.id)"
117
+ @click="handleSelectedOrg($event, option.id)"
118
+ >
119
+ <span :class="{ pinned: option.pinned, 'item-flex': true }"
120
+ >{{ option.name }}
121
+ <span v-if="option.intranet" class="badge selected">
122
+ <a-icon icon="16:lock-locked" />
123
+ {{ $t("navigation.orgBadge") }}
124
+ </span>
125
+ </span>
126
+ </div>
127
+ </div>
128
+ </div>
129
+ </template>
130
+
129
131
  <style scoped>
130
132
  #organizations-options-list {
131
133
  position: absolute;
@@ -133,7 +135,7 @@ function handleSelectedOrg($event: KeyboardEvent | MouseEvent, orgId: number) {
133
135
  max-height: 300px;
134
136
  overflow-y: auto;
135
137
  background-color: var(--primary-white);
136
- z-index: 50;
138
+ z-index: v-bind(zIndex);
137
139
  }
138
140
 
139
141
  .org-selection {
@@ -171,8 +173,11 @@ function handleSelectedOrg($event: KeyboardEvent | MouseEvent, orgId: number) {
171
173
  .org-selection .dropdown-trigger .org-title:focus {
172
174
  outline: none;
173
175
  }
176
+ .org-selection .dropdown {
177
+ border-radius: 0 0 4px 4px;
178
+ box-shadow: 0px 6px 20px 0px rgba(0, 0, 0, 0.06);
179
+ }
174
180
  .org-selection .dropdown .org-option {
175
- display: block;
176
181
  padding: 12px;
177
182
  min-height: 40px;
178
183
  line-height: 16px;
@@ -200,7 +205,7 @@ function handleSelectedOrg($event: KeyboardEvent | MouseEvent, orgId: number) {
200
205
  background-color: var(--purple-50);
201
206
  padding: 2px 4px;
202
207
  color: white;
203
- border-radius: 4px;
208
+ border-radius: 2px;
204
209
  text-transform: uppercase;
205
210
  }
206
211
  .org-selection .badge svg {
@@ -20,7 +20,6 @@
20
20
  <NavSidebarSection
21
21
  :application="application"
22
22
  :active="currentApplication === application.text"
23
- :navbar-expanded="expanded"
24
23
  >
25
24
  <slot v-if="currentApplication === application.text" />
26
25
  </NavSidebarSection>
@@ -28,7 +27,6 @@
28
27
  <li>
29
28
  <NavHelpArticles
30
29
  v-if="showHelpArticles"
31
- :navbar-expanded="expanded"
32
30
  :help-article-options="helpArticleOptions"
33
31
  />
34
32
  </li>
@@ -45,8 +43,7 @@
45
43
  <slot name="logo">
46
44
  <NuxtLink :to="homepageUrl">
47
45
  <div class="navbar--logo">
48
- <img v-if="expanded" :src="logo.src" :alt="logo.alt">
49
- <img v-else :src="logo.iconSrc" :alt="logo.alt">
46
+ <img :src="logo.src" :alt="logo.alt">
50
47
  </div>
51
48
  </NuxtLink>
52
49
  </slot>
@@ -54,8 +51,9 @@
54
51
  </template>
55
52
 
56
53
  <script setup lang="ts">
57
- import { useNuxtApp } from '#imports';
54
+ import { useNuxtApp, useSidebar } from '#imports';
58
55
  const { $t } = useNuxtApp();
56
+ const { state: expanded } = useSidebar();
59
57
 
60
58
  interface IApplications {
61
59
  id: number;
@@ -81,7 +79,6 @@ interface ILogo {
81
79
  interface ISidebarProps {
82
80
  applications: Array<IApplications>;
83
81
  currentApplication?: IApplications['text'];
84
- expanded?: boolean;
85
82
  homepageUrl?: string;
86
83
  showHelpArticles?: boolean;
87
84
  helpArticleOptions?: Array<unknown>;
@@ -94,7 +91,6 @@ withDefaults(defineProps<ISidebarProps>(), {
94
91
  currentApplication: 'media',
95
92
  homepageUrl: '/',
96
93
  showHelpArticles: true,
97
- expanded: true,
98
94
  helpArticleOptions: () => [],
99
95
  impersonatedUser: () => ({
100
96
  show: false,
@@ -109,6 +105,8 @@ withDefaults(defineProps<ISidebarProps>(), {
109
105
  iconSrc: 'logo.svg',
110
106
  })
111
107
  })
108
+
109
+
112
110
  </script>
113
111
 
114
112
  <style scoped>
@@ -119,10 +117,10 @@ withDefaults(defineProps<ISidebarProps>(), {
119
117
  font: var(--font-regular);
120
118
  background-color: var(--dscl-nav-background-color, var(--purple-70));
121
119
  color: var(--dscl-nav-font-color, var(--dscl-light-font, var(--primary-white)));
122
- transition: min-width 0.3s ease-in-out, translate 0.2s ease-in-out;
120
+ transition: width 0.3s ease-in-out, translate 0.2s ease-in-out;
123
121
  height: 100vh;
124
122
  overflow-y: auto;
125
- min-width: 0px;
123
+ /* min-width: 0px; */
126
124
  translate: -256px;
127
125
  }
128
126
  .navbar a:focus-visible {
@@ -131,7 +129,7 @@ withDefaults(defineProps<ISidebarProps>(), {
131
129
  box-shadow: inset 0 0 0px 4px var(--primary-white);
132
130
  }
133
131
  .navbar.expanded {
134
- transition: min-width 0.3s ease-in-out, translate 0.2s ease-in-out;
132
+ transition: width 0.3s ease-in-out, translate 0.2s ease-in-out;
135
133
  min-width: 256px;
136
134
  translate: 0px;
137
135
  }
@@ -17,7 +17,6 @@ import { computed } from 'vue';
17
17
  const props = defineProps<{
18
18
  application: IApplication;
19
19
  active: boolean;
20
- navbarExpanded: boolean;
21
20
  }>();
22
21
 
23
22
  const iconUrl = computed(() =>
@@ -5,12 +5,10 @@
5
5
  </button>
6
6
  </template>
7
7
 
8
- <script setup>
9
- const emit = defineEmits(["toggle-sidebar"]);
8
+ <script setup lang="ts">
9
+ import { useSidebar } from '#imports';
10
10
 
11
- function toggleSidebar() {
12
- emit("toggle-sidebar");
13
- }
11
+ const { toggleSidebar } = useSidebar();
14
12
  </script>
15
13
 
16
14
  <style scoped>
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
+ import { useDropdown, useAppConfig } from "#imports";
2
3
  import { ref } from "vue";
3
- import { useDropdown } from "#imports";
4
4
  import { vOnClickOutside } from "@vueuse/components";
5
5
 
6
6
  interface IUserDropdown {
@@ -11,6 +11,10 @@ interface IUserDropdown {
11
11
  userDropdownOptions: Array<{ label: string; url: string; icon: string }>;
12
12
  }
13
13
 
14
+ const appConfig = useAppConfig();
15
+ const zIndex = computed(() => appConfig?.navigation?.zIndex || 100)
16
+
17
+
14
18
  const props = defineProps<IUserDropdown>();
15
19
  const dropdownTriggerRef = ref<HTMLDivElement>();
16
20
  const dropdownOptionsRef = ref<Array<HTMLDivElement>>();
@@ -29,7 +33,7 @@ const {
29
33
  );
30
34
 
31
35
  const emit = defineEmits<{
32
- 'select-option': [index: number]
36
+ "select-option": [index: number];
33
37
  }>();
34
38
 
35
39
  function handleSelectedClick(index: number) {
@@ -60,7 +64,7 @@ function handleKeydownAction($event: KeyboardEvent, index: number) {
60
64
  >
61
65
  <NavAvatar :name="user.name" :src="user.avatar" />
62
66
  <NavIconsUserDropdownMenu />
63
- <span class="sr-only">{{ $t('navigation.userDropdown') }}</span>
67
+ <span class="sr-only">{{ $t("navigation.userDropdown") }}</span>
64
68
  </div>
65
69
  <div
66
70
  v-show="active"
@@ -79,6 +83,7 @@ function handleKeydownAction($event: KeyboardEvent, index: number) {
79
83
  @keydown="handleKeydownAction($event, idx)"
80
84
  @click="handleSelectedClick(idx)"
81
85
  >
86
+ <!-- because of the the above handler, this component is never treated as a link and can't redirect natively? -->
82
87
  <NuxtLink class="option" :to="option.url">
83
88
  {{ option.label }}
84
89
  <a-icon :icon="option.icon" font-size="24px" />
@@ -123,7 +128,7 @@ function handleKeydownAction($event: KeyboardEvent, index: number) {
123
128
  border-radius: 4px;
124
129
  box-shadow: 0px 6px 20px 0px rgba(0, 0, 0, 0.06);
125
130
  padding: 8px;
126
- z-index: 10;
131
+ z-index: v-bind(zIndex);
127
132
  }
128
133
  .options-dropdown .option-wrapper {
129
134
  padding: 8px;
@@ -50,6 +50,9 @@ export function useDropdown(options, dropdownOptionsRef, dropdownTriggerRef, con
50
50
  });
51
51
  }
52
52
  break;
53
+ case "ArrowLeft":
54
+ case "ArrowRight":
55
+ break;
53
56
  case " ":
54
57
  if (active.value) {
55
58
  closeDropdown();
@@ -141,6 +144,9 @@ export function useDropdown(options, dropdownOptionsRef, dropdownTriggerRef, con
141
144
  dropdownOptionsRef.value[index - 1].focus();
142
145
  });
143
146
  return index;
147
+ case "ArrowLeft":
148
+ case "ArrowRight":
149
+ break;
144
150
  case "Home":
145
151
  nextTick(() => {
146
152
  dropdownOptionsRef.value[0].focus();
@@ -0,0 +1,5 @@
1
+ export declare function useSidebar(): {
2
+ state: any;
3
+ toggleSidebar: () => void;
4
+ sidebarWidth: any;
5
+ };
@@ -0,0 +1,13 @@
1
+ import { useState, ref, computed } from "#imports";
2
+ export function useSidebar() {
3
+ const state = useState("navigation:sidebar", () => ref(true));
4
+ function toggleSidebar() {
5
+ state.value = !state.value;
6
+ }
7
+ const sidebarWidth = computed(() => state.value ? "256px" : "0px");
8
+ return {
9
+ state,
10
+ toggleSidebar,
11
+ sidebarWidth
12
+ };
13
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apptegy/nuxt-navigation",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {