@nexxtmove/ui 2.5.0 → 2.7.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/editor/molecules/EditorBorder/EditorBorder.vue.d.ts +12 -0
- package/dist/components/editor/molecules/EditorColor/_ThemeRoleSwatches.vue.d.ts +16 -0
- package/dist/index.js +1094 -1135
- package/dist/nuxt.js +0 -1
- package/package.json +38 -36
- package/src/attribute-contract.test.ts +151 -0
- package/src/components/atoms/AnimatedNumber/AnimatedNumber.stories.ts +36 -0
- package/src/components/atoms/AnimatedNumber/AnimatedNumber.test.ts +21 -0
- package/src/components/atoms/Avatar/Avatar.stories.ts +122 -0
- package/src/components/atoms/Avatar/Avatar.test.ts +134 -0
- package/src/components/atoms/Button/Button.stories.ts +290 -0
- package/src/components/atoms/Button/Button.test.ts +406 -0
- package/src/components/atoms/Card/Card.stories.ts +45 -0
- package/src/components/atoms/Card/Card.test.ts +46 -0
- package/src/components/atoms/Checkbox/Checkbox.stories.ts +35 -0
- package/src/components/atoms/Checkbox/Checkbox.test.ts +55 -0
- package/src/components/atoms/Chip/Chip.stories.ts +274 -0
- package/src/components/atoms/Chip/Chip.test.ts +230 -0
- package/src/components/atoms/EnergyLabel/EnergyLabel.stories.ts +189 -0
- package/src/components/atoms/EnergyLabel/EnergyLabel.test.ts +100 -0
- package/src/components/atoms/FloatingPanel/FloatingPanel.stories.ts +677 -0
- package/src/components/atoms/FloatingPanel/FloatingPanel.test.ts +864 -0
- package/src/components/atoms/Icon/Icon.stories.ts +63 -0
- package/src/components/atoms/Icon/Icon.test.ts +89 -0
- package/src/components/atoms/Loader/Loader.stories.ts +36 -0
- package/src/components/atoms/Loader/Loader.test.ts +40 -0
- package/src/components/atoms/PickerItem/PickerItem.stories.ts +172 -0
- package/src/components/atoms/PickerItem/PickerItem.test.ts +142 -0
- package/src/components/atoms/PickerPreview/PickerPreview.stories.ts +183 -0
- package/src/components/atoms/PickerPreview/PickerPreview.test.ts +137 -0
- package/src/components/atoms/PresenceIndicator/PresenceIndicator.stories.ts +21 -0
- package/src/components/atoms/PropertyListing/PropertyListing.stories.ts +38 -0
- package/src/components/atoms/PropertyListing/PropertyListing.test.ts +46 -0
- package/src/components/atoms/SelectableOption/SelectableOption.stories.ts +131 -0
- package/src/components/atoms/SelectableOption/SelectableOption.test.ts +96 -0
- package/src/components/atoms/Skeleton/Skeleton.stories.ts +27 -0
- package/src/components/atoms/Skeleton/Skeleton.test.ts +28 -0
- package/src/components/atoms/Slider/Slider.stories.ts +151 -0
- package/src/components/atoms/Slider/Slider.test.ts +191 -0
- package/src/components/atoms/Squircle/Squircle.stories.ts +114 -0
- package/src/components/atoms/Squircle/Squircle.test.ts +70 -0
- package/src/components/atoms/Switch/Switch.stories.ts +91 -0
- package/src/components/atoms/Switch/Switch.test.ts +183 -0
- package/src/components/atoms/Tooltip/Tooltip.stories.ts +158 -0
- package/src/components/atoms/Tooltip/Tooltip.test.ts +134 -0
- package/src/components/editor/atoms/EditorDimensionField/EditorDimensionField.stories.ts +124 -0
- package/src/components/editor/atoms/EditorDimensionField/EditorDimensionField.test.ts +464 -0
- package/src/components/editor/atoms/EditorSettingsBlock/EditorSettingsBlock.stories.ts +266 -0
- package/src/components/editor/atoms/EditorSettingsBlock/EditorSettingsBlock.test.ts +421 -0
- package/src/components/editor/atoms/EditorSettingsGroup/EditorSettingsGroup.stories.ts +365 -0
- package/src/components/editor/atoms/EditorSettingsGroup/EditorSettingsGroup.test.ts +484 -0
- package/src/components/editor/composables/useRadioGrid.test.ts +261 -0
- package/src/components/editor/molecules/EditorAlignItems/EditorAlignItems.stories.ts +73 -0
- package/src/components/editor/molecules/EditorAlignItems/EditorAlignItems.test.ts +189 -0
- package/src/components/editor/molecules/EditorAlignmentGrid/EditorAlignmentGrid.stories.ts +309 -0
- package/src/components/editor/molecules/EditorAlignmentGrid/EditorAlignmentGrid.test.ts +359 -0
- package/src/components/editor/molecules/EditorAnchor/EditorAnchor.stories.ts +138 -0
- package/src/components/editor/molecules/EditorAnchor/EditorAnchor.test.ts +344 -0
- package/src/components/editor/molecules/EditorBackgroundSize/EditorBackgroundSize.stories.ts +87 -0
- package/src/components/editor/molecules/EditorBackgroundSize/EditorBackgroundSize.test.ts +262 -0
- package/src/components/editor/molecules/EditorBlur/EditorBlur.stories.ts +115 -0
- package/src/components/editor/molecules/EditorBlur/EditorBlur.test.ts +243 -0
- package/src/components/editor/molecules/EditorBorder/EditorBorder.stories.ts +187 -0
- package/src/components/editor/molecules/EditorBorder/EditorBorder.test.ts +456 -0
- package/src/components/editor/molecules/EditorBorder/EditorBorder.vue +58 -2
- package/src/components/editor/molecules/EditorColor/EditorColor.stories.ts +563 -0
- package/src/components/editor/molecules/EditorColor/EditorColor.test.ts +689 -0
- package/src/components/editor/molecules/EditorColor/EditorColorGradient.test.ts +793 -0
- package/src/components/editor/molecules/EditorColor/_ColorField.vue +7 -29
- package/src/components/editor/molecules/EditorColor/_ThemeRoleSwatches.vue +57 -0
- package/src/components/editor/molecules/EditorColor/gradientClass.test.ts +303 -0
- package/src/components/editor/molecules/EditorDashPattern/EditorDashPattern.stories.ts +72 -0
- package/src/components/editor/molecules/EditorDashPattern/EditorDashPattern.test.ts +124 -0
- package/src/components/editor/molecules/EditorFlexDirection/EditorFlexDirection.stories.ts +46 -0
- package/src/components/editor/molecules/EditorFlexDirection/EditorFlexDirection.test.ts +97 -0
- package/src/components/editor/molecules/EditorFontSize/EditorFontSize.stories.ts +248 -0
- package/src/components/editor/molecules/EditorFontSize/EditorFontSize.test.ts +288 -0
- package/src/components/editor/molecules/EditorGap/EditorGap.stories.ts +129 -0
- package/src/components/editor/molecules/EditorGap/EditorGap.test.ts +253 -0
- package/src/components/editor/molecules/EditorHeadingType/EditorHeadingType.stories.ts +68 -0
- package/src/components/editor/molecules/EditorHeadingType/EditorHeadingType.test.ts +150 -0
- package/src/components/editor/molecules/EditorJustifyContent/EditorJustifyContent.stories.ts +71 -0
- package/src/components/editor/molecules/EditorJustifyContent/EditorJustifyContent.test.ts +161 -0
- package/src/components/editor/molecules/EditorLetterSpacing/EditorLetterSpacing.stories.ts +204 -0
- package/src/components/editor/molecules/EditorLetterSpacing/EditorLetterSpacing.test.ts +238 -0
- package/src/components/editor/molecules/EditorLineHeight/EditorLineHeight.stories.ts +257 -0
- package/src/components/editor/molecules/EditorLineHeight/EditorLineHeight.test.ts +286 -0
- package/src/components/editor/molecules/EditorLineStyle/EditorLineStyle.stories.ts +135 -0
- package/src/components/editor/molecules/EditorLineStyle/EditorLineStyle.test.ts +230 -0
- package/src/components/editor/molecules/EditorMaxWidth/EditorMaxWidth.stories.ts +154 -0
- package/src/components/editor/molecules/EditorMaxWidth/EditorMaxWidth.test.ts +112 -0
- package/src/components/editor/molecules/EditorOverrideStatus/EditorOverrideStatus.stories.ts +206 -0
- package/src/components/editor/molecules/EditorOverrideStatus/EditorOverrideStatus.test.ts +332 -0
- package/src/components/editor/molecules/EditorPadding/EditorPadding.stories.ts +374 -0
- package/src/components/editor/molecules/EditorPadding/EditorPadding.test.ts +712 -0
- package/src/components/editor/molecules/EditorRadius/EditorRadius.stories.ts +64 -0
- package/src/components/editor/molecules/EditorRadius/EditorRadius.test.ts +137 -0
- package/src/components/editor/molecules/EditorShadow/EditorShadow.stories.ts +103 -0
- package/src/components/editor/molecules/EditorShadow/EditorShadow.test.ts +168 -0
- package/src/components/editor/molecules/EditorSize/EditorSize.stories.ts +84 -0
- package/src/components/editor/molecules/EditorSize/EditorSize.test.ts +253 -0
- package/src/components/editor/molecules/EditorSizeLimit/EditorSizeLimit.stories.ts +49 -0
- package/src/components/editor/molecules/EditorSizeLimit/EditorSizeLimit.test.ts +43 -0
- package/src/components/editor/molecules/EditorTextAlign/EditorTextAlign.stories.ts +69 -0
- package/src/components/editor/molecules/EditorTextAlign/EditorTextAlign.test.ts +155 -0
- package/src/components/molecules/Announcement/Announcement.stories.ts +224 -0
- package/src/components/molecules/Announcement/Announcement.test.ts +161 -0
- package/src/components/molecules/ContactInfoCard/ContactInfoCard.stories.ts +99 -0
- package/src/components/molecules/ContactInfoCard/ContactInfoCard.test.ts +70 -0
- package/src/components/molecules/CustomerJourneyTile/CustomerJourneyTile.stories.ts +148 -0
- package/src/components/molecules/CustomerJourneyTile/CustomerJourneyTile.test.ts +271 -0
- package/src/components/molecules/DoughnutChart/DoughnutChart.stories.ts +45 -0
- package/src/components/molecules/DoughnutChart/DoughnutChart.test.ts +205 -0
- package/src/components/molecules/InfoBlock/InfoBlock.stories.ts +84 -0
- package/src/components/molecules/InfoBlock/InfoBlock.test.ts +101 -0
- package/src/components/molecules/InputField/InputField.stories.ts +117 -0
- package/src/components/molecules/InputField/InputField.test.ts +138 -0
- package/src/components/molecules/InputSelect/InputSelect.stories.ts +116 -0
- package/src/components/molecules/InputSelect/InputSelect.test.ts +127 -0
- package/src/components/molecules/ModalFooter/ModalFooter.stories.ts +204 -0
- package/src/components/molecules/ModalFooter/ModalFooter.test.ts +276 -0
- package/src/components/molecules/PageCard/PageCard.stories.ts +100 -0
- package/src/components/molecules/PageCard/PageCard.test.ts +91 -0
- package/src/components/molecules/PageContainer/PageContainer.stories.ts +90 -0
- package/src/components/molecules/PageContainer/PageContainer.test.ts +50 -0
- package/src/components/molecules/PageMockup/PageMockup.stories.ts +38 -0
- package/src/components/molecules/PageMockup/PageMockup.test.ts +20 -0
- package/src/components/molecules/PageTypeTile/PageTypeTile.stories.ts +63 -0
- package/src/components/molecules/PageTypeTile/PageTypeTile.test.ts +41 -0
- package/src/components/molecules/Pagination/Pagination.stories.ts +72 -0
- package/src/components/molecules/Pagination/Pagination.test.ts +130 -0
- package/src/components/molecules/PickerGroup/PickerGroup.stories.ts +90 -0
- package/src/components/molecules/PickerGroup/PickerGroup.test.ts +145 -0
- package/src/components/molecules/PickerList/PickerList.stories.ts +436 -0
- package/src/components/molecules/PickerList/PickerList.test.ts +870 -0
- package/src/components/molecules/PlaceholderInput/PlaceholderInput.stories.ts +48 -0
- package/src/components/molecules/PlaceholderInput/PlaceholderInput.test.ts +107 -0
- package/src/components/molecules/PropertyCard/PropertyCard.stories.ts +46 -0
- package/src/components/molecules/PropertyCard/PropertyCard.test.ts +59 -0
- package/src/components/molecules/Select/Select.stories.ts +264 -0
- package/src/components/molecules/Select/Select.test.ts +315 -0
- package/src/components/molecules/SidebarMenuItem/SidebarMenuItem.stories.ts +84 -0
- package/src/components/molecules/SidebarMenuItem/SidebarMenuItem.test.ts +103 -0
- package/src/components/molecules/SkeletonPropertyCard/SkeletonPropertyCard.stories.ts +11 -0
- package/src/components/molecules/SkeletonPropertyCard/SkeletonPropertyCard.test.ts +38 -0
- package/src/components/molecules/SocialIcons/SocialIcons.stories.ts +28 -0
- package/src/components/molecules/SocialIcons/SocialIcons.test.ts +58 -0
- package/src/components/molecules/SocialMediaCustomTemplate/SocialMediaCustomTemplate.stories.ts +11 -0
- package/src/components/molecules/SocialMediaCustomTemplate/SocialMediaCustomTemplate.test.ts +116 -0
- package/src/components/molecules/SocialMediaType/SocialMediaType.stories.ts +37 -0
- package/src/components/molecules/SocialMediaType/SocialMediaType.test.ts +126 -0
- package/src/components/molecules/Source/Source.stories.ts +35 -0
- package/src/components/molecules/Source/Source.test.ts +45 -0
- package/src/components/molecules/TabbedContent/TabbedContent.stories.ts +96 -0
- package/src/components/molecules/TabbedContent/TabbedContent.test.ts +109 -0
- package/src/components/molecules/Tabs/Tabs.stories.ts +230 -0
- package/src/components/molecules/Tabs/Tabs.test.ts +280 -0
- package/src/components/molecules/TemplateCard/TemplateCard.stories.ts +327 -0
- package/src/components/molecules/TemplateCard/TemplateCard.test.ts +339 -0
- package/src/components/molecules/Textarea/Textarea.stories.ts +216 -0
- package/src/components/molecules/Textarea/Textarea.test.ts +191 -0
- package/src/components/molecules/TimelineEvent/TimelineEvent.stories.ts +319 -0
- package/src/components/molecules/TimelineEvent/TimelineEvent.test.ts +224 -0
- package/src/components/molecules/TimelineLanes/TimelineLanes.stories.ts +29 -0
- package/src/components/molecules/TimelineLanes/TimelineLanes.test.ts +30 -0
- package/src/components/molecules/Toast/Toast.stories.ts +110 -0
- package/src/components/molecules/Toast/Toast.test.ts +103 -0
- package/src/components/molecules/ToggleGroup/ToggleGroup.stories.ts +297 -0
- package/src/components/molecules/ToggleGroup/ToggleGroup.test.ts +578 -0
- package/src/components/molecules/Tree/Tree.stories.ts +884 -0
- package/src/components/molecules/Tree/Tree.test.ts +1247 -0
- package/src/components/molecules/Tree/tree-drop.test.ts +223 -0
- package/src/components/organisms/Calendar/Calendar.stories.ts +108 -0
- package/src/components/organisms/Calendar/Calendar.test.ts +279 -0
- package/src/components/organisms/Calendar/_CalendarDayView.test.ts +104 -0
- package/src/components/organisms/Calendar/_CalendarHeader.test.ts +86 -0
- package/src/components/organisms/Calendar/_CalendarMonthView.test.ts +52 -0
- package/src/components/organisms/Calendar/_CalendarTimePicker.test.ts +89 -0
- package/src/components/organisms/Calendar/_CalendarYearView.test.ts +56 -0
- package/src/components/organisms/ColorPicker/ColorPicker.stories.ts +229 -0
- package/src/components/organisms/ColorPicker/ColorPicker.test.ts +638 -0
- package/src/components/organisms/ColorPicker/gradient.test.ts +67 -0
- package/src/components/organisms/ColorPicker/gradientGeometry.test.ts +206 -0
- package/src/components/organisms/Combobox/Combobox.stories.ts +234 -0
- package/src/components/organisms/Combobox/Combobox.test.ts +512 -0
- package/src/components/organisms/Combobox/Combobox.vue +1 -1
- package/src/components/organisms/ComboboxPanel/ComboboxPanel.stories.ts +158 -0
- package/src/components/organisms/ComboboxPanel/ComboboxPanel.test.ts +524 -0
- package/src/components/organisms/ComboboxPanel/ComboboxPanel.vue +1 -1
- package/src/components/organisms/CountrySelect/CountrySelect.stories.ts +139 -0
- package/src/components/organisms/CountrySelect/CountrySelect.test.ts +149 -0
- package/src/components/organisms/DatePicker/DatePicker.stories.ts +163 -0
- package/src/components/organisms/DatePicker/DatePicker.test.ts +214 -0
- package/src/components/organisms/DropdownButton/DropdownButton.stories.ts +123 -0
- package/src/components/organisms/DropdownButton/DropdownButton.test.ts +379 -0
- package/src/components/organisms/FontPicker/FontPicker.stories.ts +476 -0
- package/src/components/organisms/FontPicker/FontPicker.test.ts +873 -0
- package/src/components/organisms/Header/Header.stories.ts +75 -0
- package/src/components/organisms/Header/Header.test.ts +233 -0
- package/src/components/organisms/IconPicker/IconPicker.stories.ts +734 -0
- package/src/components/organisms/IconPicker/IconPicker.test.ts +669 -0
- package/src/components/organisms/IconPicker/_IconPickerGrid.test.ts +184 -0
- package/src/components/organisms/IconPicker/_IconPickerRail.test.ts +102 -0
- package/src/components/organisms/IconPicker/useIconPickerNavigation.test.ts +215 -0
- package/src/components/organisms/Modal/Modal.stories.ts +350 -0
- package/src/components/organisms/Modal/Modal.test.ts +275 -0
- package/src/components/organisms/PickerPanel/PickerPanel.stories.ts +452 -0
- package/src/components/organisms/PickerPanel/PickerPanel.test.ts +358 -0
- package/src/components/organisms/ProgressBar/ProgressBar.stories.ts +100 -0
- package/src/components/organisms/ProgressBar/ProgressBar.test.ts +417 -0
- package/src/components/organisms/ReferenceCard/ReferenceCard.stories.ts +191 -0
- package/src/components/organisms/ReferenceCard/ReferenceCard.test.ts +165 -0
- package/src/components/organisms/SocialMediaTemplate/SocialMediaTemplate.stories.ts +65 -0
- package/src/components/organisms/SocialMediaTemplate/SocialMediaTemplate.test.ts +466 -0
- package/src/components/organisms/StepperHeader/StepperHeader.stories.ts +91 -0
- package/src/components/organisms/StepperHeader/StepperHeader.test.ts +279 -0
- package/src/components/organisms/Table/Table.stories.ts +332 -0
- package/src/components/organisms/Table/Table.test.ts +320 -0
- package/src/components/organisms/TimelinePhaseblock/TimelinePhaseblock.stories.ts +198 -0
- package/src/components/organisms/TimelinePhaseblock/TimelinePhaseblock.test.ts +283 -0
- package/src/components/organisms/TimelineTrack/TimelineTrack.stories.ts +120 -0
- package/src/components/organisms/TimelineTrack/TimelineTrack.test.ts +91 -0
- package/src/components/organisms/Toaster/Toaster.stories.ts +51 -0
- package/src/components/organisms/Toaster/Toaster.test.ts +75 -0
- package/src/components/organisms/VideoControls/VideoControls.stories.ts +792 -0
- package/src/components/organisms/VideoControls/VideoControls.test.ts +1056 -0
- package/src/components/organisms/VideoPlayer/VideoPlayer.stories.ts +327 -0
- package/src/components/organisms/VideoPlayer/VideoPlayer.test.ts +439 -0
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
import { afterEach, describe, it, expect, vi } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import { defineComponent, h } from 'vue'
|
|
4
|
+
import EditorSettingsGroup from './EditorSettingsGroup.vue'
|
|
5
|
+
import EditorSettingsBlock from '../EditorSettingsBlock/EditorSettingsBlock.vue'
|
|
6
|
+
|
|
7
|
+
afterEach(() => {
|
|
8
|
+
vi.restoreAllMocks()
|
|
9
|
+
vi.unstubAllEnvs()
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
/** A group holding one block, rendered as one app so both share the context. */
|
|
13
|
+
const withBlock = (
|
|
14
|
+
groupProps: Record<string, unknown>,
|
|
15
|
+
blockProps: Record<string, unknown> = {},
|
|
16
|
+
content = '<p>Inhoud</p>',
|
|
17
|
+
) =>
|
|
18
|
+
mount(
|
|
19
|
+
defineComponent({
|
|
20
|
+
components: { EditorSettingsGroup, EditorSettingsBlock },
|
|
21
|
+
setup: () => ({ groupProps, blockProps }),
|
|
22
|
+
template: `
|
|
23
|
+
<EditorSettingsGroup v-bind="groupProps">
|
|
24
|
+
<EditorSettingsBlock label="Stijl" v-bind="blockProps">${content}</EditorSettingsBlock>
|
|
25
|
+
</EditorSettingsGroup>
|
|
26
|
+
`,
|
|
27
|
+
}),
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
const blockRoot = (wrapper: ReturnType<typeof withBlock>) =>
|
|
31
|
+
wrapper.findComponent(EditorSettingsBlock).element as HTMLElement
|
|
32
|
+
|
|
33
|
+
describe('EditorSettingsGroup', () => {
|
|
34
|
+
// No assertions on typography utilities: headings are found by tag and text.
|
|
35
|
+
describe('without a label', () => {
|
|
36
|
+
it('renders no group role, no name and no heading', () => {
|
|
37
|
+
const wrapper = mount(EditorSettingsGroup, { slots: { default: '<p>Inhoud</p>' } })
|
|
38
|
+
|
|
39
|
+
expect(wrapper.attributes('role')).toBeUndefined()
|
|
40
|
+
expect(wrapper.attributes('aria-labelledby')).toBeUndefined()
|
|
41
|
+
expect(wrapper.find('h1, h2, h3, h4, h5, h6').exists()).toBe(false)
|
|
42
|
+
expect(wrapper.text()).toBe('Inhoud')
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('draws the divider on top', () => {
|
|
46
|
+
const wrapper = mount(EditorSettingsGroup)
|
|
47
|
+
|
|
48
|
+
expect(wrapper.classes()).toEqual(
|
|
49
|
+
expect.arrayContaining(['border-t', 'border-editor-divider']),
|
|
50
|
+
)
|
|
51
|
+
})
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
describe('with a label', () => {
|
|
55
|
+
it('is a group named by its heading', () => {
|
|
56
|
+
const wrapper = mount(EditorSettingsGroup, { props: { label: 'Lijn' } })
|
|
57
|
+
const heading = wrapper.get('h3')
|
|
58
|
+
|
|
59
|
+
expect(wrapper.attributes('role')).toBe('group')
|
|
60
|
+
expect(heading.text()).toBe('Lijn')
|
|
61
|
+
expect(heading.attributes('id')).toBeTruthy()
|
|
62
|
+
expect(wrapper.attributes('aria-labelledby')).toBe(heading.attributes('id'))
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it('renders the heading at the given level', () => {
|
|
66
|
+
const wrapper = mount(EditorSettingsGroup, { props: { label: 'Lijn', headingLevel: 4 } })
|
|
67
|
+
|
|
68
|
+
expect(wrapper.find('h3').exists()).toBe(false)
|
|
69
|
+
expect(wrapper.get('h4').text()).toBe('Lijn')
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
it('puts the heading before the settings', () => {
|
|
73
|
+
const wrapper = withBlock({ label: 'Lijn' })
|
|
74
|
+
|
|
75
|
+
expect(wrapper.element.firstElementChild!.tagName).toBe('H3')
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
it('gives two groups distinct heading ids', () => {
|
|
79
|
+
const wrapper = mount(
|
|
80
|
+
defineComponent({
|
|
81
|
+
render: () => [
|
|
82
|
+
h(EditorSettingsGroup, { label: 'Lijn' }),
|
|
83
|
+
h(EditorSettingsGroup, { label: 'Ruimte' }),
|
|
84
|
+
],
|
|
85
|
+
}),
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
const ids = wrapper.findAll('h3').map((heading) => heading.attributes('id'))
|
|
89
|
+
expect(new Set(ids).size).toBe(2)
|
|
90
|
+
})
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
describe('blocks inside', () => {
|
|
94
|
+
it('give a block pt-4 instead of py-4', () => {
|
|
95
|
+
const root = blockRoot(withBlock({ label: 'Lijn' }))
|
|
96
|
+
|
|
97
|
+
expect(root.classList).toContain('pt-4')
|
|
98
|
+
expect(root.classList).not.toContain('py-4')
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
it('leave the block label a paragraph under a labelled group', () => {
|
|
102
|
+
const wrapper = withBlock({ label: 'Lijn' })
|
|
103
|
+
|
|
104
|
+
expect(wrapper.findComponent(EditorSettingsBlock).get('p').text()).toBe('Stijl')
|
|
105
|
+
expect(wrapper.findAll('h3')).toHaveLength(1)
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
it('promote the block label to a heading in a group without a label', () => {
|
|
109
|
+
const wrapper = withBlock({})
|
|
110
|
+
const block = wrapper.findComponent(EditorSettingsBlock)
|
|
111
|
+
|
|
112
|
+
expect(block.get('h3').text()).toBe('Stijl')
|
|
113
|
+
expect(block.find('p').text()).toBe('Inhoud')
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
it('promote at the group heading level', () => {
|
|
117
|
+
const block = withBlock({ headingLevel: 5 }).findComponent(EditorSettingsBlock)
|
|
118
|
+
|
|
119
|
+
expect(block.get('h5').text()).toBe('Stijl')
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
it('keep a switchable promoted label as the switch label, not a heading', () => {
|
|
123
|
+
const block = withBlock({}, { switchable: true }).findComponent(EditorSettingsBlock)
|
|
124
|
+
|
|
125
|
+
expect(block.find('h3').exists()).toBe(false)
|
|
126
|
+
expect(block.get('label span').text()).toBe('Stijl')
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
it('follow a label that is added after mount', async () => {
|
|
130
|
+
const wrapper = mount(EditorSettingsGroup, {
|
|
131
|
+
slots: { default: () => h(EditorSettingsBlock, { label: 'Stijl' }) },
|
|
132
|
+
})
|
|
133
|
+
expect(wrapper.findComponent(EditorSettingsBlock).find('h3').exists()).toBe(true)
|
|
134
|
+
|
|
135
|
+
await wrapper.setProps({ label: 'Lijn' })
|
|
136
|
+
|
|
137
|
+
expect(wrapper.findComponent(EditorSettingsBlock).get('p').text()).toBe('Stijl')
|
|
138
|
+
})
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
// Colour is not typography: the title colour is a design decision for every group.
|
|
142
|
+
describe('title colour', () => {
|
|
143
|
+
it('colours the heading of a labelled group cornflower-blue-700', () => {
|
|
144
|
+
const heading = mount(EditorSettingsGroup, { props: { label: 'Lijn' } }).get('h3')
|
|
145
|
+
|
|
146
|
+
expect(heading.classes()).toContain('text-cornflower-blue-700')
|
|
147
|
+
expect(heading.classes()).not.toContain('text-gray-900')
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
it('colours the title of a collapsible group, and leaves the chevron grey', () => {
|
|
151
|
+
const wrapper = mount(EditorSettingsGroup, { props: { label: 'Lijn', collapsible: true } })
|
|
152
|
+
const button = wrapper.get('h3 > button')
|
|
153
|
+
const chevron = wrapper.get('button i')
|
|
154
|
+
|
|
155
|
+
expect(wrapper.get('h3').classes()).toContain('text-cornflower-blue-700')
|
|
156
|
+
// The button inherits the heading colour rather than setting its own.
|
|
157
|
+
expect(button.classes().filter((name) => /^text-(?!left)/.test(name))).toEqual([])
|
|
158
|
+
expect(chevron.classes()).toEqual(
|
|
159
|
+
expect.arrayContaining(['text-gray-700', 'group-hover/toggle:text-gray-900']),
|
|
160
|
+
)
|
|
161
|
+
expect(chevron.classes()).not.toContain('text-cornflower-blue-700')
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
it('colours a promoted block label like a group title', () => {
|
|
165
|
+
const block = withBlock({}).findComponent(EditorSettingsBlock)
|
|
166
|
+
|
|
167
|
+
expect(block.get('h3').classes()).toContain('text-cornflower-blue-700')
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
it('leaves a block label under a labelled group gray-900', () => {
|
|
171
|
+
const block = withBlock({ label: 'Lijn' }).findComponent(EditorSettingsBlock)
|
|
172
|
+
|
|
173
|
+
expect(block.get('p').classes()).toContain('text-gray-900')
|
|
174
|
+
expect(block.get('p').classes()).not.toContain('text-cornflower-blue-700')
|
|
175
|
+
})
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
describe('nesting', () => {
|
|
179
|
+
const nested = () =>
|
|
180
|
+
mount(
|
|
181
|
+
defineComponent({
|
|
182
|
+
components: { EditorSettingsGroup },
|
|
183
|
+
template: `
|
|
184
|
+
<EditorSettingsGroup label="Buiten">
|
|
185
|
+
<EditorSettingsGroup label="Binnen"><p>Inhoud</p></EditorSettingsGroup>
|
|
186
|
+
</EditorSettingsGroup>
|
|
187
|
+
`,
|
|
188
|
+
}),
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
it('warns exactly once in development and still renders', () => {
|
|
192
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {})
|
|
193
|
+
|
|
194
|
+
const wrapper = nested()
|
|
195
|
+
|
|
196
|
+
expect(warn).toHaveBeenCalledTimes(1)
|
|
197
|
+
expect(warn).toHaveBeenCalledWith('NexxtEditorSettingsGroup cannot be nested')
|
|
198
|
+
expect(wrapper.findAll('[role="group"]')).toHaveLength(2)
|
|
199
|
+
expect(wrapper.text()).toContain('Inhoud')
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
it('does not warn for groups side by side', () => {
|
|
203
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {})
|
|
204
|
+
|
|
205
|
+
mount(
|
|
206
|
+
defineComponent({
|
|
207
|
+
render: () => [
|
|
208
|
+
h(EditorSettingsGroup, { label: 'Lijn' }),
|
|
209
|
+
h(EditorSettingsGroup, { label: 'Ruimte' }),
|
|
210
|
+
],
|
|
211
|
+
}),
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
expect(warn).not.toHaveBeenCalled()
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
it('stays silent in production', () => {
|
|
218
|
+
vi.stubEnv('NODE_ENV', 'production')
|
|
219
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {})
|
|
220
|
+
|
|
221
|
+
nested()
|
|
222
|
+
|
|
223
|
+
expect(warn).not.toHaveBeenCalled()
|
|
224
|
+
})
|
|
225
|
+
})
|
|
226
|
+
})
|
|
227
|
+
|
|
228
|
+
// Taken before `collapsible` existed: a group that does not opt in must render
|
|
229
|
+
// exactly this markup -- no button, no wrapper, no extra ids. Since then only
|
|
230
|
+
// the rhythm changed on purpose: 24px between groups (pt-6 / pt-2 unlabelled, pb-5).
|
|
231
|
+
describe('EditorSettingsGroup without collapsible', () => {
|
|
232
|
+
it('renders a labelled group unchanged', () => {
|
|
233
|
+
const wrapper = mount(EditorSettingsGroup, {
|
|
234
|
+
props: { label: 'Lijn' },
|
|
235
|
+
slots: { default: '<p>Inhoud</p>' },
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
expect(wrapper.html()).toMatchInlineSnapshot(`
|
|
239
|
+
"<div class="border-t border-editor-divider pb-5 pt-6" role="group" aria-labelledby="v-0">
|
|
240
|
+
<!--
|
|
241
|
+
The line sits on top, always, the first group included: it separates the
|
|
242
|
+
group from whatever comes before it, so the last group has none below.
|
|
243
|
+
24px between groups: line to heading, and last control to the next line
|
|
244
|
+
(the last block's 4px of focus-ring room plus \`pb-5\`); 16px inside one.
|
|
245
|
+
Without a label the top is \`pt-2\`: the one setting inside brings its own
|
|
246
|
+
\`pt-4\`, so its promoted label also lands 24px under the line.
|
|
247
|
+
-->
|
|
248
|
+
<h3 id="v-0" class="small-semibold text-cornflower-blue-700">Lijn</h3>
|
|
249
|
+
<p>Inhoud</p>
|
|
250
|
+
</div>"
|
|
251
|
+
`)
|
|
252
|
+
})
|
|
253
|
+
|
|
254
|
+
it('renders a group without a label unchanged', () => {
|
|
255
|
+
const wrapper = mount(EditorSettingsGroup, { slots: { default: '<p>Inhoud</p>' } })
|
|
256
|
+
|
|
257
|
+
expect(wrapper.html()).toMatchInlineSnapshot(`
|
|
258
|
+
"<div class="border-t border-editor-divider pb-5 pt-2">
|
|
259
|
+
<!--
|
|
260
|
+
The line sits on top, always, the first group included: it separates the
|
|
261
|
+
group from whatever comes before it, so the last group has none below.
|
|
262
|
+
24px between groups: line to heading, and last control to the next line
|
|
263
|
+
(the last block's 4px of focus-ring room plus \`pb-5\`); 16px inside one.
|
|
264
|
+
Without a label the top is \`pt-2\`: the one setting inside brings its own
|
|
265
|
+
\`pt-4\`, so its promoted label also lands 24px under the line.
|
|
266
|
+
-->
|
|
267
|
+
<!--v-if-->
|
|
268
|
+
<p>Inhoud</p>
|
|
269
|
+
</div>"
|
|
270
|
+
`)
|
|
271
|
+
})
|
|
272
|
+
})
|
|
273
|
+
|
|
274
|
+
describe('EditorSettingsGroup collapsible', () => {
|
|
275
|
+
const collapsible = (props: Record<string, unknown> = {}) =>
|
|
276
|
+
mount(EditorSettingsGroup, {
|
|
277
|
+
props: { label: 'Lijn', collapsible: true, ...props },
|
|
278
|
+
slots: { default: '<input data-testid="field" />' },
|
|
279
|
+
attachTo: document.body,
|
|
280
|
+
})
|
|
281
|
+
|
|
282
|
+
const content = (wrapper: ReturnType<typeof collapsible>) =>
|
|
283
|
+
wrapper.get('[data-testid="editor-settings-group-content"]')
|
|
284
|
+
|
|
285
|
+
it('puts one native button inside the heading, with the label', () => {
|
|
286
|
+
const wrapper = collapsible()
|
|
287
|
+
const button = wrapper.get('h3 > button')
|
|
288
|
+
|
|
289
|
+
expect(button.attributes('type')).toBe('button')
|
|
290
|
+
expect(button.text()).toBe('Lijn')
|
|
291
|
+
expect(wrapper.findAll('button')).toHaveLength(1)
|
|
292
|
+
// Still named by its heading.
|
|
293
|
+
expect(wrapper.attributes('role')).toBe('group')
|
|
294
|
+
expect(wrapper.attributes('aria-labelledby')).toBe(wrapper.get('h3').attributes('id'))
|
|
295
|
+
expect(wrapper.attributes('aria-expanded')).toBeUndefined()
|
|
296
|
+
wrapper.unmount()
|
|
297
|
+
})
|
|
298
|
+
|
|
299
|
+
it('hides the chevron from assistive technology', () => {
|
|
300
|
+
const wrapper = collapsible()
|
|
301
|
+
|
|
302
|
+
expect(wrapper.get('button i').element.closest('[aria-hidden="true"]')).not.toBeNull()
|
|
303
|
+
wrapper.unmount()
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
// Named, so a `.group` around the panel in the app cannot light the chevron.
|
|
307
|
+
it('scopes the chevron hover to its own button', () => {
|
|
308
|
+
const wrapper = collapsible()
|
|
309
|
+
|
|
310
|
+
expect(wrapper.get('button').classes()).toContain('group/toggle')
|
|
311
|
+
expect(wrapper.get('button').classes()).not.toContain('group')
|
|
312
|
+
expect(wrapper.get('button i').classes()).toContain('group-hover/toggle:text-gray-900')
|
|
313
|
+
wrapper.unmount()
|
|
314
|
+
})
|
|
315
|
+
|
|
316
|
+
it('points aria-controls at the content, which exists', () => {
|
|
317
|
+
const wrapper = collapsible()
|
|
318
|
+
const id = wrapper.get('button').attributes('aria-controls')!
|
|
319
|
+
|
|
320
|
+
expect(document.getElementById(id)).toBe(content(wrapper).element)
|
|
321
|
+
wrapper.unmount()
|
|
322
|
+
})
|
|
323
|
+
|
|
324
|
+
it('is open by default and follows the model in aria-expanded', async () => {
|
|
325
|
+
const wrapper = collapsible()
|
|
326
|
+
expect(wrapper.get('button').attributes('aria-expanded')).toBe('true')
|
|
327
|
+
|
|
328
|
+
await wrapper.setProps({ open: false })
|
|
329
|
+
|
|
330
|
+
expect(wrapper.get('button').attributes('aria-expanded')).toBe('false')
|
|
331
|
+
wrapper.unmount()
|
|
332
|
+
})
|
|
333
|
+
|
|
334
|
+
it('emits update:open on click, and stays focused on the button', async () => {
|
|
335
|
+
const wrapper = collapsible()
|
|
336
|
+
const button = wrapper.get('button')
|
|
337
|
+
;(button.element as HTMLButtonElement).focus()
|
|
338
|
+
|
|
339
|
+
await button.trigger('click')
|
|
340
|
+
expect(wrapper.emitted('update:open')).toEqual([[false]])
|
|
341
|
+
expect(document.activeElement).toBe(button.element)
|
|
342
|
+
|
|
343
|
+
await wrapper.setProps({ open: false })
|
|
344
|
+
await button.trigger('click')
|
|
345
|
+
expect(wrapper.emitted('update:open')).toEqual([[false], [true]])
|
|
346
|
+
wrapper.unmount()
|
|
347
|
+
})
|
|
348
|
+
|
|
349
|
+
it('makes closed content inert, and open content not inert at all', async () => {
|
|
350
|
+
const wrapper = collapsible({ open: false })
|
|
351
|
+
expect(content(wrapper).attributes('inert')).toBeDefined()
|
|
352
|
+
expect(content(wrapper).classes()).toContain('grid-rows-[0fr]')
|
|
353
|
+
|
|
354
|
+
await wrapper.setProps({ open: true })
|
|
355
|
+
|
|
356
|
+
// Absent, not "false": a browser treats inert="false" as inert.
|
|
357
|
+
expect(content(wrapper).element.hasAttribute('inert')).toBe(false)
|
|
358
|
+
expect(content(wrapper).classes()).toContain('grid-rows-[1fr]')
|
|
359
|
+
wrapper.unmount()
|
|
360
|
+
})
|
|
361
|
+
|
|
362
|
+
it('keeps the content mounted while closed', () => {
|
|
363
|
+
const wrapper = collapsible({ open: false })
|
|
364
|
+
|
|
365
|
+
expect(wrapper.find('[data-testid="field"]').exists()).toBe(true)
|
|
366
|
+
wrapper.unmount()
|
|
367
|
+
})
|
|
368
|
+
|
|
369
|
+
it('moves focus to the button when closed from outside while focus is inside', async () => {
|
|
370
|
+
const wrapper = collapsible()
|
|
371
|
+
const field = wrapper.get('[data-testid="field"]').element as HTMLInputElement
|
|
372
|
+
field.focus()
|
|
373
|
+
expect(document.activeElement).toBe(field)
|
|
374
|
+
|
|
375
|
+
await wrapper.setProps({ open: false })
|
|
376
|
+
|
|
377
|
+
expect(document.activeElement).toBe(wrapper.get('button').element)
|
|
378
|
+
wrapper.unmount()
|
|
379
|
+
})
|
|
380
|
+
|
|
381
|
+
it('leaves focus alone when closed from outside while focus is elsewhere', async () => {
|
|
382
|
+
const outside = document.createElement('input')
|
|
383
|
+
document.body.append(outside)
|
|
384
|
+
const wrapper = collapsible()
|
|
385
|
+
outside.focus()
|
|
386
|
+
|
|
387
|
+
await wrapper.setProps({ open: false })
|
|
388
|
+
|
|
389
|
+
expect(document.activeElement).toBe(outside)
|
|
390
|
+
wrapper.unmount()
|
|
391
|
+
outside.remove()
|
|
392
|
+
})
|
|
393
|
+
|
|
394
|
+
it('drops motion for height and chevron under reduced motion, but keeps the fade', () => {
|
|
395
|
+
const wrapper = collapsible()
|
|
396
|
+
const clip = content(wrapper).element.firstElementChild!
|
|
397
|
+
const chevron = wrapper.get('button span[aria-hidden="true"]')
|
|
398
|
+
|
|
399
|
+
expect(content(wrapper).classes()).toContain('motion-reduce:transition-none')
|
|
400
|
+
expect(chevron.classes()).toContain('motion-reduce:transition-none')
|
|
401
|
+
expect(wrapper.classes()).toContain('motion-reduce:transition-none')
|
|
402
|
+
expect(clip.classList).not.toContain('motion-reduce:transition-none')
|
|
403
|
+
expect(clip.classList).toContain('transition-opacity')
|
|
404
|
+
wrapper.unmount()
|
|
405
|
+
})
|
|
406
|
+
|
|
407
|
+
it('points the chevron down when open and up when closed', async () => {
|
|
408
|
+
const wrapper = collapsible()
|
|
409
|
+
const chevron = () => wrapper.get('button span[aria-hidden="true"]')
|
|
410
|
+
expect(chevron().classes()).toContain('rotate-0')
|
|
411
|
+
|
|
412
|
+
await wrapper.setProps({ open: false })
|
|
413
|
+
|
|
414
|
+
expect(chevron().classes()).toContain('rotate-180')
|
|
415
|
+
expect(chevron().classes()).not.toContain('-rotate-90')
|
|
416
|
+
wrapper.unmount()
|
|
417
|
+
})
|
|
418
|
+
|
|
419
|
+
it('opens on ease-out-strong and closes on ease-in-out-strong, in step', async () => {
|
|
420
|
+
const wrapper = collapsible()
|
|
421
|
+
const root = () => wrapper.classes()
|
|
422
|
+
const rows = () => content(wrapper).classes()
|
|
423
|
+
const clip = () => [...content(wrapper).element.firstElementChild!.classList]
|
|
424
|
+
const chevron = () => wrapper.get('button span[aria-hidden="true"]').classes()
|
|
425
|
+
|
|
426
|
+
for (const classes of [root(), rows(), clip(), chevron()]) {
|
|
427
|
+
expect(classes).toEqual(expect.arrayContaining(['duration-200', 'ease-out-strong']))
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
await wrapper.setProps({ open: false })
|
|
431
|
+
|
|
432
|
+
// Height, root padding and chevron share duration and curve when closing.
|
|
433
|
+
for (const classes of [root(), rows(), chevron()]) {
|
|
434
|
+
expect(classes).toEqual(expect.arrayContaining(['duration-200', 'ease-in-out-strong']))
|
|
435
|
+
}
|
|
436
|
+
// The fade is shorter and softer, so the content stays readable.
|
|
437
|
+
expect(clip()).toEqual(expect.arrayContaining(['duration-150', 'ease-in-out']))
|
|
438
|
+
wrapper.unmount()
|
|
439
|
+
})
|
|
440
|
+
|
|
441
|
+
it('moves the closed compensation to the root: pb-6 closed, pb-5 open', async () => {
|
|
442
|
+
const wrapper = collapsible()
|
|
443
|
+
expect(wrapper.classes()).toContain('pb-5')
|
|
444
|
+
expect(wrapper.classes()).toContain('transition-[padding-bottom]')
|
|
445
|
+
|
|
446
|
+
await wrapper.setProps({ open: false })
|
|
447
|
+
|
|
448
|
+
expect(wrapper.classes()).toContain('pb-6')
|
|
449
|
+
expect(wrapper.classes()).not.toContain('pb-5')
|
|
450
|
+
// The content wrapper carries no padding of its own, so closed it is 0px.
|
|
451
|
+
expect(
|
|
452
|
+
content(wrapper)
|
|
453
|
+
.classes()
|
|
454
|
+
.some((name) => /^p[bty]?-/.test(name)),
|
|
455
|
+
).toBe(false)
|
|
456
|
+
wrapper.unmount()
|
|
457
|
+
})
|
|
458
|
+
|
|
459
|
+
describe('without a label', () => {
|
|
460
|
+
it('warns once, renders no button and always shows the content', () => {
|
|
461
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {})
|
|
462
|
+
|
|
463
|
+
const wrapper = mount(EditorSettingsGroup, {
|
|
464
|
+
props: { collapsible: true, open: false },
|
|
465
|
+
slots: { default: '<p>Inhoud</p>' },
|
|
466
|
+
})
|
|
467
|
+
|
|
468
|
+
expect(warn).toHaveBeenCalledTimes(1)
|
|
469
|
+
expect(wrapper.find('button').exists()).toBe(false)
|
|
470
|
+
expect(wrapper.find('[inert]').exists()).toBe(false)
|
|
471
|
+
expect(wrapper.find('[data-testid="editor-settings-group-content"]').exists()).toBe(false)
|
|
472
|
+
expect(wrapper.text()).toBe('Inhoud')
|
|
473
|
+
})
|
|
474
|
+
|
|
475
|
+
it('stays silent in production', () => {
|
|
476
|
+
vi.stubEnv('NODE_ENV', 'production')
|
|
477
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {})
|
|
478
|
+
|
|
479
|
+
mount(EditorSettingsGroup, { props: { collapsible: true } })
|
|
480
|
+
|
|
481
|
+
expect(warn).not.toHaveBeenCalled()
|
|
482
|
+
})
|
|
483
|
+
})
|
|
484
|
+
})
|