@nexxtmove/ui 1.15.0 → 1.17.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/dist/nuxt.js CHANGED
@@ -64,7 +64,9 @@ var s = {
64
64
  NexxtTimelineTrack: "components/organisms/TimelineTrack/TimelineTrack.vue",
65
65
  NexxtToaster: "components/organisms/Toaster/Toaster.vue",
66
66
  NexxtVideoPlayer: "components/organisms/VideoPlayer/VideoPlayer.vue",
67
- NexxtEditorSettingsBlock: "components/editor/atoms/EditorSettingsBlock/EditorSettingsBlock.vue"
67
+ NexxtEditorSettingsBlock: "components/editor/atoms/EditorSettingsBlock/EditorSettingsBlock.vue",
68
+ NexxtEditorFlexDirection: "components/editor/molecules/EditorFlexDirection/EditorFlexDirection.vue",
69
+ NexxtEditorJustifyContent: "components/editor/molecules/EditorJustifyContent/EditorJustifyContent.vue"
68
70
  }, c = ["@nexxtmove/ui/ui.css", "@nexxtmove/ui/dist/ui.css"], l = (e, t) => e.some((e) => e === t || c.includes(e)), u = i({
69
71
  meta: {
70
72
  name: "@nexxtmove/ui",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nexxtmove/ui",
3
3
  "type": "module",
4
- "version": "1.15.0",
4
+ "version": "1.17.0",
5
5
  "exports": {
6
6
  ".": {
7
7
  "types": "./dist/index.d.ts",
@@ -74,7 +74,7 @@ const inert = computed(() => (open.value ? undefined : true))
74
74
  ]"
75
75
  >
76
76
  <!-- Padding sits on the inner element so nothing is left over at 0fr. -->
77
- <div class="px-1 pt-3 pb-1">
77
+ <div class="px-1 pt-1.5 pb-1">
78
78
  <slot />
79
79
  </div>
80
80
  </div>
@@ -0,0 +1,73 @@
1
+ <script lang="ts">
2
+ /**
3
+ * The flex direction as the editor needs it: the Tailwind class itself, so the
4
+ * consumer can put the model value straight on the element it styles.
5
+ */
6
+ export type EditorFlexDirectionValue = 'flex-row' | 'flex-col'
7
+
8
+ /** Overridable copy for the two options. Every key is optional. */
9
+ export interface EditorFlexDirectionMessages {
10
+ /** Label of the `flex-row` option. Defaults to `'Horizontaal'`. */
11
+ horizontal?: string
12
+ /** Label of the `flex-col` option. Defaults to `'Verticaal'`. */
13
+ vertical?: string
14
+ }
15
+
16
+ export interface NexxtEditorFlexDirectionProps {
17
+ /**
18
+ * Header text of the settings block. Defaults to the Dutch `'Richting'`;
19
+ * the library has no i18n layer, so a consumer in another language passes
20
+ * its own copy in.
21
+ */
22
+ label?: string
23
+ /**
24
+ * Labels of the two options. Defaults are Dutch and are merged per key, so
25
+ * overriding one label keeps the default of the other. Copy is never
26
+ * translated inside the component.
27
+ */
28
+ messages?: EditorFlexDirectionMessages
29
+ }
30
+
31
+ const DEFAULT_MESSAGES = {
32
+ horizontal: 'Horizontaal',
33
+ vertical: 'Verticaal',
34
+ } satisfies Required<EditorFlexDirectionMessages>
35
+ </script>
36
+
37
+ <script lang="ts" setup>
38
+ import { computed } from 'vue'
39
+ import NexxtEditorSettingsBlock from '../../atoms/EditorSettingsBlock/EditorSettingsBlock.vue'
40
+ import NexxtToggleGroup from '../../../molecules/ToggleGroup/ToggleGroup.vue'
41
+ import type { NexxtToggleGroupOption } from '../../../molecules/ToggleGroup/ToggleGroup.vue'
42
+
43
+ defineOptions({ name: 'NexxtEditorFlexDirection' })
44
+
45
+ const { label = 'Richting', messages } = defineProps<NexxtEditorFlexDirectionProps>()
46
+
47
+ /** The selected direction, as the Tailwind class to apply. */
48
+ const model = defineModel<EditorFlexDirectionValue>({ required: true })
49
+
50
+ const copy = computed(() => ({ ...DEFAULT_MESSAGES, ...messages }))
51
+
52
+ const options = computed<NexxtToggleGroupOption[]>(() => [
53
+ { value: 'flex-row', label: copy.value.horizontal, icon: 'arrow-right' },
54
+ { value: 'flex-col', label: copy.value.vertical, icon: 'arrow-down' },
55
+ ])
56
+
57
+ // ToggleGroup types its model as the open `string` of its options, so writing
58
+ // straight back into the narrower model is a type error. The setter is the one
59
+ // place that narrowing happens, and it is safe: the only values ToggleGroup can
60
+ // emit are the option values built above.
61
+ const selected = computed({
62
+ get: () => model.value,
63
+ set: (value: string) => {
64
+ model.value = value as EditorFlexDirectionValue
65
+ },
66
+ })
67
+ </script>
68
+
69
+ <template>
70
+ <NexxtEditorSettingsBlock :label="label">
71
+ <NexxtToggleGroup v-model="selected" :options="options" />
72
+ </NexxtEditorSettingsBlock>
73
+ </template>
@@ -0,0 +1,95 @@
1
+ <script lang="ts">
2
+ /**
3
+ * The justification as the editor needs it: the Tailwind class itself, so the
4
+ * consumer can put the model value straight on the element it styles.
5
+ */
6
+ export type EditorJustifyContentValue =
7
+ 'justify-start' | 'justify-center' | 'justify-end' | 'justify-between'
8
+
9
+ /** Overridable copy for the four options. Every key is optional. */
10
+ export interface EditorJustifyContentMessages {
11
+ /** Accessible name of the `justify-start` option. Defaults to `'Begin'`. */
12
+ start?: string
13
+ /** Accessible name of the `justify-center` option. Defaults to `'Midden'`. */
14
+ center?: string
15
+ /** Accessible name of the `justify-end` option. Defaults to `'Einde'`. */
16
+ end?: string
17
+ /** Accessible name of the `justify-between` option. Defaults to `'Verdelen'`. */
18
+ between?: string
19
+ }
20
+
21
+ export interface NexxtEditorJustifyContentProps {
22
+ /**
23
+ * Header text of the settings block. Defaults to the Dutch `'Uitlijning'`;
24
+ * the library has no i18n layer, so a consumer in another language passes
25
+ * its own copy in.
26
+ */
27
+ label?: string
28
+ /**
29
+ * Copy of the four options. The options are icon-only and show no tooltip, so
30
+ * this copy is purely the accessible name of each button. Defaults are Dutch
31
+ * and are merged per key, so overriding one keeps the defaults of the others.
32
+ * Copy is never translated inside the component.
33
+ */
34
+ messages?: EditorJustifyContentMessages
35
+ }
36
+
37
+ const DEFAULT_MESSAGES = {
38
+ start: 'Begin',
39
+ center: 'Midden',
40
+ end: 'Einde',
41
+ between: 'Verdelen',
42
+ } satisfies Required<EditorJustifyContentMessages>
43
+ </script>
44
+
45
+ <script lang="ts" setup>
46
+ import { computed } from 'vue'
47
+ import NexxtEditorSettingsBlock from '../../atoms/EditorSettingsBlock/EditorSettingsBlock.vue'
48
+ import NexxtToggleGroup from '../../../molecules/ToggleGroup/ToggleGroup.vue'
49
+ import type { NexxtToggleGroupOption } from '../../../molecules/ToggleGroup/ToggleGroup.vue'
50
+
51
+ defineOptions({ name: 'NexxtEditorJustifyContent' })
52
+
53
+ const { label = 'Uitlijning', messages } = defineProps<NexxtEditorJustifyContentProps>()
54
+
55
+ /** The selected justification, as the Tailwind class to apply. */
56
+ const model = defineModel<EditorJustifyContentValue>({ required: true })
57
+
58
+ const copy = computed(() => ({ ...DEFAULT_MESSAGES, ...messages }))
59
+
60
+ // Icon-only and deliberately without tooltips: four labels do not fit side by
61
+ // side at the width the editor sidebar gives this block, and the icons are
62
+ // conventional enough to stand on their own. The copy travels as `ariaLabel`,
63
+ // so the buttons still have a name for assistive technology.
64
+ const options = computed<NexxtToggleGroupOption[]>(() => [
65
+ { value: 'justify-start', icon: 'objects-align-left', ariaLabel: copy.value.start },
66
+ {
67
+ value: 'justify-center',
68
+ icon: 'objects-align-center-horizontal',
69
+ ariaLabel: copy.value.center,
70
+ },
71
+ { value: 'justify-end', icon: 'objects-align-right', ariaLabel: copy.value.end },
72
+ {
73
+ value: 'justify-between',
74
+ icon: 'distribute-spacing-horizontal',
75
+ ariaLabel: copy.value.between,
76
+ },
77
+ ])
78
+
79
+ // ToggleGroup types its model as the open `string` of its options, so writing
80
+ // straight back into the narrower model is a type error. The setter is the one
81
+ // place that narrowing happens, and it is safe: the only values ToggleGroup can
82
+ // emit are the option values built above.
83
+ const selected = computed({
84
+ get: () => model.value,
85
+ set: (value: string) => {
86
+ model.value = value as EditorJustifyContentValue
87
+ },
88
+ })
89
+ </script>
90
+
91
+ <template>
92
+ <NexxtEditorSettingsBlock :label="label">
93
+ <NexxtToggleGroup v-model="selected" :options="options" />
94
+ </NexxtEditorSettingsBlock>
95
+ </template>
@@ -10,6 +10,13 @@ export interface NexxtToggleGroupOption {
10
10
  icon?: IconName
11
11
  label?: string
12
12
  tooltip?: string
13
+ /**
14
+ * Accessible name for an icon-only option without a visible label. A button
15
+ * whose only content is an icon has no discernible text, so axe flags it with
16
+ * `button-name`; this is the copy that names it. Takes precedence over the
17
+ * `tooltip` fallback below, and is not needed when `label` is set.
18
+ */
19
+ ariaLabel?: string
13
20
  activeClass?: string
14
21
  }
15
22
 
@@ -88,12 +95,23 @@ onMounted(async () => {
88
95
  :style="sliderStyle"
89
96
  />
90
97
 
91
- <!-- buttons with gray text underneath -->
98
+ <!--
99
+ buttons with gray text underneath.
100
+
101
+ An icon-only option renders a button with no text at all, so its
102
+ accessible name has to come from somewhere: the tooltip is a sibling in
103
+ a portal, not a label, and axe flags these buttons with `button-name`.
104
+ `ariaLabel` is the explicit way to name such a button. Falling back to
105
+ the tooltip keeps the consumers that were already relying on it named,
106
+ and neither applies once there is a visible label -- an `aria-label`
107
+ would override the text the user can actually read.
108
+ -->
92
109
  <template v-for="(option, index) in options" :key="option.value">
93
110
  <NexxtTooltip v-if="option.tooltip" disable-closing-trigger>
94
111
  <button
95
112
  :ref="(el) => (buttonRefs[index] = el as HTMLButtonElement)"
96
113
  type="button"
114
+ :aria-label="option.ariaLabel ?? (option.label ? undefined : option.tooltip)"
97
115
  class="relative z-10 flex cursor-pointer items-center justify-center gap-1.5 rounded-lg px-4 py-1.5 whitespace-nowrap text-gray-500 hover:text-gray-700"
98
116
  :class="{ 'flex-1': equalWidth }"
99
117
  @click="model = option.value"
@@ -107,6 +125,7 @@ onMounted(async () => {
107
125
  v-else
108
126
  :ref="(el) => (buttonRefs[index] = el as HTMLButtonElement)"
109
127
  type="button"
128
+ :aria-label="option.ariaLabel ?? (option.label ? undefined : option.tooltip)"
110
129
  class="relative z-10 flex cursor-pointer items-center justify-center gap-1.5 rounded-lg px-4 py-1.5 whitespace-nowrap text-gray-500 hover:text-gray-700"
111
130
  :class="{ 'flex-1': equalWidth }"
112
131
  @click="model = option.value"
@@ -61,5 +61,7 @@
61
61
  "NexxtTimelineTrack": "components/organisms/TimelineTrack/TimelineTrack.vue",
62
62
  "NexxtToaster": "components/organisms/Toaster/Toaster.vue",
63
63
  "NexxtVideoPlayer": "components/organisms/VideoPlayer/VideoPlayer.vue",
64
- "NexxtEditorSettingsBlock": "components/editor/atoms/EditorSettingsBlock/EditorSettingsBlock.vue"
64
+ "NexxtEditorSettingsBlock": "components/editor/atoms/EditorSettingsBlock/EditorSettingsBlock.vue",
65
+ "NexxtEditorFlexDirection": "components/editor/molecules/EditorFlexDirection/EditorFlexDirection.vue",
66
+ "NexxtEditorJustifyContent": "components/editor/molecules/EditorJustifyContent/EditorJustifyContent.vue"
65
67
  }
package/src/index.ts CHANGED
@@ -13,6 +13,14 @@ export type { EnergyLabelLetter } from './components/atoms/EnergyLabel/EnergyLab
13
13
  export type { IconType, NexxtIconName } from './components/atoms/Icon/Icon.vue'
14
14
  export type { CustomIconName } from './components/atoms/Icon/customIcons'
15
15
  export type { NexxtTabItem } from './components/molecules/Tabs/Tabs.vue'
16
+ export type {
17
+ EditorFlexDirectionMessages,
18
+ EditorFlexDirectionValue,
19
+ } from './components/editor/molecules/EditorFlexDirection/EditorFlexDirection.vue'
20
+ export type {
21
+ EditorJustifyContentMessages,
22
+ EditorJustifyContentValue,
23
+ } from './components/editor/molecules/EditorJustifyContent/EditorJustifyContent.vue'
16
24
  export type {
17
25
  NexxtTemplateCardContentFeature,
18
26
  NexxtTemplateCardProps,
@@ -36,6 +44,8 @@ export { default as NexxtCustomerJourneyTile } from './components/molecules/Cust
36
44
  export { default as NexxtDatePicker } from './components/organisms/DatePicker/DatePicker.vue'
37
45
  export { default as NexxtDoughnutChart } from './components/molecules/DoughnutChart/DoughnutChart.vue'
38
46
  export { default as NexxtDropdownButton } from './components/organisms/DropdownButton/DropdownButton.vue'
47
+ export { default as NexxtEditorFlexDirection } from './components/editor/molecules/EditorFlexDirection/EditorFlexDirection.vue'
48
+ export { default as NexxtEditorJustifyContent } from './components/editor/molecules/EditorJustifyContent/EditorJustifyContent.vue'
39
49
  export { default as NexxtEditorSettingsBlock } from './components/editor/atoms/EditorSettingsBlock/EditorSettingsBlock.vue'
40
50
  export { default as NexxtEnergyLabel } from './components/atoms/EnergyLabel/EnergyLabel.vue'
41
51
  export { default as NexxtFloatingPanel } from './components/atoms/FloatingPanel/FloatingPanel.vue'