@nexxtmove/ui 1.2.4 → 1.2.5

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/nuxt.js CHANGED
@@ -47613,7 +47613,9 @@ var Xw, Zw, Qw, $w, eT, tT = f((() => {
47613
47613
  NexxtTabs: "components/Tabs/Tabs.vue",
47614
47614
  NexxtTemplateCard: "components/TemplateCard/TemplateCard.vue",
47615
47615
  NexxtTimelineEvent: "components/TimelineEvent/TimelineEvent.vue",
47616
+ NexxtTimelineLanes: "components/TimelineLanes/TimelineLanes.vue",
47616
47617
  NexxtTimelinePhaseblock: "components/TimelinePhaseblock/TimelinePhaseblock.vue",
47618
+ NexxtTimelineTrack: "components/TimelineTrack/TimelineTrack.vue",
47617
47619
  NexxtToast: "components/Toast/Toast.vue",
47618
47620
  NexxtToaster: "components/Toaster/Toaster.vue",
47619
47621
  NexxtToggleGroup: "components/ToggleGroup/ToggleGroup.vue",
@@ -47645,7 +47647,7 @@ var Xw, Zw, Qw, $w, eT, tT = f((() => {
47645
47647
  getContents: () => `
47646
47648
  @import "tailwindcss";
47647
47649
  @import "@nexxtmove/ui/theme";
47648
- @source "${e}/**/*.vue";
47650
+ @source "${e}/**/*.{vue,ts}";
47649
47651
  `,
47650
47652
  write: !0
47651
47653
  }), o.options.css.push("#build/nexxtmove-ui.css");
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nexxtmove/ui",
3
3
  "type": "module",
4
- "version": "1.2.4",
4
+ "version": "1.2.5",
5
5
  "exports": {
6
6
  ".": {
7
7
  "types": "./dist/index.d.ts",
@@ -2,7 +2,8 @@
2
2
  import Button from '../Button/Button.vue'
3
3
 
4
4
  interface NexxtHeaderProps {
5
- title: string
5
+ /** Optional when the title slot is used. */
6
+ title?: string
6
7
  headingType?: 'heading-1' | 'heading-2' | 'heading-3' | 'heading-4'
7
8
  backButtonText?: string
8
9
  backButtonAction?: () => void
@@ -37,7 +38,12 @@ const {
37
38
  {{ backButtonText }}
38
39
  </Button>
39
40
  </slot>
40
- <span class="min-w-0 flex-1 truncate text-sapphire-500" :class="headingType">
41
+ <!-- The title slot replaces the static title, keeping the same flex-1 and
42
+ min-w-0 sizing so a centered slot stays centered. -->
43
+ <div v-if="$slots.title" class="flex min-w-0 flex-1 items-center">
44
+ <slot name="title" />
45
+ </div>
46
+ <span v-else class="min-w-0 flex-1 truncate text-sapphire-500" :class="headingType">
41
47
  {{ title }}
42
48
  </span>
43
49
  </div>
@@ -3,7 +3,8 @@ import Header from '../Header/Header.vue'
3
3
  import ProgressBar from '../ProgressBar/ProgressBar.vue'
4
4
 
5
5
  interface NexxtStepperHeaderProps {
6
- title: string
6
+ /** Optional when the title slot is used. */
7
+ title?: string
7
8
  currentStep: InstanceType<typeof ProgressBar>['currentStep']
8
9
  steps: InstanceType<typeof ProgressBar>['stepTitles']
9
10
  backButtonText?: InstanceType<typeof Header>['backButtonText']
@@ -21,6 +22,12 @@ defineProps<NexxtStepperHeaderProps>()
21
22
 
22
23
  <template>
23
24
  <Header :title="title" :back-button-action="backButtonAction" :back-button-text="backButtonText">
25
+ <template v-if="$slots['back-button']" #back-button>
26
+ <slot name="back-button" />
27
+ </template>
28
+ <template v-if="$slots.title" #title>
29
+ <slot name="title" />
30
+ </template>
24
31
  <template v-if="steps" #center>
25
32
  <ProgressBar
26
33
  class="w-full"
@@ -19,8 +19,16 @@ const defaultEventConfig: EventConfig = {
19
19
  color: 'bg-gray-500',
20
20
  }
21
21
 
22
- const eventConfig = computed(() => {
23
- return EVENT_CONFIG_MAP[props.event.type] || { ...defaultEventConfig, label: props.event.type }
22
+ // Resolved per field so an event can override only its label (e.g. a dynamic
23
+ // "Status gewijzigd van X naar Y") and still take icon and color from the map.
24
+ const eventConfig = computed<EventConfig>(() => {
25
+ const mapped = EVENT_CONFIG_MAP[props.event.type]
26
+
27
+ return {
28
+ label: props.event.label ?? mapped?.label ?? props.event.type,
29
+ icon: props.event.icon ?? mapped?.icon ?? defaultEventConfig.icon,
30
+ color: props.event.color ?? mapped?.color ?? defaultEventConfig.color,
31
+ }
24
32
  })
25
33
 
26
34
  const props = withDefaults(
@@ -102,6 +110,9 @@ const isContactEvent = computed(() => {
102
110
  </span>
103
111
  <NexxtIcon name="external-link" class="ml-1 h-4 w-4 text-gray-950" />
104
112
  </a>
113
+ <span v-else-if="event.description" class="mt-1 text-sm text-gray-500">
114
+ {{ event.description }}
115
+ </span>
105
116
  <span v-if="event.request_reason" class="mt-1 text-sm text-gray-500">
106
117
  Reden: {{ event.request_reason }}
107
118
  </span>
@@ -1,15 +1,22 @@
1
1
  export interface TimelineEvent {
2
- id: number
2
+ id: string | number
3
3
  type: string
4
4
  happened_at: string
5
- medium_type: string | null
6
- url: string | null
7
- page_title: string | null
8
- request_reason: string | null
9
- agenda_item_type: string | null
10
- source: string
11
- direction: string
12
- description: string | null
5
+ /** Required when the event is rendered in split view ('outbound' | 'inbound'). */
6
+ direction?: string
7
+ medium_type?: string | null
8
+ url?: string | null
9
+ page_title?: string | null
10
+ request_reason?: string | null
11
+ agenda_item_type?: string | null
12
+ source?: string
13
+ description?: string | null
14
+ /** Overrides the label from EVENT_CONFIG_MAP. Use for dynamic labels. */
15
+ label?: string | null
16
+ /** Overrides the icon from EVENT_CONFIG_MAP. */
17
+ icon?: string | null
18
+ /** Overrides the background color class from EVENT_CONFIG_MAP. */
19
+ color?: string | null
13
20
  }
14
21
 
15
22
  export interface TimelinePhase {
@@ -137,9 +144,34 @@ export const EVENT_CONFIG_MAP: Record<string, { label: string; icon: string; col
137
144
  icon: 'pen-fancy',
138
145
  color: 'bg-emerald-500',
139
146
  },
147
+ proposal_created: { label: 'Voorstel aangemaakt', icon: 'file-plus', color: 'bg-blue-500' },
148
+ proposal_scheduled: { label: 'Voorstel ingepland', icon: 'calendar-clock', color: 'bg-blue-400' },
140
149
  proposal_sent: { label: 'Voorstel verzonden', icon: 'paper-plane-top', color: 'bg-blue-400' },
150
+ proposal_delivered: {
151
+ label: 'Voorstel afgeleverd',
152
+ icon: 'envelope-circle-check',
153
+ color: 'bg-blue-300',
154
+ },
155
+ // Mail geopend (read_at) is a different moment than the proposal itself being
156
+ // viewed (opened_at, proposal_opened below).
157
+ proposal_mail_opened: {
158
+ label: 'Mail geopend',
159
+ icon: 'envelope-open-text',
160
+ color: 'bg-blue-200',
161
+ },
141
162
  proposal_opened: { label: 'Voorstel geopend', icon: 'envelope-open', color: 'bg-blue-300' },
142
163
  proposal_accepted: { label: 'Voorstel geaccepteerd', icon: 'check', color: 'bg-emerald-500' },
164
+ proposal_send_failed: {
165
+ label: 'Verzenden mislukt',
166
+ icon: 'triangle-exclamation',
167
+ color: 'bg-red-500',
168
+ },
169
+ proposal_expired: { label: 'Voorstel verlopen', icon: 'clock-rotate-left', color: 'bg-gray-500' },
170
+ proposal_status_changed: {
171
+ label: 'Status gewijzigd',
172
+ icon: 'repeat',
173
+ color: 'bg-purple-500',
174
+ },
143
175
 
144
176
  // Aftercare
145
177
  final_inspection_agenda_item_scheduled: {
@@ -0,0 +1,50 @@
1
+ <script setup lang="ts">
2
+ import NexxtIcon from '../Icon/Icon.vue'
3
+ import NexxtTooltip from '../Tooltip/Tooltip.vue'
4
+
5
+ defineOptions({
6
+ name: 'NexxtTimelineLanes',
7
+ })
8
+
9
+ withDefaults(
10
+ defineProps<{
11
+ leftLabel?: string
12
+ rightLabel?: string
13
+ /** Tooltip next to the left label. Omit or pass an empty string to hide it. */
14
+ leftTooltip?: string
15
+ /** Tooltip next to the right label. Omit or pass an empty string to hide it. */
16
+ rightTooltip?: string
17
+ }>(),
18
+ {
19
+ leftLabel: 'Outbound',
20
+ rightLabel: 'Inbound',
21
+ leftTooltip: 'Vanuit Nexxtmove',
22
+ rightTooltip: 'Vanuit relatie',
23
+ },
24
+ )
25
+ </script>
26
+
27
+ <template>
28
+ <div class="relative z-10">
29
+ <div class="flex items-center justify-between px-4 py-2">
30
+ <span class="flex gap-1">
31
+ {{ leftLabel }}
32
+ <NexxtTooltip v-if="leftTooltip">
33
+ <NexxtIcon name="circle-info" class="h-4 w-4 text-xs text-gray-600" />
34
+ <template #tooltip
35
+ ><span class="text-sm">{{ leftTooltip }}</span></template
36
+ >
37
+ </NexxtTooltip>
38
+ </span>
39
+ <span class="flex gap-1">
40
+ {{ rightLabel }}
41
+ <NexxtTooltip v-if="rightTooltip">
42
+ <NexxtIcon name="circle-info" class="h-4 w-4 text-xs text-gray-600" />
43
+ <template #tooltip
44
+ ><span class="text-sm">{{ rightTooltip }}</span></template
45
+ >
46
+ </NexxtTooltip>
47
+ </span>
48
+ </div>
49
+ </div>
50
+ </template>
@@ -1,12 +1,12 @@
1
1
  <script setup lang="ts">
2
2
  import NexxtIcon from '../Icon/Icon.vue'
3
- import NexxtTooltip from '../Tooltip/Tooltip.vue'
4
3
  import { computed } from 'vue'
5
4
 
6
5
  defineOptions({
7
6
  name: 'NexxtTimelinePhaseblock',
8
7
  })
9
8
  import NexxtTimelineEvent from '../TimelineEvent/TimelineEvent.vue'
9
+ import NexxtTimelineLanes from '../TimelineLanes/TimelineLanes.vue'
10
10
  import { PHASE_MAP, type TimelinePhase } from '../TimelineEvent/TimelineTypes'
11
11
 
12
12
  const props = defineProps<{
@@ -69,26 +69,7 @@ const getPhaseDirection = () => {
69
69
 
70
70
  <template>
71
71
  <div class="relative z-10 flex flex-col gap-16" :data-phase="phase.phase.value">
72
- <template v-if="index === 0 && isSplitView">
73
- <div class="relative z-10">
74
- <div class="flex items-center justify-between px-4 py-2">
75
- <span class="flex gap-1">
76
- Outbound
77
- <NexxtTooltip>
78
- <NexxtIcon name="circle-info" class="h-4 w-4 text-xs text-gray-600" />
79
- <template #tooltip><span class="text-sm">Vanuit Nexxtmove</span></template>
80
- </NexxtTooltip>
81
- </span>
82
- <span class="flex gap-1">
83
- Inbound
84
- <NexxtTooltip as-child>
85
- <NexxtIcon name="circle-info" class="h-4 w-4 text-xs text-gray-600" />
86
- <template #tooltip><span class="text-sm">Vanuit relatie</span></template>
87
- </NexxtTooltip>
88
- </span>
89
- </div>
90
- </div>
91
- </template>
72
+ <NexxtTimelineLanes v-if="index === 0 && isSplitView" />
92
73
  <!-- Left timeline line (always shown) -->
93
74
  <div
94
75
  class="absolute bottom-0 left-5 w-0 border-l"
@@ -0,0 +1,67 @@
1
+ <script setup lang="ts">
2
+ import { computed } from 'vue'
3
+
4
+ defineOptions({
5
+ name: 'NexxtTimelineTrack',
6
+ })
7
+ import NexxtTimelineEvent from '../TimelineEvent/TimelineEvent.vue'
8
+ import NexxtTimelineLanes from '../TimelineLanes/TimelineLanes.vue'
9
+ import type { TimelineEvent as Event } from '../TimelineEvent/TimelineTypes'
10
+
11
+ const props = withDefaults(
12
+ defineProps<{
13
+ /** Events, newest first. Ignored when the default slot is used. */
14
+ events?: Event[]
15
+ splitView?: boolean
16
+ /** Border color class for the vertical timeline lines. */
17
+ color?: string
18
+ /** Set to false to hide the lane headers in split view. */
19
+ showLanes?: boolean
20
+ leftLabel?: string
21
+ rightLabel?: string
22
+ leftTooltip?: string
23
+ rightTooltip?: string
24
+ }>(),
25
+ {
26
+ events: () => [],
27
+ splitView: true,
28
+ color: 'border-gray-200',
29
+ showLanes: true,
30
+ leftLabel: 'Outbound',
31
+ rightLabel: 'Inbound',
32
+ leftTooltip: 'Vanuit Nexxtmove',
33
+ rightTooltip: 'Vanuit relatie',
34
+ },
35
+ )
36
+
37
+ const hasLanes = computed(() => props.splitView && props.showLanes)
38
+ </script>
39
+
40
+ <template>
41
+ <div class="relative z-10 flex flex-col gap-16">
42
+ <NexxtTimelineLanes
43
+ v-if="hasLanes"
44
+ :left-label="leftLabel"
45
+ :right-label="rightLabel"
46
+ :left-tooltip="leftTooltip"
47
+ :right-tooltip="rightTooltip"
48
+ />
49
+
50
+ <!-- Left timeline line (always shown) -->
51
+ <div
52
+ class="absolute bottom-0 left-5 w-0 border-l"
53
+ :class="[color, hasLanes ? 'top-10' : 'top-0']"
54
+ ></div>
55
+
56
+ <!-- Right timeline line (split view only) -->
57
+ <div
58
+ v-if="splitView"
59
+ class="absolute right-5 bottom-0 w-0 border-l"
60
+ :class="[color, hasLanes ? 'top-10' : 'top-0']"
61
+ ></div>
62
+
63
+ <slot>
64
+ <NexxtTimelineEvent v-for="ev in events" :key="ev.id" :event="ev" :split-view="splitView" />
65
+ </slot>
66
+ </div>
67
+ </template>
@@ -48,7 +48,9 @@
48
48
  "NexxtTabs": "components/Tabs/Tabs.vue",
49
49
  "NexxtTemplateCard": "components/TemplateCard/TemplateCard.vue",
50
50
  "NexxtTimelineEvent": "components/TimelineEvent/TimelineEvent.vue",
51
+ "NexxtTimelineLanes": "components/TimelineLanes/TimelineLanes.vue",
51
52
  "NexxtTimelinePhaseblock": "components/TimelinePhaseblock/TimelinePhaseblock.vue",
53
+ "NexxtTimelineTrack": "components/TimelineTrack/TimelineTrack.vue",
52
54
  "NexxtToast": "components/Toast/Toast.vue",
53
55
  "NexxtToaster": "components/Toaster/Toaster.vue",
54
56
  "NexxtToggleGroup": "components/ToggleGroup/ToggleGroup.vue",
package/src/index.ts CHANGED
@@ -2,6 +2,14 @@
2
2
  // Third-party type re-exports for consumers of this library
3
3
  export type { Placement } from '@floating-ui/vue'
4
4
 
5
+ // Non-component modules that consumers need (types, config maps)
6
+ export { EVENT_CONFIG_MAP, PHASE_MAP } from './components/TimelineEvent/TimelineTypes'
7
+ export type {
8
+ TimelineEvent,
9
+ TimelinePhase,
10
+ TimelineResponse,
11
+ } from './components/TimelineEvent/TimelineTypes'
12
+
5
13
  export { default as NexxtAnimatedNumber } from './components/AnimatedNumber/AnimatedNumber.vue'
6
14
  export { default as NexxtAnnouncement } from './components/Announcement/Announcement.vue'
7
15
  export { default as NexxtAvatar } from './components/Avatar/Avatar.vue'
@@ -51,7 +59,9 @@ export { default as NexxtTable } from './components/Table/Table.vue'
51
59
  export { default as NexxtTabs } from './components/Tabs/Tabs.vue'
52
60
  export { default as NexxtTemplateCard } from './components/TemplateCard/TemplateCard.vue'
53
61
  export { default as NexxtTimelineEvent } from './components/TimelineEvent/TimelineEvent.vue'
62
+ export { default as NexxtTimelineLanes } from './components/TimelineLanes/TimelineLanes.vue'
54
63
  export { default as NexxtTimelinePhaseblock } from './components/TimelinePhaseblock/TimelinePhaseblock.vue'
64
+ export { default as NexxtTimelineTrack } from './components/TimelineTrack/TimelineTrack.vue'
55
65
  export { default as NexxtToast } from './components/Toast/Toast.vue'
56
66
  export { default as NexxtToaster } from './components/Toaster/Toaster.vue'
57
67
  export { default as NexxtToggleGroup } from './components/ToggleGroup/ToggleGroup.vue'
package/src/nuxt.ts CHANGED
@@ -62,8 +62,11 @@ const module: NuxtModule<ModuleOptions> = defineNuxtModule<ModuleOptions>({
62
62
  }
63
63
 
64
64
  if (options.addCSS) {
65
- // Tailwind scans the shipped .vue source for class names only — this
66
- // does not involve the consumer's type-checker.
65
+ // Tailwind scans the shipped source for class names only — this does not
66
+ // involve the consumer's type-checker. The .ts files are scanned too
67
+ // because config maps hold class names outside any template (e.g.
68
+ // EVENT_CONFIG_MAP and PHASE_MAP in TimelineEvent/TimelineTypes.ts);
69
+ // without them those utilities are never generated.
67
70
  const componentsDir = resolve('../src/components')
68
71
 
69
72
  addTemplate({
@@ -71,7 +74,7 @@ const module: NuxtModule<ModuleOptions> = defineNuxtModule<ModuleOptions>({
71
74
  getContents: () => `
72
75
  @import "tailwindcss";
73
76
  @import "@nexxtmove/ui/theme";
74
- @source "${componentsDir}/**/*.vue";
77
+ @source "${componentsDir}/**/*.{vue,ts}";
75
78
  `,
76
79
  write: true,
77
80
  })