@nexxtmove/ui 1.17.0 → 1.19.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/components/atoms/Slider/Slider.vue.d.ts +11 -0
- package/dist/components/editor/molecules/EditorAlignItems/EditorAlignItems.vue.d.ts +44 -0
- package/dist/components/editor/molecules/EditorGap/EditorGap.vue.d.ts +43 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +484 -367
- package/dist/nuxt.js +2 -0
- package/package.json +1 -1
- package/src/components/atoms/Slider/Slider.vue +22 -1
- package/src/components/editor/molecules/EditorAlignItems/EditorAlignItems.vue +94 -0
- package/src/components/editor/molecules/EditorGap/EditorGap.vue +115 -0
- package/src/components.json +2 -0
- package/src/index.ts +10 -0
package/dist/nuxt.js
CHANGED
|
@@ -65,7 +65,9 @@ var s = {
|
|
|
65
65
|
NexxtToaster: "components/organisms/Toaster/Toaster.vue",
|
|
66
66
|
NexxtVideoPlayer: "components/organisms/VideoPlayer/VideoPlayer.vue",
|
|
67
67
|
NexxtEditorSettingsBlock: "components/editor/atoms/EditorSettingsBlock/EditorSettingsBlock.vue",
|
|
68
|
+
NexxtEditorAlignItems: "components/editor/molecules/EditorAlignItems/EditorAlignItems.vue",
|
|
68
69
|
NexxtEditorFlexDirection: "components/editor/molecules/EditorFlexDirection/EditorFlexDirection.vue",
|
|
70
|
+
NexxtEditorGap: "components/editor/molecules/EditorGap/EditorGap.vue",
|
|
69
71
|
NexxtEditorJustifyContent: "components/editor/molecules/EditorJustifyContent/EditorJustifyContent.vue"
|
|
70
72
|
}, c = ["@nexxtmove/ui/ui.css", "@nexxtmove/ui/dist/ui.css"], l = (e, t) => e.some((e) => e === t || c.includes(e)), u = i({
|
|
71
73
|
meta: {
|
package/package.json
CHANGED
|
@@ -8,6 +8,17 @@ type SliderVariant = 'filled' | 'plain'
|
|
|
8
8
|
|
|
9
9
|
interface NexxtSliderProps {
|
|
10
10
|
label?: string
|
|
11
|
+
/**
|
|
12
|
+
* Accessible name of the thumb for a slider without a visible `label`. When both are given the
|
|
13
|
+
* visible `label` wins, so the name matches what a sighted user reads.
|
|
14
|
+
*/
|
|
15
|
+
ariaLabel?: string
|
|
16
|
+
/**
|
|
17
|
+
* Human-readable version of the value, announced instead of the raw number — `'16 px'` for a
|
|
18
|
+
* slider whose model is an index into a scale. Ignored on a range: one string cannot describe two
|
|
19
|
+
* thumbs, and repeating it on both would announce the wrong value on one of them.
|
|
20
|
+
*/
|
|
21
|
+
ariaValuetext?: string
|
|
11
22
|
min?: number
|
|
12
23
|
max?: number
|
|
13
24
|
step?: number
|
|
@@ -27,6 +38,8 @@ defineOptions({
|
|
|
27
38
|
|
|
28
39
|
const {
|
|
29
40
|
label,
|
|
41
|
+
ariaLabel,
|
|
42
|
+
ariaValuetext,
|
|
30
43
|
min = 0,
|
|
31
44
|
max = 100,
|
|
32
45
|
step = 1,
|
|
@@ -80,6 +93,13 @@ const onFocusOut = (event: FocusEvent) => {
|
|
|
80
93
|
if (!next || !(event.currentTarget as HTMLElement).contains(next)) usingPointer.value = false
|
|
81
94
|
}
|
|
82
95
|
|
|
96
|
+
/**
|
|
97
|
+
* A range has one string per thumb at most, and there is only one prop, so the text is dropped
|
|
98
|
+
* there rather than repeated. `undefined` is what keeps the attribute off the element — an empty
|
|
99
|
+
* string would render `aria-valuetext=""` and silence the value entirely.
|
|
100
|
+
*/
|
|
101
|
+
const thumbValuetext = computed(() => (model.value.length > 1 ? undefined : ariaValuetext))
|
|
102
|
+
|
|
83
103
|
const displayValue = computed(() =>
|
|
84
104
|
model.value.map((value) => `${value}${valueSuffix}`).join(' – '),
|
|
85
105
|
)
|
|
@@ -120,7 +140,8 @@ const displayValue = computed(() =>
|
|
|
120
140
|
<SliderThumb
|
|
121
141
|
v-for="(_, index) in model"
|
|
122
142
|
:key="index"
|
|
123
|
-
:aria-label="label"
|
|
143
|
+
:aria-label="label ?? ariaLabel"
|
|
144
|
+
:aria-valuetext="thumbValuetext"
|
|
124
145
|
:class="[
|
|
125
146
|
'block size-4 rounded-full border shadow-sm transition-colors',
|
|
126
147
|
variant === 'filled' ? 'border-gray-200 bg-white' : thumbColorClasses[color],
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* The cross-axis alignment as the editor needs it: the Tailwind class itself,
|
|
4
|
+
* so the consumer can put the model value straight on the element it styles.
|
|
5
|
+
*/
|
|
6
|
+
export type EditorAlignItemsValue = 'items-start' | 'items-center' | 'items-end' | 'items-stretch'
|
|
7
|
+
|
|
8
|
+
/** Overridable copy for the four options. Every key is optional. */
|
|
9
|
+
export interface EditorAlignItemsMessages {
|
|
10
|
+
/** Accessible name of the `items-start` option. Defaults to `'Begin'`. */
|
|
11
|
+
start?: string
|
|
12
|
+
/** Accessible name of the `items-center` option. Defaults to `'Midden'`. */
|
|
13
|
+
center?: string
|
|
14
|
+
/** Accessible name of the `items-end` option. Defaults to `'Einde'`. */
|
|
15
|
+
end?: string
|
|
16
|
+
/** Accessible name of the `items-stretch` option. Defaults to `'Uitrekken'`. */
|
|
17
|
+
stretch?: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface NexxtEditorAlignItemsProps {
|
|
21
|
+
/**
|
|
22
|
+
* Header text of the settings block. Defaults to the Dutch
|
|
23
|
+
* `'Uitlijning items'`; the library has no i18n layer, so a consumer in
|
|
24
|
+
* another language passes its own copy in.
|
|
25
|
+
*/
|
|
26
|
+
label?: string
|
|
27
|
+
/**
|
|
28
|
+
* Copy of the four options. The options are icon-only and show no tooltip, so
|
|
29
|
+
* this copy is purely the accessible name of each button. Defaults are Dutch
|
|
30
|
+
* and are merged per key, so overriding one keeps the defaults of the others.
|
|
31
|
+
* Copy is never translated inside the component.
|
|
32
|
+
*/
|
|
33
|
+
messages?: EditorAlignItemsMessages
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const DEFAULT_MESSAGES = {
|
|
37
|
+
start: 'Begin',
|
|
38
|
+
center: 'Midden',
|
|
39
|
+
end: 'Einde',
|
|
40
|
+
stretch: 'Uitrekken',
|
|
41
|
+
} satisfies Required<EditorAlignItemsMessages>
|
|
42
|
+
</script>
|
|
43
|
+
|
|
44
|
+
<script lang="ts" setup>
|
|
45
|
+
import { computed } from 'vue'
|
|
46
|
+
import NexxtEditorSettingsBlock from '../../atoms/EditorSettingsBlock/EditorSettingsBlock.vue'
|
|
47
|
+
import NexxtToggleGroup from '../../../molecules/ToggleGroup/ToggleGroup.vue'
|
|
48
|
+
import type { NexxtToggleGroupOption } from '../../../molecules/ToggleGroup/ToggleGroup.vue'
|
|
49
|
+
|
|
50
|
+
defineOptions({ name: 'NexxtEditorAlignItems' })
|
|
51
|
+
|
|
52
|
+
const { label = 'Uitlijning items', messages } = defineProps<NexxtEditorAlignItemsProps>()
|
|
53
|
+
|
|
54
|
+
/** The selected alignment, as the Tailwind class to apply. */
|
|
55
|
+
const model = defineModel<EditorAlignItemsValue>({ required: true })
|
|
56
|
+
|
|
57
|
+
const copy = computed(() => ({ ...DEFAULT_MESSAGES, ...messages }))
|
|
58
|
+
|
|
59
|
+
// Icon-only and deliberately without tooltips, matching the justify-content
|
|
60
|
+
// block it sits next to: four labels do not fit side by side at the width the
|
|
61
|
+
// editor sidebar gives this block. The icons are the vertical counterparts of
|
|
62
|
+
// that block's horizontal ones. `items-stretch` gets `arrows-up-down` rather
|
|
63
|
+
// than a distribute-spacing icon, because stretching fills the cross axis --
|
|
64
|
+
// the spacing icons depict gaps between separate objects, which is the
|
|
65
|
+
// justify-between metaphor, not this one. The copy travels as `ariaLabel`, so
|
|
66
|
+
// the buttons still have a name for assistive technology.
|
|
67
|
+
const options = computed<NexxtToggleGroupOption[]>(() => [
|
|
68
|
+
{ value: 'items-start', icon: 'objects-align-top', ariaLabel: copy.value.start },
|
|
69
|
+
{
|
|
70
|
+
value: 'items-center',
|
|
71
|
+
icon: 'objects-align-center-vertical',
|
|
72
|
+
ariaLabel: copy.value.center,
|
|
73
|
+
},
|
|
74
|
+
{ value: 'items-end', icon: 'objects-align-bottom', ariaLabel: copy.value.end },
|
|
75
|
+
{ value: 'items-stretch', icon: 'arrows-up-down', ariaLabel: copy.value.stretch },
|
|
76
|
+
])
|
|
77
|
+
|
|
78
|
+
// ToggleGroup types its model as the open `string` of its options, so writing
|
|
79
|
+
// straight back into the narrower model is a type error. The setter is the one
|
|
80
|
+
// place that narrowing happens, and it is safe: the only values ToggleGroup can
|
|
81
|
+
// emit are the option values built above.
|
|
82
|
+
const selected = computed({
|
|
83
|
+
get: () => model.value,
|
|
84
|
+
set: (value: string) => {
|
|
85
|
+
model.value = value as EditorAlignItemsValue
|
|
86
|
+
},
|
|
87
|
+
})
|
|
88
|
+
</script>
|
|
89
|
+
|
|
90
|
+
<template>
|
|
91
|
+
<NexxtEditorSettingsBlock :label="label">
|
|
92
|
+
<NexxtToggleGroup v-model="selected" :options="options" />
|
|
93
|
+
</NexxtEditorSettingsBlock>
|
|
94
|
+
</template>
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* The steps the slider can land on, as the numeric part of the Tailwind class.
|
|
4
|
+
* 13 and 15 are missing on purpose: the theme defines `--spacing-0` through
|
|
5
|
+
* `--spacing-12` and then only 14 and 16, so stepping over the px value instead
|
|
6
|
+
* of over this list would offer gaps that have no token behind them.
|
|
7
|
+
*/
|
|
8
|
+
const GAP_STEPS = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16] as const
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The gap as the editor needs it: the Tailwind class itself, so the consumer
|
|
12
|
+
* can put the model value straight on the element it styles.
|
|
13
|
+
*/
|
|
14
|
+
export type EditorGapValue = `gap-${(typeof GAP_STEPS)[number]}`
|
|
15
|
+
|
|
16
|
+
/** Overridable copy of the value readout. Every key is optional. */
|
|
17
|
+
export interface EditorGapMessages {
|
|
18
|
+
/** Unit shown behind the value. Defaults to `'px'`. */
|
|
19
|
+
unit?: string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface NexxtEditorGapProps {
|
|
23
|
+
/**
|
|
24
|
+
* Header text of the settings block. Defaults to the Dutch
|
|
25
|
+
* `'Tussenruimte'`; the library has no i18n layer, so a consumer in another
|
|
26
|
+
* language passes its own copy in.
|
|
27
|
+
*/
|
|
28
|
+
label?: string
|
|
29
|
+
/**
|
|
30
|
+
* Copy of the value readout. Merged per key, so overriding one key keeps the
|
|
31
|
+
* defaults of the others. Copy is never translated inside the component.
|
|
32
|
+
*/
|
|
33
|
+
messages?: EditorGapMessages
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const DEFAULT_MESSAGES = {
|
|
37
|
+
unit: 'px',
|
|
38
|
+
} satisfies Required<EditorGapMessages>
|
|
39
|
+
|
|
40
|
+
/** The spacing scale is built on 0.25rem, so `gap-4` is 4 × 4 = 16 px. */
|
|
41
|
+
const PX_PER_STEP = 4
|
|
42
|
+
</script>
|
|
43
|
+
|
|
44
|
+
<script lang="ts" setup>
|
|
45
|
+
import { computed } from 'vue'
|
|
46
|
+
import NexxtEditorSettingsBlock from '../../atoms/EditorSettingsBlock/EditorSettingsBlock.vue'
|
|
47
|
+
import NexxtSlider from '../../../atoms/Slider/Slider.vue'
|
|
48
|
+
|
|
49
|
+
defineOptions({ name: 'NexxtEditorGap' })
|
|
50
|
+
|
|
51
|
+
const { label = 'Tussenruimte', messages } = defineProps<NexxtEditorGapProps>()
|
|
52
|
+
|
|
53
|
+
/** The selected gap, as the Tailwind class to apply. */
|
|
54
|
+
const model = defineModel<EditorGapValue>({ required: true })
|
|
55
|
+
|
|
56
|
+
const copy = computed(() => ({ ...DEFAULT_MESSAGES, ...messages }))
|
|
57
|
+
|
|
58
|
+
const maxIndex = GAP_STEPS.length - 1
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Position of the current value on the step list. A value that is not on the
|
|
62
|
+
* list -- a stored `gap-13` from before this component, say -- falls back to
|
|
63
|
+
* the first step instead of leaving the thumb off the track; the first change
|
|
64
|
+
* writes a valid class back.
|
|
65
|
+
*/
|
|
66
|
+
const stepIndex = computed(() =>
|
|
67
|
+
Math.max(
|
|
68
|
+
0,
|
|
69
|
+
GAP_STEPS.findIndex((step) => `gap-${step}` === model.value),
|
|
70
|
+
),
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
// The slider moves over the index, not over the px value, so its model is
|
|
74
|
+
// translated both ways here.
|
|
75
|
+
const sliderValue = computed({
|
|
76
|
+
get: () => [stepIndex.value],
|
|
77
|
+
set: ([index]) => {
|
|
78
|
+
model.value = `gap-${GAP_STEPS[index]}`
|
|
79
|
+
},
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
const displayValue = computed(
|
|
83
|
+
() => `${GAP_STEPS[stepIndex.value] * PX_PER_STEP} ${copy.value.unit}`,
|
|
84
|
+
)
|
|
85
|
+
</script>
|
|
86
|
+
|
|
87
|
+
<template>
|
|
88
|
+
<NexxtEditorSettingsBlock :label="label">
|
|
89
|
+
<div class="flex items-center gap-4">
|
|
90
|
+
<!--
|
|
91
|
+
Slider's own `showValue` prints its model, which here is the step index
|
|
92
|
+
rather than the gap, so the readout is rendered next to it instead. The
|
|
93
|
+
thumb has the same problem in `aria-valuenow`, which `aria-valuetext`
|
|
94
|
+
overrides with the string the readout shows. The block label is a <p>,
|
|
95
|
+
not a <label>, so the name goes on the thumb explicitly.
|
|
96
|
+
-->
|
|
97
|
+
<NexxtSlider
|
|
98
|
+
v-model="sliderValue"
|
|
99
|
+
:min="0"
|
|
100
|
+
:max="maxIndex"
|
|
101
|
+
:step="1"
|
|
102
|
+
:aria-label="label"
|
|
103
|
+
:aria-valuetext="displayValue"
|
|
104
|
+
/>
|
|
105
|
+
|
|
106
|
+
<!--
|
|
107
|
+
gray-700, not the gray-500 Slider uses for its own readout: axe puts
|
|
108
|
+
gray-500 on white at 1.84:1, well under the 4.5:1 it needs at this size.
|
|
109
|
+
-->
|
|
110
|
+
<span class="min-w-12 shrink-0 text-right small-normal whitespace-nowrap text-gray-700">
|
|
111
|
+
{{ displayValue }}
|
|
112
|
+
</span>
|
|
113
|
+
</div>
|
|
114
|
+
</NexxtEditorSettingsBlock>
|
|
115
|
+
</template>
|
package/src/components.json
CHANGED
|
@@ -62,6 +62,8 @@
|
|
|
62
62
|
"NexxtToaster": "components/organisms/Toaster/Toaster.vue",
|
|
63
63
|
"NexxtVideoPlayer": "components/organisms/VideoPlayer/VideoPlayer.vue",
|
|
64
64
|
"NexxtEditorSettingsBlock": "components/editor/atoms/EditorSettingsBlock/EditorSettingsBlock.vue",
|
|
65
|
+
"NexxtEditorAlignItems": "components/editor/molecules/EditorAlignItems/EditorAlignItems.vue",
|
|
65
66
|
"NexxtEditorFlexDirection": "components/editor/molecules/EditorFlexDirection/EditorFlexDirection.vue",
|
|
67
|
+
"NexxtEditorGap": "components/editor/molecules/EditorGap/EditorGap.vue",
|
|
66
68
|
"NexxtEditorJustifyContent": "components/editor/molecules/EditorJustifyContent/EditorJustifyContent.vue"
|
|
67
69
|
}
|
package/src/index.ts
CHANGED
|
@@ -13,10 +13,18 @@ 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
|
+
EditorAlignItemsMessages,
|
|
18
|
+
EditorAlignItemsValue,
|
|
19
|
+
} from './components/editor/molecules/EditorAlignItems/EditorAlignItems.vue'
|
|
16
20
|
export type {
|
|
17
21
|
EditorFlexDirectionMessages,
|
|
18
22
|
EditorFlexDirectionValue,
|
|
19
23
|
} from './components/editor/molecules/EditorFlexDirection/EditorFlexDirection.vue'
|
|
24
|
+
export type {
|
|
25
|
+
EditorGapMessages,
|
|
26
|
+
EditorGapValue,
|
|
27
|
+
} from './components/editor/molecules/EditorGap/EditorGap.vue'
|
|
20
28
|
export type {
|
|
21
29
|
EditorJustifyContentMessages,
|
|
22
30
|
EditorJustifyContentValue,
|
|
@@ -44,7 +52,9 @@ export { default as NexxtCustomerJourneyTile } from './components/molecules/Cust
|
|
|
44
52
|
export { default as NexxtDatePicker } from './components/organisms/DatePicker/DatePicker.vue'
|
|
45
53
|
export { default as NexxtDoughnutChart } from './components/molecules/DoughnutChart/DoughnutChart.vue'
|
|
46
54
|
export { default as NexxtDropdownButton } from './components/organisms/DropdownButton/DropdownButton.vue'
|
|
55
|
+
export { default as NexxtEditorAlignItems } from './components/editor/molecules/EditorAlignItems/EditorAlignItems.vue'
|
|
47
56
|
export { default as NexxtEditorFlexDirection } from './components/editor/molecules/EditorFlexDirection/EditorFlexDirection.vue'
|
|
57
|
+
export { default as NexxtEditorGap } from './components/editor/molecules/EditorGap/EditorGap.vue'
|
|
48
58
|
export { default as NexxtEditorJustifyContent } from './components/editor/molecules/EditorJustifyContent/EditorJustifyContent.vue'
|
|
49
59
|
export { default as NexxtEditorSettingsBlock } from './components/editor/atoms/EditorSettingsBlock/EditorSettingsBlock.vue'
|
|
50
60
|
export { default as NexxtEnergyLabel } from './components/atoms/EnergyLabel/EnergyLabel.vue'
|