@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,64 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite'
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
import EditorRadius from './EditorRadius.vue'
|
|
4
|
+
import type { EditorRadiusValue } from './EditorRadius.vue'
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
title: 'Components/Editor Components/Molecules/Editor Radius',
|
|
8
|
+
component: EditorRadius,
|
|
9
|
+
decorators: [() => ({ template: '<div class="w-100 mx-auto"><story /></div>' })],
|
|
10
|
+
argTypes: {
|
|
11
|
+
label: { control: 'text' },
|
|
12
|
+
},
|
|
13
|
+
} satisfies Meta<typeof EditorRadius>
|
|
14
|
+
|
|
15
|
+
type Story = StoryObj<typeof EditorRadius>
|
|
16
|
+
|
|
17
|
+
export const Default: Story = {
|
|
18
|
+
render: (args) => ({
|
|
19
|
+
components: { EditorRadius },
|
|
20
|
+
setup() {
|
|
21
|
+
const radius = ref<EditorRadiusValue>('rounded-lg')
|
|
22
|
+
return { args, radius }
|
|
23
|
+
},
|
|
24
|
+
// The value is shown as-is: it is the Tailwind class the editor applies.
|
|
25
|
+
template: `
|
|
26
|
+
<div>
|
|
27
|
+
<EditorRadius v-bind="args" v-model="radius" />
|
|
28
|
+
<p class="small-normal text-gray-700">{{ radius }}</p>
|
|
29
|
+
</div>
|
|
30
|
+
`,
|
|
31
|
+
}),
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const Full: Story = {
|
|
35
|
+
render: (args) => ({
|
|
36
|
+
components: { EditorRadius },
|
|
37
|
+
setup() {
|
|
38
|
+
const radius = ref<EditorRadiusValue>('rounded-full')
|
|
39
|
+
return { args, radius }
|
|
40
|
+
},
|
|
41
|
+
// The last step has no px size, so the readout names it instead.
|
|
42
|
+
template: `
|
|
43
|
+
<div>
|
|
44
|
+
<EditorRadius v-bind="args" v-model="radius" />
|
|
45
|
+
<p class="small-normal text-gray-700">{{ radius }}</p>
|
|
46
|
+
</div>
|
|
47
|
+
`,
|
|
48
|
+
}),
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export const CustomMessages: Story = {
|
|
52
|
+
args: {
|
|
53
|
+
label: 'Corner radius',
|
|
54
|
+
messages: { unit: 'pixels', full: 'Pill' },
|
|
55
|
+
},
|
|
56
|
+
render: (args) => ({
|
|
57
|
+
components: { EditorRadius },
|
|
58
|
+
setup() {
|
|
59
|
+
const radius = ref<EditorRadiusValue>('rounded-lg')
|
|
60
|
+
return { args, radius }
|
|
61
|
+
},
|
|
62
|
+
template: `<EditorRadius v-bind="args" v-model="radius" />`,
|
|
63
|
+
}),
|
|
64
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import EditorRadius from './EditorRadius.vue'
|
|
4
|
+
import type { EditorRadiusValue } from './EditorRadius.vue'
|
|
5
|
+
import Slider from '../../../atoms/Slider/Slider.vue'
|
|
6
|
+
|
|
7
|
+
// jsdom ships no ResizeObserver, and reka-ui's slider observes its track to place the thumbs
|
|
8
|
+
vi.stubGlobal(
|
|
9
|
+
'ResizeObserver',
|
|
10
|
+
class {
|
|
11
|
+
observe() {}
|
|
12
|
+
unobserve() {}
|
|
13
|
+
disconnect() {}
|
|
14
|
+
},
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
// jsdom implements no pointer capture either, and reka-ui captures the pointer on thumb pointerdown
|
|
18
|
+
Element.prototype.setPointerCapture ??= () => {}
|
|
19
|
+
Element.prototype.releasePointerCapture ??= () => {}
|
|
20
|
+
Element.prototype.hasPointerCapture ??= () => false
|
|
21
|
+
|
|
22
|
+
/** The index the slider sits on, read from the model handed to the slider. */
|
|
23
|
+
const sliderIndex = (wrapper: ReturnType<typeof mount>) =>
|
|
24
|
+
wrapper.findComponent(Slider).props('modelValue')
|
|
25
|
+
|
|
26
|
+
describe('EditorRadius', () => {
|
|
27
|
+
// No assertions on typography utilities: the label and the value are found by
|
|
28
|
+
// text or by structure, so restyling the block or the slider cannot turn
|
|
29
|
+
// these red.
|
|
30
|
+
it('renders the Dutch default label', () => {
|
|
31
|
+
const wrapper = mount(EditorRadius, { props: { modelValue: 'rounded-lg' } })
|
|
32
|
+
|
|
33
|
+
expect(wrapper.find('p').text()).toBe('Hoekafronding')
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it('renders the radius in pixels with the default unit', () => {
|
|
37
|
+
const wrapper = mount(EditorRadius, { props: { modelValue: 'rounded-lg' } })
|
|
38
|
+
|
|
39
|
+
expect(wrapper.text()).toContain('8 px')
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('renders a custom label', () => {
|
|
43
|
+
const wrapper = mount(EditorRadius, {
|
|
44
|
+
props: { modelValue: 'rounded-lg', label: 'Corner radius' },
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
expect(wrapper.find('p').text()).toBe('Corner radius')
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it('renders a custom unit', () => {
|
|
51
|
+
const wrapper = mount(EditorRadius, {
|
|
52
|
+
props: { modelValue: 'rounded-lg', messages: { unit: 'pixels' } },
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
expect(wrapper.text()).toContain('8 pixels')
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
// The tokens are not evenly spaced in px (0, 2, 4, 6, 8, 12, 16, 24, 32), so
|
|
59
|
+
// the slider steps over the list rather than over the px value.
|
|
60
|
+
it('puts the slider on the index of the value, not on its px size', () => {
|
|
61
|
+
const wrapper = mount(EditorRadius, { props: { modelValue: 'rounded-xl' } })
|
|
62
|
+
|
|
63
|
+
expect(sliderIndex(wrapper)).toEqual([5])
|
|
64
|
+
expect(wrapper.text()).toContain('12 px')
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
it('puts the slider on the index of a Tailwind default step', () => {
|
|
68
|
+
const wrapper = mount(EditorRadius, { props: { modelValue: 'rounded-4xl' } })
|
|
69
|
+
|
|
70
|
+
expect(sliderIndex(wrapper)).toEqual([8])
|
|
71
|
+
expect(wrapper.text()).toContain('32 px')
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
it('names the last step instead of measuring it', () => {
|
|
75
|
+
const wrapper = mount(EditorRadius, { props: { modelValue: 'rounded-full' } })
|
|
76
|
+
const thumb = wrapper.find('[role="slider"]')
|
|
77
|
+
|
|
78
|
+
expect(wrapper.text()).toContain('Rond')
|
|
79
|
+
expect(wrapper.text()).not.toContain('px')
|
|
80
|
+
expect(thumb.attributes('aria-valuetext')).toBe('Rond')
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
it('renders custom copy for the last step', () => {
|
|
84
|
+
const wrapper = mount(EditorRadius, {
|
|
85
|
+
props: { modelValue: 'rounded-full', messages: { full: 'Pill' } },
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
expect(wrapper.text()).toContain('Pill')
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
it('spans the whole step list', () => {
|
|
92
|
+
const wrapper = mount(EditorRadius, { props: { modelValue: 'rounded-none' } })
|
|
93
|
+
const slider = wrapper.findComponent(Slider)
|
|
94
|
+
|
|
95
|
+
expect(slider.props('min')).toBe(0)
|
|
96
|
+
expect(slider.props('max')).toBe(9)
|
|
97
|
+
expect(slider.props('step')).toBe(1)
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
it('emits update:modelValue with the Tailwind class of the new step', async () => {
|
|
101
|
+
const wrapper = mount(EditorRadius, { props: { modelValue: 'rounded-lg' } })
|
|
102
|
+
|
|
103
|
+
// Index 2 on the list is the `sm` token.
|
|
104
|
+
wrapper.findComponent(Slider).vm.$emit('update:modelValue', [2])
|
|
105
|
+
await wrapper.vm.$nextTick()
|
|
106
|
+
|
|
107
|
+
expect(wrapper.emitted('update:modelValue')).toEqual([['rounded-sm']])
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
it('falls back to the first step for a value outside the scale', () => {
|
|
111
|
+
// `rounded-5xl` is on neither the theme nor the Tailwind scale, so there is
|
|
112
|
+
// no step for it to sit on. The type rules it out, which is exactly why the
|
|
113
|
+
// runtime fallback is worth a test: a consumer restoring an old stored
|
|
114
|
+
// value gets past the types.
|
|
115
|
+
const outOfScale = 'rounded-5xl' as unknown as EditorRadiusValue
|
|
116
|
+
const wrapper = mount(EditorRadius, { props: { modelValue: outOfScale } })
|
|
117
|
+
|
|
118
|
+
expect(sliderIndex(wrapper)).toEqual([0])
|
|
119
|
+
expect(wrapper.text()).toContain('0 px')
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
// aria-valuenow is the step index, which is meaningless read aloud; the text
|
|
123
|
+
// the readout shows is what the thumb announces instead.
|
|
124
|
+
it('announces the radius in pixels on the thumb', () => {
|
|
125
|
+
const wrapper = mount(EditorRadius, { props: { modelValue: 'rounded-lg' } })
|
|
126
|
+
const thumb = wrapper.find('[role="slider"]')
|
|
127
|
+
|
|
128
|
+
expect(thumb.attributes('aria-valuetext')).toBe('8 px')
|
|
129
|
+
expect(thumb.attributes('aria-label')).toBe('Hoekafronding')
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
it('is always visible, so it renders no switch', () => {
|
|
133
|
+
const wrapper = mount(EditorRadius, { props: { modelValue: 'rounded-lg' } })
|
|
134
|
+
|
|
135
|
+
expect(wrapper.find('input[type="checkbox"]').exists()).toBe(false)
|
|
136
|
+
})
|
|
137
|
+
})
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite'
|
|
2
|
+
import { expect, userEvent, waitFor, within } from 'storybook/test'
|
|
3
|
+
import { ref } from 'vue'
|
|
4
|
+
import EditorShadow from './EditorShadow.vue'
|
|
5
|
+
import type { EditorShadowValue } from './EditorShadow.vue'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The collapsing wrapper, found by the grid row it animates rather than by any
|
|
9
|
+
* styling class, so restyling the block cannot quietly break the assertions.
|
|
10
|
+
*/
|
|
11
|
+
const contentWrapper = (canvasElement: HTMLElement) =>
|
|
12
|
+
canvasElement.querySelector('[class*="grid-rows-"]') as HTMLElement
|
|
13
|
+
|
|
14
|
+
export default {
|
|
15
|
+
title: 'Components/Editor Components/Molecules/Editor Shadow',
|
|
16
|
+
component: EditorShadow,
|
|
17
|
+
decorators: [() => ({ template: '<div class="w-100 mx-auto"><story /></div>' })],
|
|
18
|
+
argTypes: {
|
|
19
|
+
label: { control: 'text' },
|
|
20
|
+
switchable: { control: 'boolean' },
|
|
21
|
+
},
|
|
22
|
+
} satisfies Meta<typeof EditorShadow>
|
|
23
|
+
|
|
24
|
+
type Story = StoryObj<typeof EditorShadow>
|
|
25
|
+
|
|
26
|
+
export const Default: Story = {
|
|
27
|
+
render: (args) => ({
|
|
28
|
+
components: { EditorShadow },
|
|
29
|
+
setup() {
|
|
30
|
+
const shadow = ref<EditorShadowValue>('shadow-sm')
|
|
31
|
+
const enabled = ref(true)
|
|
32
|
+
return { args, shadow, enabled }
|
|
33
|
+
},
|
|
34
|
+
// The value is shown as-is: it is the Tailwind class the editor applies.
|
|
35
|
+
template: `
|
|
36
|
+
<div>
|
|
37
|
+
<EditorShadow v-bind="args" v-model="shadow" v-model:enabled="enabled" />
|
|
38
|
+
<p class="small-normal text-gray-700">{{ shadow }}</p>
|
|
39
|
+
<p class="small-normal text-gray-700">{{ enabled }}</p>
|
|
40
|
+
</div>
|
|
41
|
+
`,
|
|
42
|
+
}),
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Two things jsdom cannot see: a pick moves the value in the browser, and the
|
|
47
|
+
* collapse that follows leaves that value alone. Its own story, so that the
|
|
48
|
+
* default one stays open for whoever is looking at it.
|
|
49
|
+
*/
|
|
50
|
+
export const KeepsStrengthWhenSwitchedOff: Story = {
|
|
51
|
+
render: Default.render,
|
|
52
|
+
play: async ({ canvasElement }) => {
|
|
53
|
+
const canvas = within(canvasElement)
|
|
54
|
+
const content = contentWrapper(canvasElement)
|
|
55
|
+
|
|
56
|
+
await userEvent.click(canvas.getByRole('button', { name: 'Gemiddeld' }))
|
|
57
|
+
|
|
58
|
+
await waitFor(() => expect(canvas.getByText('shadow-md')).toBeInTheDocument())
|
|
59
|
+
expect(content).not.toHaveAttribute('inert')
|
|
60
|
+
|
|
61
|
+
await userEvent.click(canvas.getByRole('switch'))
|
|
62
|
+
|
|
63
|
+
await waitFor(() => {
|
|
64
|
+
expect(content).toHaveAttribute('inert')
|
|
65
|
+
expect(canvas.getByText('false')).toBeInTheDocument()
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
// The strength survives the collapse: only the switch state changed.
|
|
69
|
+
expect(canvas.getByText('shadow-md')).toBeInTheDocument()
|
|
70
|
+
},
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export const Disabled: Story = {
|
|
74
|
+
render: (args) => ({
|
|
75
|
+
components: { EditorShadow },
|
|
76
|
+
setup() {
|
|
77
|
+
const shadow = ref<EditorShadowValue>('shadow-lg')
|
|
78
|
+
const enabled = ref(false)
|
|
79
|
+
return { args, shadow, enabled }
|
|
80
|
+
},
|
|
81
|
+
template: `
|
|
82
|
+
<div>
|
|
83
|
+
<EditorShadow v-bind="args" v-model="shadow" v-model:enabled="enabled" />
|
|
84
|
+
<p class="small-normal text-gray-700">{{ shadow }}</p>
|
|
85
|
+
</div>
|
|
86
|
+
`,
|
|
87
|
+
}),
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export const CustomMessages: Story = {
|
|
91
|
+
args: {
|
|
92
|
+
label: 'Shadow',
|
|
93
|
+
messages: { strength: 'Strength', sm: 'Light', md: 'Medium', lg: 'Strong' },
|
|
94
|
+
},
|
|
95
|
+
render: (args) => ({
|
|
96
|
+
components: { EditorShadow },
|
|
97
|
+
setup() {
|
|
98
|
+
const shadow = ref<EditorShadowValue>('shadow-md')
|
|
99
|
+
return { args, shadow }
|
|
100
|
+
},
|
|
101
|
+
template: `<EditorShadow v-bind="args" v-model="shadow" />`,
|
|
102
|
+
}),
|
|
103
|
+
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from 'vitest'
|
|
2
|
+
import { mount, type VueWrapper } from '@vue/test-utils'
|
|
3
|
+
import EditorShadow, { EDITOR_SHADOW_OPTIONS } from './EditorShadow.vue'
|
|
4
|
+
import type { EditorShadowValue } from './EditorShadow.vue'
|
|
5
|
+
import NexxtToggleGroup from '../../../molecules/ToggleGroup/ToggleGroup.vue'
|
|
6
|
+
|
|
7
|
+
// ToggleGroup awaits document.fonts.ready on mount, which jsdom does not ship.
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
Object.defineProperty(document, 'fonts', {
|
|
10
|
+
value: { ready: Promise.resolve() },
|
|
11
|
+
configurable: true,
|
|
12
|
+
})
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
/** The names of the options, which are their visible text. */
|
|
16
|
+
const optionNames = (wrapper: VueWrapper) =>
|
|
17
|
+
wrapper.findAll('button').map((button) => button.text())
|
|
18
|
+
|
|
19
|
+
/** The option the toggle group is told to show as selected. */
|
|
20
|
+
const selectedOption = (wrapper: VueWrapper) =>
|
|
21
|
+
wrapper.findComponent(NexxtToggleGroup).props('modelValue')
|
|
22
|
+
|
|
23
|
+
/** The collapsing wrapper, found by the grid row it animates, not by styling. */
|
|
24
|
+
const contentWrapper = (wrapper: VueWrapper) => wrapper.find('[class*="grid-rows-"]')
|
|
25
|
+
|
|
26
|
+
describe('EditorShadow', () => {
|
|
27
|
+
// No assertions on typography utilities: copy is found by text or by
|
|
28
|
+
// structure, so restyling the block or the toggle group cannot turn these red.
|
|
29
|
+
it('renders the Dutch default label', () => {
|
|
30
|
+
const wrapper = mount(EditorShadow, { props: { modelValue: 'shadow-sm' } })
|
|
31
|
+
|
|
32
|
+
expect(wrapper.text()).toContain('Schaduw')
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('renders the Dutch default label above the strengths', () => {
|
|
36
|
+
const wrapper = mount(EditorShadow, { props: { modelValue: 'shadow-sm' } })
|
|
37
|
+
|
|
38
|
+
expect(wrapper.text()).toContain('Sterkte')
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('renders a button for each of the three strengths', () => {
|
|
42
|
+
const wrapper = mount(EditorShadow, { props: { modelValue: 'shadow-sm' } })
|
|
43
|
+
|
|
44
|
+
expect(wrapper.findAll('button')).toHaveLength(3)
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
it('names the strengths with the Dutch defaults', () => {
|
|
48
|
+
const wrapper = mount(EditorShadow, { props: { modelValue: 'shadow-sm' } })
|
|
49
|
+
|
|
50
|
+
expect(optionNames(wrapper)).toEqual(['Licht', 'Gemiddeld', 'Sterk'])
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('renders a custom label', () => {
|
|
54
|
+
const wrapper = mount(EditorShadow, {
|
|
55
|
+
props: { modelValue: 'shadow-sm', label: 'Shadow' },
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
expect(wrapper.text()).toContain('Shadow')
|
|
59
|
+
expect(wrapper.text()).not.toContain('Schaduw')
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
it('renders custom messages', () => {
|
|
63
|
+
const wrapper = mount(EditorShadow, {
|
|
64
|
+
props: {
|
|
65
|
+
modelValue: 'shadow-sm',
|
|
66
|
+
messages: { strength: 'Strength', sm: 'Light', md: 'Medium', lg: 'Strong' },
|
|
67
|
+
},
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
expect(wrapper.text()).toContain('Strength')
|
|
71
|
+
expect(optionNames(wrapper)).toEqual(['Light', 'Medium', 'Strong'])
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
it('keeps the untouched defaults when only one message is overridden', () => {
|
|
75
|
+
const wrapper = mount(EditorShadow, {
|
|
76
|
+
props: { modelValue: 'shadow-sm', messages: { md: 'Medium' } },
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
expect(wrapper.text()).toContain('Sterkte')
|
|
80
|
+
expect(optionNames(wrapper)).toEqual(['Licht', 'Medium', 'Sterk'])
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
it('shows the strength of the model as the selected one', () => {
|
|
84
|
+
const wrapper = mount(EditorShadow, { props: { modelValue: 'shadow-lg' } })
|
|
85
|
+
|
|
86
|
+
expect(selectedOption(wrapper)).toBe('shadow-lg')
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it('emits update:modelValue with the Tailwind class of the clicked strength', async () => {
|
|
90
|
+
const wrapper = mount(EditorShadow, { props: { modelValue: 'shadow-sm' } })
|
|
91
|
+
|
|
92
|
+
await wrapper.findAll('button')[1].trigger('click')
|
|
93
|
+
await wrapper.findAll('button')[2].trigger('click')
|
|
94
|
+
|
|
95
|
+
expect(wrapper.emitted('update:modelValue')).toEqual([['shadow-md'], ['shadow-lg']])
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
it('shows the first strength for a value outside the list', () => {
|
|
99
|
+
// `shadow-xl` is on the theme scale but not among the options, so there is
|
|
100
|
+
// no option for it to sit on. The type rules it out, which is exactly why
|
|
101
|
+
// the runtime fallback is worth a test: a consumer restoring an old stored
|
|
102
|
+
// value gets past the types.
|
|
103
|
+
const outOfList = 'shadow-xl' as unknown as EditorShadowValue
|
|
104
|
+
const wrapper = mount(EditorShadow, { props: { modelValue: outOfList } })
|
|
105
|
+
|
|
106
|
+
expect(selectedOption(wrapper)).toBe('shadow-sm')
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
it('follows the model when the parent changes it', async () => {
|
|
110
|
+
const wrapper = mount(EditorShadow, { props: { modelValue: 'shadow-sm' } })
|
|
111
|
+
|
|
112
|
+
await wrapper.setProps({ modelValue: 'shadow-md' })
|
|
113
|
+
|
|
114
|
+
expect(selectedOption(wrapper)).toBe('shadow-md')
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
it('emits update:enabled when the switch is toggled', async () => {
|
|
118
|
+
const wrapper = mount(EditorShadow, { props: { modelValue: 'shadow-sm', enabled: true } })
|
|
119
|
+
|
|
120
|
+
await wrapper.find('input[type="checkbox"]').setValue(false)
|
|
121
|
+
|
|
122
|
+
expect(wrapper.emitted('update:enabled')).toEqual([[false]])
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
it('leaves the strength alone when the switch is toggled', async () => {
|
|
126
|
+
const wrapper = mount(EditorShadow, { props: { modelValue: 'shadow-lg', enabled: true } })
|
|
127
|
+
|
|
128
|
+
await wrapper.find('input[type="checkbox"]').setValue(false)
|
|
129
|
+
|
|
130
|
+
expect(wrapper.emitted('update:modelValue')).toBeUndefined()
|
|
131
|
+
expect(selectedOption(wrapper)).toBe('shadow-lg')
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
it('makes the strengths inert when enabled is false', () => {
|
|
135
|
+
const wrapper = mount(EditorShadow, { props: { modelValue: 'shadow-sm', enabled: false } })
|
|
136
|
+
|
|
137
|
+
expect(contentWrapper(wrapper).attributes('inert')).toBeDefined()
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
it('keeps the strengths interactive when enabled is true', () => {
|
|
141
|
+
const wrapper = mount(EditorShadow, { props: { modelValue: 'shadow-sm', enabled: true } })
|
|
142
|
+
|
|
143
|
+
expect(contentWrapper(wrapper).attributes('inert')).toBeUndefined()
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
// Switchable by default, like the border: a shadow is off as often as it is on.
|
|
147
|
+
it('renders the switch by default', () => {
|
|
148
|
+
const wrapper = mount(EditorShadow, { props: { modelValue: 'shadow-sm' } })
|
|
149
|
+
|
|
150
|
+
expect(wrapper.find('input[type="checkbox"]').exists()).toBe(true)
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
it('renders no switch when switchable is false', () => {
|
|
154
|
+
const wrapper = mount(EditorShadow, {
|
|
155
|
+
props: { modelValue: 'shadow-sm', switchable: false },
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
expect(wrapper.find('input[type="checkbox"]').exists()).toBe(false)
|
|
159
|
+
})
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
// The consumer derives its class matchers from this list, so the list is a
|
|
163
|
+
// contract: any change here changes what the app recognises.
|
|
164
|
+
describe('EDITOR_SHADOW_OPTIONS', () => {
|
|
165
|
+
it('offers exactly the agreed strengths', () => {
|
|
166
|
+
expect(EDITOR_SHADOW_OPTIONS).toEqual([{ token: 'sm' }, { token: 'md' }, { token: 'lg' }])
|
|
167
|
+
})
|
|
168
|
+
})
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite'
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
import { expect, userEvent, waitFor, within } from 'storybook/test'
|
|
4
|
+
import EditorSize from './EditorSize.vue'
|
|
5
|
+
import type { EditorSizeValue } from './EditorSize.vue'
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
title: 'Components/Editor Components/Molecules/Editor Size',
|
|
9
|
+
component: EditorSize,
|
|
10
|
+
decorators: [() => ({ template: '<div class="w-100 mx-auto"><story /></div>' })],
|
|
11
|
+
argTypes: {
|
|
12
|
+
label: { control: 'text' },
|
|
13
|
+
},
|
|
14
|
+
} satisfies Meta<typeof EditorSize>
|
|
15
|
+
|
|
16
|
+
type Story = StoryObj<typeof EditorSize>
|
|
17
|
+
|
|
18
|
+
const render = (args: Story['args'], initial: EditorSizeValue) => ({
|
|
19
|
+
components: { EditorSize },
|
|
20
|
+
setup() {
|
|
21
|
+
const size = ref(initial)
|
|
22
|
+
return { args, size }
|
|
23
|
+
},
|
|
24
|
+
template: `
|
|
25
|
+
<div>
|
|
26
|
+
<EditorSize v-bind="args" v-model="size" />
|
|
27
|
+
<p data-testid="size-value" class="small-normal text-gray-700">{{ JSON.stringify(size) }}</p>
|
|
28
|
+
</div>
|
|
29
|
+
`,
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
export const Default: Story = {
|
|
33
|
+
args: { label: 'Breedte' },
|
|
34
|
+
render: (args) => render(args, { mode: 'auto' }),
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Picking Vast opens the field under the toggle. The model already carries a
|
|
39
|
+
* fixed size -- what a consumer measured, say -- so the field starts there.
|
|
40
|
+
*/
|
|
41
|
+
export const OpensOnFixed: Story = {
|
|
42
|
+
args: { label: 'Breedte' },
|
|
43
|
+
render: (args) => render(args, { mode: 'fill', fixed: { value: 480, unit: 'px' } }),
|
|
44
|
+
play: async ({ canvasElement }) => {
|
|
45
|
+
const canvas = within(canvasElement)
|
|
46
|
+
const row = canvasElement.querySelector('[data-testid="editor-size-fixed-row"]')!
|
|
47
|
+
|
|
48
|
+
expect(row.getAttribute('inert')).not.toBeNull()
|
|
49
|
+
|
|
50
|
+
await userEvent.click(canvas.getByRole('button', { name: 'Breedte vast' }))
|
|
51
|
+
|
|
52
|
+
await waitFor(() => expect(row.getAttribute('inert')).toBeNull())
|
|
53
|
+
expect(
|
|
54
|
+
(canvas.getByRole('spinbutton', { name: 'Breedte (px)' }) as HTMLInputElement).value,
|
|
55
|
+
).toBe('480')
|
|
56
|
+
},
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** The Vast state, px only. */
|
|
60
|
+
export const Fixed: Story = {
|
|
61
|
+
args: { label: 'Hoogte' },
|
|
62
|
+
render: (args) => render(args, { mode: 'fixed', fixed: { value: 320, unit: 'px' } }),
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** The Vast state with px and %. */
|
|
66
|
+
export const FixedWithPercent: Story = {
|
|
67
|
+
args: { label: 'Breedte', units: ['px', '%'] },
|
|
68
|
+
render: (args) => render(args, { mode: 'fixed', fixed: { value: 50, unit: '%' } }),
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export const CustomMessages: Story = {
|
|
72
|
+
args: {
|
|
73
|
+
label: 'Width',
|
|
74
|
+
units: ['px', '%'],
|
|
75
|
+
messages: { auto: 'Hug', fill: 'Fill', fixed: 'Fixed', unit: 'Unit' },
|
|
76
|
+
},
|
|
77
|
+
render: (args) => render(args, { mode: 'fixed', fixed: { value: 320, unit: 'px' } }),
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** An image has nothing to fill, so it is offered Automatisch and Vast only. */
|
|
81
|
+
export const WithoutFill: Story = {
|
|
82
|
+
args: { label: 'Breedte', modes: ['auto', 'fixed'] },
|
|
83
|
+
render: (args) => render(args, { mode: 'auto' }),
|
|
84
|
+
}
|