@citizenplane/pimp 18.8.1 → 18.8.3

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": "@citizenplane/pimp",
3
- "version": "18.8.1",
3
+ "version": "18.8.3",
4
4
  "scripts": {
5
5
  "dev": "storybook dev -p 8081",
6
6
  "build-storybook": "storybook build --output-dir ./docs",
@@ -2,4 +2,5 @@
2
2
  --cp-easing-elastic: cubic-bezier(0.34, 1.66, 0.64, 1);
3
3
  --cp-easing-elastic-soft: cubic-bezier(0.34, 1.2, 0.64, 1);
4
4
  --cp-easing-ease-in-out-quart: cubic-bezier(0.76, 0, 0.24, 1);
5
+ --cp-easing-ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1);
5
6
  }
@@ -0,0 +1,34 @@
1
+ /* Transitions classes that are globally used */
2
+
3
+ .scale-elastic-enter-active,
4
+ .scale-elastic-leave-active {
5
+ transition:
6
+ scale 200ms var(--cp-easing-elastic),
7
+ opacity 200ms ease;
8
+ }
9
+
10
+ .scale-elastic-enter-from,
11
+ .scale-elastic-leave-to {
12
+ opacity: 0;
13
+ scale: 0.9;
14
+ }
15
+
16
+ .drawer-enter-active,
17
+ .drawer-leave-active {
18
+ transition: transform 500ms var(--cp-easing-ease-out-quart);
19
+ }
20
+
21
+ .drawer-enter-from,
22
+ .drawer-leave-to {
23
+ transform: translate3d(0, 100%, 0);
24
+ }
25
+
26
+ .fade-enter-active,
27
+ .fade-leave-active {
28
+ transition: opacity 300ms ease;
29
+ }
30
+
31
+ .fade-enter-from,
32
+ .fade-leave-to {
33
+ opacity: 0;
34
+ }
@@ -4,4 +4,5 @@
4
4
  @import "./css/shadows.css";
5
5
  @import "./css/typography.css";
6
6
  @import "./css/easings.css";
7
+ @import "./css/transitions.css";
7
8
  @import "./css/tokens.css";
@@ -1,5 +1,6 @@
1
1
  <template>
2
2
  <div class="cpMenu">
3
+ <div v-if="isDrawer" class="cpMenu__drawerOverlay" :class="drawerOverlayDynamicClass" />
3
4
  <div
4
5
  ref="trigger"
5
6
  :aria-controls="menuId"
@@ -62,25 +63,28 @@
62
63
  import PrimevueDrawer from 'primevue/drawer'
63
64
  import type { MenuItem } from 'primevue/menuitem'
64
65
  import PrimevuePopover from 'primevue/popover'
65
- import { computed, nextTick, onUnmounted, ref, useId } from 'vue'
66
+ import { computed, nextTick, ref, useId } from 'vue'
67
+
68
+ import { useIsBreakpoint } from '@/composables/useIsBreakpoint'
66
69
 
67
70
  import CpButton from '@/components/CpButton.vue'
68
71
  import CpIcon from '@/components/CpIcon.vue'
69
72
  import CpMenuList from '@/components/CpMenuList.vue'
70
73
 
74
+ import { Breakpoints } from '@/constants/layout'
71
75
  import { getKeyboardFocusableElements } from '@/helpers/dom'
72
76
 
73
77
  export interface Props {
74
78
  class?: string
75
79
  forcePopover?: boolean
76
- fullHeightDrawer?: boolean
80
+ isFullHeightDrawer?: boolean
77
81
  items?: MenuItem[]
78
82
  keepOpenOnClick?: boolean
79
83
  }
80
84
 
81
85
  const props = withDefaults(defineProps<Props>(), {
82
86
  class: undefined,
83
- fullHeightDrawer: false,
87
+ isFullHeightDrawer: false,
84
88
  items: undefined,
85
89
  keepOpenOnClick: false,
86
90
  })
@@ -90,37 +94,33 @@ const emits = defineEmits<{
90
94
  show: []
91
95
  }>()
92
96
 
93
- const MOBILE_BREAKPOINT_PX = 640
94
-
95
97
  const trigger = ref<HTMLElement | null>(null)
96
98
  const popover = ref<InstanceType<typeof PrimevuePopover>>()
97
99
  const closeButton = ref<InstanceType<typeof CpButton> | null>(null)
98
100
  const isOpen = ref(false)
99
101
  const menuId = useId()
100
102
 
101
- const mediaQuery = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT_PX}px)`)
102
- const isMobileViewport = ref(mediaQuery.matches)
103
- const onMediaChange = (event: MediaQueryListEvent) => {
104
- isMobileViewport.value = event.matches
105
- }
106
- mediaQuery.addEventListener('change', onMediaChange)
107
- onUnmounted(() => mediaQuery.removeEventListener('change', onMediaChange))
103
+ const isMobileViewport = useIsBreakpoint(Breakpoints.TABLET)
108
104
 
109
105
  const isDrawer = computed(() => isMobileViewport.value && !props.forcePopover)
110
106
  const hasItems = computed(() => props.items?.length)
111
107
  const popupType = computed(() => (hasItems.value ? 'menu' : 'dialog'))
112
108
 
113
109
  const popoverPt = {
114
- root: { class: ['cpMenu__overlay', props.class] },
115
- content: { class: 'cpMenu__overlayContent' },
110
+ root: { class: ['cpMenu__menu', props.class] },
111
+ content: { class: 'cpMenu__menuContent' },
116
112
  transition: { name: 'scale-elastic', duration: 100 },
117
113
  }
118
114
 
115
+ const drawerOverlayDynamicClass = computed(() => ({
116
+ 'cpMenu__drawerOverlay--isOpen': isOpen.value,
117
+ }))
118
+
119
119
  const drawerPt = {
120
- root: { class: ['cpMenu__drawer', { 'cpMenu__drawer--fullHeight': props.fullHeightDrawer }] },
120
+ root: { class: ['cpMenu__drawer', { 'cpMenu__drawer--isFullHeight': props.isFullHeightDrawer }] },
121
121
  content: { class: 'cpMenu__drawerContent' },
122
- mask: { class: 'cpMenu__drawerMask' },
123
122
  header: { class: 'cpMenu__drawerHeader' },
123
+ transition: { name: 'drawer', duration: 300 },
124
124
  }
125
125
 
126
126
  const show = (event: Event) => {
@@ -171,7 +171,7 @@ defineExpose({ show, hide, toggle })
171
171
  cursor: pointer;
172
172
  }
173
173
 
174
- &__overlay {
174
+ &__menu {
175
175
  position: absolute;
176
176
  min-width: calc(var(--cp-dimensions-1) * 62.5);
177
177
  border-radius: var(--cp-radius-md);
@@ -182,18 +182,25 @@ defineExpose({ show, hide, toggle })
182
182
  will-change: opacity, transform;
183
183
  }
184
184
 
185
- &__overlayContent {
185
+ &__menuContent {
186
186
  padding: var(--cp-spacing-sm) 0;
187
187
  }
188
188
 
189
- &__drawerMask {
189
+ &__drawerOverlay {
190
190
  position: fixed;
191
- z-index: 2;
191
+ z-index: 0;
192
192
  display: flex;
193
193
  align-items: flex-end;
194
194
  justify-content: center;
195
195
  background-color: var(--cp-background-overlay);
196
196
  inset: 0;
197
+ opacity: 0;
198
+ pointer-events: none;
199
+ transition: opacity 250ms ease;
200
+
201
+ &--isOpen {
202
+ opacity: 1;
203
+ }
197
204
  }
198
205
 
199
206
  &__drawer {
@@ -208,7 +215,7 @@ defineExpose({ show, hide, toggle })
208
215
  box-shadow: var(--cp-shadows-overlay);
209
216
  }
210
217
 
211
- &__drawer--fullHeight {
218
+ &__drawer--isFullHeight {
212
219
  height: 100%;
213
220
  max-height: 100%;
214
221
  border-radius: 0;
@@ -230,29 +237,4 @@ defineExpose({ show, hide, toggle })
230
237
  padding: var(--cp-spacing-md) var(--cp-spacing-xl);
231
238
  }
232
239
  }
233
-
234
- .scale-elastic-enter-active,
235
- .scale-elastic-leave-active {
236
- transition:
237
- scale 200ms var(--cp-easing-elastic),
238
- opacity 200ms ease;
239
- }
240
-
241
- .scale-elastic-enter-from,
242
- .scale-elastic-leave-to {
243
- opacity: 0;
244
- scale: 0.9;
245
- }
246
-
247
- .p-drawer-enter-active,
248
- .p-drawer-leave-active {
249
- transition:
250
- transform 300ms ease,
251
- opacity 250ms ease;
252
- }
253
-
254
- .p-drawer-enter-from,
255
- .p-drawer-leave-to {
256
- transform: translateY(100%);
257
- }
258
240
  </style>
@@ -96,6 +96,8 @@ const uniqueAirlines = computed(() => {
96
96
 
97
97
  <style lang="scss">
98
98
  .cpTrip {
99
+ width: 100%;
100
+
99
101
  &__header {
100
102
  display: flex;
101
103
  align-items: center;
@@ -126,6 +128,7 @@ const uniqueAirlines = computed(() => {
126
128
  position: relative;
127
129
  display: flex;
128
130
  flex-direction: column;
131
+ align-items: flex-start;
129
132
  justify-content: center;
130
133
 
131
134
  &:last-child {
@@ -0,0 +1,16 @@
1
+ import { useWindowSize } from '@vueuse/core'
2
+ import { computed, onMounted, ref } from 'vue'
3
+
4
+ import { Breakpoints } from '@/constants/layout'
5
+
6
+ export const useIsBreakpoint = (breakpoint: Breakpoints = Breakpoints.MOBILE) => {
7
+ const isMounted = ref(false)
8
+ onMounted(() => (isMounted.value = true))
9
+
10
+ const { width } = useWindowSize()
11
+
12
+ return computed(() => {
13
+ if (!isMounted.value) return false
14
+ return width.value < breakpoint
15
+ })
16
+ }
@@ -29,7 +29,7 @@ const meta = {
29
29
  description: 'Disable the bottom-drawer behavior on mobile and keep the popover anchored to the trigger.',
30
30
  table: { defaultValue: { summary: 'false' } },
31
31
  },
32
- fullHeightDrawer: {
32
+ isFullHeightDrawer: {
33
33
  control: 'boolean',
34
34
  description: 'When enabled, the mobile drawer takes the full available height.',
35
35
  table: { defaultValue: { summary: 'false' } },
@@ -132,7 +132,10 @@ export const ForcePopoverOnMobile: Story = {
132
132
  */
133
133
  export const FullHeightDrawer: Story = {
134
134
  args: {
135
- fullHeightDrawer: true,
135
+ isFullHeightDrawer: true,
136
+ },
137
+ globals: {
138
+ viewport: { value: 'mobile1', isRotated: false },
136
139
  },
137
140
  render: (args) => ({
138
141
  components: { CpButton, CpMenu },
@@ -150,7 +153,7 @@ export const FullHeightDrawer: Story = {
150
153
  template: `
151
154
  <CpMenu v-bind="args" :items="items">
152
155
  <template #trigger>
153
- <CpButton>Open full-height drawer</CpButton>
156
+ <CpButton size="xs" appearance="secondary">Open drawer</CpButton>
154
157
  </template>
155
158
  </CpMenu>
156
159
  `,