@nexxtmove/ui 1.11.0 → 1.13.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.
Files changed (43) hide show
  1. package/dist/components/molecules/PageContainer/PageContainer.vue.d.ts +35 -0
  2. package/dist/index.d.ts +1 -0
  3. package/dist/index.js +382 -334
  4. package/dist/nuxt.js +1 -0
  5. package/dist/ui.css +1 -1
  6. package/package.json +2 -1
  7. package/src/components/atoms/Avatar/Avatar.vue +3 -3
  8. package/src/components/atoms/Button/Button.vue +11 -1
  9. package/src/components/atoms/Card/Card.vue +1 -1
  10. package/src/components/atoms/Checkbox/Checkbox.vue +1 -1
  11. package/src/components/atoms/EnergyLabel/EnergyLabel.vue +1 -1
  12. package/src/components/atoms/PresenceIndicator/PresenceIndicator.vue +3 -3
  13. package/src/components/atoms/PropertyListing/PropertyListing.vue +1 -1
  14. package/src/components/atoms/SelectableOption/SelectableOption.vue +1 -1
  15. package/src/components/atoms/Skeleton/Skeleton.vue +1 -1
  16. package/src/components/atoms/Squircle/Squircle.vue +1 -1
  17. package/src/components/molecules/CustomerJourneyTile/CustomerJourneyTile.vue +1 -1
  18. package/src/components/molecules/DoughnutChart/DoughnutChart.vue +1 -4
  19. package/src/components/molecules/InputField/InputField.vue +1 -1
  20. package/src/components/molecules/InputSelect/InputSelect.vue +1 -1
  21. package/src/components/molecules/PageContainer/PageContainer.vue +63 -0
  22. package/src/components/molecules/Pagination/Pagination.vue +5 -5
  23. package/src/components/molecules/PropertyCard/PropertyCard.vue +4 -4
  24. package/src/components/molecules/SkeletonPropertyCard/SkeletonPropertyCard.vue +2 -2
  25. package/src/components/molecules/SocialIcons/SocialIcons.vue +1 -1
  26. package/src/components/molecules/SocialMediaCustomTemplate/SocialMediaCustomTemplate.vue +1 -1
  27. package/src/components/molecules/TemplateCard/TemplateCard.vue +1 -1
  28. package/src/components/molecules/TimelineEvent/TimelineEvent.vue +3 -3
  29. package/src/components/molecules/TimelineLanes/TimelineLanes.vue +2 -2
  30. package/src/components/molecules/Toast/Toast.vue +11 -3
  31. package/src/components/organisms/Calendar/_CalendarDayView.vue +2 -2
  32. package/src/components/organisms/Calendar/_CalendarHeader.vue +7 -7
  33. package/src/components/organisms/Calendar/_CalendarTimePicker.vue +4 -4
  34. package/src/components/organisms/ColorPicker/ColorPicker.vue +12 -12
  35. package/src/components/organisms/DropdownButton/DropdownButton.vue +1 -1
  36. package/src/components/organisms/Modal/Modal.vue +2 -2
  37. package/src/components/organisms/SocialMediaTemplate/SocialMediaTemplate.vue +4 -4
  38. package/src/components/organisms/Table/Table.vue +1 -1
  39. package/src/components/organisms/TimelinePhaseblock/TimelinePhaseblock.vue +3 -6
  40. package/src/components/organisms/VideoPlayer/VideoPlayer.vue +5 -5
  41. package/src/components.json +1 -0
  42. package/src/index.ts +1 -0
  43. package/tailwind/nexxtmove.tailwind.custom.css +8 -0
package/dist/nuxt.js CHANGED
@@ -28,6 +28,7 @@ var s = {
28
28
  NexxtInputField: "components/molecules/InputField/InputField.vue",
29
29
  NexxtInputSelect: "components/molecules/InputSelect/InputSelect.vue",
30
30
  NexxtModalFooter: "components/molecules/ModalFooter/ModalFooter.vue",
31
+ NexxtPageContainer: "components/molecules/PageContainer/PageContainer.vue",
31
32
  NexxtPagination: "components/molecules/Pagination/Pagination.vue",
32
33
  NexxtPropertyCard: "components/molecules/PropertyCard/PropertyCard.vue",
33
34
  NexxtSelect: "components/molecules/Select/Select.vue",
package/dist/ui.css CHANGED
@@ -1,2 +1,2 @@
1
- rect[data-v-0a5d9b21]{animation-duration:4s;animation-timing-function:cubic-bezier(.77,0,.175,1);animation-iteration-count:infinite}rect[data-v-0a5d9b21]:first-child{animation-name:load-1-0a5d9b21}rect[data-v-0a5d9b21]:nth-child(2){animation-name:load-2-0a5d9b21}rect[data-v-0a5d9b21]:nth-child(3){animation-name:load-3-0a5d9b21}rect[data-v-0a5d9b21]:nth-child(4){animation-name:load-4-0a5d9b21}rect[data-v-0a5d9b21]:nth-child(5){animation-name:load-5-0a5d9b21}rect[data-v-0a5d9b21]:nth-child(6){animation-name:load-6-0a5d9b21}rect[data-v-0a5d9b21]:nth-child(7){animation-name:load-7-0a5d9b21}rect[data-v-0a5d9b21]:nth-child(8){animation-name:load-8-0a5d9b21}@media (prefers-reduced-motion:reduce){rect[data-v-0a5d9b21]{animation:none}svg[data-v-0a5d9b21]{animation:2.5s ease-in-out infinite pulse-0a5d9b21}}@keyframes pulse-0a5d9b21{0%,to{opacity:1}50%{opacity:.65}}@keyframes load-1-0a5d9b21{0%,80%{transform:translate(0)}5%,20%,60%,75%{transform:translate(-25px,25px)}30%,50%{transform:translate(-75px,75px)}}@keyframes load-2-0a5d9b21{5%,75%{transform:translate(0%)}10%,20%,60%,70%{transform:translate(50px)}30%,50%{transform:translateY(50px)}}@keyframes load-3-0a5d9b21{10%,70%{transform:translate(0%)}15%,65%{transform:translateY(-50px)}20%,60%{fill:var(--color-sapphire-500);transform:translateY(-50px)}30%,50%{fill:var(--color-purple-500);transform:translate(-50px)}}@keyframes load-4-0a5d9b21{20%,60%{transform:translate(0%)}30%,50%{transform:translate(50px,-50px)}}@keyframes load-5-0a5d9b21{0%,80%{transform:translate(0%)}5%,20%,60%,75%{transform:translateY(50px)}30%,50%{transform:translate(50px)}}@keyframes load-6-0a5d9b21{5%,75%{transform:translate(0%)}10%,20%,60%,70%{transform:translate(-50px)}30%,50%{transform:translateY(-50px)}}@keyframes load-7-0a5d9b21{10%,70%{transform:translate(0%)}15%,20%,60%,65%{transform:translate(50px)}30%,50%{transform:translate(100px,-50px)}}@keyframes load-8-0a5d9b21{15%,65%{transform:translate(0%)}20%,60%{transform:translateY(-50px)}30%,50%{transform:translate(50px,-100px)}}.timer-circle[data-v-d13bb383]{stroke-dashoffset:0;animation:linear forwards toast-timer-d13bb383}@keyframes toast-timer-d13bb383{to{stroke-dashoffset:var(--b622135e)}}
1
+ rect[data-v-0a5d9b21]{animation-duration:4s;animation-timing-function:cubic-bezier(.77,0,.175,1);animation-iteration-count:infinite}rect[data-v-0a5d9b21]:first-child{animation-name:load-1-0a5d9b21}rect[data-v-0a5d9b21]:nth-child(2){animation-name:load-2-0a5d9b21}rect[data-v-0a5d9b21]:nth-child(3){animation-name:load-3-0a5d9b21}rect[data-v-0a5d9b21]:nth-child(4){animation-name:load-4-0a5d9b21}rect[data-v-0a5d9b21]:nth-child(5){animation-name:load-5-0a5d9b21}rect[data-v-0a5d9b21]:nth-child(6){animation-name:load-6-0a5d9b21}rect[data-v-0a5d9b21]:nth-child(7){animation-name:load-7-0a5d9b21}rect[data-v-0a5d9b21]:nth-child(8){animation-name:load-8-0a5d9b21}@media (prefers-reduced-motion:reduce){rect[data-v-0a5d9b21]{animation:none}svg[data-v-0a5d9b21]{animation:2.5s ease-in-out infinite pulse-0a5d9b21}}@keyframes pulse-0a5d9b21{0%,to{opacity:1}50%{opacity:.65}}@keyframes load-1-0a5d9b21{0%,80%{transform:translate(0)}5%,20%,60%,75%{transform:translate(-25px,25px)}30%,50%{transform:translate(-75px,75px)}}@keyframes load-2-0a5d9b21{5%,75%{transform:translate(0%)}10%,20%,60%,70%{transform:translate(50px)}30%,50%{transform:translateY(50px)}}@keyframes load-3-0a5d9b21{10%,70%{transform:translate(0%)}15%,65%{transform:translateY(-50px)}20%,60%{fill:var(--color-sapphire-500);transform:translateY(-50px)}30%,50%{fill:var(--color-purple-500);transform:translate(-50px)}}@keyframes load-4-0a5d9b21{20%,60%{transform:translate(0%)}30%,50%{transform:translate(50px,-50px)}}@keyframes load-5-0a5d9b21{0%,80%{transform:translate(0%)}5%,20%,60%,75%{transform:translateY(50px)}30%,50%{transform:translate(50px)}}@keyframes load-6-0a5d9b21{5%,75%{transform:translate(0%)}10%,20%,60%,70%{transform:translate(-50px)}30%,50%{transform:translateY(-50px)}}@keyframes load-7-0a5d9b21{10%,70%{transform:translate(0%)}15%,20%,60%,65%{transform:translate(50px)}30%,50%{transform:translate(100px,-50px)}}@keyframes load-8-0a5d9b21{15%,65%{transform:translate(0%)}20%,60%{transform:translateY(-50px)}30%,50%{transform:translate(50px,-100px)}}.timer-circle[data-v-7e3c5bda]{stroke-dashoffset:0;animation:linear forwards toast-timer-7e3c5bda}@keyframes toast-timer-7e3c5bda{to{stroke-dashoffset:var(--fa0d20de)}}
2
2
  /*$vite$:1*/
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nexxtmove/ui",
3
3
  "type": "module",
4
- "version": "1.11.0",
4
+ "version": "1.13.0",
5
5
  "exports": {
6
6
  ".": {
7
7
  "types": "./dist/index.d.ts",
@@ -57,6 +57,7 @@
57
57
  "consola": "^3.4.2",
58
58
  "eslint": "^10.8.1",
59
59
  "eslint-config-prettier": "^10.1.8",
60
+ "eslint-plugin-better-tailwindcss": "4.7.0",
60
61
  "eslint-plugin-prettier": "^5.5.6",
61
62
  "eslint-plugin-storybook": "10.5.10",
62
63
  "eslint-plugin-vue": "^10.10.0",
@@ -63,14 +63,14 @@ const fontSizeClasses = {
63
63
  <template>
64
64
  <NexxtSquircle v-if="squircle" :size="size">
65
65
  <div
66
- class="flex h-full w-full items-center justify-center bg-cornflower-blue-50 font-semibold text-cornflower-blue-500"
66
+ class="flex size-full items-center justify-center bg-cornflower-blue-50 font-semibold text-cornflower-blue-500"
67
67
  :class="[fontSizeClasses[size]]"
68
68
  >
69
69
  <img
70
70
  v-if="showImage"
71
71
  :src="src"
72
72
  :alt="name"
73
- class="h-full w-full object-cover"
73
+ class="size-full object-cover"
74
74
  @error="imageFailed = true"
75
75
  />
76
76
  <template v-else>{{ computedInitials }}</template>
@@ -88,7 +88,7 @@ const fontSizeClasses = {
88
88
  v-if="showImage"
89
89
  :src="src"
90
90
  :alt="name"
91
- class="h-full w-full object-cover"
91
+ class="size-full object-cover"
92
92
  @error="imageFailed = true"
93
93
  />
94
94
  <template v-else>{{ computedInitials }}</template>
@@ -23,6 +23,16 @@ const {
23
23
  rounded = false,
24
24
  fullWidth = false,
25
25
  } = defineProps<NexxtButtonProps>()
26
+
27
+ // Full class names so Tailwind and the no-unknown-classes lint rule see them.
28
+ const VARIANT_CLASSES = {
29
+ primary: 'button-primary',
30
+ secondary: 'button-secondary',
31
+ success: 'button-success',
32
+ danger: 'button-danger',
33
+ warning: 'button-warning',
34
+ link: 'button-link',
35
+ } as const
26
36
  </script>
27
37
 
28
38
  <template>
@@ -33,7 +43,7 @@ const {
33
43
  'button relative flex h-10 cursor-pointer items-center overflow-hidden transition-colors duration-200 focus-visible:outline-3 disabled:cursor-not-allowed',
34
44
  fullWidth ? 'w-full justify-start' : 'justify-center',
35
45
  rounded ? 'rounded-full' : 'rounded-lg',
36
- `button-${variant}`,
46
+ VARIANT_CLASSES[variant],
37
47
  $slots.default ?? 'w-10',
38
48
  !$slots.default && icon ? 'aspect-square px-0' : '',
39
49
  loading ? 'pointer-events-none' : '',
@@ -14,7 +14,7 @@ defineProps<Props>()
14
14
  v-if="image"
15
15
  :src="image"
16
16
  :alt="imageAlt ?? 'Card afbeelding'"
17
- class="block h-40 max-h-40 min-h-40 w-full rounded-tl-lg rounded-tr-lg object-cover"
17
+ class="block h-40 max-h-40 min-h-40 w-full rounded-t-lg object-cover"
18
18
  />
19
19
  </slot>
20
20
 
@@ -33,7 +33,7 @@ watchEffect(() => {
33
33
  <span
34
34
  aria-hidden="true"
35
35
  :class="[
36
- 'flex h-5 w-5 shrink-0 items-center justify-center rounded border transition-colors duration-200',
36
+ 'flex size-5 shrink-0 items-center justify-center rounded-sm border transition-colors duration-200',
37
37
  'peer-focus-visible:ring-2 peer-focus-visible:ring-cornflower-blue-400 peer-focus-visible:ring-offset-2',
38
38
  model || indeterminate
39
39
  ? 'border-cornflower-blue-600 text-cornflower-blue-600'
@@ -37,7 +37,7 @@ const color = computed(() => COLORS[normalized.value])
37
37
  <span
38
38
  role="img"
39
39
  :aria-label="`Energielabel ${normalized}`"
40
- class="relative isolate mr-3 inline-flex h-6 items-center justify-center rounded-l px-2 extra-small-semibold text-white after:absolute after:top-1/2 after:left-full after:size-4.25 after:-translate-x-1/2 after:-translate-y-1/2 after:rotate-45 after:rounded-tr after:bg-(--energy-label-color) after:content-['']"
40
+ class="relative isolate mr-3 inline-flex h-6 items-center justify-center rounded-l px-2 extra-small-semibold text-white after:absolute after:top-1/2 after:left-full after:size-4.25 after:-translate-1/2 after:rotate-45 after:rounded-tr after:bg-(--energy-label-color) after:content-['']"
41
41
  :style="{ backgroundColor: color, '--energy-label-color': color }"
42
42
  >
43
43
  <span aria-hidden="true" class="relative z-10">{{ normalized }}</span>
@@ -17,13 +17,13 @@ const { online = false } = defineProps<NexxtPresenceIndicatorProps>()
17
17
  :aria-label="online ? 'Online' : 'Offline'"
18
18
  role="status"
19
19
  >
20
- <span class="relative flex h-1.5 w-1.5">
20
+ <span class="relative flex size-1.5">
21
21
  <span
22
22
  v-if="online"
23
- class="absolute inline-flex h-full w-full animate-ping rounded-full bg-green-400 opacity-75"
23
+ class="absolute inline-flex size-full animate-ping rounded-full bg-green-400 opacity-75"
24
24
  />
25
25
  <i
26
- class="relative block h-1.5 w-1.5 rounded-full"
26
+ class="relative block size-1.5 rounded-full"
27
27
  :class="online ? 'bg-green-500' : 'bg-gray-700'"
28
28
  />
29
29
  </span>
@@ -20,7 +20,7 @@ defineProps<Props>()
20
20
  </div>
21
21
  </div>
22
22
 
23
- <div v-if="text" class="wrap-break-words w-full body-normal text-gray-950">
23
+ <div v-if="text" class="w-full body-normal wrap-break-word text-gray-950">
24
24
  {{ text }}
25
25
  </div>
26
26
  </div>
@@ -56,7 +56,7 @@ const RADIUS = {
56
56
  <slot :selected="selected" />
57
57
  <span
58
58
  v-if="checkmark && selected"
59
- class="absolute -top-2 -right-2 flex h-6 w-6 items-center justify-center rounded-full bg-cornflower-blue-500 text-white shadow"
59
+ class="absolute -top-2 -right-2 flex size-6 items-center justify-center rounded-full bg-cornflower-blue-500 text-white shadow-sm"
60
60
  >
61
61
  <NexxtIcon name="check" type="solid" class="text-xs" />
62
62
  </span>
@@ -3,5 +3,5 @@ defineOptions({ name: 'NexxtSkeleton' })
3
3
  </script>
4
4
 
5
5
  <template>
6
- <div class="animate-pulse rounded bg-gray-200" />
6
+ <div class="animate-pulse rounded-sm bg-gray-200" />
7
7
  </template>
@@ -43,7 +43,7 @@ const style = computed(() => ({
43
43
  <template>
44
44
  <div class="relative block shrink-0 overflow-hidden" :style="style">
45
45
  <svg
46
- class="absolute h-0 w-0 overflow-hidden"
46
+ class="absolute size-0 overflow-hidden"
47
47
  aria-hidden="true"
48
48
  focusable="false"
49
49
  width="0"
@@ -102,7 +102,7 @@ const iconColors = computed(() => {
102
102
  >
103
103
  <div
104
104
  v-if="icon"
105
- class="flex min-h-10 w-14 items-center justify-center overflow-hidden rounded-tl-md rounded-bl-md"
105
+ class="flex min-h-10 w-14 items-center justify-center overflow-hidden rounded-l-md"
106
106
  :class="iconColors"
107
107
  >
108
108
  <NexxtIcon :name="icon" class="text-2xl" aria-hidden="true" />
@@ -107,10 +107,7 @@ const resolvedBackgroundColor = computed(() =>
107
107
  :width="size - thickness * 2"
108
108
  :height="size - thickness * 2"
109
109
  >
110
- <div
111
- xmlns="http://www.w3.org/1999/xhtml"
112
- class="flex h-full w-full items-center justify-center"
113
- >
110
+ <div xmlns="http://www.w3.org/1999/xhtml" class="flex size-full items-center justify-center">
114
111
  <slot>
115
112
  <span class="heading-1">{{ value }}</span>
116
113
  </slot>
@@ -97,7 +97,7 @@ const decrement = () => {
97
97
  v-model="modelValue"
98
98
  :placeholder="placeholder"
99
99
  v-bind="inputAttrs"
100
- class="bg-transparant h-10 w-full min-w-60 text-sm text-gray-900 placeholder-gray-400 focus:outline-none [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none"
100
+ class="h-10 w-full min-w-60 bg-transparent text-sm text-gray-900 placeholder-gray-400 focus:outline-none [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none"
101
101
  :class="{ 'pl-3': !leftIcon, 'pr-3': !rightIcon }"
102
102
  />
103
103
  <slot name="right">
@@ -141,7 +141,7 @@ const select = (opt: SelectOption, close: () => void) => {
141
141
  v-model="inputModel"
142
142
  :placeholder="placeholder"
143
143
  v-bind="inputAttrs"
144
- class="bg-transparant h-10 w-full min-w-40 px-3 text-sm text-gray-900 placeholder-gray-400 focus:outline-none"
144
+ class="h-10 w-full min-w-40 bg-transparent px-3 text-sm text-gray-900 placeholder-gray-400 focus:outline-none"
145
145
  />
146
146
  </div>
147
147
 
@@ -0,0 +1,63 @@
1
+ <script setup lang="ts">
2
+ type ContentWidth = keyof typeof CONTENT_WIDTHS
3
+
4
+ interface NexxtPageContainerProps {
5
+ /** Maximum width of the content area; the content is centered within it. */
6
+ maxWidth?: ContentWidth
7
+ }
8
+
9
+ defineOptions({
10
+ name: 'NexxtPageContainer',
11
+ })
12
+
13
+ const { maxWidth = '7xl' } = defineProps<NexxtPageContainerProps>()
14
+
15
+ // Full class names so Tailwind and the no-unknown-classes lint rule see them.
16
+ const CONTENT_WIDTHS = {
17
+ xs: 'max-w-xs',
18
+ sm: 'max-w-sm',
19
+ md: 'max-w-md',
20
+ lg: 'max-w-lg',
21
+ xl: 'max-w-xl',
22
+ '2xl': 'max-w-2xl',
23
+ '3xl': 'max-w-3xl',
24
+ '4xl': 'max-w-4xl',
25
+ '5xl': 'max-w-5xl',
26
+ '6xl': 'max-w-6xl',
27
+ '7xl': 'max-w-7xl',
28
+ '8xl': 'max-w-8xl',
29
+ full: 'max-w-full-width',
30
+ } as const
31
+ </script>
32
+
33
+ <template>
34
+ <div class="flex h-full min-h-0 flex-1">
35
+ <div class="h-full min-w-0 grow overflow-y-auto p-8">
36
+ <div :class="['mx-auto', CONTENT_WIDTHS[maxWidth]]">
37
+ <slot />
38
+ </div>
39
+ </div>
40
+
41
+ <Transition
42
+ enter-active-class="transition-[max-width,opacity] duration-300 ease-[cubic-bezier(0.77,0,0.175,1)] motion-reduce:transition-none"
43
+ enter-from-class="max-w-0 opacity-0"
44
+ enter-to-class="max-w-105 opacity-100"
45
+ leave-active-class="transition-[max-width,opacity] duration-300 ease-[cubic-bezier(0.77,0,0.175,1)] motion-reduce:transition-none"
46
+ leave-from-class="max-w-105 opacity-100"
47
+ leave-to-class="max-w-0 opacity-0"
48
+ >
49
+ <aside
50
+ v-if="$slots.sidebar"
51
+ class="h-full w-105 shrink-0 overflow-hidden border-l border-gray-100 bg-white"
52
+ >
53
+ <!-- Fixed width on purpose: the transition shrinks the aside's
54
+ max-width, and a w-full wrapper would reflow (rewrap) the content
55
+ every frame. At w-105 the content keeps its layout and the
56
+ aside's overflow-hidden clips it instead. -->
57
+ <div class="h-full w-105 overflow-y-auto p-8">
58
+ <slot name="sidebar" />
59
+ </div>
60
+ </aside>
61
+ </Transition>
62
+ </div>
63
+ </template>
@@ -47,13 +47,13 @@ const {
47
47
  >
48
48
  <PaginationFirst
49
49
  v-if="items.some((item) => item.type === 'ellipsis')"
50
- class="flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg bg-transparent transition hover:bg-cornflower-blue-50 disabled:cursor-not-allowed disabled:opacity-50"
50
+ class="flex size-8 cursor-pointer items-center justify-center rounded-lg bg-transparent transition hover:bg-cornflower-blue-50 disabled:cursor-not-allowed disabled:opacity-50"
51
51
  :disabled="disabled"
52
52
  >
53
53
  <NexxtIcon name="angles-left" />
54
54
  </PaginationFirst>
55
55
  <PaginationPrev
56
- class="mr-4 flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg bg-transparent transition hover:bg-cornflower-blue-50 disabled:cursor-not-allowed disabled:opacity-50"
56
+ class="mr-4 flex size-8 cursor-pointer items-center justify-center rounded-lg bg-transparent transition hover:bg-cornflower-blue-50 disabled:cursor-not-allowed disabled:opacity-50"
57
57
  :disabled="disabled"
58
58
  >
59
59
  <NexxtIcon name="chevron-left" />
@@ -72,20 +72,20 @@ const {
72
72
  v-else
73
73
  :key="page.type"
74
74
  :index="index"
75
- class="flex h-8 w-8 items-center justify-center"
75
+ class="flex size-8 items-center justify-center"
76
76
  >
77
77
  &#8230;
78
78
  </PaginationEllipsis>
79
79
  </template>
80
80
  <PaginationNext
81
- class="ml-4 flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg bg-transparent transition hover:bg-cornflower-blue-50 disabled:cursor-not-allowed disabled:opacity-50"
81
+ class="ml-4 flex size-8 cursor-pointer items-center justify-center rounded-lg bg-transparent transition hover:bg-cornflower-blue-50 disabled:cursor-not-allowed disabled:opacity-50"
82
82
  :disabled="disabled"
83
83
  >
84
84
  <NexxtIcon name="chevron-right" />
85
85
  </PaginationNext>
86
86
  <PaginationLast
87
87
  v-if="items.some((item) => item.type === 'ellipsis')"
88
- class="flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg bg-transparent transition hover:bg-cornflower-blue-50 disabled:cursor-not-allowed disabled:opacity-50"
88
+ class="flex size-8 cursor-pointer items-center justify-center rounded-lg bg-transparent transition hover:bg-cornflower-blue-50 disabled:cursor-not-allowed disabled:opacity-50"
89
89
  :disabled="disabled"
90
90
  >
91
91
  <NexxtIcon name="angles-right" />
@@ -20,17 +20,17 @@ defineProps<NexxtPropertyCardProps>()
20
20
  <template>
21
21
  <NexxtCard :image="image" :image-alt="imageAlt">
22
22
  <template v-if="!image" #image>
23
- <div class="relative isolate h-40 w-full overflow-hidden rounded-tl-lg rounded-tr-lg">
23
+ <div class="relative isolate h-40 w-full overflow-hidden rounded-t-lg">
24
24
  <img
25
25
  :src="PropertyPlaceholder"
26
26
  alt="Woning placeholder"
27
27
  loading="lazy"
28
- class="h-full w-full object-cover"
28
+ class="size-full object-cover"
29
29
  />
30
30
  <div
31
- class="absolute inset-0 flex items-center justify-center rounded-tl-lg rounded-tr-lg bg-white/20 backdrop-blur-sm"
31
+ class="absolute inset-0 flex items-center justify-center rounded-t-lg bg-white/20 backdrop-blur-sm"
32
32
  >
33
- <NexxtIcon name="house" class="text-6xl text-white drop-shadow" />
33
+ <NexxtIcon name="house" class="text-6xl text-white drop-shadow-sm" />
34
34
  </div>
35
35
  </div>
36
36
  </template>
@@ -18,14 +18,14 @@ withDefaults(defineProps<NexxtSkeletonPropertyCardProps>(), {
18
18
  role="status"
19
19
  :aria-label="ariaLabel"
20
20
  >
21
- <NexxtSkeleton class="h-40 w-full rounded-tl-lg rounded-tr-lg rounded-b-none" />
21
+ <NexxtSkeleton class="h-40 w-full rounded-t-lg rounded-b-none" />
22
22
 
23
23
  <div
24
24
  class="box-border flex w-full flex-col gap-2 rounded-b-lg border border-gray-200 px-4 py-2"
25
25
  >
26
26
  <div class="flex items-center gap-2">
27
27
  <NexxtSkeleton class="h-4 w-24" />
28
- <NexxtSkeleton class="h-4 w-4" />
28
+ <NexxtSkeleton class="size-4" />
29
29
  <NexxtSkeleton class="h-4 w-28" />
30
30
  </div>
31
31
 
@@ -48,7 +48,7 @@ const activeIcons = computed(() =>
48
48
  <li
49
49
  v-for="platform in activeIcons"
50
50
  :key="platform.name"
51
- class="inline-flex h-5 w-5 items-center justify-center rounded-full outline-1 outline-white"
51
+ class="inline-flex size-5 items-center justify-center rounded-full outline-1 outline-white"
52
52
  :class="brandColors[platform.name]"
53
53
  :aria-label="platform.label"
54
54
  >
@@ -47,7 +47,7 @@ onMounted(() => {
47
47
  muted
48
48
  playsinline
49
49
  :loop="hasPlayedOnce"
50
- class="h-full w-full object-cover"
50
+ class="size-full object-cover"
51
51
  poster="../../../assets/images/Template_aanvragen.jpg"
52
52
  @ended.once="handleEnded"
53
53
  />
@@ -80,7 +80,7 @@ const featureMessages = computed<Record<NexxtTemplateCardContentFeature, string>
80
80
  <NexxtIcon :name="ICON_MAP[feature].icon" />
81
81
  </div>
82
82
  <template #tooltip>
83
- <span class="body-small text-gray-700">{{ featureMessages[feature] }}</span>
83
+ <span class="small-normal text-gray-700">{{ featureMessages[feature] }}</span>
84
84
  </template>
85
85
  </NexxtTooltip>
86
86
  </li>
@@ -87,10 +87,10 @@ const isContactEvent = computed(() => {
87
87
  }"
88
88
  >
89
89
  <div
90
- class="flex h-10 w-10 shrink-0 items-center justify-center rounded-full"
90
+ class="flex size-10 shrink-0 items-center justify-center rounded-full"
91
91
  :class="[eventConfig.color]"
92
92
  >
93
- <NexxtIcon :name="eventConfig.icon as any" class="flex h-6 w-6 text-xl text-white" />
93
+ <NexxtIcon :name="eventConfig.icon as any" class="flex size-6 text-xl text-white" />
94
94
  </div>
95
95
  <div
96
96
  class="flex w-full flex-col gap-2 rounded-xl border border-gray-200 p-8"
@@ -108,7 +108,7 @@ const isContactEvent = computed(() => {
108
108
  <span class="truncate group-hover:underline">
109
109
  {{ event.description || event.url }}
110
110
  </span>
111
- <NexxtIcon name="external-link" class="ml-1 h-4 w-4 text-gray-950" />
111
+ <NexxtIcon name="external-link" class="ml-1 size-4 text-gray-950" />
112
112
  </a>
113
113
  <span v-else-if="event.description" class="mt-1 text-sm text-gray-500">
114
114
  {{ event.description }}
@@ -30,7 +30,7 @@ withDefaults(
30
30
  <span class="flex gap-1">
31
31
  {{ leftLabel }}
32
32
  <NexxtTooltip v-if="leftTooltip">
33
- <NexxtIcon name="circle-info" class="h-4 w-4 text-xs text-gray-600" />
33
+ <NexxtIcon name="circle-info" class="size-4 text-xs text-gray-600" />
34
34
  <template #tooltip
35
35
  ><span class="text-sm">{{ leftTooltip }}</span></template
36
36
  >
@@ -39,7 +39,7 @@ withDefaults(
39
39
  <span class="flex gap-1">
40
40
  {{ rightLabel }}
41
41
  <NexxtTooltip v-if="rightTooltip">
42
- <NexxtIcon name="circle-info" class="h-4 w-4 text-xs text-gray-600" />
42
+ <NexxtIcon name="circle-info" class="size-4 text-xs text-gray-600" />
43
43
  <template #tooltip
44
44
  ><span class="text-sm">{{ rightTooltip }}</span></template
45
45
  >
@@ -48,6 +48,14 @@ const VARIANT_CONFIG: Record<
48
48
  },
49
49
  }
50
50
 
51
+ // Full class names so Tailwind and the no-unknown-classes lint rule see them.
52
+ const VARIANT_CLASSES: Record<ToastVariant, string> = {
53
+ info: 'toast-info',
54
+ success: 'toast-success',
55
+ warning: 'toast-warning',
56
+ error: 'toast-error',
57
+ }
58
+
51
59
  const { variant = 'info', dismissible = true, autoClose = 0 } = defineProps<NexxtToastProps>()
52
60
  const emit = defineEmits<{ dismiss: [] }>()
53
61
 
@@ -94,13 +102,13 @@ onUnmounted(() => {
94
102
  :aria-live="variant === 'error' ? 'assertive' : 'polite'"
95
103
  aria-atomic="true"
96
104
  class="toast flex w-100 gap-4 rounded-xl bg-white shadow-md"
97
- :class="`toast-${variant}`"
105
+ :class="VARIANT_CLASSES[variant]"
98
106
  @mouseenter="autoClose ? pause() : undefined"
99
107
  @mouseleave="autoClose ? resume() : undefined"
100
108
  >
101
109
  <div
102
110
  aria-hidden="true"
103
- class="flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-white"
111
+ class="flex size-8 shrink-0 items-center justify-center rounded-full text-white"
104
112
  :class="selectedVariant.iconBg"
105
113
  >
106
114
  <NexxtIcon :name="selectedVariant.icon" class="text-xl" />
@@ -115,7 +123,7 @@ onUnmounted(() => {
115
123
  <button
116
124
  v-if="dismissible"
117
125
  type="button"
118
- class="relative flex h-8 w-8 shrink-0 cursor-pointer items-center justify-center focus:outline-none"
126
+ class="relative flex size-8 shrink-0 cursor-pointer items-center justify-center focus:outline-none"
119
127
  :aria-label="
120
128
  autoClose ? `Sluiten (verdwijnt automatisch na ${autoClose / 1000} seconden)` : 'Sluiten'
121
129
  "
@@ -137,7 +137,7 @@ defineExpose({
137
137
  :aria-label="format(day, 'd MMMM yyyy', { locale })"
138
138
  :tabindex="isSameMonth(day, viewDate) ? 0 : -1"
139
139
  :class="[
140
- 'relative flex h-8 w-8 items-center justify-center rounded-xl text-xs transition-colors duration-150 outline-none focus:ring-2 focus:ring-cornflower-blue-500 focus:ring-offset-1',
140
+ 'relative flex size-8 items-center justify-center rounded-xl text-xs transition-colors duration-150 outline-none focus:ring-2 focus:ring-cornflower-blue-500 focus:ring-offset-1',
141
141
  !isSameMonth(day, viewDate) ? 'text-gray-300' : 'text-gray-900',
142
142
  isSelected(day) ? 'bg-cornflower-blue-500 font-medium text-white!' : '',
143
143
  isTodayByTimezone(day) && !isSelected(day)
@@ -158,7 +158,7 @@ defineExpose({
158
158
  <span
159
159
  v-if="isMarked(day)"
160
160
  :class="[
161
- 'absolute bottom-1 left-1/2 h-1 w-1 -translate-x-1/2 rounded-full',
161
+ 'absolute bottom-1 left-1/2 size-1 -translate-x-1/2 rounded-full',
162
162
  isSelected(day) ? 'bg-white' : 'bg-cornflower-blue-500',
163
163
  ]"
164
164
  />
@@ -44,7 +44,7 @@ const monthTransition = {
44
44
  v-if="pickerView === 'days'"
45
45
  type="button"
46
46
  :disabled="!canGoPrev"
47
- class="flex h-7 w-7 cursor-pointer items-center justify-center rounded-full bg-gray-200 text-gray-950 transition-colors hover:bg-gray-300 disabled:cursor-not-allowed disabled:bg-transparent disabled:opacity-30"
47
+ class="flex size-7 cursor-pointer items-center justify-center rounded-full bg-gray-200 text-gray-950 transition-colors hover:bg-gray-300 disabled:cursor-not-allowed disabled:bg-transparent disabled:opacity-30"
48
48
  @click="emit('prev')"
49
49
  aria-label="Vorige maand"
50
50
  >
@@ -53,13 +53,13 @@ const monthTransition = {
53
53
  <button
54
54
  v-else-if="pickerView === 'years'"
55
55
  type="button"
56
- class="flex h-7 w-7 cursor-pointer items-center justify-center rounded-full bg-gray-200 text-gray-950 transition-colors hover:bg-gray-300"
56
+ class="flex size-7 cursor-pointer items-center justify-center rounded-full bg-gray-200 text-gray-950 transition-colors hover:bg-gray-300"
57
57
  @click="emit('closePicker')"
58
58
  aria-label="Terug naar maanden"
59
59
  >
60
60
  <NexxtIcon name="arrow-left" class="text-xs" />
61
61
  </button>
62
- <div v-else class="h-7 w-7" />
62
+ <div v-else class="size-7" />
63
63
 
64
64
  <!-- Center: month + year labels -->
65
65
  <div
@@ -74,7 +74,7 @@ const monthTransition = {
74
74
  v-if="monthYearPicker"
75
75
  :key="`button-${monthName}`"
76
76
  type="button"
77
- class="block cursor-pointer rounded px-0.5 leading-5 whitespace-nowrap outline-none hover:text-cornflower-blue-700"
77
+ class="block cursor-pointer rounded-sm px-0.5 leading-5 whitespace-nowrap outline-none hover:text-cornflower-blue-700"
78
78
  @click="emit('openMonthPicker')"
79
79
  >
80
80
  {{ monthName }}
@@ -92,7 +92,7 @@ const monthTransition = {
92
92
  v-if="monthYearPicker"
93
93
  :key="`button-${yearValue}`"
94
94
  type="button"
95
- class="block cursor-pointer rounded px-0.5 leading-5 whitespace-nowrap outline-none hover:text-cornflower-blue-700"
95
+ class="block cursor-pointer rounded-sm px-0.5 leading-5 whitespace-nowrap outline-none hover:text-cornflower-blue-700"
96
96
  @click="emit('openYearPicker')"
97
97
  >
98
98
  {{ yearValue }}
@@ -112,12 +112,12 @@ const monthTransition = {
112
112
  v-if="pickerView === 'days'"
113
113
  type="button"
114
114
  :disabled="!canGoNext"
115
- class="flex h-7 w-7 cursor-pointer items-center justify-center rounded-full bg-gray-200 text-gray-950 transition-colors hover:bg-gray-300 disabled:cursor-not-allowed disabled:bg-transparent disabled:opacity-30"
115
+ class="flex size-7 cursor-pointer items-center justify-center rounded-full bg-gray-200 text-gray-950 transition-colors hover:bg-gray-300 disabled:cursor-not-allowed disabled:bg-transparent disabled:opacity-30"
116
116
  @click="emit('next')"
117
117
  aria-label="Volgende maand"
118
118
  >
119
119
  <NexxtIcon name="chevron-right" class="text-xs" />
120
120
  </button>
121
- <div v-else class="h-7 w-7" />
121
+ <div v-else class="size-7" />
122
122
  </div>
123
123
  </template>
@@ -55,7 +55,7 @@ const decrementMinutes = () => {
55
55
  <div class="flex flex-col items-center">
56
56
  <button
57
57
  type="button"
58
- class="flex h-8 w-8 items-center justify-center rounded-full text-gray-400 transition-colors hover:bg-gray-100 hover:text-cornflower-blue-500"
58
+ class="flex size-8 items-center justify-center rounded-full text-gray-400 transition-colors hover:bg-gray-100 hover:text-cornflower-blue-500"
59
59
  @click="incrementHours"
60
60
  >
61
61
  <NexxtIcon name="chevron-up" />
@@ -65,7 +65,7 @@ const decrementMinutes = () => {
65
65
  </span>
66
66
  <button
67
67
  type="button"
68
- class="flex h-8 w-8 items-center justify-center rounded-full text-gray-400 transition-colors hover:bg-gray-100 hover:text-cornflower-blue-500"
68
+ class="flex size-8 items-center justify-center rounded-full text-gray-400 transition-colors hover:bg-gray-100 hover:text-cornflower-blue-500"
69
69
  @click="decrementHours"
70
70
  >
71
71
  <NexxtIcon name="chevron-down" />
@@ -78,7 +78,7 @@ const decrementMinutes = () => {
78
78
  <div class="flex flex-col items-center">
79
79
  <button
80
80
  type="button"
81
- class="flex h-8 w-8 items-center justify-center rounded-full text-gray-400 transition-colors hover:bg-gray-100 hover:text-cornflower-blue-500"
81
+ class="flex size-8 items-center justify-center rounded-full text-gray-400 transition-colors hover:bg-gray-100 hover:text-cornflower-blue-500"
82
82
  @click="incrementMinutes"
83
83
  >
84
84
  <NexxtIcon name="chevron-up" />
@@ -88,7 +88,7 @@ const decrementMinutes = () => {
88
88
  </span>
89
89
  <button
90
90
  type="button"
91
- class="flex h-8 w-8 items-center justify-center rounded-full text-gray-400 transition-colors hover:bg-gray-100 hover:text-cornflower-blue-500"
91
+ class="flex size-8 items-center justify-center rounded-full text-gray-400 transition-colors hover:bg-gray-100 hover:text-cornflower-blue-500"
92
92
  @click="decrementMinutes"
93
93
  >
94
94
  <NexxtIcon name="chevron-down" />