fds-vue-core 2.1.4 → 2.1.6
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/components.d.ts +8 -0
- package/configs/tsconfig.base.json +2 -1
- package/dist/fds-vue-core.cjs.js +35 -15
- package/dist/fds-vue-core.cjs.js.map +1 -1
- package/dist/fds-vue-core.es.js +35 -15
- package/dist/fds-vue-core.es.js.map +1 -1
- package/dist/global-components.d.ts +35 -33
- package/package.json +23 -21
- package/src/.DS_Store +0 -0
- package/src/App.vue +133 -0
- package/src/apply.css +60 -0
- package/src/assets/icons.ts +517 -0
- package/src/components/Blocks/FdsBlockAlert/FdsBlockAlert.stories.ts +94 -0
- package/src/components/Blocks/FdsBlockAlert/FdsBlockAlert.vue +112 -0
- package/src/components/Blocks/FdsBlockAlert/types.ts +12 -0
- package/src/components/Blocks/FdsBlockContent/FdsBlockContent.stories.ts +110 -0
- package/src/components/Blocks/FdsBlockContent/FdsBlockContent.vue +66 -0
- package/src/components/Blocks/FdsBlockContent/types.ts +6 -0
- package/src/components/Blocks/FdsBlockExpander/FdsBlockExpander.stories.ts +123 -0
- package/src/components/Blocks/FdsBlockExpander/FdsBlockExpander.vue +87 -0
- package/src/components/Blocks/FdsBlockExpander/types.ts +8 -0
- package/src/components/Blocks/FdsBlockInfo/FdsBlockInfo.stories.ts +110 -0
- package/src/components/Blocks/FdsBlockInfo/FdsBlockInfo.vue +75 -0
- package/src/components/Blocks/FdsBlockInfo/types.ts +9 -0
- package/src/components/Blocks/FdsBlockLink/FdsBlockLink.css +9 -0
- package/src/components/Blocks/FdsBlockLink/FdsBlockLink.stories.ts +179 -0
- package/src/components/Blocks/FdsBlockLink/FdsBlockLink.vue +149 -0
- package/src/components/Blocks/FdsBlockLink/types.ts +14 -0
- package/src/components/Buttons/ButtonBaseProps.ts +18 -0
- package/src/components/Buttons/FdsButtonCopy/FdsButtonCopy.stories.ts +53 -0
- package/src/components/Buttons/FdsButtonCopy/FdsButtonCopy.vue +87 -0
- package/src/components/Buttons/FdsButtonCopy/types.ts +8 -0
- package/src/components/Buttons/FdsButtonDownload/FdsButtonDownload.stories.ts +111 -0
- package/src/components/Buttons/FdsButtonDownload/FdsButtonDownload.vue +187 -0
- package/src/components/Buttons/FdsButtonIcon/FdsButtonIcon.stories.ts +55 -0
- package/src/components/Buttons/FdsButtonIcon/FdsButtonIcon.vue +57 -0
- package/src/components/Buttons/FdsButtonIcon/types.ts +12 -0
- package/src/components/Buttons/FdsButtonMinor/FdsButtonMinor.stories.ts +68 -0
- package/src/components/Buttons/FdsButtonMinor/FdsButtonMinor.vue +126 -0
- package/src/components/Buttons/FdsButtonPrimary/FdsButtonPrimary.stories.ts +86 -0
- package/src/components/Buttons/FdsButtonPrimary/FdsButtonPrimary.vue +107 -0
- package/src/components/Buttons/FdsButtonSecondary/FdsButtonSecondary.stories.ts +68 -0
- package/src/components/Buttons/FdsButtonSecondary/FdsButtonSecondary.vue +107 -0
- package/src/components/FdsIcon/FdsIcon.stories.ts +69 -0
- package/src/components/FdsIcon/FdsIcon.vue +34 -0
- package/src/components/FdsIcon/types.ts +9 -0
- package/src/components/FdsModal/FdsModal.stories.ts +241 -0
- package/src/components/FdsModal/FdsModal.vue +269 -0
- package/src/components/FdsModal/types.ts +12 -0
- package/src/components/FdsPagination/FdsPagination.stories.ts +109 -0
- package/src/components/FdsPagination/FdsPagination.vue +193 -0
- package/src/components/FdsPagination/types.ts +6 -0
- package/src/components/FdsSearchSelect/FdsSearchSelect.stories.ts +428 -0
- package/src/components/FdsSearchSelect/FdsSearchSelect.vue +621 -0
- package/src/components/FdsSearchSelect/types.ts +25 -0
- package/src/components/FdsSpinner/FdsSpinner.stories.ts +31 -0
- package/src/components/FdsSpinner/FdsSpinner.vue +90 -0
- package/src/components/FdsSpinner/types.ts +6 -0
- package/src/components/FdsSticker/FdsSticker.stories.ts +148 -0
- package/src/components/FdsSticker/FdsSticker.vue +44 -0
- package/src/components/FdsSticker/types.ts +4 -0
- package/src/components/FdsTreeView/FdsTreeView.stories.ts +136 -0
- package/src/components/FdsTreeView/FdsTreeView.vue +162 -0
- package/src/components/FdsTreeView/TreeNode.vue +383 -0
- package/src/components/FdsTreeView/types.ts +141 -0
- package/src/components/FdsTreeView/useTreeState.ts +607 -0
- package/src/components/FdsTreeView/utils.ts +69 -0
- package/src/components/FdsTruncatedText/FdsTruncatedText.stories.ts +78 -0
- package/src/components/FdsTruncatedText/FdsTruncatedText.vue +85 -0
- package/src/components/FdsTruncatedText/types.ts +6 -0
- package/src/components/Form/FdsCheckbox/FdsCheckbox.stories.ts +275 -0
- package/src/components/Form/FdsCheckbox/FdsCheckbox.vue +155 -0
- package/src/components/Form/FdsCheckbox/types.ts +10 -0
- package/src/components/Form/FdsInput/FdsInput.stories.ts +319 -0
- package/src/components/Form/FdsInput/FdsInput.vue +233 -0
- package/src/components/Form/FdsInput/types.ts +25 -0
- package/src/components/Form/FdsRadio/FdsRadio.stories.ts +63 -0
- package/src/components/Form/FdsRadio/FdsRadio.vue +88 -0
- package/src/components/Form/FdsRadio/types.ts +12 -0
- package/src/components/Form/FdsSelect/FdsSelect.stories.ts +78 -0
- package/src/components/Form/FdsSelect/FdsSelect.vue +136 -0
- package/src/components/Form/FdsSelect/types.ts +13 -0
- package/src/components/Form/FdsTextarea/FdsTextarea.stories.ts +52 -0
- package/src/components/Form/FdsTextarea/FdsTextarea.vue +110 -0
- package/src/components/Form/FdsTextarea/types.ts +12 -0
- package/src/components/Table/FdsTable/FdsTable.stories.ts +221 -0
- package/src/components/Table/FdsTable/FdsTable.vue +25 -0
- package/src/components/Table/FdsTable/types.ts +4 -0
- package/src/components/Table/FdsTableHead/FdsTableHead.stories.ts +151 -0
- package/src/components/Table/FdsTableHead/FdsTableHead.vue +54 -0
- package/src/components/Table/FdsTableHead/types.ts +5 -0
- package/src/components/Tabs/FdsTabs/FdsTabs.stories.ts +247 -0
- package/src/components/Tabs/FdsTabs/FdsTabs.vue +27 -0
- package/src/components/Tabs/FdsTabs/types.ts +4 -0
- package/src/components/Tabs/FdsTabsItem/FdsTabsItem.vue +125 -0
- package/src/components/Tabs/FdsTabsItem/types.ts +16 -0
- package/src/components/Typography/FdsHeading/FdsHeading.stories.ts +93 -0
- package/src/components/Typography/FdsHeading/FdsHeading.vue +51 -0
- package/src/components/Typography/FdsHeading/types.ts +5 -0
- package/src/components/Typography/FdsListHeading/FdsListHeading.stories.ts +58 -0
- package/src/components/Typography/FdsListHeading/FdsListHeading.vue +62 -0
- package/src/components/Typography/FdsListHeading/types.ts +8 -0
- package/src/components/Typography/FdsSeparator/FdsSeparator.stories.ts +31 -0
- package/src/components/Typography/FdsSeparator/FdsSeparator.vue +5 -0
- package/src/components/Typography/FdsText/FdsText.stories.ts +66 -0
- package/src/components/Typography/FdsText/FdsText.vue +28 -0
- package/src/components/Typography/FdsText/types.ts +3 -0
- package/src/composables/useBoldQuery.ts +29 -0
- package/src/composables/useElementFinalSize.ts +24 -0
- package/src/composables/useHasSlots.ts +17 -0
- package/src/composables/useIsPid.ts +48 -0
- package/src/docs/Start/Start.mdx +12 -0
- package/src/docs/Usage.md +117 -0
- package/src/fonts.css +28 -0
- package/src/global-components.ts +75 -0
- package/src/index.ts +180 -0
- package/src/main.ts +7 -0
- package/src/slot-styles.css +93 -0
- package/src/style.css +89 -0
- package/src/tokens.css +252 -0
- package/dist/index.d.ts +0 -2
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, ref, watch } from 'vue'
|
|
3
|
+
import FdsButtonIcon from '@/components/Buttons/FdsButtonIcon/FdsButtonIcon.vue'
|
|
4
|
+
import FdsSpinner from '@/components/FdsSpinner/FdsSpinner.vue'
|
|
5
|
+
import FdsInput from '@/components/Form/FdsInput/FdsInput.vue'
|
|
6
|
+
import type { FdsPaginationProps } from './types'
|
|
7
|
+
|
|
8
|
+
const props = withDefaults(defineProps<FdsPaginationProps>(), {
|
|
9
|
+
id: undefined,
|
|
10
|
+
loading: false,
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
const emit = defineEmits<{
|
|
14
|
+
(e: 'paginate', payload: { target: { id: string }; detail: number }): void
|
|
15
|
+
}>()
|
|
16
|
+
|
|
17
|
+
const loadingIndicator = ref<'start' | 'prev' | 'input' | 'next' | 'end' | ''>('')
|
|
18
|
+
const internalValue = ref(props.current)
|
|
19
|
+
|
|
20
|
+
const autoId = `fds-pagination-${Math.random().toString(36).slice(2, 9)}`
|
|
21
|
+
const inputId = computed(() => props.id ?? autoId)
|
|
22
|
+
|
|
23
|
+
const inputValue = computed(() => String(internalValue.value))
|
|
24
|
+
|
|
25
|
+
watch(
|
|
26
|
+
() => props.current,
|
|
27
|
+
(newValue) => {
|
|
28
|
+
internalValue.value = newValue
|
|
29
|
+
},
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
const debounce = <T extends (...args: any[]) => void>(fn: T, delay = 300) => {
|
|
33
|
+
let timer: ReturnType<typeof setTimeout>
|
|
34
|
+
return (...args: Parameters<T>) => {
|
|
35
|
+
clearTimeout(timer)
|
|
36
|
+
timer = setTimeout(() => {
|
|
37
|
+
fn(...args)
|
|
38
|
+
}, delay)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const handlePageChange = debounce((event: Event) => {
|
|
43
|
+
const target = event.target as HTMLInputElement
|
|
44
|
+
const incomingPage = Number.parseInt(target.value)
|
|
45
|
+
|
|
46
|
+
if (Number.isNaN(incomingPage)) {
|
|
47
|
+
internalValue.value = props.current
|
|
48
|
+
return
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
loadingIndicator.value = 'input'
|
|
52
|
+
|
|
53
|
+
let page = props.current
|
|
54
|
+
if (incomingPage > props.max) {
|
|
55
|
+
page = props.max
|
|
56
|
+
} else if (incomingPage < 1) {
|
|
57
|
+
page = 1
|
|
58
|
+
} else {
|
|
59
|
+
page = incomingPage
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
internalValue.value = page
|
|
63
|
+
emit('paginate', { target: { id: inputId.value }, detail: page })
|
|
64
|
+
}, 500)
|
|
65
|
+
|
|
66
|
+
const handlePagination = (action: 'start' | 'prev' | 'next' | 'end') => {
|
|
67
|
+
let page = 0
|
|
68
|
+
|
|
69
|
+
switch (action) {
|
|
70
|
+
case 'start':
|
|
71
|
+
if (props.current === 1) return
|
|
72
|
+
loadingIndicator.value = 'start'
|
|
73
|
+
page = 1
|
|
74
|
+
break
|
|
75
|
+
case 'prev':
|
|
76
|
+
if (props.current === 1) return
|
|
77
|
+
loadingIndicator.value = 'prev'
|
|
78
|
+
page = props.current === 1 ? props.current : props.current - 1
|
|
79
|
+
break
|
|
80
|
+
case 'next':
|
|
81
|
+
if (props.current === props.max) return
|
|
82
|
+
loadingIndicator.value = 'next'
|
|
83
|
+
page = props.current === props.max ? props.current : props.current + 1
|
|
84
|
+
break
|
|
85
|
+
case 'end':
|
|
86
|
+
if (props.current === props.max) return
|
|
87
|
+
loadingIndicator.value = 'end'
|
|
88
|
+
page = props.max
|
|
89
|
+
break
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
emit('paginate', { target: { id: inputId.value }, detail: page })
|
|
93
|
+
}
|
|
94
|
+
</script>
|
|
95
|
+
|
|
96
|
+
<template>
|
|
97
|
+
<div
|
|
98
|
+
class="my-6 flex items-between justify-between gap-2"
|
|
99
|
+
:id="inputId"
|
|
100
|
+
>
|
|
101
|
+
<!-- Prev -->
|
|
102
|
+
<div class="flex items-center justify-start gap-1 w-[100px]">
|
|
103
|
+
<FdsSpinner
|
|
104
|
+
v-if="loading && loadingIndicator === 'start'"
|
|
105
|
+
size="32px"
|
|
106
|
+
color="blue"
|
|
107
|
+
/>
|
|
108
|
+
<FdsButtonIcon
|
|
109
|
+
v-else
|
|
110
|
+
icon="first"
|
|
111
|
+
:size="28"
|
|
112
|
+
:disabled="current === 1"
|
|
113
|
+
:ariaDisabled="current === 1"
|
|
114
|
+
:class="{ 'hidden!': current === 1 }"
|
|
115
|
+
class="w-8 h-8 sm:w-12 sm:h-12"
|
|
116
|
+
@click="handlePagination('start')"
|
|
117
|
+
/>
|
|
118
|
+
|
|
119
|
+
<FdsSpinner
|
|
120
|
+
v-if="loading && loadingIndicator === 'prev'"
|
|
121
|
+
size="24px"
|
|
122
|
+
color="blue"
|
|
123
|
+
/>
|
|
124
|
+
<FdsButtonIcon
|
|
125
|
+
v-else
|
|
126
|
+
icon="arrowLeft"
|
|
127
|
+
:size="28"
|
|
128
|
+
:disabled="current === 1"
|
|
129
|
+
:ariaDisabled="current === 1"
|
|
130
|
+
:class="{ 'hidden!': current === 1 }"
|
|
131
|
+
class="w-8 h-8 sm:w-12 sm:h-12"
|
|
132
|
+
@click="handlePagination('prev')"
|
|
133
|
+
/>
|
|
134
|
+
</div>
|
|
135
|
+
|
|
136
|
+
<!-- Numbers -->
|
|
137
|
+
<div class="flex items-center justify-center w-auto gap-2 order-0 sm:order-0">
|
|
138
|
+
<FdsSpinner
|
|
139
|
+
v-if="loading && loadingIndicator === 'input'"
|
|
140
|
+
size="24px"
|
|
141
|
+
color="blue"
|
|
142
|
+
label="Laddar"
|
|
143
|
+
label-position="right"
|
|
144
|
+
/>
|
|
145
|
+
<template v-else>
|
|
146
|
+
<FdsInput
|
|
147
|
+
:value="inputValue"
|
|
148
|
+
type="text"
|
|
149
|
+
:size="max.toString().length"
|
|
150
|
+
:maxlength="max.toString().length"
|
|
151
|
+
@input="handlePageChange"
|
|
152
|
+
class="mb-0! text-center"
|
|
153
|
+
/>
|
|
154
|
+
<div class="whitespace-nowrap">/ {{ max }}</div>
|
|
155
|
+
</template>
|
|
156
|
+
</div>
|
|
157
|
+
|
|
158
|
+
<!-- Next -->
|
|
159
|
+
<div class="flex items-center justify-end gap-1 order-2 sm:order-0 w-[100px]">
|
|
160
|
+
<FdsSpinner
|
|
161
|
+
v-if="loading && loadingIndicator === 'next'"
|
|
162
|
+
size="24px"
|
|
163
|
+
color="blue"
|
|
164
|
+
/>
|
|
165
|
+
<FdsButtonIcon
|
|
166
|
+
v-else
|
|
167
|
+
icon="arrowRight"
|
|
168
|
+
:size="28"
|
|
169
|
+
:disabled="current === max"
|
|
170
|
+
:ariaDisabled="current === max"
|
|
171
|
+
:class="{ 'hidden!': current === max }"
|
|
172
|
+
class="w-8 h-8 sm:w-12 sm:h-12"
|
|
173
|
+
@click="handlePagination('next')"
|
|
174
|
+
/>
|
|
175
|
+
|
|
176
|
+
<FdsSpinner
|
|
177
|
+
v-if="loading && loadingIndicator === 'end'"
|
|
178
|
+
size="24px"
|
|
179
|
+
color="blue"
|
|
180
|
+
/>
|
|
181
|
+
<FdsButtonIcon
|
|
182
|
+
v-else
|
|
183
|
+
icon="last"
|
|
184
|
+
:size="28"
|
|
185
|
+
:disabled="current === max"
|
|
186
|
+
:ariaDisabled="current === max"
|
|
187
|
+
:class="{ 'hidden!': current === max }"
|
|
188
|
+
class="w-8 h-8 sm:w-12 sm:h-12"
|
|
189
|
+
@click="handlePagination('end')"
|
|
190
|
+
/>
|
|
191
|
+
</div>
|
|
192
|
+
</div>
|
|
193
|
+
</template>
|
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3'
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
import FdsSearchSelect from './FdsSearchSelect.vue'
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof FdsSearchSelect> = {
|
|
6
|
+
title: 'FDS/Form/FdsSearchSelect',
|
|
7
|
+
component: FdsSearchSelect,
|
|
8
|
+
tags: ['autodocs'],
|
|
9
|
+
argTypes: {
|
|
10
|
+
items: {
|
|
11
|
+
control: { type: 'object' },
|
|
12
|
+
description: 'Array of items to display in the search select dropdown',
|
|
13
|
+
},
|
|
14
|
+
page: {
|
|
15
|
+
control: { type: 'number' },
|
|
16
|
+
description: 'Current page number for server-side pagination',
|
|
17
|
+
},
|
|
18
|
+
totalPages: {
|
|
19
|
+
control: { type: 'number' },
|
|
20
|
+
description: 'Total number of pages for server-side pagination',
|
|
21
|
+
},
|
|
22
|
+
totalCount: {
|
|
23
|
+
control: { type: 'number' },
|
|
24
|
+
description: 'Total count of unfiltered items (displayed as "x av y")',
|
|
25
|
+
},
|
|
26
|
+
loading: {
|
|
27
|
+
control: { type: 'boolean' },
|
|
28
|
+
description: 'Shows loading spinner in the dropdown when true',
|
|
29
|
+
},
|
|
30
|
+
searchFields: {
|
|
31
|
+
control: { type: 'object' },
|
|
32
|
+
description: 'Array of field names to search in (e.g., ["fullName", "email"])',
|
|
33
|
+
},
|
|
34
|
+
preserveOrder: {
|
|
35
|
+
control: { type: 'boolean' },
|
|
36
|
+
description: 'If true, preserves the order of searchFields when displaying results',
|
|
37
|
+
},
|
|
38
|
+
initialValue: {
|
|
39
|
+
control: { type: 'text' },
|
|
40
|
+
description: 'Initial value to display in the input field',
|
|
41
|
+
},
|
|
42
|
+
disabled: {
|
|
43
|
+
control: { type: 'boolean' },
|
|
44
|
+
description: 'Disables the search select component',
|
|
45
|
+
},
|
|
46
|
+
dropdownAbsolute: {
|
|
47
|
+
control: { type: 'boolean' },
|
|
48
|
+
description: 'If true, positions the dropdown absolutely',
|
|
49
|
+
},
|
|
50
|
+
labelLeft: {
|
|
51
|
+
control: { type: 'boolean' },
|
|
52
|
+
description: 'If true, positions the label to the left of the input',
|
|
53
|
+
},
|
|
54
|
+
label: {
|
|
55
|
+
control: { type: 'text' },
|
|
56
|
+
description: 'Label text for the input field',
|
|
57
|
+
},
|
|
58
|
+
meta: {
|
|
59
|
+
control: { type: 'text' },
|
|
60
|
+
description: 'Meta text displayed below the label',
|
|
61
|
+
},
|
|
62
|
+
singleItemLabel: {
|
|
63
|
+
control: { type: 'text' },
|
|
64
|
+
description: 'Label text displayed when a single item is shown',
|
|
65
|
+
},
|
|
66
|
+
searchContext: {
|
|
67
|
+
control: { type: 'object' },
|
|
68
|
+
description: 'Context object with "context" and "linkWord" for displaying search results count',
|
|
69
|
+
},
|
|
70
|
+
valid: {
|
|
71
|
+
control: { type: 'select' },
|
|
72
|
+
options: ['true', 'false', 'null'],
|
|
73
|
+
description: 'Validation state: "true" for valid, "false" for invalid, "null" for neutral',
|
|
74
|
+
},
|
|
75
|
+
invalidMessage: {
|
|
76
|
+
control: { type: 'text' },
|
|
77
|
+
description: 'Error message displayed when validation is false',
|
|
78
|
+
},
|
|
79
|
+
noResultPrompt: {
|
|
80
|
+
control: { type: 'text' },
|
|
81
|
+
description: 'Message displayed when no search results are found',
|
|
82
|
+
},
|
|
83
|
+
borderless: {
|
|
84
|
+
control: { type: 'boolean' },
|
|
85
|
+
description: 'If true, removes borders from the dropdown list',
|
|
86
|
+
},
|
|
87
|
+
marginless: {
|
|
88
|
+
control: { type: 'boolean' },
|
|
89
|
+
description: 'If true, removes bottom margin from the component',
|
|
90
|
+
},
|
|
91
|
+
maxListHeight: {
|
|
92
|
+
control: { type: 'number' },
|
|
93
|
+
description: 'Maximum height of the dropdown list in pixels',
|
|
94
|
+
},
|
|
95
|
+
locale: {
|
|
96
|
+
control: { type: 'select' },
|
|
97
|
+
options: ['sv', 'en'],
|
|
98
|
+
description: 'Locale for translations ("sv" for Swedish, "en" for English)',
|
|
99
|
+
},
|
|
100
|
+
clearTrigger: {
|
|
101
|
+
control: { type: 'boolean' },
|
|
102
|
+
description: 'When set to true, clears the search input and selection',
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
args: {
|
|
106
|
+
items: [],
|
|
107
|
+
searchFields: ['companyName', 'orgNumber'],
|
|
108
|
+
preserveOrder: false,
|
|
109
|
+
initialValue: '',
|
|
110
|
+
disabled: false,
|
|
111
|
+
dropdownAbsolute: false,
|
|
112
|
+
labelLeft: false,
|
|
113
|
+
label: 'Sök organisation',
|
|
114
|
+
meta: undefined,
|
|
115
|
+
singleItemLabel: 'Vald organisation',
|
|
116
|
+
searchContext: { context: 'organisationer', linkWord: 'av' },
|
|
117
|
+
valid: undefined,
|
|
118
|
+
invalidMessage: 'Vänligen välj en organisation',
|
|
119
|
+
noResultPrompt: 'Inga resultat hittades',
|
|
120
|
+
borderless: false,
|
|
121
|
+
marginless: false,
|
|
122
|
+
maxListHeight: undefined,
|
|
123
|
+
locale: 'sv',
|
|
124
|
+
clearTrigger: false,
|
|
125
|
+
},
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export default meta
|
|
129
|
+
type Story = StoryObj<typeof meta>
|
|
130
|
+
|
|
131
|
+
// Mock data for items examples
|
|
132
|
+
const mockItems = [
|
|
133
|
+
{
|
|
134
|
+
companyName: 'Acme Corporation',
|
|
135
|
+
orgNumber: '1234567890',
|
|
136
|
+
companyFqn: 'Acme Corporation | 1234567890',
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
companyName: 'Tech Solutions AB',
|
|
140
|
+
orgNumber: '9876543210',
|
|
141
|
+
companyFqn: 'Tech Solutions AB | 9876543210',
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
companyName: 'Global Industries',
|
|
145
|
+
orgNumber: '5555555555',
|
|
146
|
+
companyFqn: 'Global Industries | 5555555555',
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
companyName: 'Nordic Ventures',
|
|
150
|
+
orgNumber: '1111111111',
|
|
151
|
+
companyFqn: 'Nordic Ventures | 1111111111',
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
companyName: 'Scandinavian Group',
|
|
155
|
+
orgNumber: '2222222222',
|
|
156
|
+
companyFqn: 'Scandinavian Group | 2222222222',
|
|
157
|
+
},
|
|
158
|
+
]
|
|
159
|
+
|
|
160
|
+
export const WithItems: Story = {
|
|
161
|
+
render: (args) => ({
|
|
162
|
+
components: { FdsSearchSelect },
|
|
163
|
+
setup: () => {
|
|
164
|
+
const selected = ref<Record<string, unknown> | null>(null)
|
|
165
|
+
const handleSearchSelected = (value: Record<string, unknown> | null) => {
|
|
166
|
+
selected.value = value
|
|
167
|
+
}
|
|
168
|
+
return { args, selected, handleSearchSelected }
|
|
169
|
+
},
|
|
170
|
+
template: `
|
|
171
|
+
<FdsSearchSelect
|
|
172
|
+
v-bind="args"
|
|
173
|
+
:items="args.items"
|
|
174
|
+
@searchSelected="handleSearchSelected"
|
|
175
|
+
/>
|
|
176
|
+
|
|
177
|
+
`,
|
|
178
|
+
}),
|
|
179
|
+
args: {
|
|
180
|
+
items: mockItems,
|
|
181
|
+
label: 'Sök bland organisationer',
|
|
182
|
+
meta: 'Börja skriva för att söka',
|
|
183
|
+
},
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export const WithSelectedEarlier: Story = {
|
|
187
|
+
render: (args) => ({
|
|
188
|
+
components: { FdsSearchSelect },
|
|
189
|
+
setup: () => {
|
|
190
|
+
const selected = ref<Record<string, unknown> | null>(null)
|
|
191
|
+
const handleSearchSelected = (value: Record<string, unknown> | null) => {
|
|
192
|
+
selected.value = value
|
|
193
|
+
}
|
|
194
|
+
return { args, selected, handleSearchSelected }
|
|
195
|
+
},
|
|
196
|
+
template: `
|
|
197
|
+
<FdsSearchSelect
|
|
198
|
+
v-bind="args"
|
|
199
|
+
:items="args.items"
|
|
200
|
+
@searchSelected="handleSearchSelected"
|
|
201
|
+
/>
|
|
202
|
+
`,
|
|
203
|
+
}),
|
|
204
|
+
args: {
|
|
205
|
+
items: mockItems,
|
|
206
|
+
initialValue: 'Acme Corporation',
|
|
207
|
+
label: 'Organisation',
|
|
208
|
+
},
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export const SingleOrganization: Story = {
|
|
212
|
+
render: (args) => ({
|
|
213
|
+
components: { FdsSearchSelect },
|
|
214
|
+
setup: () => {
|
|
215
|
+
const selected = ref<Record<string, unknown> | null>(null)
|
|
216
|
+
const handleSearchSelected = (value: Record<string, unknown> | null) => {
|
|
217
|
+
selected.value = value
|
|
218
|
+
}
|
|
219
|
+
return { args, selected, handleSearchSelected }
|
|
220
|
+
},
|
|
221
|
+
template: `
|
|
222
|
+
<FdsSearchSelect
|
|
223
|
+
v-bind="args"
|
|
224
|
+
:items="args.items"
|
|
225
|
+
@searchSelected="handleSearchSelected"
|
|
226
|
+
/>
|
|
227
|
+
`,
|
|
228
|
+
}),
|
|
229
|
+
args: {
|
|
230
|
+
items: [
|
|
231
|
+
{
|
|
232
|
+
companyName: 'Acme Corporation',
|
|
233
|
+
orgNumber: '1234567890',
|
|
234
|
+
companyFqn: 'Acme Corporation | 1234567890',
|
|
235
|
+
},
|
|
236
|
+
],
|
|
237
|
+
singleItemLabel: 'Vald organisation',
|
|
238
|
+
label: 'Organisation',
|
|
239
|
+
},
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export const WithValidation: Story = {
|
|
243
|
+
render: (args) => ({
|
|
244
|
+
components: { FdsSearchSelect },
|
|
245
|
+
setup: () => {
|
|
246
|
+
const selected = ref<Record<string, unknown> | null>(null)
|
|
247
|
+
const valid = ref<string | undefined>('null')
|
|
248
|
+
const handleSearchSelected = (value: Record<string, unknown> | null) => {
|
|
249
|
+
selected.value = value
|
|
250
|
+
valid.value = value ? 'true' : 'null'
|
|
251
|
+
}
|
|
252
|
+
return { args, selected, valid, handleSearchSelected }
|
|
253
|
+
},
|
|
254
|
+
template: `
|
|
255
|
+
<FdsSearchSelect
|
|
256
|
+
v-bind="args"
|
|
257
|
+
:items="args.items"
|
|
258
|
+
:valid="valid"
|
|
259
|
+
@searchSelected="handleSearchSelected"
|
|
260
|
+
/>
|
|
261
|
+
`,
|
|
262
|
+
}),
|
|
263
|
+
args: {
|
|
264
|
+
items: mockItems,
|
|
265
|
+
label: 'Välj organisation',
|
|
266
|
+
invalidMessage: 'Vänligen välj en organisation',
|
|
267
|
+
},
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
export const WithLabelLeft: Story = {
|
|
271
|
+
render: (args) => ({
|
|
272
|
+
components: { FdsSearchSelect },
|
|
273
|
+
setup: () => {
|
|
274
|
+
const selected = ref<Record<string, unknown> | null>(null)
|
|
275
|
+
const handleSearchSelected = (value: Record<string, unknown> | null) => {
|
|
276
|
+
selected.value = value
|
|
277
|
+
}
|
|
278
|
+
return { args, selected, handleSearchSelected }
|
|
279
|
+
},
|
|
280
|
+
template: `
|
|
281
|
+
<div>
|
|
282
|
+
<FdsSearchSelect
|
|
283
|
+
v-bind="args"
|
|
284
|
+
:items="args.items"
|
|
285
|
+
@searchSelected="handleSearchSelected"
|
|
286
|
+
/>
|
|
287
|
+
</div>
|
|
288
|
+
`,
|
|
289
|
+
}),
|
|
290
|
+
args: {
|
|
291
|
+
items: mockItems,
|
|
292
|
+
label: 'Organisation',
|
|
293
|
+
labelLeft: true,
|
|
294
|
+
meta: 'Sök efter organisation',
|
|
295
|
+
},
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
export const WithAbsoluteList: Story = {
|
|
299
|
+
render: (args) => ({
|
|
300
|
+
components: { FdsSearchSelect },
|
|
301
|
+
setup: () => {
|
|
302
|
+
const selected = ref<Record<string, unknown> | null>(null)
|
|
303
|
+
const handleSearchSelected = (value: Record<string, unknown> | null) => {
|
|
304
|
+
selected.value = value
|
|
305
|
+
}
|
|
306
|
+
return { args, selected, handleSearchSelected }
|
|
307
|
+
},
|
|
308
|
+
template: `
|
|
309
|
+
<div style="position: relative; padding: 2rem;">
|
|
310
|
+
<FdsSearchSelect
|
|
311
|
+
v-bind="args"
|
|
312
|
+
:items="args.items"
|
|
313
|
+
@searchSelected="handleSearchSelected"
|
|
314
|
+
/>
|
|
315
|
+
</div>
|
|
316
|
+
`,
|
|
317
|
+
}),
|
|
318
|
+
args: {
|
|
319
|
+
items: mockItems,
|
|
320
|
+
dropdownAbsolute: true,
|
|
321
|
+
label: 'Sök organisation',
|
|
322
|
+
},
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
export const Disabled: Story = {
|
|
326
|
+
render: (args) => ({
|
|
327
|
+
components: { FdsSearchSelect },
|
|
328
|
+
setup: () => ({ args }),
|
|
329
|
+
template: '<FdsSearchSelect v-bind="args" :items="args.items" />',
|
|
330
|
+
}),
|
|
331
|
+
args: {
|
|
332
|
+
items: mockItems,
|
|
333
|
+
disabled: true,
|
|
334
|
+
label: 'Sök organisation',
|
|
335
|
+
},
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
export const EnglishLocale: Story = {
|
|
339
|
+
render: (args) => ({
|
|
340
|
+
components: { FdsSearchSelect },
|
|
341
|
+
setup: () => {
|
|
342
|
+
const selected = ref<Record<string, unknown> | null>(null)
|
|
343
|
+
const handleSearchSelected = (value: Record<string, unknown> | null) => {
|
|
344
|
+
selected.value = value
|
|
345
|
+
}
|
|
346
|
+
return { args, selected, handleSearchSelected }
|
|
347
|
+
},
|
|
348
|
+
template: `
|
|
349
|
+
<div>
|
|
350
|
+
<FdsSearchSelect
|
|
351
|
+
v-bind="args"
|
|
352
|
+
:items="args.items"
|
|
353
|
+
@searchSelected="handleSearchSelected"
|
|
354
|
+
/>
|
|
355
|
+
</div>
|
|
356
|
+
`,
|
|
357
|
+
}),
|
|
358
|
+
args: {
|
|
359
|
+
items: mockItems,
|
|
360
|
+
locale: 'en',
|
|
361
|
+
label: 'Search organization',
|
|
362
|
+
meta: 'Start typing to search',
|
|
363
|
+
singleItemLabel: 'Selected organization',
|
|
364
|
+
searchContext: { context: 'organizations', linkWord: 'of' },
|
|
365
|
+
noResultPrompt: 'No results found',
|
|
366
|
+
invalidMessage: 'Please select an organization',
|
|
367
|
+
},
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
export const WithPagination: Story = {
|
|
371
|
+
render: (args) => ({
|
|
372
|
+
components: { FdsSearchSelect },
|
|
373
|
+
setup: () => {
|
|
374
|
+
const selected = ref<Record<string, unknown> | null>(null)
|
|
375
|
+
const handleSearchSelected = (value: Record<string, unknown> | null) => {
|
|
376
|
+
selected.value = value
|
|
377
|
+
}
|
|
378
|
+
const handlePaginate = (page: number) => {
|
|
379
|
+
// eslint-disable-next-line no-console
|
|
380
|
+
console.log('Paginate to page:', page)
|
|
381
|
+
}
|
|
382
|
+
return { args, selected, handleSearchSelected, handlePaginate }
|
|
383
|
+
},
|
|
384
|
+
template: `
|
|
385
|
+
<div>
|
|
386
|
+
<FdsSearchSelect
|
|
387
|
+
v-bind="args"
|
|
388
|
+
:items="args.items"
|
|
389
|
+
@searchSelected="handleSearchSelected"
|
|
390
|
+
@paginate="handlePaginate"
|
|
391
|
+
/>
|
|
392
|
+
</div>
|
|
393
|
+
`,
|
|
394
|
+
}),
|
|
395
|
+
args: {
|
|
396
|
+
items: [
|
|
397
|
+
...mockItems,
|
|
398
|
+
{
|
|
399
|
+
companyName: 'Company 6',
|
|
400
|
+
orgNumber: '6666666666',
|
|
401
|
+
companyFqn: 'Company 6 | 6666666666',
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
companyName: 'Company 7',
|
|
405
|
+
orgNumber: '7777777777',
|
|
406
|
+
companyFqn: 'Company 7 | 7777777777',
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
companyName: 'Company 8',
|
|
410
|
+
orgNumber: '8888888888',
|
|
411
|
+
companyFqn: 'Company 8 | 8888888888',
|
|
412
|
+
},
|
|
413
|
+
{
|
|
414
|
+
companyName: 'Company 9',
|
|
415
|
+
orgNumber: '9999999999',
|
|
416
|
+
companyFqn: 'Company 9 | 9999999999',
|
|
417
|
+
},
|
|
418
|
+
{
|
|
419
|
+
companyName: 'Company 10',
|
|
420
|
+
orgNumber: '1010101010',
|
|
421
|
+
companyFqn: 'Company 10 | 1010101010',
|
|
422
|
+
},
|
|
423
|
+
],
|
|
424
|
+
page: 1,
|
|
425
|
+
totalPages: 2,
|
|
426
|
+
label: 'Sök organisation',
|
|
427
|
+
},
|
|
428
|
+
}
|